How to deal with array vars in Twig on EasyAdminBundle? - php

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

Related

Use service in entity

I need to use a service in one of my entities but I don't know how to get the container. My attributes $numHeure and $numSem are conversions of $dateDebut.
<?php
namespace Agnez\CoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* EdtHeure
*
* #ORM\Table(name="agnez_edt_heure")
* #ORM\Entity(repositoryClass="Agnez\CoreBundle\Repository\EdtHeureRepository")
*/
class EdtHeure
{
/**
*#var datetime
*#ORM\Column(type="datetime", name="dateDebut")
*/
private $dateDebut;
/**
*#var int
*#ORM\Column(type="int", name="numHeure")
*/
private $numHeure;
/**
*#var int
*#ORM\Column(type="int", name="numSem")
*/
private $numSem;
/**
* Set dateDebut
*
* #param \DateTime $dateDebut
*
* #return EdtHeure
*/
public function setDateDebut($dateDebut)
{
$this->dateDebut = $dateDebut;
$servicedate = $this->container->get('agnez_core.servicedate');
$this->numSem=$servicedate->numSem($date);
$this->numHeure=$servicedate->numHeure($date);
return $this;
}
}
I got the error:
Notice: Undefined property:
Agnez\CoreBundle\Entity\EdtHeure::$container
I don't think you need a service in your entity, and you should avoid it.
1) You can use a doctrine Event [documentation]
public function __construct(ServiceDate servicedate)
{
$this->servicedate = $servicedate
}
public function postUpdate(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
if (!$entity instanceof EdtHeure) {
return;
}
$entityManager = $args->getEntityManager();
// Call your service here
}
2) An other way is to call the service outside your entity
public function setDateDebut($dateDebut, $numSem, $numHeure)
And to call it outside, in a service EdtHeureUpdater. Its responsability will be to call various needed services and made change to your entity.
public function __construct(ServiceDate servicedate)
{
$this->servicedate = $servicedate
}
public function updateHeure(EdtHeure $edt, \DateTime $date)
{
$numSem = $this->servicedate->numSem($date);
$numHeure = $this->servicedate->numHeure($date)
$edt->setDateDebut($dateDebut, $numSem, $numHeure)
}

Symfony2 argument 1 passed must be a type of array, object given error

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);

Doctrine: Convert array to Doctrine entity

I am looking for a way to convert an array to doctrine Entity. I am using doctrine 2.
I have an entity class like:
class User
{
/**
* #Id
* #Column(type="integer", nullable=false)
* #GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #Column(type="string", length=255, unique=true, nullable=false)
*/
protected $email;
/**
* #Column(type="string", length=64, nullable=false)
*/
protected $password;
/**
* #var DateTime
* #Column(type="datetime", nullable=false)
*/
protected $dob;
//getter and setters
}
When I post data from a html form, I want to convert the post array to the User entity. So I have an array like
$userAsArray = array("email"=>"abc#xyz.com","password"=>"hello","dob"=>"10\20\1990");
$user = new User();
covert($userAsArray,$user) // I am looking for something like this
I am looking for a generic way to accomplish this. I have tried something like this:
function fromArray(array $array,$class){
$user = new $class();
foreach($array as $key => $field){
$keyUp = ucfirst($key);
if(method_exists($user,'set'.$keyUp)){
call_user_func(array($user,'set'.$keyUp),$field);
}
}
return $user;
}
But the problem is it sets everything as string. But for the date I want to have it as a DateTime object. Any help?
what if one of your array elements is a foreign key ? before setting entity properties, you might need to prepare foreign key attributes. This is how I accomplish similar task:
Extend Repository
<?php
namespace My\Doctrine;
use Doctrine\ORM\EntityRepository;
class Repository extends EntityRepository
{
/**
* Prepare attributes for entity
* replace foreign keys with entity instances
*
* #param array $attributes entity attributes
* #return array modified attributes values
*/
public function prepareAttributes(array $attributes)
{
foreach ($attributes as $fieldName => &$fieldValue) {
if (!$this->getClassMetadata()->hasAssociation($fieldName)) {
continue;
}
$association = $this->getClassMetadata()
->getAssociationMapping($fieldName);
if (is_null($fieldValue)) {
continue;
}
$fieldValue = $this->getEntityManager()
->getReference($association['targetEntity'], $fieldValue);
unset($fieldValue);
}
return $attributes;
}
}
Create parent Entity class :
namespace My\Doctrine;
class Entity
{
/**
* Assign entity properties using an array
*
* #param array $attributes assoc array of values to assign
* #return null
*/
public function fromArray(array $attributes)
{
foreach ($attributes as $name => $value) {
if (property_exists($this, $name)) {
$methodName = $this->_getSetterName($name);
if ($methodName) {
$this->{$methodName}($value);
} else {
$this->$name = $value;
}
}
}
}
/**
* Get property setter method name (if exists)
*
* #param string $propertyName entity property name
* #return false|string
*/
protected function _getSetterName($propertyName)
{
$prefixes = array('add', 'set');
foreach ($prefixes as $prefix) {
$methodName = sprintf('%s%s', $prefix, ucfirst(strtolower($propertyName)));
if (method_exists($this, $methodName)) {
return $methodName;
}
}
return false;
}
}
Usage, a method in your repo:
$entity = new User();
$attributes = array(
"email" =>"abc#xyz.com",
"password" =>"hello",
"dob" =>"10\20\1990"));
$entity->fromArray($this->prepareAttributes($attributes));
$this->getEntityManager()->persist($entity);
$this->getEntityManager()->flush();
Why not write your setDob() method to detect a string and convert it if necessary
public function setDob($dob) {
if (!$dob instanceof DateTime) {
$dob = new DateTime((string) $dob); // or however you want to do the conversion
}
$this->dob = $dob;
}
You are trying to de-serialize
I would check out the Zend Framework 2 Stdlib component. You do not need to use the whole framework.
The Hydrators, specifically the DoctrineModule\Stdlib\Hydrator\DoctrineObject, do what you are asking.

__get error in php 5.3 indirect modification

Hello i'm having some trouble with __get __set in php 5.3 it seems that i have an error there.. already googled about it and seems it's a change of behaviour since php 5 but i didn't find a solution that would work :-(
$config['url']['uri'] = $request->uri();
=>
Notice: Indirect modification of overloaded element of Library\Config\Config has no effect in subdomains/prod/index.php on line 33
use \ArrayObject;
use \ArrayAccess;
use \Countable;
use \IteratorAggregate;
use \ArrayIterator;
use \Twelve\SingletonPattern\LazySingleton;
use \Twelve\SingletonPattern\Interfaces\ILazySingleton;
/**
* Singleton With Configuration Info
*/
class Config extends ArrayObject implements ArrayAccess, Countable, IteratorAggregate, ILazySingleton
{
/**
* Instance Var
* #var Config
*/
protected static $_instance = null;
/**
* Stores FileName
* #var Config
*/
protected static $_configFile = '';
/**
* Config Settings Array
* #var Config
*/
protected $_settings = array();
public static function getInstance(){
return LazySingleton::getInstance(__CLASS__);
}
/**
* Set the Config File Path
*/
public static function setFile($filePath)
{
static::$_configFile = $filePath;
}
public function __construct()
{
LazySingleton::validate(__CLASS__);
// Allow accessing properties as either array keys or object properties:
parent::__construct($this->_settings, ArrayObject::ARRAY_AS_PROPS);
$values = include(static::$_configFile);
if(is_array($values))
{
$this->_settings = $values;
}
}
/**
* Prevent Cloning
*/
public function __clone()
{
trigger_error('Clone is not allowed.', E_USER_ERROR);
// No Cloning Allowed
}
/**
* Returns the Number of Elements Inside the Config File
* #var Config
* #return Integer Number of Elements Inside Config
*/
public function count()
{
return sizeof($this->_settings);
}
/**
* Check if a Given Key Exists
* #var Config
* #param mixed $offset Key of Item to Check
* #return Boolean True if Key Exists, False Otherwise
*/
public function offsetExists($offset)
{
return key_exists($offset, $this->_settings);
}
/**
* Retrieve the Value of a Given Key
* #param mixed $offset Key of Item to Fetch
* #return mixed Value of the Matched Element
*/
public function offsetGet($offset)
{
return $this->_settings[$offset];
}
/**
* Assign a new Value to a Key
* #param mixed $offset Key of the Element to Set
* #param mixed $value Value to Assign
*/
public function offsetSet($offset, $value)
{
$this->_settings[$offset] = $value;
}
/**
* Remove an Item from the Config
* #param mixed $offset Key of the Element to Remove
*/
public function offsetUnset($offset)
{
unset($this->_settings[$offset]);
}
/**
* Retrieve an Iterator for Config Values
* #return Iterator Iterator of Config Values
*/
public function getIterator()
{
return new ArrayIterator($this->_settings);
}
/**
* Enables to Set Values Using the Object Notation i.e $config->myValue = 'Something';
*/
public function __set($key, $value)
{
(array) $this->_settings[$key] = $value;
}
/**
* Enables to Get Values using the Object Notation i.e $config->myValue;
*/
public function &__get($key)
{
return $this->_settings[$key];
}
public function __isset($key)
{
return isset($this->_settings[$key]);
}
}
New Edit:
parent::__construct($this->_settings, ArrayObject::ARRAY_AS_PROPS);

Symfony2 & Doctrine2 : removeElement doesn't work

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;
}

Categories