I am trying to follow the advice from the doctrine docs on this page - initialising a class member with the ArrayCollection. All works well for the example given in the docs. I'm trying to do it with an inherited class but get an error saying:
Class Doctrine\Common\Collections\ArrayCollection is not a valid entity or mapped super class
Inherited class:
/**
* #Entity
* #InheritanceType("JOINED")
* #DiscriminatorColumn(name="discr", type="string")
* #DiscriminatorMap({"user" = "App_User", "group" = "App_Group"})
*/
abstract class App_Acl_Role_Abstract implements Zend_Acl_Role_Interface {
/**
* #ManyToOne(targetEntity="App_Acl_Role_Abstract", inversedBy="children", cascade={"persist"})
*/
private $parents;
/**
* #OneToMany(targetEntity="App_Acl_Role_Abstract", mappedBy="parents", cascade={"persist"})
*/
private $children;
public function __construct()
{
$this->parents = new Doctrine\Common\Collections\ArrayCollection();
$this->children = new Doctrine\Common\Collections\ArrayCollection();
}
}
Inheriting class:
/**
* #Entity
* #Table(name="App_User")
*/
class App_User extends App_Acl_Role_Abstract
{
...
}
When I move the constructor to the inheriting class all works fine. But it would be much neater to have them in the inherited abstract class. Why does it not work? Is it possible?
My bad. I stuffed up the mapping. This is the mapping I'm now using:
/**
* #ManyToMany(targetEntity="App_Acl_Role_Abstract", cascade={"persist"})
* #JoinTable(name="role_parents",
* joinColumns={#JoinColumn(name="role_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="parent_id", referencedColumnName="id", unique=true)}
* )
*/
private $parents;
/**
* #ManyToMany(targetEntity="App_Acl_Role_Abstract", cascade={"persist"})
* #JoinTable(name="role_children",
* joinColumns={#JoinColumn(name="role_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="child_id", referencedColumnName="id", unique=true)}
* )
*/
private $children;
A role should be able to have many parents and many children
Related
I want to override an Extbase Controller, e.g. news in TYPO3 v10.4. Therefore I register an XClass in my ext_locaconf.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][\GeorgRinger\News\Controller\NewsController::class] = [
'className' => \Clickstorm\CsEvents\Controller\EventController::class
];
Afterwards I want to inject my new Repository
/**
* eventDateRepository
*
* #var EventDateRepository
*/
protected $eventDateRepository = null;
/**
* Inject a eventDateRepository
*
* #param EventDateRepository $eventDateRepository
*/
public function injectEventDateRepository(EventDateRepository $eventDateRepository)
{
$this->eventDateRepository = $eventDateRepository;
}
But my eventDateRepository is null. Also when I use a constructor instead.
Even though I don't know the reason for such a behaviour, a sustainable workaround is to manually instantiate your dependencies in the initializeAction method.
In my case, this is what I wrote:
/**
* #var \TYPO3\CMS\Extbase\Service\ImageService
*/
protected $imageService;
public function initializeAction()
{
parent::initializeAction();
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
$this->imageService = $objectManager->get(\TYPO3\CMS\Extbase\Service\ImageService::class);
}
I cant get my head around how to access properties over 2 relationships with the neo4j-php-ogm library.
Say for example I have a "user" node, which connects to MANY "resource" nodes, which in return are each connected to a fixed number of predefined "MetaResource" node. The "resource" nodes have properties and the "MetaResource" nodes have the Meta-Properties of each resource type. How can I know access the properties of the "MetaResource" nodes starting from a "user" node? In Neo4j one such route looks like this:
(user)-[r:HAS_RESOURCE]->(resource)-[m:METARESOURCE]->(metaResource)
My example user entity:
/**
* #OGM\Node(label="User")
*/
class User
{
/**
* #OGM\GraphId()
* #var int
*/
private $id;
/**
* #OGM\Relationship(type="HAS_RESOURCE", direction="OUTGOING", targetEntity="\AppBundle\Entity\Resources", collection=true)
* #var ArrayCollection|\AppBundle\Entity\Resources[]
*/
protected $resources;
/**
* #return \Doctrine\Common\Collections\ArrayCollection|\AppBundle\Entity\Resources[]
*/
public function getResources()
{
return $this->resources;
}
/**
* #return \Doctrine\Common\Collections\ArrayCollection|\AppBundle\Entity\Resources[]
*/
public function getResource($name)
{
foreach($this->resources as $resource){
if($resource->getResourceType() == $name){
return $resource;
break;
}
}
}
/**
* #param AppBundle\Entity\Resources $resources
*/
public function addResource(Resources $resources)
{
if (!$this->resources->contains($resources)) {
$this->resources->add($resources);
}
}
}
My Example Resource Entity:
/**
* #OGM\Node(label="Resources")
*/
class Resources
{
/**
* #OGM\GraphId()
* #var int
*/
protected $id;
/**
* #OGM\Property(type="int")
* #var int
*/
protected $resourcecount;
/**
* #OGM\Relationship(type="METARESOURCE", direction="OUTGOING", targetEntity="\AppBundle\Entity\MetaResource", collection=false)
* #var MetaResource
*/
protected $metaResource;
/**
* #param \AppBundle\Entity\MetaResource $metaResource
*/
public function __construct(MetaResource $metaResource)
{
$this->metaResource = $metaResource;
}
public function getId()
{
return $this->id;
}
public function getResourceCount()
{
return $this->resourcecount;
}
public function setResourceCount($resourcecount)
{
$this->resourcecount = $resourcecount;
}
/**
* #return \AppBundle\Entity\MetaResource
*/
public function getMetaResource()
{
return $this->metaResource;
}
}
And my Example MetaResource Entity:
/**
* #OGM\Node(label="MetaResource")
*/
class MetaResource
{
/**
* #OGM\GraphId()
* #var int
*/
protected $id;
/**
* #OGM\Property(type="string")
* #var string
*/
protected $resourceType;
/**
* #OGM\Property(type="string")
* #var string
*/
protected $name_DE;
/**
* #OGM\Property(type="string")
* #var string
*/
protected $icon;
/**
* #OGM\Property(type="string")
* #var string
*/
protected $iconColour;
/**
* #OGM\Property(type="string")
* #var string
*/
protected $colour;
public function getResourceType()
{
return $this->resourceType;
}
public function getName_DE()
{
return $this->name_DE;
}
public function getIcon()
{
return $this->icon;
}
public function getIconColour()
{
return $this->iconColour;
}
public function getColour()
{
return $this->colour;
}
}
And finally the code from my controller, which sets up the relations:
$metaResource=$em->getRepository(MetaResource::class)->findOneBy('resourceType', 'wood');
$rWood = new Resources($metaResource);
$rWood->setResourceCount(20);
$em->persist($rWood);
$em->flush();
$user->addResource($rWood);
If I now have a look at the Neo4j webconsole, all relationships and nodes are correctly inserted.
Now, if I get the resources of a user with $user->getResources() I successfully get all the resource objects, but the "$metaResource" property is always NULL instead of the anticipated Object of my MetaResource entity. For example if I do:
foreach($user->getResources() as $resource){
var_dump($resource->getMetaResource());
}
Then it outputs only NULLs.
On the other hand, if I directly get a resource object (for example with $resource = $em->getRepository(Resources::class)->findOneById(123) ) and then try to get the connected MetaResource with $resource->getMetaResource() it works. What am I missing?
Cheers
I have made some progress regarding this use case. I'm using now a proxy generator that can handle this use case (this was a big missing part into the lib actually but takes time to implement).
So please test with the latest release 1.0.0-beta7.
I have a relation one-to-many between project and images and many-to-one between project and propriety. I would to select the procts ho have image.cover=1 and propriety.activated=1 but the code always give me all images for projects
class ProjectImage
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
*
* #ORM\ManyToOne(targetEntity="BI\AdminBundle\Entity\Project", inversedBy="images")
* #ORM\JoinColumn(nullable=false, name="id_project", referencedColumnName="id")
*/
private $idProject;
******************
class Project
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
*
* #ORM\ManyToOne(targetEntity="BI\AdminBundle\Entity\Promoteur", inversedBy="projects")
* #ORM\JoinColumn(nullable=false, name="id_promoteur", referencedColumnName="id")
*/
private $idPromoteur;
/**
*
* #ORM\ManyToOne(targetEntity="BI\AdminBundle\Entity\Governorate")
* #ORM\JoinColumn(nullable=false, name="id_governorate")
*/
private $idGovernorate;
/**
*
* #ORM\ManyToOne(targetEntity="BI\AdminBundle\Entity\Delegation")
* #ORM\JoinColumn(nullable=true, name="id_delegation")
*/
private $idDelegation;
/**
* #ORM\ManyToOne(targetEntity="BI\AdminBundle\Entity\Locality")
* #ORM\JoinColumn(nullable=true, name="id_locality")
*/
private $idLocality;
/**
* #ORM\OneToMany(targetEntity="BI\AdminBundle\Entity\ProjectImage", mappedBy="idProject",cascade={"persist", "remove", "merge"})
*/
private $images;
**********************************
class Promoteur
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity = "BI\AdminBundle\Entity\Project", mappedBy = "idPromoteur")
*/
private $projects;
On your OneToMany associations, you should use an ArrayCollection since you store can several instances of your target entity on this end. You should also import the ArrayCollection class and instanciate this collection in your constructor.
So in your Project class you may want to add something like this:
use Doctrine\Common\Collections\ArrayCollection;
/**
* #var ArrayCollection
* #ORM\OneToMany(targetEntity="BI\AdminBundle\Entity\ProjectImage",
mappedBy="idProject",cascade={"persist", "remove", "merge"})
*/
private $images;
public function __construct() {
$this->images = new ArrayCollection();
}
Then you can generate the getters and setters with app/console doctrine:generate:entities. This command will also create two additional methods addImage and removeImage to manage your collection.
Hope this will helps
I have the User entity:
class User extends Entity implements UserInterface, ProviderInterface
{
/**
* #var int
* #ORM\Id
* #ORM\Column(name="user_id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var \Doctrine\Common\Collections\Collection
* #ORM\ManyToMany(targetEntity="Application\Entity\Child", mappedBy="parents")
*/
protected $children;
...
}
And the Child entity:
class Child extends Entity
{
/**
* #var int
* #ORM\Id
* #ORM\Column(name="child_id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var \Application\Entity\Classroom
*
* #ORM\ManyToOne(targetEntity="Application\Entity\Classroom")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="classroom_id", referencedColumnName="classroom_id")
* })
*/
protected $classroom;
/**
* #var \Doctrine\Common\Collections\Collection
* #ORM\ManyToMany(targetEntity="Application\Entity\User", inversedBy="children")
* #ORM\JoinTable(name="child_parent",
* joinColumns={#ORM\JoinColumn(name="child_id", referencedColumnName="child_id")},
* inverseJoinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="user_id")}
* )
*/
protected $parents;
...
}
What I need to do is to add in the UserRepository a condition for obtaining the users whose children are in the classroom X. I haven't seen any example on making join clauses for ManyToMany relationships. Have you got any idea or good example?
Thanks in advance.
The most straightforward way would be using a DQL query, I think this one should be close to what you want:
SELECT u
FROM Application\Entity\User u
JOIN u.children ch
JOIN c.classroom cr
WHERE cr.id = :classroom
GROUP BY u
Hope this helps!
The first entity called BUNDLE
/**
* #var \Doctrine\Common\Collections\Collection of \Akademie\Course\Course
* #ManyToMany(targetEntity="Akademie\Course\Course", mappedBy="bundles")
*/
private $courses;
The second entity is called COURSE
/**
* #var \Doctrine\Common\Collections\Collection of \Akademie\Bundle\Bundle
* #ManyToMany(targetEntity="Akademie\Bundle\Bundle", inversedBy="courses")
*/
private $bundles;
/**
* #var \Doctrine\Common\Collections\Collection of \Akademie\Course\CourseDate
* #OneToMany(targetEntity="Akademie\Course\CourseDate", mappedBy="course")
*/
private $courseDates;
/**
* #var int
* #Column(type="boolean")
*/
private $hidden;
and the third is called COURSEDATE
/**
* #var \Akademie\Course\Course
* #ManyToOne(targetEntity="Akademie\Course\Course", inversedBy="courseDates")
* #JoinColumn(nullable=false)
*/
private $course;
/**
* #var \DateTime
* #Column(type="datetimetz", nullable=true)
*/
private $beginDate;
I have parameter course and I need to get all bundles, which contains this course. What's more, all other courses in that bundle has to have courseDate newer than current date and can't be hidden. Otherwise I don't want to get this bundle. I hope it is clear now...
In a repository (bundle of entity BUNDLE for example), you have to create a custom method :
public function myMethod($course){
$qb = $this->createQueryBuilder("b")
->join("b.course", "c")
->join("c.courseDates", "cd")
->Where("c = :course")
->andWhere(" cd.beginDate > :now ")
->andWhere("c.hidden = 1")// if 1 means not hidden
->setParameter(":course", $course)
->setParameter(":now", new \DateTime('now'));
And then, in your controller, you have to do something like that :
$bundles = $this->getDoctrine()->getManager()->getRepository('namespace of your BUNDLE entity')->myMethod($course);