2016-07-20 10 views
1

J'ai un produit qui peut avoir un ou plusieurs tags.Symfony: Comment trier ArrayCollection dans une relation OneToMany (3 entités)?

Pour une raison particulière, j'ai 3 entités qui correspondent à:

  • Product
  • Tag
  • ProductTag (relation):

Je veux commander par taper mon ArrayCollection de tags. Cette collection contient ProductTag entités.

La difficulté est que je n'ai pas une propriété type dans ProductType, cette propriété est dans Tag entité.

Produit

/** 
* @ORM\OneToMany(targetEntity="ProductTag", mappedBy="product", cascade={"persist", "remove"}) 
* @Assert\Valid 
*/ 
private $tags; 

Tag

/** 
* @ORM\Column(type="string", length=15) 
*/ 
private $type; 

ProductTag

/** 
* @ORM\Column(name="Product_id", type="integer") 
* @ORM\Id 
*/ 
private $product_id; 

/** 
* @ORM\Column(name="Tag_id", type="integer") 
* @ORM\Id 
*/ 
private $tag_id; 

/** 
* @ORM\ManyToOne(targetEntity="Product", inversedBy="tags") 
* @ORM\JoinColumn(name="Product_id", referencedColumnName="Product_id") 
*/ 
private $product; 

/** 
* @ORM\ManyToOne(targetEntity="Tag") 
* @ORM\JoinColumn(name="Tag_id", referencedColumnName="Tag_id") 
*/ 
private $tag; 

La solution ci-dessous ne peut pas fonctionner parce ProductTag n'a pas une propriété type:

// Product entity 

/** 
* @ORM\OneToMany(targetEntity="ProductTag", mappedBy="product", cascade={"persist", "remove"}) 
* @ORM\OrderBy({"type" = "ASC"}) 
* @Assert\Valid 
*/ 
private $tags; 

Je voudrais faire quelque chose comme ça @ORM\OrderBy({"tag.type" = "ASC"}).

Une idée?

Merci.

--- EDIT ---

En PhpMyAdmin, je crée une vue qui obtient les données des balises et l'identifiant du produit pour chaque tags.

Puis, dans Symfony, j'ai créé une entité qui correspond à ma vue. Dans le référentiel de cette entité, j'ai créé une requête qui concatène mes tags par leur type.

public function findByProductGroupByType($productId) 
{ 
    return $this->getEntityManager() 
     ->createQuery(
      'SELECT v.tagTypeCode, v.tagType, 
       GROUP_CONCAT(v.tagCode) as tagCode, 
       GROUP_CONCAT(v.tagName) as tagName, 
       GROUP_CONCAT(v.picto) as tagPicto 
       FROM AppBundle:ProductTagView v 
       WHERE v.productId = :id 
       GROUP BY v.tagTypeCode 
       ORDER BY v.tagType ASC' 
     )->setParameter('id', $productId) 
     ->getResult(); 
} 

Pour que cela fonctionne, il est nécessaire d'installer this bundle pour que Symfony reconnaît GROUP_CONCAT.Après l'installation, ajouter ceci config.yml:

doctrine: 
    orm: 
     dql: 
      string_functions: 
       group_concat: DoctrineExtensions\Query\Mysql\GroupConcat 

La liste complète est ici: https://github.com/beberlei/DoctrineExtensions/blob/master/config/mysql.yml

La requête renvoie quelque chose comme ceci:

array (size=2) 
    0 => 
    array (size=5) 
     'tagTypeCode' => string 'KFEAT' (length=5) 
     'tagType' => string 'Key Feature' (length=11) 
     'tagCode' => string 'double_sanglage' (length=15) 
     'tagName' => string 'double sanglage' (length=15) 
     'tagPicto' => string 'double_sanglage.jpg' (length=19) 
    1 => 
    array (size=5) 
     'tagTypeCode' => string 'SIZE' (length=4) 
     'tagType' => string 'Size' (length=4) 
     'tagCode' => string 'h26_ceintures,h21_ceintures' (length=27) 
     'tagName => string 'ceintures h26cm,ceintures H21 cm' (length=32) 
     'tagPicto' => string 'h26_ceintures.jpg,h21_ceintures.jpg' (length=35) 

Les balises de type SIZE sont concaténés avec , séparateur .

+0

Ajouter '' 'getTagType()' '' à votre entité ProductType puis '' '@ORM \ OrderBy ({" tagType "=" ASC "})' '' devrait fonctionner. –

Répondre

0

Vous ne pouvez pas le faire directement. Mais il y a une solution de contournement.

  • Ajouter une propriété Mots clés vous entité produit commandé:

    private $orderedTags; 
    
    public function __construct() 
    { 
        //... 
        $this->orderedTags = new \Doctrine\Common\Collections\ArrayCollection(); 
    } 
    
  • Créer une nouvelle doctrine de l'événement Listener et registre dans services.yml dans

    services: 
        my.listener: 
         class: AppBundle\EventListener\OrderedTagsListener 
         arguments: ["@doctrine.orm.entity_manager"] 
         tags: 
          - { name: doctrine.event_listener, event: postLoad } 
    
    
    
    // src/AppBundle/EventListener/OrderedTagsListener.php 
    namespace AppBundle\EventListener; 
    
    use Doctrine\ORM\Event\LifecycleEventArgs; 
    use AppBundle\Entity\Product; 
    
    class OrderedTagsListener 
    { 
        private $em; 
    
        public function __construct($em) 
        { 
         $this->em = $em; 
        } 
    
        public function postPersist(LifecycleEventArgs $args) 
        { 
         $product = $args->getEntity(); 
    
         // Retrieve your tags ordered with a query defined in your tags repository 
         $orderedTags = $this->em->getManager()->getRepository('AppBundle:Tags')->getOrderedTags($product); 
    
         $product->setOrderedTags(); 
        } 
    } 
    
+0

Merci pour votre réponse, je n'ai pas testé mais cela semble être une solution correcte. En attendant, j'ai créé une vue dans PhpMyAdmin qui obtient toutes les données dont j'ai besoin. Ensuite, dans Symfony, j'ai créé une entité qui correspond à cette vue et j'ai créé une requête dans le Repository avec GROUP_CONCAT, GROUP BY et ORDER BY afin de trier mes tags. Je vais modifier mon post avec cette solution. – Felurian

+0

OK, n'oubliez pas de marquer la réponse comme «acceptée» pour empêcher d'autres personnes de chercher une solution. – Alsatian