Jerram
Jerram

Reputation: 51

Symfony2 Relationship returns null, should return object

I have run into a problem that defies all my attempts to unproblem it. Its probably simple, I have just totally exhausted myself on this one :)

Basically I want to give the user the ability to add modules (facebook id, a bio, text inputs) and assets (image logo, pdf, et al) to a page object.

I have set up a onetomany relationship for Module and Asset to Page.

Module works as expected, however Asset will not work at all: when PageController calls getAsset() from its entity, it is null. There is no error until I try to iterate over the Assets.

Also, in PageController there are the following namespace declarations:

use Linkme\SiteBundle\Entity\Module;
use Linkme\SiteBundle\Entity\Asset;

If I remove the Module declaration I get an error, but if I remove the Asset line, nothing changes. Therefore I believe the relationship is not created.

If I run

app/console doctrine:schema:create --dump-sql

then amongst others I get the following line:

ALTER TABLE Asset ADD CONSTRAINT FK_C36E75589D3B65E3 FOREIGN KEY (pageId) REFERENCES Page(id);

which makes me think the schema is correct. It as least understands Asset is related to Page

Im starting to feel I have a typo or I am totally missing something equally as obvious - any assistance on troubleshooting or other suggestions would be much appreciated!

app/console --version
Symfony version 2.0.1 - app/dev/debug

Page.php

/*
 * @ORM\OneToMany(targetEntity="Asset", mappedBy="pageId", cascade={"persist", "remove"})
 * @ORM\OrderBy({"type" = "ASC"})
 * @ORM\OrderBy({"id" = "ASC"})
 * 
 * @var ArrayCollection $assets
 */
protected $assets;

/**
 * @ORM\OneToMany(targetEntity="Module", mappedBy="pageId", cascade={"persist", "remove"})
 * @ORM\OrderBy({"type" = "ASC"})
 * @ORM\OrderBy({"id" = "ASC"})
 *
 * @var ArrayCollection $modules
 */
protected $modules;

/**
 * Set assets
 * @param Asset $assets
 */
public function setAssets(Asset $assets = null)
{
    $this->assets = $assets;
}

/**
 * Get assets
 *
 * @return Asset
 */
public function getAssets()
{
    echo '<br />Asset is '.gettype($this->assets); //   outut:  Asset is NULL
    return $this->assets;
}

/**
 * Set modules
 * @param Module $modules
 */
public function setModules(Module $modules = null)
{
    $this->modules = $modules;
}

/**
 * Get modules
 * @return Module
 */
public function getModules()
{
    echo '<br />Module is '.gettype($this->assets); //   output:  Module is object
    return $this->modules;
}

Asset.php

/**
 * @var integer $pageId
 *
 * @ORM\ManyToOne(targetEntity="Page", inversedBy="assets")
 * @ORM\JoinColumn(name="pageId", referencedColumnName="id")
 */
protected $pageId;

Module.php

/**
 * @var integer $pageId
 *
 * @ORM\ManyToOne(targetEntity="Page", inversedBy="modules")
 * @ORM\JoinColumn(name="pageId", referencedColumnName="id")
 */
protected $pageId;

PageController.php

use Linkme\SiteBundle\Entity\Module;
use Linkme\SiteBundle\Entity\Asset;

/**
 * Add modules  and assets to a page
 *
 * @Route("/{id}/wizardmodule", name="page_wizardmodule")
 * @Template()
 */
public function wizardmoduleAction($id)
{
    $em = $this->getDoctrine()->getEntityManager();
    $page = $em->getRepository('LinkmeSiteBundle:Page')->find($id);
    $modules = $page->getModules();
    $assets = $page->getAssets();        

depmod

[symfony]
    git=http://github.com/symfony/symfony.git
    version=v2.0.1

[twig]
    git=http://github.com/fabpot/Twig.git
    version=v1.1.2

[monolog]
    git=http://github.com/Seldaek/monolog.git
    version=1.0.1

[doctrine-common]
    git=http://github.com/doctrine/common.git
    version=2.1.1

[doctrine-dbal]
    git=http://github.com/doctrine/dbal.git
    version=2.1.1

[doctrine]
    git=http://github.com/doctrine/doctrine2.git
    version=2.1.1

[swiftmailer]
    git=http://github.com/swiftmailer/swiftmailer.git
    version=v4.1.1

[assetic]
    git=http://github.com/kriswallsmith/assetic.git
    version=v1.0.1

[twig-extensions]
    git=http://github.com/fabpot/Twig-extensions.git

[metadata]
    git=http://github.com/schmittjoh/metadata.git
    version=1.0.0

[SensioFrameworkExtraBundle]
    git=http://github.com/sensio/SensioFrameworkExtraBundle.git
    target=/bundles/Sensio/Bundle/FrameworkExtraBundle
    version=v2.0.1

[JMSSecurityExtraBundle]
    git=http://github.com/schmittjoh/JMSSecurityExtraBundle.git
    target=/bundles/JMS/SecurityExtraBundle
    version=v2.0.1

[SensioDistributionBundle]
    git=http://github.com/sensio/SensioDistributionBundle.git
    target=/bundles/Sensio/Bundle/DistributionBundle
    version=v2.0.1

[SensioGeneratorBundle]
    git=http://github.com/sensio/SensioGeneratorBundle.git
    target=/bundles/Sensio/Bundle/GeneratorBundle
    version=v2.0.1

[AsseticBundle]
    git=http://github.com/symfony/AsseticBundle.git
    target=/bundles/Symfony/Bundle/AsseticBundle
    version=v1.0.0

Upvotes: 1

Views: 1881

Answers (3)

Jerram
Jerram

Reputation: 51

I got it! and as I predicted, it was an incredibly annoying PEBKAC....

The relationship was not being created because the annotations were not being read, because I was missing a * on the annotations comment box..... ddddoooohhhhh!

Page.php

Before:

/*      <==========================   there is only one * here. It needs to be two: **
 * @ORM\OneToMany(targetEntity="Asset", mappedBy="pageId", cascade={"persist", "remove"})
 * @ORM\OrderBy({"type" = "ASC"})
 * @ORM\OrderBy({"id" = "ASC"})
 *
 * @var ArrayCollection $assets
 */
protected $assets;

After:

/**      <==========================   like this.
 * @ORM\OneToMany(targetEntity="Asset", mappedBy="pageId", cascade={"persist", "remove"})
 * @ORM\OrderBy({"type" = "ASC"})
 * @ORM\OrderBy({"id" = "ASC"})
 *
 * @var ArrayCollection $assets
 */
protected $assets;

I'd just like to say a big thanks to everyone who helped out with this problem.

Upvotes: 2

linuxatico
linuxatico

Reputation: 1896

This is because you don't initialize your $assets collection in your Page constructor.

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

Then I think you haven't run the doctrine:generate:entities command, it simplifies your life a little, creating get, set and add methods for every mapped field. In your case it would create a

public function addModules(Module $modules)
{
    $this->modules[] = $modules;
}

Note that actually you simply assign $modules to $this->modules, this is wrong, it's an array not a scalar.

And to add the reference to the page referred by every module you'll have to add another instruction:

public function addModules(Module $modules)
{
    $this->modules[] = $modules;
    $modules->setPage($this);
}

I've done this in my code and it works, let me know if it works for you too, bye

Linuxatico

Upvotes: 0

Olivier Dolbeau
Olivier Dolbeau

Reputation: 1204

Check this: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#one-to-many-bidirectional

Do you correctly initialize collections into your page constructor?

Upvotes: 0

Related Questions