I have 2 entities, document and field, inside entities I have some relation OneToMany and ManyToOne..
I'm troubled cause when I try to get values of fields from document in the controller. I get error cause I can't use methode on string.
to resume:
part of document.php:
/**
* #var ArrayCollection $fields
*
* #ORM\OneToMany(targetEntity="AUTOFUSION\AutofusionBundle\Entity\Field", mappedBy="document", cascade={"persist", "remove", "merge"})
*/
private $fields;
/**
* Constructor
*/
public function __construct()
{
$this->fields = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add field
*
* #param \AUTOFUSION\Autofusionbundle\Entity\Field $field
*
* #return Document
*/
public function addField(\AUTOFUSION\AutofusionBundle\Entity\Field $field)
{
$this->fields[] = $field;
return $this;
}
/**
* Remove field
*
* #param \AUTOFUSION\AutofusionBundle\Entity\Field $field
*/
public function removeField(\AUTOFUSION\AutofusionBundle\Entity\Field $field)
{
$this->fields->removeElement($field);
}
/**
* Get fields
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getFields()
{
return $this->fields;
}
Part of DefaultController.php:
public function indexAction{
$regroupings = $em->getRepository('AUTOFUSIONAutofusionBundle:Regrouping')->FindRegrouping();
}
public function DocumentsArray($regroupings){
$i=0;
foreach($regroupings as $regrouping){
foreach($regrouping->getDocuments() as $document){
foreach($document->getFields() as $fields){
var_dump($document->getFields());
die();
//$documents[$i] = $document->getFields()->getValue();
}
$i++;
}
return $documents;
}
}
Part of Repository:
public function FindRegrouping(){
return $this->_em->createQueryBuilder()
->select('p','gdt','dt','d','f')
->from('AUTOFUSION\AutofusionBundle\Entity\Regrouping', 'p')
->leftJoin('p.groupDocType', 'gdt')
->leftJoin('p.documents','d')
->leftJoin('d.docType', 'dt')
->leftJoin('d.fields', 'f')
//->where('v.cp=:cp')
//->setParameter('cp', $cp);
->getQuery()
->getResult();
}
here part of the output var_dump($document->getFields());:
protected 'collection' =>
object(Doctrine\Common\Collections\ArrayCollection)[590]
private 'elements' =>
array (size=4)
0 => string 'NOM_CLIENT' (length=10)
1 =>
object(AUTOFUSION\AutofusionBundle\Entity\Field)[599]
...
2 =>
object(AUTOFUSION\AutofusionBundle\Entity\Field)[600]
...
3 =>
object(AUTOFUSION\AutofusionBundle\Entity\Field)[601]
...
So, I don't understant why the first item of arraycollection is a string?!
Look at my code. When you iterate over getFields(), there is no need to call it again inside loop. getFields() returns array, so when you're not trying to treat it as array, it can behave different. In this case, it tried to be a string.
PS - you don't need $i counter in your code.
foreach($document->getFields() as $field){
var_dump($field);
$documents[] = $field->getValue();
}
Related
I have a table "table_b" that contain the following details
I would like to use doctrine to query an output with a specific condition. Currently I'm using the block below to query.
$table_a= $em->getRepository('table_a')->findOneBy(['id'=>1]);
foreach($table_a->table_b as $records){
echo $records->name. " : " . $records->value;
}
It will output the entire ArrayCollection. Is there a way to query the record base on latest 'Date Created', that is base on the grouping of column 'Foreign Key Table 2'.
If you want to use native Doctrine query methods, you should use findOneBy with the order byparameter.
findOneBy(['id' => 1], ['DateCreated' => 'desc'])
Then, you says the result is an ArrayCollection, so using the ArrayCollection::first() method, you'll get the last created element
EDIT
Imagine you have a Group entity and a Member entity. groups table is your table_a and members table is your table_b.
Entity description should be something like that :
class Group
{
...
/**
* #ORM\OneToMany(targetEntity="Group", mappedBy="member", cascade={"persist", "remove", "merge"})
* #ORM\OrderBy({"dateCreated"="DESC"})
*/
protected $members;
...
public function __construct()
{
$members = new ArrayCollection();
}
// members handling accessors
/**
* #return ArrayCollection
*/
public function getMembers()
{
return $this->members;
}
/**
* #param $members
*
* #return $this
*/
public function setMembers($members)
{
$this->members = new ArrayCollection();
return $this->addMembers($members);
}
/**
* #param $members
*
* #return $this
*/
public function addMembers($members)
{
foreach ($members as $member)
{
$this->addMember($member);
}
return $this;
}
/**
* #param Member $member
*
* #return $this
*/
public function addMember(Member $member)
{
$this->members->add($member);
$member->setGroup($this);
return $this;
}
/**
* #param Member $member
*
* #return $this
*/
public function removeMember(Member $member)
{
if ($this->members->contains($member))
{
$this->members->removeElement($member);
}
return $this;
}
/**
* #param $members
*
* #return $this
*/
public function removeMembers($members)
{
foreach ($members as $member)
{
$this->removeMember($member);
}
return $this;
}
}
And Member entity :
class Member
{
/**
* #ORM\ManyToOne(targetEntity="Group", inversedBy="members")
* #ORM\JoinColumn(name="group_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $group;
/**
* #ORM\Column(type="datetime", name="date_created")
*/
protected $dateCreated;
/**
* #return Group
*/
public function getGroup()
{
return $this->group;
}
/**
* #param Group $group
*
* #return $this
*/
public function setGroup(Group $group)
{
$this->group = $group;
return $this;
}
}
Now, we have one group with a dateCreated ordered collection of members.
Example 1 : You want to get the last member created for a given group
$group = $em->getRepository(Group::class)->findOneBy(['id' => 1]);
$lastMember = $group->getMembers()->first();
Example 2 : You want to get all members created on 2014-01-30 :
$members = $group->getMembers()->filter(function (Member $member) {
return ($member->getDateCreated->format('Y-m-d') == '2014-01-30');
});
That's all folk !
PS : I haven't test this code
In TableRepository:
public function getLatestRecord()
{
return $this->getEntityManager()
->createQuery('SELECT t FROM MyBundle:MyEntity t GROUP BY t.table2NameField ORDER BY t.created DESC')
->setMaxResults(1)
->getOneOrNullResult();
}
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);
Well, I think the title explains most of it. Lets get right into it!
Blank Model:
class Blank extends Eloquent
{
protected $table = 'blanks';
protected $softDelete = true;
protected $hidden = array();
/**
* Get associated jobs.
*
* #return mixed
*/
public function jobs()
{
return $this->belongsToMany('Job')->withPivot('status', 'inventory', 'sizes', 'mill', 'po', 'location', 'ordered_at', 'expected_at', 'note')->withTimestamps();
}
/**
* Blanks sizes accessor
*
* #return object
*/
public function getSizesAttribute($value)
{
return json_decode($this->pivot->sizes);
}
/**
* Blanks sizes mutator
*
* #return void
*/
public function setSizesAttribute($value)
{
$this->pivot->attributes['sizes'] = json_encode($this->pivot->sizes);
}
}
Job Model:
class Job extends Eloquent
{
protected $table = 'jobs';
protected $softDelete = true;
protected $hidden = array();
/**
* Get associated blank.
*
* #return mixed
*/
public function blanks()
{
return $this->belongsToMany('Blank')->withPivot('status', 'inventory', 'sizes', 'mill', 'po', 'location', 'ordered_at', 'expected_at', 'note')->withTimestamps();
}
/**
* Blanks sizes accessor
*
* #return object
*/
public function getSizesAttribute($value)
{
return json_decode($this->pivot->sizes);
}
/**
* Blanks sizes mutator
*
* #return void
*/
public function setSizesAttribute($value)
{
$this->pivot->attributes['sizes'] = json_encode($this->pivot->sizes);
}
}
Attaching Code:
$job->blanks()->attach($blank->id,[
'status' => Input::get('status'),
'inventory' => Input::get('inventory'),
//'sizes' => $sizes,
'mill' => Input::get('mill'),
'po' => Input::get('po'),
'location' => Input::get('location'),
'ordered_at' => Carbon::parse(Input::get('ordered_at'))->format('Y-m-d H:i:s'),
'expected_at' => Carbon::parse(Input::get('expected_at'))->format('Y-m-d H:i:s'),
'note' => Input::get('note'),
]);
The mutator is not being called at all.. Any ideas?
Seems like that not possible to do this through ::attach() method.
But maybe you would like to use 'Defining A Custom Pivot Model'
public function newPivot(Model $parent, array $attributes, $table, $exists)
{
return new YourCustomPivot($parent, $attributes, $table, $exists);
}
So, you can define your own pivot class with mutators:
class BlankJobPivot extends Eloquent
{
// ...
/**
* Blanks sizes accessor
*
* #return object
*/
public function getSizesAttribute($value)
{
return json_decode($value);
}
/**
* Blanks sizes mutator
*
* #return void
*/
public function setSizesAttribute($value)
{
$this->attributes['sizes'] = json_encode($value);
return $value; // return for multiple assignment statement: $arr = $pivot->sizes = array(12, 23, 34);
}
}
And than you can use getters:
$blank->jobs[$i]->pivot->sizes; // - ::getSizesAttribute() will called ( I hope :) )
And maybe you will find a way to save / attach through the setSizesAttribute mutator.
Good luck.
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;
}
Every time I try to instantiate a certain model and use it, like for example:
$categories = Model::factory('category')->by_sale($id)->find_all();
I get a weird error. If i have i bootstrap in kohana::init set 'errors' => TRUE,the error is: Could not execute Model_Category::__construct() else i get only a warning Warning: array_keys() expects parameter 1 to be array, null given in /application/classes/model.php on line 42
meaning here:
private function _get_real_property_name($property)
{
if (isset($this->_belongs_to[$property]) OR
isset($this->_has_one[$property]) OR
isset($this->_has_many[$property]))
return $property;
$column_prefix = $this->_table_name . '_';
$property_prefix = substr($property, 0, strlen($column_prefix));
if ($property_prefix != $column_prefix)
{
$prefixed_property = $column_prefix . $property;
if (in_array($prefixed_property, array_keys($this->table_columns())))
{
return $prefixed_property;
}
}
return $property;
}
The category model looks like this:
class Model_Category extends Model {
/**
* #see ORM::_table_name
*
* #var array
*/
protected $_table_name = 'category';
/**
* #see ORM::_primary_key
*
* #var array
*/
protected $_primary_key = 'category_id';
/**
* #see ORM::_belongs_to
*
* #var array
*/
protected $_belongs_to = array(
'parent' => array('model' => 'category', 'foreign_key' => 'category_category'),
'sale' => array('foreign_key' => 'category_sale')
);
/**
* #see ORM::_has_many
*
* #var array
*/
protected $_has_many = array(
'products' => array('model' => 'product', 'foreign_key' => 'product_category')
);
/**
* Adds the 'top_level' condition to the query
*
* #return Model_Sale
*/
public function top_level()
{
return $this->where('category_category', '=', 0);
}
/**
* Adds the 'by_sale' condition to the query
*
* #return Model_Sale
*/
public function by_sale($sale_id)
{
return $this->where('category_sale', '=', $sale_id);
}
public function __get($property)
{
if ($property == 'siblings')
{
return $this->where('category_sale', '=', $this->sale->id)
->where('category_category', '=', $this->category_category);
}
if ($property == 'children')
{
return $this->where('category_category', '=', $this->pk());
}
return parent::__get($property);
}
} // End Model_Category
Thank you!
I don't recognize the $this->table_columns(). When looking at http://kohanaframework.org/3.0/guide/api/Model I don't see it there either.
Have you added this method to the Model class yourself? I'm guessing it's not returning the proper type.
I am not familiar with Kohana, but it is quite resembling with Codeigniter. You can try this in your model that extends model class:
function __construct(){
parent::Model();
}
(eventually pass the parameters that you have)
Try replacing $this->table_columns() by $this->table_columns (in _get_real_property_name()) because table_columns seems to be a variable, not a method :3