CakePHP 3 : Filtrer des produits avec plusieurs catégories

Par Bed0sk!l, il y a 10 ans


Bonjour, je cherche a afficher une liste de produits associé à plusieurs catégories.
Actuellement :

CategoriesTable.php

$this->belongsToMany('Products', [ 'foreignKey' => 'category_id', 'targetForeignKey' => 'product_id', 'joinTable' => 'categories_products' ]);

ProdtuctsTable.php

$this->belongsToMany('Categories', [ 'foreignKey' => 'product_id', 'targetForeignKey' => 'category_id', 'joinTable' => 'categories_products' ]);

Tables SQL
categories
categories_products
products

debug d'un produit

(int) 0 => object(App\Model\Entity\Product) { 'id' => (int) 15, 'name' => 'Nom du Produit', 'description' => 'Description du produit ', 'price' => (float) 0, 'ref' => '', 'living_space' => null, 'opening_space' => null, 'nb_room' => null, 'categories' => [ (int) 0 => object(App\Model\Entity\Category) { 'id' => (int) 30, 'name' => 'catégorie 1', 'description' => '', 'order' => (int) 0, 'parent_id' => null, 'lft' => (int) 3, 'rght' => (int) 4, '_joinData' => object(Cake\ORM\Entity) { 'category_id' => (int) 30, 'id' => (int) 43, 'product_id' => (int) 15, '[new]' => false, '[accessible]' => [ '*' => true ], '[dirty]' => [], '[original]' => [], '[virtual]' => [], '[errors]' => [], '[repository]' => 'CategoriesProducts' }, '[new]' => false, '[accessible]' => [ '*' => true ], '[dirty]' => [], '[original]' => [], '[virtual]' => [], '[errors]' => [], '[repository]' => 'Categories' }, (int) 1 => object(App\Model\Entity\Category) { 'id' => (int) 33, 'name' => 'catégorie 2', 'description' => '', 'order' => (int) 1, 'parent_id' => null, 'lft' => (int) 7, 'rght' => (int) 8, '_joinData' => object(Cake\ORM\Entity) { 'category_id' => (int) 33, 'id' => (int) 44, 'product_id' => (int) 15, '[new]' => false, '[accessible]' => [ '*' => true ], '[dirty]' => [], '[original]' => [], '[virtual]' => [], '[errors]' => [], '[repository]' => 'CategoriesProducts' }, '[new]' => false, '[accessible]' => [ '*' => true ], '[dirty]' => [], '[original]' => [], '[virtual]' => [], '[errors]' => [], '[repository]' => 'Categories' }, (int) 2 => object(App\Model\Entity\Category) { 'id' => (int) 37, 'name' => 'catégorie 3', 'description' => '', 'order' => (int) 2, 'parent_id' => null, 'lft' => (int) 17, 'rght' => (int) 18, '_joinData' => object(Cake\ORM\Entity) { 'category_id' => (int) 37, 'id' => (int) 45, 'product_id' => (int) 15, '[new]' => false, '[accessible]' => [ '*' => true ], '[dirty]' => [], '[original]' => [], '[virtual]' => [], '[errors]' => [], '[repository]' => 'CategoriesProducts' }, '[new]' => false, '[accessible]' => [ '*' => true ], '[dirty]' => [], '[original]' => [], '[virtual]' => [], '[errors]' => [], '[repository]' => 'Categories' }, [...] ], '[new]' => false, '[accessible]' => [ '*' => true ], '[dirty]' => [], '[original]' => [], '[virtual]' => [], '[errors]' => [], '[repository]' => 'Products' },

(Le produit a bien N catégories)

Je ne sais pas comment effectuer une requête sur plusieurs categories_id

ex :

$products = $this->Products->find('all', [ 'contain' => [ 'Categories' => [ 'conditions' => [ 'Categories.id' => $data[0]['category_id'].','.$data[1]['category_id'].','.$data[2]['category_id'].','.$data[3]['category_id'], ] ] ] ]);

Si vous avez une piste pour filter les produits avec en paramètre un nombre N de catégories je prend
Merci

10 réponses

Bed0sk!l, il y a 10 ans

Salut, Xeta, merci pour ta réponse, cependant je n'arrive toujours pas a afficher uniquement les produits qui sont dans la sommes des 4 catégories , ma requête est probablement fausse :

$category_ids = [ $data[0]['category_id'], $data[1]['category_id'], $data[2]['category_id'], $data[3]['category_id'] ]; $products = $this->Products->find('all', [ 'contain' => [ 'Categories' => [ 'conditions' => [ 'Categories.id IN' => $category_ids, ] ] ] ]);

As tu la possibilité de m'aiguiller pour faire proprement cette requête ?

Merci

Xeta, il y a 10 ans

Tu es sûr que ceci $data[3]['category_id'] affiche bien l'id de la catégorie ? Car sa parait bizarre d'utiliser une typographie de type array alors que les résultats sont des entities.

Bed0sk!l, il y a 10 ans

Yep! :)

$data[3]['category_id'] c'est juste un tableau fait à la main pour les tests

[...] FROM `categories` `Categories` INNER JOIN `categories_products` `CategoriesProducts` ON `Categories`.`id` = ( `CategoriesProducts`.`category_id` ) WHERE ( `Categories`.`id` in (29, 33, 35, 42) AND `CategoriesProducts`.`product_id` in ( '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29' ) )
Xeta, il y a 10 ans

Et ceci ?

$products = $this->Products ->find() ->contain([ 'Categories' ]) ->where([ 'Categories.id IN' => $category_ids ]);
Bed0sk!l, il y a 10 ans

Nop!
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Categories.id' in 'where clause'

Config:

Tables SQL
categories
categories_products
`products``

CategoriesTable.php

$this->belongsToMany('Products', [ 'foreignKey' => 'category_id', 'targetForeignKey' => 'product_id', 'joinTable' => 'categories_products' ]);

ProdtuctsTable.php

$this->belongsToMany('Categories', [ 'foreignKey' => 'product_id', 'targetForeignKey' => 'category_id', 'joinTable' => 'categories_products' ]);

C'est ce qui me semble étonnant

Xeta, il y a 10 ans

Ah mais j'avais mal vue, il faut faire ta requête sur la table de jointure categories_products.
Quel est la structure de cette table ?

Bed0sk!l, il y a 10 ans

categories_products

CREATE TABLE `categories_products` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `category_id` int(11) DEFAULT NULL, `product_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

Par contre je n'ai pas créé de model pour cette table je dois en créer un ?

Xeta, il y a 10 ans

Non pas besoin en faite.

Test voir ceci :

$products = $this->Products->find(); $products->matching('Categories', function ($q) use ($category_ids) { return $q->where(['Categories.id IN' => $category_ids]); });
Bed0sk!l, il y a 10 ans

Nop toujours pas ! Merci pour ton aide,
là pour le coups la requête m'affiche la totalité des produits..
Je sèche complètement