diff --git a/app/Enums/Products/RayEnum.php b/app/Enums/Products/RayEnum.php index cf746bd..ddd32c0 100644 --- a/app/Enums/Products/RayEnum.php +++ b/app/Enums/Products/RayEnum.php @@ -13,10 +13,10 @@ enum RayEnum : int case freshlyPackaged = 3; case roastery = 4; case caterer = 5; - case creamery = 6; - case groceryStore = 7; - case frozen = 8; - case others = 9; + case creamery = 7; + case groceryStore = 8; + case frozen = 9; + case others = 10; /** * Custom added functions definition diff --git a/app/Http/Resources/ProductResource.php b/app/Http/Resources/ProductResource.php index 9ae2f2c..4c144b9 100644 --- a/app/Http/Resources/ProductResource.php +++ b/app/Http/Resources/ProductResource.php @@ -22,7 +22,7 @@ class ProductResource extends JsonResource 'user_id' => null, 'brand_id' => null, 'name' => null, - 'saw_at' => null, + 'seen_at' => null, 'source' => null, 'fair' => null, 'shop' => null, @@ -112,7 +112,7 @@ class ProductResource extends JsonResource 'user_id' => User::where('id', $this->product->user_id)->firstOrFail(), 'brand_id' => Brand::where('id', $this->product->brand_id)->firstOrFail(), 'name' => $this->product->name, - 'saw_at' => Carbon::createFromFormat('Y-m-d H:i:s', $this->product->saw_at)->format('d/m/Y'), + 'seen_at' => Carbon::createFromFormat('Y-m-d H:i:s', $this->product->seen_at)->format('d/m/Y'), 'source' => $this->product->source->label(), 'fair' => $this->product->fair, 'shop' => $this->product->shop, diff --git a/app/Models/Keyword.php b/app/Models/Keyword.php index 346f729..2607945 100644 --- a/app/Models/Keyword.php +++ b/app/Models/Keyword.php @@ -8,9 +8,9 @@ use Illuminate\Database\Eloquent\Model; /** * @property integer $id * @property string $label - * @property string $keyword_cat - * @property string $created_at - * @property string $updated_at + * @property \App\Enums\KeywordCategoryEnum $keyword_cat + * @property \Carbon\Carbon $created_at + * @property \Carbon\Carbon $updated_at * @property Keywordable[] $keywordables */ class Keyword extends Model @@ -39,7 +39,7 @@ class Keyword extends Model */ public function keywordables() { - return $this->hasMany('App\Models\Keywordable'); + return $this->hasMany(Keywordable::class); } /** diff --git a/app/Models/Product.php b/app/Models/Product.php index d0cb5e7..9c23f54 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -23,7 +23,7 @@ use Symfony\Component\HttpFoundation\StreamedResponse; * @property integer $brand_id * @property string $name * @property string $brand - * @property string $saw_at + * @property string $seen_at * @property enum $source * @property string $fair * @property string $shop @@ -62,8 +62,9 @@ class Product extends Model 'user_id', 'brand_id', 'name', + // ? FIXME: ?why is there brand here, column is not in DB. 'brand', - 'saw_at', + 'seen_at', 'source', 'fair', 'shop', @@ -108,7 +109,7 @@ class Product extends Model 'product_range' => RangeEnum::class, 'geo_area' => GeoAreaEnum::class, 'is_tasted' => 'boolean', - 'saw_at' => 'datetime:Y-m-d', + 'seen_at' => 'datetime:Y-m-d', 'created_at' => 'datetime:Y-m-d', 'updated_at' => 'datetime:Y-m-d', 'deleted_at' => 'datetime:Y-m-d', diff --git a/database/factories/ProductFactory.php b/database/factories/ProductFactory.php index 9e4c9ef..a524965 100644 --- a/database/factories/ProductFactory.php +++ b/database/factories/ProductFactory.php @@ -50,7 +50,7 @@ final class ProductFactory extends Factory 'user_id' => fake()->randomElement(User::pluck('id')), 'brand_id' => fake()->randomElement(Brand::pluck('id')), 'name' => fake()->unique()->word . " " . fake()->unique()->word, - 'saw_at' => fake()->dateTime(), + 'seen_at' => fake()->dateTime(), 'source' => $source, 'fair' => $fair, 'shop' => $shop, diff --git a/database/migrations/2023_02_23_120913_create_products_table.php b/database/migrations/2023_02_23_120913_create_products_table.php index dc63b5d..37da7c9 100644 --- a/database/migrations/2023_02_23_120913_create_products_table.php +++ b/database/migrations/2023_02_23_120913_create_products_table.php @@ -19,7 +19,7 @@ return new class extends Migration $table->bigInteger('user_id')->index(); $table->bigInteger('brand_id')->index()->comment('Marque - Required - Texte libre avec auto-suggestion sur la table elle même'); $table->string('name')->comment('Nom du produit - Required'); - $table->timestamp('saw_at')->useCurrentOnUpdate()->useCurrent()->comment('Produit vue le (champs date)'); + $table->timestamp('seen_at')->useCurrentOnUpdate()->useCurrent()->comment('Produit vue le (champs date)'); $table->unsignedTinyInteger('source')->comment('Source - Required - (valeur de l\'enum SourceEnum) -> champ SELECT'); $table->string('fair')->nullable()->comment('Salon - Affiché en front si SourceEnum = Salon Professionnel ou Salon Clients ou Salon Grand Public - Texte libre avec auto-suggestion sur la table elle même'); $table->string('shop')->nullable()->comment('Magasin - Affiché en front si SourceEnum = Magasin - Texte libre avec auto-suggestion sur la table elle même'); diff --git a/database/migrations/2023_08_14_124752_migrate_oci_tables.php b/database/migrations/2023_08_14_124752_migrate_oci_tables.php index adb4317..b65e0e9 100644 --- a/database/migrations/2023_08_14_124752_migrate_oci_tables.php +++ b/database/migrations/2023_08_14_124752_migrate_oci_tables.php @@ -1,10 +1,30 @@ truncate(); + DB::table('keywordables')->truncate(); + DB::table('keywords')->truncate(); + DB::table('products')->truncate(); + Schema::enableForeignKeyConstraints(); + if (Artisan::call('db:seed', ['--class' => 'KeywordInitSeeder']) !== 0) { + throw new \RuntimeException('Failed to seed keywords'); + } + + // * Seed a dummy user. + $this->dummyUser = User::factory()->createOne([ + 'firstname' => 'Dummy', + 'lastname' => 'User' + ]); + + // * Apply DB corrections + $this->setUniqueOnBrandName(); + $this->setJsonColumnsAsJsonOnProducts(); + $this->fixForeignKeyActionOnKeywordables(); + $this->fixForeignKeyActionOnProcesses(); + + // ! DEV: Comment this after running once, to develop a migration without remigrating every temp table. $this->createAndFillTempTables(); + // * Migrate PRODUCTS, comment all except the one you want to develop here. + $this->migrateBrands(); + $this->migrateProducts(); + + + // ! DEV: Add a die here to develop migration and prevent droping temp tables + dd('toto'); + $this->dropTempTables(); } @@ -50,6 +106,376 @@ return new class extends Migration throw new \Error('Wont rollback'); } + // - MIGRATION METHODS - + + /** + * Migrate products + * + * + * @return void + * @throws \Error In case of failure. + * @phpcs:disable Generic.Metrics.CyclomaticComplexity.MaxExceeded + */ + private function migrateProducts(): void + { + // phpcs:enable + $otherAllegations = Str::of(File::get(base_path('database/migrations/other_allegations.txt'))) + ->explode(PHP_EOL)->map(fn (string $other_allegation) => Str::of($other_allegation)->squish()) + ->unique(); + + $MOTKS = Keyword::all(); + /** @var \Illuminate\Support\Collection */ + $START_SOURCES = $this->getQuery('SOURCE')->get(); + /** @var \Illuminate\Support\Collection */ + $START_CERTIFICATIONS = $this->getQuery('CERTIFICATION')->get(); + /** @var \Illuminate\Support\Collection */ + $START_FAMILLES = $this->getQuery('FAMILLE')->get(); + /** @var \Illuminate\Support\Collection */ + $START_SECTEURS = $this->getQuery('SECTEUR')->get(); + /** @var \Illuminate\Support\Collection */ + $START_RAYONS = $this->getQuery('RAYON')->get(); + + // No need to paginate here, column name is unique. + $brands = Brand::all(); + $sources = collect(SourceEnum::cases()); + $certifications = collect(CertificationEnum::cases()); + $claims = collect(ClaimEnum::cases()); + $ranges = collect(RangeEnum::cases()); + $geo_areas = collect(GeoAreaEnum::cases()); + $origins = collect(OriginEnum::cases()); + + $index = "NUM_VEILLE_PROD"; + $query = $this->getQuery("VEILLE_PROD")->orderBy($index); + $nbRowsToMigrate = (clone $query)->count(); + $totalRowsToMigrate = $nbRowsToMigrate; + + $console = new ConsoleOutput(); + $console->writeln(''); + $progress = new ProgressBar($console, $nbRowsToMigrate); + $progress->setMessage(str_pad('Migrate Products', 24, ' ')); + $progress->setFormat(' - %message% [%bar%] %percent:3s%% %current%/%max% %elapsed:6s%/%estimated:-6s%'); + + while ($nbRowsToMigrate > 0) { + $progress->display(); + $progress->advance(1); + $row = (clone $query)->skip($totalRowsToMigrate - $nbRowsToMigrate--)->limit(1)->first(); + + $resolveAllegation = function (string $alleg) use ($claims, $otherAllegations) { + // phpcs:ignore Generic.Files.LineLength.TooLong + if ($alleg === 'Sans additif, sans colorant, sans conservateur,100% simple, sans polyphosphate,sans sel nutrite') { + return ClaimEnum::withoutAdditives; + } + if (in_array(Str::of($alleg)->squish(), $otherAllegations->all())) { + return ClaimEnum::others; + } + try { + return $claims->firstOrFail( + fn (ClaimEnum $claim) => Str::of($claim->label())->ascii()->replace(' ', '') + == Str::of($alleg)->trim()->ascii()->replace(' ', '') + ); + } catch (\Exception) { + dump( + $alleg, + $claims->map(fn (ClaimEnum $claim) => $claim->label()) + ); + throw new \Error("allegation `{$alleg}` no found"); + } + }; + $resolveOrigin = function (string $ori) use ($origins) { + if ( + in_array(Str::of($ori)->squish(), [ + 'N??,??lev?? et pr??par?? en France', + 'N???,???lev??? et pr???par??? en France' + ]) + ) { + return ClaimEnum::others; + } + try { + return $origins->firstOrFail( + fn (OriginEnum $origin) => Str::of($origin->label())->ascii()->replace(' ', '') + == Str::of($ori)->trim()->ascii()->replace(' ', '') + ); + } catch (\Exception) { + dump( + $ori, + $origins->map(fn (OriginEnum $origin) => $origin->label()) + ); + throw new \Error("origin `{$ori}` no found"); + } + }; + $resolveMotk = function (string $motk) use ($MOTKS) { + // * Uu OMG !!! + if ($motk === 'Gain de temps Nomadisme') { + return $MOTKS->where('label', 'Gain de temps') + ->where('keyword_cat', KeywordCategoryEnum::productPracticality)->firstOrFail(); + } + if ($motk === 'Vari??t?? des sens') { + return $MOTKS->where('label', 'Variété des sens') + ->where('keyword_cat', KeywordCategoryEnum::productPleasure)->firstOrFail(); + } + if ($motk === 'V??g??tal') { + return $MOTKS->where('label', 'Végétal') + ->where('keyword_cat', KeywordCategoryEnum::productHealth)->firstOrFail(); + } + try { + return $MOTKS->firstOrFail( + fn (Keyword $keyword) => Str::of($keyword->label)->ascii()->replace(' ', '') + == Str::of($motk)->trim()->ascii()->replace(' ', '') + ); + } catch (\Exception) { + dump( + $motk, + $MOTKS->pluck('label') + ); + throw new \Error("keyword `{$motk}` no found"); + } + }; + + // FIXME: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9740 . + if (empty($row->MARQUE)) { + continue; + } + // FIXME: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9750 . + if (empty($row->NUM_RESEAU)) { + continue; + } + // FIXME: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9758 . + if (empty($row->NUM_SECTEUR)) { + continue; + } + // FIXME: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9760 . + if (empty($row->NUM_RAYON)) { + continue; + } + // FIXME: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9767 . + if (empty($row->NUM_FAMILLE)) { + continue; + } + + $brandName = Str::of($row->MARQUE)->slug()->studly(); + /** name is unique on brand */ + $brand = null; + try { + $brand = $brands->where('name', $brandName)->firstOrFail(); + } catch (\Exception) { + throw new \Error("brand` {$brandName}` not found"); + } + $url = $row->URL ? Str::of(url($row->URL))->lower() : null; + $date_saisie = $row->DATE_SAISIE ? $this->tryToParseCarbon($row->DATE_SAISIE, true) : null; + $is_tasted = Str::of($row->DEGUSTER_O_N)->lower() === 'o' ? true : false; + $claimList = collect([ + $row->ALLEG0, $row->ALLEG1, $row->ALLEG2 + ])->filter()->map(fn (string $alleg) => $resolveAllegation($alleg)); + $originList = collect([ + $row->ORI0, $row->ORI1, $row->ORI2 + ])->filter()->map(fn (string $origin) => $resolveOrigin($origin)); + $keywordsList = collect([ + $row->MOTK0, $row->MOTK1, $row->MOTK2, $row->MOTK3, $row->MOTK4, $row->MOTK5 + ])->filter()->map(fn (string $motk) => $resolveMotk($motk)); + + $sourceEnum = null; + if ($row->NUM_SOURCE) { + $sourceEnum = $sources->firstOrFail(fn (SourceEnum $source) => $source->value() == $row->NUM_SOURCE); + } + + $certificationEnum = null; + if ($row->CERTIFICATION) { + $certificationEnum = $certifications->firstOrFail( + fn (CertificationEnum $certification) => $certification->value() == $row->CERTIFICATION + ); + } + + $distributionNetwork = $row->NUM_RESEAU ? DistributionNetworkEnum::from($row->NUM_RESEAU) : null; + $ray = $row->NUM_RAYON ? RayEnum::from($row->NUM_RAYON) : null; + $product_range = null; + if ($row->NUM_FAMILLE) { + $product_range = $ranges->firstOrFail( + fn (RangeEnum $range) => $range->value() == $row->NUM_FAMILLE + ); + } + $geo_area = null; + if ($row->NUM_SECTEUR) { + $geo_area = $geo_areas->firstOrFail( + fn (GeoAreaEnum $geoArea) => $geoArea->value() == $row->NUM_SECTEUR + ); + } + + $claim = null; + if ($row->COMP_ALLEG) { + try { + $claim = $resolveAllegation($row->COMP_ALLEG); + } catch (\Exception) { + throw new \Error("`{$row->COMP_ALLEG}` not found"); + } + } + + /** @var \App\Models\Product $product */ + $product = Product::query()->where('id', $row->{$index})->firstOrNew(); + $product->id = $row->NUM_VEILLE_PROD; + $fill = [ + 'brand_id' => $brand->id, + 'catalogue' => $row->CATALOGUE, + 'certification' => $certificationEnum, + 'comment' => $row->COMM_LIBRE, + 'distribution_network' => $distributionNetwork, + 'fair' => $row->SALON, + 'geo_area' => $geo_area, + 'name' => $row->NOM, + 'product_range' => $product_range, + 'ray' => $ray, + 'shop' => $row->MAGASIN, + 'source' => $sourceEnum, + 'pvc' => $row->PVC, + 'weight' => $row->POIDS, + 'is_tasted' => $is_tasted, + 'gencod' => $row->GENCOD, + 'url' => $url, + 'claims' => $claimList, + 'specified_claim' => $claim, + 'tasters_number' => $row->NB_DEGUST, + 'origins' => $originList, + 'docs' => 'tttt', + 'picture_alt' => 'tttt', + 'picture_title' => 'tttt', + 'picture' => 'tttt', + 'user_id' => $this->dummyUser->id + ]; + if ($date_saisie) { + // ? FIXME: IS this pertinent ? + $fill['seen_at'] = $date_saisie; + $fill['created_at'] = $date_saisie; + $fill['updated_at'] = $date_saisie; + } + if (Str::of($row->SUPPRIMER_O_N)->lower() === 'o') { + $fill['deleted_at'] = $date_saisie; + } + $product->fill($fill); + if (!DB::transaction(fn () => $product->saveQuietly())) { + throw new \Error("Failed to save product {$row->NUM_VEILLE_PROD}"); + } + + $product->productKeywords()->sync($keywordsList->pluck('id')); + } //end while + $progress->finish(); + } + + /** + * Create unique brands using veille products + * + * @return void + */ + private function migrateBrands(): void + { + $query = $this->getQuery("VEILLE_PROD"); + /** @var \Illuminate\Support\Collection */ + $brands = (clone $query)->pluck('MARQUE')->filter() + ->map(fn (string $brandName) => Str::of($brandName)->slug()->studly())->unique(); + $console = new ConsoleOutput(); + $console->writeln(''); + $progress = new ProgressBar($console, $brands->count()); + $progress->setMessage(str_pad('Migrate Brands', 24, ' ')); + $progress->setFormat(' - %message% [%bar%] %percent:3s%% %current%/%max% %elapsed:6s%/%estimated:-6s%'); + // FIXME: Insert brand->filter and find from where it should be fetched. + $brands->each(function ($brandName) use ($progress) { + Brand::query()->where('name', $brandName)->firstOrNew()->fill([ + 'name' => $brandName + ])->saveQuietly(); + $progress->advance(); + }); + $progress->finish(); + } + + // - END MIGRATION METHODS - + // -- DB CORRECTIONS -- + + /** + * Set unique on brands.name + * + * @return void + */ + private function setUniqueOnBrandName(): void + { + try { + Schema::table('brands', function (Blueprint $table) { + $table->dropUnique(['name']); + }); + // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch + } catch (QueryException) { + // * Do nothing + } finally { + Schema::table('brands', function (Blueprint $table) { + $table->unique(['name']); + }); + } + } + + /** + * Correct some columns to effectively json + * + * @return void + */ + private function setJsonColumnsAsJsonOnProducts(): void + { + Schema::table('products', function (Blueprint $table) { + $table->json('origins')->nullable()->change() + ->comment('Origine - Tableau d\'Enum (entier) JSON (valeur de l\'enum OriginEnum)'); + $table->json('claims')->nullable()->change() + ->comment('Autres allégations - Tableau d\'Enum (entier) JSON (valeur de l\'enum ClaimEnum)'); + $table->json('docs')->nullable()->change() + ->comment('Docs complémentaires - Tableau de path - 0 a 5 docs PDF'); + }); + } + + /** + * Restrict foreign keys on keywordables + * + * @return void + */ + private function fixForeignKeyActionOnKeywordables(): void + { + Schema::table('keywordables', function (Blueprint $table) { + $table->dropForeign(['keyword_id']); + }); + Schema::table('keywordables', function (Blueprint $table) { + $table->foreign(['keyword_id'])->references(['id'])->on('keywords') + ->restrictOnUpdate()->cascadeOnDelete(); + }); + } + + /** + * Restrict foreign keys on processes + * + * @return void + */ + private function fixForeignKeyActionOnProcesses(): void + { + Schema::table('processes', function (Blueprint $table) { + $table->dropForeign(['user_id']); + }); + Schema::table('processes', function (Blueprint $table) { + $table->foreign(['user_id'])->references(['id'])->on('users') + ->restrictOnUpdate()->restrictOnDelete(); + }); + } + + // -- END DB CORRECTION -- + // --- LIB METHODS --- + + /** + * Get Temp DB query builder + * + * @param string $tableName + * @return \Illuminate\Contracts\Database\Query\Builder + * @throws \Error If $tableName does not exists. + */ + private function getQuery(string $tableName): Builder + { + if (!DB::table($this->getTableName($tableName))->exists()) { + throw new \Error("table {$tableName} does not exists"); + } + return DB::table($this->getTableName($tableName)); + } + /** * Get a table if it exists * @@ -107,17 +533,27 @@ return new class extends Migration */ private function createAndFillTempTables(): void { + $console = new ConsoleOutput(); foreach ($this->tableList as $tableName) { - $header = $this->fetchOciTableHeader($tableName); + $section = $console->section(); + $header = $this->fetchOciTableHeader($tableName); $this->createTable( $this->getTableName($tableName), $header ); + $message = str_pad("{$this->tablePrefix} {$tableName}", 24, ' '); + $section->write(" - {$message} -> Fetching OCI DATA.."); $content = $this->fetchOciTableContent($tableName, $header); + $section->clear(); + $progress = new ProgressBar($section, count($content)); + $progress->setMessage($message); + $progress->setFormat(' - %message% [%bar%] %percent:3s%% %current%/%max% %elapsed:6s%/%estimated:-6s%'); foreach ($content as $row) { + $progress->advance(); DB::table($this->getTableName($tableName))->insert((array)$row); } - } + $progress->finish(); + }//end foreach } /** @@ -247,12 +683,30 @@ return new class extends Migration /** * Try to parse freaking Start coq dates * - * @param string $date + * @param string $date The string date to parse. + * @param boolean $asTimestamp To force the return of a valid TIMESTAMP (in epoch). * @return \Carbon\Carbon - * @throws \Carbon\Exceptions\InvalidFormatException In case of failure. + * @throws \Error If the date cannot fit in a timestamp. */ - private function tryToParseCarbon(string $date): Carbon + private function tryToParseCarbon(string $date, bool $asTimestamp = false): Carbon { - return Carbon::parse($date); + $utcTimeZone = new DateTimeZone('UTC'); + $cDate = Carbon::parse($date, $utcTimeZone); + if ( + $asTimestamp and + $cDate->lt(Carbon::createFromTimestamp(0, $utcTimeZone)) or + $cDate->gt(Carbon::createFromTimestamp( + (new DateTime("99999/12/31 00:00:00"))->getTimestamp(), + $utcTimeZone + )) + ) { + throw new \Error("The date {$date} is cannot fit in a Timestamp"); + } + + if ($cDate->timestamp === 0) { + // * Prevent Invalid datetime format: 1292 Incorrect datetime value: '1970-01-01 00:00:00' + $cDate->addSecond(); + } + return $cDate; } }; diff --git a/database/migrations/other_allegations.txt b/database/migrations/other_allegations.txt new file mode 100644 index 0000000..8821579 --- /dev/null +++ b/database/migrations/other_allegations.txt @@ -0,0 +1,185 @@ +# EXPORT THIS FROM DB USING +# `COMP_ALLEG` NOT IN( +# 'Sans additif, sans colorant, sans conservateur,100% simple, sans polyphosphate,sans sel nutrite', +# 'Sans additif, sans colorant, sans conservateur, 100% simple, sans polyphosphate, sans sel nitrité', +# 'Produit de l\'année', +# 'Bleu Blanc Coeur, source d\'Omega 3', +# 'Sans OGM', +# 'Sans gluten', +# 'Sans Antibiotique', +# 'Vegan', +# 'Allégé', +# 'Halal, Casher', +# 'Riche en protéines, fibres, calcium…', +# 'Autres' +# ) +Agri ethique france commerce equitable +Commerce equitable +eleveurs engages, alimentation 100% vegetaux, mineraux vitamines, cereales d'origines locales, collecte de proximite, respect du bien-etre animal +Emballage produit en Vendee +Faible en MG / pauvre en sel +producteurs partenaires +Recette Vegetarienne +Sans colorant +Sans pesticides +Saumon garanti jamais congele +saumon garanti jamais congele +Creme fraiche origine france et chablis AOC +Elabore a la main, petits pois origine france +sans colorant ni conservateur , sans huile de palme +SANS COLORANT SANS HUILE DE PALME SANS EXHAUSTEUR DE GOUT +sans colorant, conservateur et huile de palme +sans colorant, conservatuer et huile de palme +VEGETAL +vegetarien +Antioxydant/ Vitamine C +equitable +Filiere cacao equitable +Ferme engagee +Filiere courte des eleveurs aux consommateurs ; +meilleur remuneration des producteurs +-25% sel +-60% de plastique +100% filets +Barquette en bois issue de cultures durables +bien eleve et nourri +COLLECTION FESTIVE +filet de poulet +fume au bois de hetre +Origine France +Sans additif, Sans conservateur +sans conservateur +sans conservateur - vegetarien +sans conservateur, colorant, arome ajoute, +sans conservateur, sans colorant, sans huile de palme, sans exhausteur de gout, sans huile hydrogenee +sans huile de palem , sans exhausteur de gout +Sans huile de palme, Sans exhausteur de gout +Sans sel nitrite ajoute +source de proteines vegetales et sources de fibres +viande 100% Filet +Eleve en plein air +certifie +Cooperative engagee +Faible en matiere grasse +Le porc Francais +Mache cultivee en Pays de la Loire +Melusines Bieres Artisanales +Pauvre en sel +Porc francais +Porc Francais, produit de Bretagne +Poulet fermier +Poulet Francais, sans conservateur ni colorant +SANS ADDITIF +Sans colorant, avec du poulet eleve au sol et bien nourri +Sans huile de palme / sans exhausteur de gout +Sans sel nitrite +Source de proteines ++ de 40 eleveurs de votre region +100 % local +100% Alimentation vegetale, minerale er vitamines +100% local, +100% local, issu de votre region +100% viande de volaille +5 min a la poele +AB +Agri cnfiance +Alimentation 100% vegetale +Alimentation 100% vegetale CLASSE A +alimentation 100% vegetale minerale et vitaminee +alimentation 100% vegetale minerale et vitamines +alimentation 100% vegetale, 50% mais +Alimentation 100% vegetale, minerale et vitamines +Alimentation 100% vegetale, Minerale et vitamines +Alimentation cereales 100% francaises +Alimentation cereales entieres 100% francaises +alimente avec 100% vegetaux mineraux et vitamines +Avec de la dinde bien nourrie +avec du poulet bien nourri +avec du poulet bien nourri, sans colorant +barquette avec 60% de plastique recycle +Barquette avec 60% recycle +Barquette cuisson +Barquettes recyclables a 60 % en carton +Bien etre animal +Bien-etre animal +Bq 100% recyclable issu de 85% de plastique recycle +Cereales entieres 100% francaises +Cereales produites localement; preparation et abattage local; j'achete local +Chair plus gouteuse +Clean label +Clean Label +Confit de France +Contribue a l'economie locale, revenu des eleveurs protege, + de 5 900 emplois soutenus en regions +cuit a l'etouffee +Eleve en France +Eleve en plein air et Emballage eco-concu -45% de plastique +Eleve en plein air, Emballage eco-concu +Elevee en plein air, Emballage eco-concu +Emballage eco-concu -45% de plastique +Engagee pour la vie de nos eleveurs, Barquette avec 60% de plastique recycle +Ethik food +Faconne traditionnellement a la main +Fait main +Faite main +Ficele a la main +Fromage AOP +fume au bois de hetre et de chene +Garantie volaille bien elevee et bien nourrie +Garantie Volaille bien elevee et bien nourrie et bien +Issu de souche rustique +J'aime manger local +Juste remuneration des eleveurs +La moins calorique +La viande du quotidien la moins calorique +moins de 2% de mG +montees a la main +Montees a la main +montees main +naturellement tendres +ne et eleve en France abattue en Allemagne +NIVEAU BIEN ETRE ANIMAL +nourri aux cereales locales +Nourri avec 100% de vegetaux, mineraux et vitamines +Nourri avec 100% vegetaux, mineraux et vitamines +Nourri avec des cereales 100% francaises +Nourrie sans OGM (<0,9%) cereales francaises, elevage respectueux, barquette 100% recyclable +Origine certifie sud ouest +Planete positive +PRET A CONSOMMER +sans antibio +sans huile de palme +Sans Huile de palme +sans huile de palme sans colorant +Sans lactose +Sans lactose, Sources de proteines +sans traitement antibiotique , aux aromes naturels, sans conservateur +Sortant a l'exterieur +Sources de proteines +Viande francaise +Volaille bien nourie +volaille francaise +volaille nourrie 100% vegetaux mineraux et vitamines +Barquette Cuisson +Cuisson facile +Elabores par nos bouchers +Eleve en large enlos +En direct de nos ateliers +extra tendre +Faite mains +Filiere responsable engagee pour vous +gigot d'agneau +les eleveurs cooperateurs; sans colorant ni conservateur +Montees main, pic inox, qualite superieur +Omega 3 +Porc Francais, fabrication savoie +qualite superieur +recette traditionnelle, sans colorant ni conservateur +Sans additif +sans os +Savoir faire boucher francais +Selectionne par nos Bouchers +Terres d'Eure et Loir +Tous engages : nourris aux cereales francaise sans OGM +Viande de cheval fraiche +100% pur beure +100% vegetal diff --git a/database/seeders/KeywordInitSeeder.php b/database/seeders/KeywordInitSeeder.php new file mode 100644 index 0000000..646a25d --- /dev/null +++ b/database/seeders/KeywordInitSeeder.php @@ -0,0 +1,197 @@ +keyword_cat = \collect(KeywordCategoryEnum::cases())[0]; + $keyword->label = "Sophistication"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[0]; + $keyword->label = "Exotisme"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[0]; + $keyword->label = "Fun"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[1]; + $keyword->label = "Clean label/naturalité"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[1]; + $keyword->label = "Végétarien/vegan"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[1]; + $keyword->label = "Bien être"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[2]; + $keyword->label = "Solidarité"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[2]; + $keyword->label = "Écologie"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[3]; + $keyword->label = "Emballage individuel"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[3]; + $keyword->label = "Facilité de mise en oeuvre"; + $keyword->saveOrFail(); + + /** + * * PRODUCTS + */ + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4]; + $keyword->label = "Sophistication"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4]; + $keyword->label = "Exotisme"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4]; + $keyword->label = "Variété des sens"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4]; + $keyword->label = "Fun"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[5]; + $keyword->label = "Minceur"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[5]; + $keyword->label = "Énergie/Bien-être"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[5]; + $keyword->label = "Cosmétique"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[6]; + $keyword->label = "Manipulation produit"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[6]; + $keyword->label = "Gain de temps"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[6]; + $keyword->label = "Nomadisme"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[7]; + $keyword->label = "Naturalité"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[7]; + $keyword->label = "Végétal"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[7]; + $keyword->label = "Médical"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[8]; + $keyword->label = "Solidarité"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[8]; + $keyword->label = "Écologie"; + $keyword->saveOrFail(); + + /** + * * PACKAGING + */ + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[9]; + $keyword->label = "Sophistication"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[9]; + $keyword->label = "Exotisme"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[9]; + $keyword->label = "Fun"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[10]; + $keyword->label = "Manipulation produit"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[10]; + $keyword->label = "Gain de temps"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[10]; + $keyword->label = "Nomadisme"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[11]; + $keyword->label = "Décor/forme"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[11]; + $keyword->label = "Matériaux"; + $keyword->saveOrFail(); + + $keyword = new Keyword(); + $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[12]; + $keyword->label = "Écologie"; + $keyword->saveOrFail(); + } +} diff --git a/database/seeders/KeywordSeeder.php b/database/seeders/KeywordSeeder.php index 5aabe81..e3c0dd2 100644 --- a/database/seeders/KeywordSeeder.php +++ b/database/seeders/KeywordSeeder.php @@ -16,186 +16,7 @@ class KeywordSeeder extends Seeder */ public function run() { - $id = 0; - /** - * * INGREDIENTS - */ - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[0]; - $keyword->label = "Sophistication"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[0]; - $keyword->label = "Exotisme"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[0]; - $keyword->label = "Fun"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[1]; - $keyword->label = "Clean label/naturalité"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[1]; - $keyword->label = "Végétarien/vegan"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[1]; - $keyword->label = "Bien être"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[2]; - $keyword->label = "Solidarité"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[2]; - $keyword->label = "Écologie"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[3]; - $keyword->label = "Emballage individuel"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[3]; - $keyword->label = "Facilité de mise en oeuvre"; - $keyword->save(); - - /** - * * PRODUCTS - */ - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4]; - $keyword->label = "Sophistication"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4]; - $keyword->label = "Exotisme"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4]; - $keyword->label = "Variété des sens"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4]; - $keyword->label = "Fun"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[5]; - $keyword->label = "Minceur"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[5]; - $keyword->label = "Énergie/Bien-être"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[5]; - $keyword->label = "Cosmétique"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[6]; - $keyword->label = "Manipulation produit"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[6]; - $keyword->label = "Gain de temps"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[6]; - $keyword->label = "Nomadisme"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[7]; - $keyword->label = "Naturalité"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[7]; - $keyword->label = "Végétal"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[7]; - $keyword->label = "Médical"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[8]; - $keyword->label = "Solidarité"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[8]; - $keyword->label = "Écologie"; - $keyword->save(); - - /** - * * PACKAGING - */ - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[9]; - $keyword->label = "Sophistication"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[9]; - $keyword->label = "Exotisme"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[9]; - $keyword->label = "Fun"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[10]; - $keyword->label = "Manipulation produit"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[10]; - $keyword->label = "Gain de temps"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[10]; - $keyword->label = "Nomadisme"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[11]; - $keyword->label = "Décor/forme"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[11]; - $keyword->label = "Matériaux"; - $keyword->save(); - - $keyword = new Keyword(); - $keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[12]; - $keyword->label = "Écologie"; - $keyword->save(); - + $this->call(KeywordInitSeeder::class); // Seeder for keywordables table. Keyword::query()->get()->each(function (Keyword $keyword) { Keywordable::factory(mt_rand(1, 3))->make()->each(function (Keywordable $keywordable) use ($keyword) { @@ -226,7 +47,7 @@ class KeywordSeeder extends Seeder $keywordable->keyword()->associate($keyword); $keywordable->keywordable_type = 'App\Models\Packaging'; $keywordable->saveOrFail(); - } + }//end if }); }); } diff --git a/resources/views/documents/product-body.blade.php b/resources/views/documents/product-body.blade.php index 6ad91b6..d663cdf 100644 --- a/resources/views/documents/product-body.blade.php +++ b/resources/views/documents/product-body.blade.php @@ -96,7 +96,7 @@ @endif - @if (isset($product->saw_at)) + @if (isset($product->seen_at))
{{ __('Téléchargez les documents :') }} {{ __('ICI') }} @@ -104,7 +104,7 @@ @endif @if (isset($product->source)) -

{{ __('Vu le : ') }}{{ $product->saw_at }}

+

{{ __('Vu le : ') }}{{ $product->seen_at }}

{{ __('Lieu : ') }}{{ $product->source }}, {{ $product->fair }}{{ $product->shop }}{{ $product->catalogue }}

{{ __('Par : ') }}{{ $product->user_id->firstname }} {{ $product->user_id->lastname }}