From 71c038a9a06cce625d672ad2fe2200183f64f263 Mon Sep 17 00:00:00 2001 From: Brandon Shipley Date: Wed, 10 Sep 2025 22:06:12 -0700 Subject: [PATCH] start of variant values --- ...06074703_CreateProductSkuVariantValues.php | 37 ++++++ src/Controller/ProductSkusController.php | 42 +++++-- src/Model/Entity/ProductSkuVariantValue.php | 39 +++++++ .../Table/ProductSkuVariantValuesTable.php | 109 ++++++++++++++++++ templates/ProductSkus/add.php | 10 +- templates/ProductSkus/view.php | 41 +++++-- .../ProductSkuVariantValuesFixture.php | 37 ++++++ 7 files changed, 290 insertions(+), 25 deletions(-) create mode 100644 config/Migrations/20250906074703_CreateProductSkuVariantValues.php create mode 100644 src/Model/Entity/ProductSkuVariantValue.php create mode 100644 src/Model/Table/ProductSkuVariantValuesTable.php create mode 100644 tests/Fixture/ProductSkuVariantValuesFixture.php diff --git a/config/Migrations/20250906074703_CreateProductSkuVariantValues.php b/config/Migrations/20250906074703_CreateProductSkuVariantValues.php new file mode 100644 index 0000000..16d3f86 --- /dev/null +++ b/config/Migrations/20250906074703_CreateProductSkuVariantValues.php @@ -0,0 +1,37 @@ +table('product_sku_variant_values', ['id' => false, 'primary_key' => ['id']]); + $table->addColumn('id', 'uuid', [ + 'default' => null, + 'null' => false, + ]); + $table->addColumn('product_sku_id', 'uuid', [ + 'default' => null, + 'null' => false, + ]); + $table->addColumn('product_category_variant_id', 'uuid', [ + 'default' => null, + 'null' => false, + ]); + $table->addColumn('product_category_variant_option_id', 'uuid', [ + 'default' => null, + 'null' => false, + ]); + $table->create(); + } +} diff --git a/src/Controller/ProductSkusController.php b/src/Controller/ProductSkusController.php index f57a611..fe37e93 100644 --- a/src/Controller/ProductSkusController.php +++ b/src/Controller/ProductSkusController.php @@ -50,7 +50,12 @@ class ProductSkusController extends AppController */ public function view($id = null) { - $productSku = $this->ProductSkus->get($id, contain: ['Products']); + $productSku = $this->ProductSkus->get($id, contain: [ + 'Products', + 'ProductSkuVariantValues', + 'ProductSkuVariantValues.ProductCategoryVariants', + 'ProductSkuVariantValues.ProductCategoryVariantOptions', + ]); $this->set(compact('productSku')); } @@ -91,30 +96,43 @@ class ProductSkusController extends AppController if ($this->request->is('post')) { $postedSkus = $this->request->getData(); $saveOptions = [ - 'associated' => [], + 'associated' => [ + 'ProductSkuVariantValues', + ], ]; - + $finalPostData = []; $postedSkus = Hash::insert($postedSkus, '{n}.product_id', $productId); foreach ($postedSkus as $postedSkuCnt => $postedSku) { - if ($postedSku['add'] ?? false) { + if (!isset($postedSku['add']) || !$postedSku['add']) { + unset($productSkus[$postedSkuCnt]); + continue; } - unset($postedSkus[$postedSkuCnt]); - if ($productSkus[$postedSkuCnt] ?? false) { - unset($productSkus[$postedSkuCnt]); - } + $finalPostData[$postedSkuCnt] = $postedSku; } - if (!$productSkus || !$postedSkus) { $this->Flash->error('Nothing to save! Add at least one SKU next time.'); return; } - $productSkus = $table->patchEntities($productSkus, $postedSkus, $saveOptions); - if ($table->saveManyOrFail($productSkus, $saveOptions)) { - $this->Flash->success(__(count($productSkus) . ' New SKUs have been saved.')); + + $productSkus = $table->patchEntities($productSkus, $finalPostData, $saveOptions); + $errors = []; + $successes = []; + foreach ($productSkus as $productSkuToSave) { + if (!$table->save($productSkuToSave, $saveOptions)) { + Log::debug(print_r('$productSkuToSave->getErrors()', true)); + Log::debug(print_r($productSkuToSave->getErrors(), true)); + + continue; + } + $successes[] = $productSkuToSave; + } + + if ($successes) { + $this->Flash->success(__(count($successes) . ' New SKUs have been saved.')); return $this->redirect(['action' => 'index']); } diff --git a/src/Model/Entity/ProductSkuVariantValue.php b/src/Model/Entity/ProductSkuVariantValue.php new file mode 100644 index 0000000..15ce82b --- /dev/null +++ b/src/Model/Entity/ProductSkuVariantValue.php @@ -0,0 +1,39 @@ + + */ + protected array $_accessible = [ + 'product_sku_id' => true, + 'product_category_variant_id' => true, + 'product_category_variant_option_id' => true, + 'product_skus' => true, + 'product_category_variant' => true, + 'product_category_variant_option' => true, + ]; +} diff --git a/src/Model/Table/ProductSkuVariantValuesTable.php b/src/Model/Table/ProductSkuVariantValuesTable.php new file mode 100644 index 0000000..c0edd89 --- /dev/null +++ b/src/Model/Table/ProductSkuVariantValuesTable.php @@ -0,0 +1,109 @@ + newEntities(array $data, array $options = []) + * @method ProductSkuVariantValue get(mixed $primaryKey, array|string $finder = 'all', CacheInterface|string|null $cache = null, Closure|string|null $cacheKey = null, mixed ...$args) + * @method ProductSkuVariantValue findOrCreate($search, ?callable $callback = null, array $options = []) + * @method ProductSkuVariantValue patchEntity(EntityInterface $entity, array $data, array $options = []) + * @method array patchEntities(iterable $entities, array $data, array $options = []) + * @method ProductSkuVariantValue|false save(EntityInterface $entity, array $options = []) + * @method ProductSkuVariantValue saveOrFail(EntityInterface $entity, array $options = []) + * @method iterable|ResultSetInterface|false saveMany(iterable $entities, array $options = []) + * @method iterable|ResultSetInterface saveManyOrFail(iterable $entities, array $options = []) + * @method iterable|ResultSetInterface|false deleteMany(iterable $entities, array $options = []) + * @method iterable|ResultSetInterface deleteManyOrFail(iterable $entities, array $options = []) + */ +class ProductSkuVariantValuesTable extends Table +{ + /** + * Initialize method + * + * @param array $config The configuration for the Table. + * @return void + */ + public function initialize(array $config): void + { + parent::initialize($config); + + $this->setTable('product_sku_variant_values'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('ProductSkus', [ + 'className' => 'CakeProducts.ProductSkus', + 'foreignKey' => 'product_sku_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('ProductCategoryVariants', [ + 'className' => 'CakeProducts.ProductCategoryVariants', + 'foreignKey' => 'product_category_variant_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('ProductCategoryVariantOptions', [ + 'className' => 'CakeProducts.ProductCategoryVariantOptions', + 'foreignKey' => 'product_category_variant_option_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param Validator $validator Validator instance. + * @return Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->uuid('product_sku_id') + ->notEmptyString('product_sku_id'); + + $validator + ->uuid('product_category_variant_id') + ->notEmptyString('product_category_variant_id'); + + $validator + ->uuid('product_category_variant_option_id') + ->notEmptyString('product_category_variant_option_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param RulesChecker $rules The rules object to be modified. + * @return RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn(['product_sku_id'], 'ProductSkus'), ['errorField' => 'product_sku_id']); + $rules->add($rules->existsIn(['product_category_variant_id'], 'ProductCategoryVariants'), ['errorField' => 'product_category_variant_id']); + $rules->add($rules->existsIn(['product_category_variant_option_id'], 'ProductCategoryVariantOptions'), ['errorField' => 'product_category_variant_option_id']); + + return $rules; + } +} diff --git a/templates/ProductSkus/add.php b/templates/ProductSkus/add.php index 9a30aed..994aefd 100644 --- a/templates/ProductSkus/add.php +++ b/templates/ProductSkus/add.php @@ -4,7 +4,11 @@ use function BenTools\CartesianProduct\combinations; /** * @var \App\View\AppView $this - * @var \App\Model\Entity\ProductSku[] $productSkus + * @var \App\Model\Entity\ProductSku $productSku + * @var \Cake\Collection\CollectionInterface|string[] $products + * @var array $optionMapping + * @var array $variantNameMapping + * @var array $toGetCartesianProductsFrom */ @@ -52,8 +56,8 @@ use function BenTools\CartesianProduct\combinations; $variantCnt = 0; foreach ($variantNameMapping as $singleVariantId => $singleVariantName) : ?> - Form->hidden($cnt . '.product_skus_variant_values.' . $variantCnt . '.product_category_variant_id', ['value' => $singleVariantId ?? null]); ?> - Form->hidden($cnt . '.product_skus_variant_values.' . $variantCnt . '.product_category_variant_option_id', ['value' => $combination[$singleVariantId] ?? null]); ?> + Form->hidden($cnt . '.product_sku_variant_values.' . $variantCnt . '.product_category_variant_id', ['value' => $singleVariantId ?? null]); ?> + Form->hidden($cnt . '.product_sku_variant_values.' . $variantCnt . '.product_category_variant_option_id', ['value' => $combination[$singleVariantId] ?? null]); ?>

- Html->link(__('Edit Product Skus'), ['action' => 'edit', $productSku->id], ['class' => 'side-nav-item']) ?> - Form->postLink(__('Delete Product Skus'), ['action' => 'delete', $productSku->id], ['confirm' => __('Are you sure you want to delete # {0}?', $productSku->id), 'class' => 'side-nav-item']) ?> - Html->link(__('List Product Skus'), ['action' => 'index'], ['class' => 'side-nav-item']) ?> - Html->link(__('New Product Skus'), ['action' => 'add'], ['class' => 'side-nav-item']) ?> + Html->link(__('Edit Product SKU'), ['action' => 'edit', $productSku->id], ['class' => 'side-nav-item']) ?> + Form->postLink(__('Delete Product SKU'), ['action' => 'delete', $productSku->id], ['confirm' => __('Are you sure you want to delete # {0}?', $productSku->id), 'class' => 'side-nav-item']) ?> + Html->link(__('List Product SKU'), ['action' => 'index'], ['class' => 'side-nav-item']) ?> + Html->link(__('New Product SKU'), ['action' => 'add'], ['class' => 'side-nav-item']) ?>
@@ -19,12 +19,8 @@

sku) ?>

- - - - - - + + @@ -55,6 +51,31 @@
id) ?>
product_id) ?>hasValue('product') ? $this->Html->link($productSku->product->name, ['controller' => 'Products', 'action' => 'view', $productSku->product->id]) : '' ?>
deleted) ?>
+
diff --git a/tests/Fixture/ProductSkuVariantValuesFixture.php b/tests/Fixture/ProductSkuVariantValuesFixture.php new file mode 100644 index 0000000..5879698 --- /dev/null +++ b/tests/Fixture/ProductSkuVariantValuesFixture.php @@ -0,0 +1,37 @@ +records = [ + [ + 'id' => '98b609d8-1d4f-484c-a13a-6adb7102da56', + 'product_sku_id' => '3a477e3e-7977-4813-81f6-f85949613979', + 'product_category_variant_id' => '5a386e9f-6e7a-4ae7-9360-c8e529f78d93', + 'product_category_variant_option_id' => '5a386e9f-6e7a-4ae7-9360-c8e529f78d23', + ], + ]; + parent::init(); + } +}