Bellum
Bellum

Reputation: 175

PHP : Association error using doctrine

I've got the following problem with doctrine 2: I want to join my world entity, poll entity to my player entity. So after some tries it works fine in the database, when using my custom findOneBy I'm having : tw_player.security.error.[Semantical Error] line 0, col 170 near 'polls INNER JOIN': Error: Class Tw\PlayerBundle\Entity\Player has no association named polls.

Player Entity :

<?php
namespace Tw\PlayerBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Tw\PollBundle\Entity\Poll;

/**
 * Player
 *
 * @ORM\Table(name="players")
 * @ORM\Entity(repositoryClass="Tw\PlayerBundle\Entity\PlayerRepository")
 */
class Player
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", options={"unsigned"=true})
     * @ORM\Id
     */
    private $id;

    /**
     * @var PlayerWorld
     * 
     * @ORM\OneToMany(targetEntity="PlayerWorld", mappedBy="player")
     */
    private $worlds;

    /**
     * @var PlayerPoll
     * 
     * @ORM\OneToMany(targetEntity="PlayerPoll", mappedBy="player")
     */
    private $polls;

    /**
     *  === Id === 
     */
    public function setId($id)
    {
        //if ($id !== (int) $id) 
          //  return false;

        $this->id = $id;

        return $this;
    }

    public function getId()
    {
        return $this->id;
    }

    /**
     *  === Worlds === 
     */
    public function getWorlds()
    {
        return $this->worlds ?: $this->worlds = new ArrayCollection();
    }

    public function getWorldsId()
    {
        $ids = array();
        foreach ($this->getWorlds() as $world) {
            $ids[] = $world->getWorld()->getId();
        }

        return $ids;
    }

    public function hasWorld($id)
    {
        return in_array($id, $this->getWorldsId());
    }

    public function addWorld(World $world)
    {
        if (!$this->getWorlds()->contains($world)) {
            $this->getWorlds()->add($world);
        }

        return $this;
    }

    public function removeWorld(World $world)
    {
        if ($this->getWorlds()->contains($world)) {
            $this->getWorlds()->removeElement($world);
        }

        return $this;
    }

    /**
     *  === Polls === 
     */
    public function getPolls()
    {
        return $this->polls ?: $this->polls = new ArrayCollection();
    }

    public function getPollsId()
    {
        $ids = array();
        foreach ($this->getPolls() as $poll) {
            $ids[] = $poll->getPoll()->getId();
        }

        return $ids;
    }

    public function hasPoll($id)
    {
        return in_array($id, $this->getPollsId());
    }

    public function addPoll(Poll $poll)
    {
        if (!$this->getPolls()->contains($poll)) {
            $this->getPolls()->add($poll);
        }

        return $this;
    }

    public function removePoll(Poll $poll)
    {
        if ($this->getPolls()->contains($poll)) {
            $this->getPolls()->removeElement($poll);
        }

        return $this;
    }
}

World entity

<?php
namespace Tw\PlayerBundle\Entity;

use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;

/**
 * World
 *
 * @ORM\Table(name="worlds")
 * @ORM\Entity(repositoryClass="Tw\PlayerBundle\Entity\WorldRepository")
 */
class World
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", options={"unsigned"=true})
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=6, unique=true)
     */
    private $name;

    /**
     *  === Id === 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     *  === Name === 
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    public function getName()
    {
        return $this->name;
    }
}

Poll entity

<?php
namespace Tw\PollBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Poll
 *
 * @ORM\Table(name="polls")
 * @ORM\Entity(repositoryClass="Tw\PollBundle\Entity\PollRepository")
 */
class Poll
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="title", type="string", length=255)
     */
    private $title;

    /**
     * @var Tw\PlayerBundle\Entity\World
     *
     * @ORM\ManyToOne(targetEntity="Tw\PlayerBundle\Entity\World")
     * @ORM\JoinColumn(nullable=true)
     */
    private $world;

    /**
     *  === Id === 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     *  === title === 
     */
    public function setTitle($title)
    {
        $this->title = $title;

        return $this;
    }

    public function getTitle()
    {
        return $this->title;
    }

    /**
     *  === world === 
     */
    public function setWorld($world)
    {
        $this->world = $world;

        return $this;
    }

    public function getWorld()
    {
        return $this->world;
    }
}

PlayerPoll entity

<?php
namespace Tw\PlayerBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Tw\PollBundle\Entity\Poll;

/**
 * PlayerPoll
 *
 * @ORM\Table(name="players_polls")
 * @ORM\Entity(repositoryClass="Tw\PlayerBundle\Entity\PlayerPollRepository")
 */
class PlayerPoll
{   
    /**
     * @var Player
     *
     * @ORM\Id
     * @ORM\ManyToOne(targetEntity="Player", inversedBy="polls")
     */
    private $player;

    /**
     * @var Tw\PollBundle\Entity\Poll
     *
     * @ORM\Id
     * @ORM\ManyToOne(targetEntity="Tw\PollBundle\Entity\Poll")
     */
    private $poll;

    /**
     *  === Player === 
     */
    public function setPlayer(Player $player)
    {
        $this->player = $player;

        return $this;
    }

    public function getPlayer()
    {
        return $this->player;
    }

    /**
     *  === Poll === 
     */
    public function setPoll(Poll $poll)
    {
        $this->poll = $poll;

        return $this;
    }

    public function getPoll()
    {
        return $this->poll;
    }
}

PlayerWorld Entity

<?php
namespace Tw\PlayerBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * PlayerWorld
 *
 * @ORM\Table(name="players_worlds")
 * @ORM\Entity(repositoryClass="Tw\PlayerBundle\Entity\PlayerWorldRepository")
 */
class PlayerWorld
{
    /**
     * @var integer
     *
     * @ORM\Id
     * @ORM\ManyToOne(targetEntity="Player", inversedBy="worlds")
     */
    private $player;

    /**
     * @var integer
     *
     * @ORM\Id
     * @ORM\ManyToOne(targetEntity="World")
     */
    private $world;

    /**
     *  === Player === 
     */
    public function setPlayer(Player $player)
    {
        $this->player = $player;

        return $this;
    }

    public function getPlayer()
    {
        return $this->player;
    }

    /**
     *  === World === 
     */
    public function setWorld(World $world)
    {
        $this->world = $world;

        return $this;
    }

    public function getWorld()
    {
        return $this->world;
    }

}

And finally the fonction used in the player repository

/**
 * Finds one player using various criterias
 *
 * @param array.string - criteria
 * 
 * @return Player|null
 */
public function findOneBy(array $criteria)
{   
    // build base query
    $qb = $this->createQueryBuilder('player')
               ->join('player.worlds', 'worlds')
               ->join('worlds.world',  'world')
               ->join('player.polls',  'polls')
               ->join('polls.poll',    'poll')
               ->addSelect('worlds, world, polls, poll');

    // add select criterias to query
    foreach ($criteria as $field => $value) {
        $qb->andWhere("player.$field = :$field")
           ->setParameter($field, $value);
    }

    // run query
    $q = $qb->getQuery();//->useResultCache(true, 120, 'player_'.serialize($criteria));
    $player = $q->getResult();

    // return player only if one was found
    if(is_array($player) && count($player) === 1)
        return $player[0];

    return null;
}

I've removed some not related attributes / functions. Any idea on what I'm doing wrong ? Thanks

Upvotes: 0

Views: 102

Answers (1)

Ramy Nasr
Ramy Nasr

Reputation: 2527

I don't see a reason to have PlayerPoll and PlayerWorld Entities. You only need Player, Poll and World.

Player Entity will be linking both Poll and World using $polls and $worlds properties.

You can then get the Player repository and use the standard find() to get the Player with any set of criteria you want.

Please let me know if I didn't get your question directly.

Have a look at the bidirectional references docs as well as association mapping.

Upvotes: 0

Related Questions