Like this I created a method to get an array of the Ids of my category bundle:
class Event
{
/**
* #ORM\ManyToMany(targetEntity="Bundle\CategoryBundle\Entity\Category")
*/
private $categories;
/**
* #return array<string, mixed>
* #Serializer\VirtualProperty()
* #Serializer\SerializedName("categories")
*/
public function getCategories(): ?array
{
if($this->categories != NULL){
return $this->categories->map(fn($a) => $a->getId())->toArray();
} else {
return null;
}
}
But instead if "id" I try to get the "name". So I simply try to change this line:
return $this->categories->map(fn($a) => $a->getName())->toArray();
But I get the error:
Attempted to call an undefined method named "getName" of class
"Bundle\CategoryBundle\Entity\Category".
Did I need to join name field before?
Related
I try to create a method that returns an array of IDs:
/**
* #ORM\OneToMany(targetEntity="App\Entity\Event", mappedBy="project")
*
* #Serializer\Expose()
*/
private $event;
public function __construct()
{
$this->enabled = false;
$this->event = new ArrayCollection();
}
/**
* #return array<string, mixed>
*
* #Serializer\VirtualProperty()
* #Serializer\SerializedName("event")
*/
public function getEvent(): ?array
{
if ($event = $this->getEvent()) {
return [
'id' => $event->getId(),
];
}
return null;
}
But I get an error message in my console:
The "selection" field with the path "event/" expects an array of ids
as value but received an array of objects instead. Is it possible that
your API returns an array serialized objects?
To fix this I tried:
public function getEvent()
{
return $this->event;
}
/**
* #return array<string, mixed>
*
* #Serializer\VirtualProperty()
* #Serializer\SerializedName("event")
*/
public function getEventData(): ?array
{
if ($event = $this->getEvent()) {
return [
'id' => $event->getId(),
];
}
return null;
}
But here I get the error message:
Attempted to call an undefined method named "getId" of class
"Doctrine\ORM\PersistentCollection".
$event is a OneToMany relationship, which mean it would be better if you renamed it $events.
$event is an ArrayCollection made of Event object.
Which mean that if you want to get an array made only of ids, you need to turn your ArrayCollection into an array of ID.
So you could use ArrayCollection map method to apply a callback on each element to return an array of id.
Example:
public function getEventData(): ?array
{
return $this->event->map(fn($e) => $e->getId())->toArray();
}
map (from doctrine doc)
Applies the given function to each element in the collection and
returns a new collection with the elements returned by the function.
We use toArray to turn the ArrayCollection into an array.
I want to make alternative way for making stored procedures by using Doctrine but I am stuck, could any one help me?
Example stored procedure to be formed:
CREATE PROCEDURE catalog_get_department_details(IN DepartmentName)
BEGIN
SELECT name, description
FROM
department
WHERE name = name;
Departments Entity:
/**
* #ORM\Entity(repositoryClass="AppBundle\Repository\departmentsRepository")
* #ORM\Table(name="departments")
*/
class departments
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $department_id;
/**
* #ORM\Column(type="string")
*/
private $name;
/**
* #ORM\Column(type="string", nullable=true)
*/
private $description;
/**
* #ORM\OneToMany(targetEntity="categories",mappedBy="departments")
*/
private $categories;
function __construct()
{
$this->categories = new ArrayCollection();
}
public function getDepartmentId()
{
return $this->department_id;
}
public function setDepartmentId($department_id)
{
$this->department_id = $department_id;
}
/**
* #return mixed
*/
public function getName()
{
return $this->name;
}
/**
* #param mixed $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* #return mixed
*/
public function getDescription()
{
return $this->description;
}
/**
* #param mixed $description
*/
public function setDescription($description)
{
$this->description = $description;
}
The scenario is when the route is /index/departmentname/Regional ;
my DefaultController will capture Regional as parameter
DefaultController:
class DefaultController extends Controller
{
/**
* #Route ("/index/department/{department_name}")
*/
function departmentAction($department_name)
{
// accessing departmentsRepository
$categoriesRepository = $this->getDoctrine()->getManager()
->getRepository('AppBundle:departments');
$categoriesRepository->getDepartmentDetails($department_name);
}
departmentsRepository:
class departmentsRepository extends \Doctrine\ORM\EntityRepository
{
function getDepartmentDetails($departmentName)
{
$em=$this->getEntityManager()->getRepository('AppBundle:departments');
$qb=$em->createQueryBuilder('dep');
$qb->select('dep.name','dep.description');
$qb->where("dep.name=$departmentName");
When I call var_dump($qb->getDQL());die; it shows me exactly what I want:
SELECT dep.name, dep.description FROM AppBundle\Entity\departments dep WHERE dep.name=Regional
I then execute it by calling
$qb->getQuery()->execute();
But I receive the following error:
[Semantical Error] line 0, col 86 near 'Regional': Error: 'Regional'
is not defined.
Any idea what I'm doing wrong?
Your dep.name value isn't being escaped. You would expect the query to look like this instead:
WHERE dep.name='Regional'
But what you should be doing, and what is safer, is binding that to a parameter, like so:
$em = $this->getEntityManager()->getRepository('AppBundle:departments');
$qb = $em->createQueryBuilder('dep');
$qb->select('dep.name', 'dep.description');
$qb->where("dep.name = :departmentName");
$qb->setParameter('departmentName', $departmentName);
Doctrine will handle the escaping for you, and safely. This also allows you to avoid SQL injection attacks. Also since you are already in your departments repository you should be able to use the _em value as a shortcut, and also not have to re-specify the departments entity, like so:
$qb = $this->_em->createQueryBuilder('dep');
$qb->select('dep.name', 'dep.description');
$qb->where("dep.name = :departmentName");
$qb->setParameter('departmentName', $departmentName);
Side not, in your controller action you are calling the repository function but not actually saving the results to any variable.
I have this entity definition:
class Operator
{
...
/**
* #var array
* #ORM\Column(type="text", nullable=true)
*/
private $prefix;
/**
* #param $prefix
* #return $this
*/
public function addPrefix($prefix)
{
if (!in_array($prefix, $this->prefix, true)) {
$this->prefix[] = $prefix;
}
return $this;
}
/**
* #param array $prefixes
* #return $this
*/
public function setPrefix(array $prefixes)
{
$this->prefix = array();
foreach($prefixes as $prefix) {
$this->addPrefix($prefix);
}
return $this;
}
/**
* #return array The prefixes
*/
public function getPrefix()
{
$prefix = is_array($this->prefix) ? $this->prefix : ['04XX'];
return array_unique($prefix);
}
...
}
I am using EasyAdminBundle for manage this entity in the backend so here is the config for it:
easy_admin:
entities:
Operator:
class: PlatformAdminBundle\Entity\Operator
...
form:
fields:
...
- { property: 'prefix', label: 'prefix' }
Any time I try to create a new Operator I run into this error:
ContextErrorException: Notice: Array to string conversion
I can't find where is the problem since I am using the same on a User entity that inherit from BaseUser (from FOSUser) and it works. This is how it looks like for User entity and should be the same for Operator:
What I am missing? Can any give me some advice? I am stuck!
Orm prefix column should be array type.
/**
* #var array
* #ORM\Column(type="array", nullable=true)
*/
private $prefix;
And run
php app/console doctrine:schema:update --force
A simple problem that has many answers on SO... Yet none of them work on my project... So I get this error:
ContextErrorException: Catchable Fatal Error: Argument 1 passed to Doctrine\Common\Collections\ArrayCollection::__construct() must be of the type array, object given, called in C:\wamp\www\Dig\front\vendor\doctrine\orm\lib\Doctrine\ORM\UnitOfWork.php on line 528 and defined in C:\wamp\www\Digidis\front\vendor\doctrine\collections\lib\Doctrine\Common\Collections\ArrayCollection.php line 48
This happens everytime I create a new Email and try to save it in the database. The email is in a relationship with skin..
This is how I try to save it:
/**
* #Route("/{skin_id}/new", name="cms_email_new")
* #Method({"GET"})
* #Template()
*/
public function newAction($skin_id) {
$skin = $this->getRepository('ProjectSkinBundle:Skin')->find($skin_id);
$item = new Email();
$form = $this->createForm(new EmailType($this->container->getParameter("langs")), $item);
return array('form' => $form->createView(), 'item' => $item, 'skin' => $skin_id);
}
/**
* #Route("/{skin_id}/save", name="cms_email_save")
* #Template("ProjectUserBundle:EmailAdmin:new.html.twig")
* #Method({"POST"})
*/
public function saveAction(Request $request, $skin_id) {
$skin = $this->getRepository('ProjectSkinBundle:Skin')->find($skin_id);
$item = new Email();
$type = new EmailType($this->container->getParameter("langs"));
$form = $this->createForm($type, $item);
$form->handleRequest($request);
$em = $this->getEntityManager();
if ($form->isValid()) {
$this->upload($form, $item);
$skin->setEmailId($item);
$item->setSkin($skin); /// the error is here
$em->persist($skin);
$em->persist($item);
$em->flush();
return $this->redirect($this->generateUrl('cms_skin_email_edit', array('skin_id' => $skin_id)));
}
return array('form' => $form->createView(), 'item' => $item);
}
So by doing some testing I found out that this line is causing the problem:
$item->setSkin($skin);
Without this line everything works like a charm. However I need this line to work.
So this is the Entity with the setSkin method:
/**
*
* #ORM\OneToMany(targetEntity="Project\SkinBundle\Entity\Skin", mappedBy="email_id")
* #ORM\JoinColumn(name="skin", referencedColumnName="id")
*/
protected $skin;
/**
* Set skin
*
* #param \Project\SkinBundle\Entity\Skin $skin
* #return Email
*/
public function setSkin(\Project\SkinBundle\Entity\Skin $skin = null)
{
$this->skin = $skin;
return $this;
}
/**
* Get skin
*
* #return \Project\SkinBundle\Entity\Skin
*/
public function getSkin()
{
return $this->skin;
}
So what can I do to make his object become an array?
I have this little line but id doesnt help me :
public function __construct()
{
$this->skin = new ArrayCollection();
}
The form for creating a new email is this:
public function buildForm(FormBuilderInterface $builder, array $option) {
$builder->add('title', 'text', array('label' => 'cms.Title'));
}
public function getDefaultOptions(array $options) {
return array(
'data_class' => 'Project\UserBundle\Entity\Email',
);
}
public function getName()
{
return 'my_email';
}
}
The $skin property is a One to Many relationship in your doctrine mapping. Doctrine is expecting an ArrayCollection object or array.
This is causing your exception:
/**
*
* #ORM\OneToMany(targetEntity="Project\SkinBundle\Entity\Skin", mappedBy="email_id")
* #ORM\JoinColumn(name="skin", referencedColumnName="id")
*/
protected $skin;
If you need a one to many relationship you should pass an array instead of a single object because you can have multiple skins. If you want a one to one relationship (a single skin per entity) you should change you doctrine mapping.
Possible solution 1:
public function __construct()
{
$this->skin = new ArrayCollection();
}
/**
* Set skin
*
* #param \Project\SkinBundle\Entity\Skin $skin
* #return Email
*/
public function setSkin(array $skin)
{
$this->skin = $skin;
return $this;
}
/**
* Get skin
*
* #return \Project\SkinBundle\Entity\Skin[]|ArrayCollection
*/
public function getSkin()
{
return $this->skin;
}
Possible solution 2 (OneToOne, but this could be a ManyToOne, that's up to you):
/**
*
* #ORM\OneToOne(targetEntity="Project\SkinBundle\Entity\Skin", mappedBy="email_id")
* #ORM\JoinColumn(name="skin", referencedColumnName="id")
*/
protected $skin;
You could prevent the error by simply wrapping the object (which you should confirm is an "Email" object) in an array:
$item->setSkin(array($skin));
However something else is going wrong here and the error is coming from when Doctrine compiles a unit-of-work to save to the database.
The skin relationship declartion of the Email entity is incorrect. The Join column declaration should be on the manyToOne side, so Email should be:
Email entity:
/*
* #ORM\OneToMany(targetEntity="Project\SkinBundle\Entity\Skin", mappedBy="email")
*/
protected $skins;
Skin entity:
/*
* #ORM\ManyToOne(targetEntity="Project\SkinBundle\Entity\Email", inversedBy="emails")
* #ORM\JoinColumn(name="email_id", referencedColumnName="id")
*/
protected $email
Running app/console doctrine:generate:entities SkinBundle:Email (or however the entity is referenced) will then generate a methods like addSkin(Skin $skin) which are used to add objects to the relationship.
More info can be found on Doctrine associations.
For a one to many relationship you should have and be using methods addSkin() and removeSkin() in place of setSkin(). Also, as a convention I recommend pluralising collection properties i.e. $skin -> $skins. It makes the code clearer and errors in declaring and using entities become more obvious.
So for your entity that has many $skins I would recommend:
/**
* #var \Doctrine\Common\Collections\Collection
*/
private $skins;
/**
* Constructor
*/
public function __construct()
{
$this->skins = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add skin
*
* #param Skin $skin
* #return Email
*/
public function addSkin(Skin $skin)
{
$this->skins[] = $skin;
return $this;
}
/**
* Remove skin
*
* #param Skin $skin
*/
public function removeSkin(Skin $skin)
{
$this->skins->removeElement($skin);
}
/**
* Get skins
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getSkins()
{
return $this->skins;
}
Then where you have:
$item->setSkin($skin);
You should instead use:
$item->addSkin($skin);
I'm have a small project in Symfony2 and doctrine, and I'm trying to update 2 related entities:
Members & cars
$carMembers = $car->getMembers();
echo count($carMembers); // --> show 2
echo get_class(carMembers[0]); // --> show MyCars\WSBundle\Entity\Member
$car->removeMember($member);
$em->persist($car);
$em->flush();
$carMembers= $car->getMembers();
echo count($carMembers); // --> show 1
echo get_class(carMembers[0]); // --> show MyCars\WSBundle\CarsController !!!
there is my Entities:
Car
/**
* #ORM\ManyToMany(targetEntity="Member", mappedBy="cars")
*/
private $members;
/**
* Remove Member
*
* #param MyCars\WSBundle\Entity\Member $member
*/
public function removeMember(\MyCars\WSBundle\Entity\Member $member)
{
$this->members->removeElement($member);
$member->removeCar($this);
}
Member
/**
* #ORM\ManyToMany(targetEntity="Car", cascade={"persist"})
* #ORM\JoinTable(name="cars_membres",
* joinColumns={#ORM\JoinColumn(name="member_id", referencedColumnName="member_id")},
* inverseJoinColumns={#ORM\JoinColumn(name="car_id", referencedColumnName="car_id")}
* )
*/
private $cars;
I think what you're looking for is orphanRemoval relation option.
#ORM\ManyToMany(targetEntity="Car", cascade={"persist"}, orphanRemoval=true)
So when you remove item from collection and flush entity manager it will remove relation record from database...
Make sure to initialise the ArrayCollection in the class constructor, if you want to use the functions add, contains or removeElement
<?php
// ...
use Doctrine\Common\Collections\ArrayCollection;
class Car
{
/**
* #MongoDB\Id
*/
protected $members;
/**
* General constructor
*/
public function __construct()
{
$this->members = new ArrayCollection();
}
/**
* #param Member $member
* #return $this
*/
public function addMember(Member $member)
{
if (!$this->hasMember($member)) {
$this->members->add($member);
}
return $this;
}
/**
* #param Member $member
* #return $this
*/
public function removeMember(Member $member)
{
if ($this->hasMember($member)) {
$this->members->removeElement($member);
}
return $this;
}
/**
* #return mixed
*/
public function getMembers()
{
return $this->tags;
}
/**
* #param Member $member
* #return mixed
*/
public function hasTag(Member $member)
{
return $this->members->contains($member);
}
}
Which Collection do you use? Do you use \Doctrine\ArrayCollecion?
Are you sure that you are removing the same member object instance?
removeElement() method removes an object from the collection only if it is the same instance.
here is the method (note the last parameter (true) in the array_search method:
public function removeElement($element)
{
$key = array_search($element, $this->_elements, true);
if ($key !== false) {
unset($this->_elements[$key]);
return true;
}
return false;
}