-1

I really hope someone can help me with this because its driving me crazy, something that should be so simple

Database Tables Example (ID is the primary column on all tables)

Exhibitors
id  |   name       |   address_line_1
3   |  Test Name   |   Test 123 Street
4   |  Test Name 2 |  Test 123 Street 1
5   |  Test Name 3 |  Test 123 Street 2
6   |  Test Name 4 |  Test 123 Street 2

Shows
id  |   name             |  location
7   |  The Greatest Show |   USA
8   |  Super Show        |   London, UK
9   |  A Great Show      |   Toronto, CA
10  |  Fab Show          |  NEC, Birmingham, UK


Links
id  |   show_id  |  exhibitor_id | agent_id | type
1   |       7    |      3        |   null   |  1
1   |       7    |      5        |   null   |  1
1   |       8    |      3        |   null   |  1
1   |       10   |      6        |   null   |  1

Now the link I'm trying to do is a manytoMany so basically, each show can have multiple exhibitors and vice versa each exhibitor can be assigned to multiple shows. The current entities are creating a whole new table called ppShowExhibLinks which I dont really want it to do but im really stuck ...

The Links table will hold different sorts of links hence the type and agent_id, so somehow I'm trying to get the relationship to do something along the lines of:

$show = new Show(); $show->getExhibitors();

This then does something like "Get all links where show_id is the current show and type is 1"

Then the reverse

$show = new Exhibitor(); $show->getShows(); This then does something like "Get all links where exhibitor_id is the current exhibitor and type is 1"

PS: I know that a new instance of the object wont have any links exhibs/shows but just to demonstate the object.

 Entities

    /**
    * @ORM\Table(name="ppShows")
    * @ORM\Entity(repositoryClass="App\Repository\ShowRepository")
    */
    class Show
    {
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255, nullable=false)
     */
    protected $name;


    /**
     * @ORM\Column(type="string", length=255, nullable=false)
     */
    protected $location;

   /**
     * @var \Doctrine\Common\Collections\Collection|Exhibitor[]
     *
     * @ORM\ManyToMany(targetEntity="Exhibitor", inversedBy="shows")
     * @ORM\JoinTable(
     *  name="ppShowExhibLinks",
     *  joinColumns={
     *      @ORM\JoinColumn(name="show_id", referencedColumnName="id")
     *  },
     *  inverseJoinColumns={
     *      @ORM\JoinColumn(name="exhibitor_id", referencedColumnName="id")
     *  }
     * )
     */
    protected $exhibitors;



********************************************


class Exhibitor
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255, nullable=false)
     */
    protected $name;

    /**
     * @ORM\Column(type="string", length=255, nullable=false)
     */
    protected $address_line_1;

   /**
     * @var \Doctrine\Common\Collections\Collection|Show[]
     *
     * @ORM\ManyToMany(targetEntity="Show", inversedBy="exhibitors")
     * @ORM\JoinTable(
     *  name="ppShowExhibLinks",
     *  joinColumns={
     *      @ORM\JoinColumn(name="show_id", referencedColumnName="id")
     *  },
     *  inverseJoinColumns={
     *      @ORM\JoinColumn(name="exhibitor_id", referencedColumnName="id")
     *  }
     * )
     */
    protected $shows;





class Link
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

     /**
     * @ORM\Column(type="integer", options={"default" : 0}, nullable=true)
     */
    protected $show_id;

     /**
     * @ORM\Column(type="integer", options={"default" : 0}, nullable=true)
     */
    protected $exhibitor_id;

    /**
     * @ORM\Column(type="integer", options={"default" : 0}, nullable=true)
     */
    protected $agent_id;

      /**
     * @ORM\Column(type="integer", options={"default" : 1}, nullable=false)
     */
    protected $type;
Koen Hollander
  • 1,687
  • 6
  • 27
  • 42
  • Are you having errors or is it just not working? I can already tell this: When using many to many you should only define @JoinTable on one side, not both. As described here: `https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/association-mapping.html#many-to-many-bidirectional` – Ciryk Popeye Jan 30 '19 at 09:05
  • Yes its not working at all, im finding it hard to get my head around it a little. – James Prince Jan 30 '19 at 09:10
  • Hi Lunin, a Junction entity, thats confusing me even more now! – James Prince Jan 30 '19 at 09:11

1 Answers1

0

You have to add a relation to Link for both Show and Exhibitor table.

Show entity:

    /**
     * One show may have many links
     * @OneToMany(targetEntity="Link", mappedBy="show")
     */
    private $links;
    // ...

    public function __construct() {
        $this->links = new ArrayCollection();
    }

Exhibitor entity

    /**
     * One Exhibitor may have many links
     * @OneToMany(targetEntity="Link", mappedBy="exhibitor")
     */
    private $links;
    // ...

    public function __construct() {
        $this->links = new ArrayCollection();
    }

Link entity:

/**
 * Many links have one product.
 * @ManyToOne(targetEntity="Show", inversedBy="links")
 * @JoinColumn(name="show_id", referencedColumnName="id")
 */
private $show;

/**
 * Many links have one exhibitor.
 * @ManyToOne(targetEntity="Exhibitor", inversedBy="links")
 * @JoinColumn(name="exhibitor_id", referencedColumnName="id")
 */
private $exhibitor;

Okay now, Show and Exhibitor are now related to each other through Many-to-Many relationship, and both related to 3rd Link entity through Many-to-One relationship. That is probably you are looking for. Now you can get all shows from exhibitor's like so

$exhibitor->getShows()

and vice versa

$show->getExibitors();

and for the last, get all links from repository

$this->linkRepository->findBy([ "show" => %show_id%, "type" => %type% ]);
Majesty
  • 2,097
  • 5
  • 24
  • 55
  • Thanks Lunin, yes this makes sense, but how does getShows() and getExhibitors() work if those methods dont exist in each entity? – James Prince Jan 30 '19 at 09:52
  • You have to add all getters/setters manually or ask Symfony to do that for you https://stackoverflow.com/questions/21317022/generating-entity-getters-and-setters-in-symfony-doctrine-orm, depending on which Symfony version do you have – Majesty Jan 30 '19 at 09:58
  • 1
    Think of it not as a manytomany Relation, since your Link Entity Contains additional Fields. Whenever thats the case, you don't just have two entities connected with a Linking table, but the Linking table is an Entity, too. In your example the Link Entity. So i.e. getExhibitors in Entity Shows would give you all exhibitors related to your Show. To get only some exhibitors you would write your own Getter getExhibitorsTypeOne i.e., that gets the exhibitors and then Filters them with criteria i.e. – Benjamin Kozlowski Jan 30 '19 at 11:47
  • Yes that makes sense Benjamin, but how would I write that getter, I'm a little confused (sorry im new to doctrine and symfony) – James Prince Jan 30 '19 at 13:08
  • @JamesPrince check the link I provided in my comment above, there is command that will generate getters for you – Majesty Jan 30 '19 at 13:18
  • Hi Lunin,Yep i tried it but im getting this Attempted to call an undefined method named "getShows" of class "App\Entity\Exhibitor". – James Prince Jan 30 '19 at 13:47
  • Then add getters and setters manually, what's the problem about that? – Majesty Jan 30 '19 at 13:51
  • But if I dont have a property in my entity for $shows .. It won't generate using the "bin/console make:entity --regenerate" command .. will it? Or am I mis understanding .. appreciate your help :) – James Prince Jan 30 '19 at 13:54
  • @JamesPrince check my answer, I've suggested you to add such a property first, and only then do the generate thing – Majesty Jan 30 '19 at 13:55
  • you do have `$shows` propert in `Exhibitors` entity, the generate command will add `getShows`, `addShow` and `removeShow` methods for you – Majesty Jan 30 '19 at 13:56
  • by the way, you should NOT use lower case naming strategy, Symfony is set to camel case by default, otherwise you have to do the switch manually – Majesty Jan 30 '19 at 13:58
  • Ahh right, think ive gone wrong ive removed the $shows property from my first post and copied using the example you very kindly gave, thanks for the info on camel casing will bare that in mind – James Prince Jan 30 '19 at 14:02
  • Yes, exactly, you should not do anything to the code you already had, just extend it with the one I provided in the answer. – Majesty Jan 30 '19 at 14:04
  • I see, ok now i've got another issue when I generate entities, its says The table with name 'symfony.ppshowexhiblinks' already exists. .. Is that because im referencing the join in both Show and Exhibitor, how do I fix that? – James Prince Jan 30 '19 at 14:10
  • Checkout official documentation https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/association-mapping.html, you are looking for `Many-to-Many Bidirectional` section, instead you tried to setup two `Many-to-Many Unidirectional` bonds. – Majesty Jan 30 '19 at 14:14
  • Thanks got it working, seems I didnt need the junction table at all .. Just needed to do a bidirectional Many To Many instead. I'll just create seperate tables for the different sort of links, which I guess is how doctrine intend for a ManyToMany to work? – James Prince Jan 30 '19 at 14:33
  • No, checkout this answer https://stackoverflow.com/questions/3542243/doctrine2-best-way-to-handle-many-to-many-with-extra-columns-in-reference-table, the brightest thought is told there `Once a relation has data, it's no more a relation!`, if `Link` entity has other fields than `show_id` and `exhibitor_id` you need an independent entity for that purpose, so you kinda start moving in a right way – Majesty Jan 30 '19 at 14:38