Symfony 2 - Clone entity to different table - php

I am trying to clone an entity-object to a different table in Symfony 2 / Doctrine. Any idea how to do this?
After retrieving the object from the database I can clone it like this:
$newobject = clone $oldbject;
This gives me a new object, which I can persist as a new record to the same table in the database. Actually I dont want to do this. I want to store the object as it is to a different table in the database. But to do this, I would have to change the parent entity, right? How to achieve this?

But then you're not really cloning an entity. In fact, you want a different entity. What do the two entities look like? Do they have the same fields? You could do something like this:
$oldEntity = $oldEntity;
$newEntity = new NewEntity();
$oldReflection = new \ReflectionObject($oldEntity);
$newReflection = new \ReflectionObject($newEntity);
foreach ($oldReflection->getProperties() as $property) {
if ($newReflection->hasProperty($property->getName())) {
$newProperty = $newReflection->getProperty($property->getName());
$newProperty->setAccessible(true);
$newProperty->setValue($newEntity, $property->getValue($oldEntity));
}
}
This is untested - and may have an error or two, but this should allow all properties to be copied from one object to another (assuming the properties have the same name on both objects).

Related

Laravel Eloquent Save model with newly created related entities

I'm new to Laravel, and trying to save the Car with a specific Wheels as follows;
$wheel1=new Wheel();
$wheel1->save();
$wheel2=new Wheel();
$wheel2->save();
$car= new Car();
$car->name='Mazda';
$car->wheelid_1='1';
$car->wheelid_2='2';
$car->save();
The problem I'm having is, I need to save the car, wheel1, and wheel2 objects at the same time without referring to or knowing their id's. But I have no wheelid_1 and wheelid_2 until I save the wheel1 and wheel2 first.
I referred this, this and other similar questions but was unable to figure out how to assign wheel1 and wheel2 as new related objects to the car model.
I have done similar tasks using Entity Framework, by just assigning child objects to relevant properties of the parent object with C#. Can I use a similar method in Eloquent?
I have added foreign keys for Wheels and Car on the table creation.
How can I make the reference between all these 03 objects without using their ids for saving?
What I can imagine is something like the below;
$wheel1=new Wheel();
$wheel2=new Wheel();
$car= new Car();
$car->name='Mazda';
$car->wheel1=$wheel1;
$car->wheel2=$wheel2;
$car->save();
Any help would be highly appreciated.
When you create a new model of item, in this case wheel. It gives you an id.
$wheel1=new Wheel();
$wheel1->save();
$wheel2=new Wheel();
$wheel2->save();
So you can use the model like this and retrieve the id
$wheel1->id;
$wheel2->id;
$car= new Car();
$car->name='Mazda';
if new car has property wheelid_1 & wheelid_2
you can save the ids of this wheel like so
$car->wheelid_1 = $wheel1->id;
$car->wheelid_2 = $wheel2->id;
$car->save();
A few bewares is that if you create a wheel model like that, make sure that in your migration the columns are set to nullable for no errors.

How to persist cloned entity object in Symfony/Doctrine

I am trying to clone an entity record along with the relationships it holds among other entities. I have successfully cloned some entity objects but this one to many entity relationship has challenged me. I have reviewed similar questions regarding the error message I have been given without progress to the challenge.
The correct records are queried out, looped through and cloned then stored in an array. I have tried to persist the array but get error
EntityManager#persist() expects parameter 1 to be an entity object,
array given
I then tried to encode the array and persist but I get error
The class 'Symfony\Component\HttpFoundation\JsonResponse' was not
found in the chain configured namespaces NameOfBundle\Entity.
This below code is in my controller
$quoteItemAddWorkCollection = $em->getRepository('UniflyteBundle:QuoteItemAdditionalWork')->findBy($params);
$quoteItemDeliverableCollection = $em->getRepository('UniflyteBundle:QuoteItemDeliverable')->findBy($params);
if (!empty($quoteItemAddWorkCollection)) {
$quoteItemAddWorkArray = [];
foreach ($quoteItemAddWorkCollection as $quoteItemAddWorkItem) {
$quoteItemAddWorkItemClone = clone $quoteItemAddWorkItem;
array_push($quoteItemAddWorkArray, $quoteItemAddWorkItemClone);
}
$quoteItemAddWorkCollection = new JsonResponse($quoteItemAddWorkArray);
$em->persist($quoteItemAddWorkCollection);
I can't persist an array, I have to encode it to json first I believe. What am I doing wrong?
I think you have a misunderstanding of Doctrine concepts here. In terms of Doctrine, each entity:
UniflyteBundle:QuoteItemAdditionalWork
and
UniflyteBundle:QuoteItemDeliverable
, and any of its relationships, could get persisted, using a configuration named Mapping.
To get this into work, any In-Memory object, MUST be an instance of a managed entity class.
There is not such a magic in Doctrine, to persist so many unknown objects at once. You may persist them, one-by-one inside a loop:
foreach ($quoteItemAddWorkCollection as $quoteItemAddWorkItem) {
$quoteItemAddWorkItemClone = clone $quoteItemAddWorkItem;
$quoteItemAddWorkItemClone->setId(null);
// Set relationships here ...
$em->persist($quoteItemAddWorkItemClone);
}
Keep in mind to set any required relationships, before persisting your new cloned objects.
If you want to use, one persist, you can assign their relationships, inside a loop:
foreach ($quoteItemAddWorkCollection as $quoteItemAddWorkItem) {
$quoteItemAddWorkItemClone = clone $quoteItemAddWorkItem;
$quoteItemAddWorkItemClone->setId(null);
$someParentCollection->add($quoteItemAddWorkItemClone);
}
$em->persist($someParentCollection);
the latter method, needs you to set cascade on mapping configuration:
class SomeParent
{
// #ORM\OneToMany(targetEntity="QuoteItemAdditionalWork", mappedBy="parent", cascade={"persist"})
private $quoteItemAddWork;
}

How can I implement projects and tasks with DDD

I have two entities: Projects and Task. I can implements this object as Value Object but I wonder about the whether that is good approach? Task might change own title or status and VO should be immutable. How implements this object?
I wonder about the in Project entity I should add addTask method or I should add Tasks via TaskController? Whether TaskController is necessary when Project entity has addTask method ?
Read this documentation on Doctrine Associations / Relations:
http://symfony.com/doc/current/doctrine/associations.html
It should explain what you need to do.
Essentially, your Project Entity should have an addTask() method where you add the task. Your Project will have an ArrayCollection of Tasks. Then you can use you getTask() method (you create this) to get the Task (if you need it).
The documentation gives good examples, so take a at that first.
EDIT #2 Based on comments.
So, it's seems you don't understand the article very well. You would have separate methods in each of your Entities to do what you need that is related to that particular Entity. I'm not certain what methods you actually want.
So for example, you gave in the comments two type of methods: changeTask and changeNameTask.
In you code, you could do something like this:
$project = new Project();
$task1 = new Task();
$task1->setName("My Task Name");
... // Do other things with task1
$project->addTask($task1);
$em = $this->getDoctrine()->getManager();
$em->persist($project); // Save to db.
$em->persist($task1);
$em->flush();
// Now let's add a new Task (different name).
$task2 = new Task();
$task2->setName("Another Task");
...
$project->addTask($task2);
// Remove the old Task...
$em->remove($task1);
$em->persist($project); // Save to db.
$em->persist($task2);
$em->flush();
// You can also get the Task if you need it.
$task2 = $project->getTask(); // Presumes that this is an object not an array.
The above should make sense...

Laravel: Create or update related model?

Please be gentle with me - I'm a Laravel noob.
So currently, I loop through a load of users deciding whether I need to update a related model (UserLocation).
I've got as far as creating a UserLocation if it needs creating, and after a bit of fumbling, I've come up with the following;
$coords = $json->features[0]->geometry->coordinates;
$location = new UserLocation(['lat'=>$coords[1],'lng'=>$coords[0]]);
$user->location()->save($location);
My issue is that one the second time around, the Location may want updating and a row will already exist for that user.
Is this handled automatically, or do I need to do something different?
The code reads like it's creating a new row, so wouldn't handle the case of needing to update it?
Update - solution:
Thanks to Matthew, I've come up with the following solution;
$location = UserLocation::firstOrNew(['user_id'=>$user->id]);
$location->user_id = $user->id;
$location->lat = $coords[1];
$location->lng = $coords[0];
$location->save();
You should reference the Laravel API Docs. I don't think they mention these methods in the "regular docs" though so I understand why you may have not seen it.
You can use the models firstOrNew or firstOrCreate methods.
firstOrNew: Get the first record matching the attributes or instantiate
it.
firstOrCreate: Get the first record matching the attributes or create it.
For Example:
$model = SomeModel::firstOrNew(['model_id' => 4]);
In the above example, if a model with a model_id of 4 isn't found then it creates a new instance of SomeModel. Which you can then manipulate and later ->save(). If it is found, it is returned.
You can also use firstOrCreate, which instead of creating a new Model instance would insert the new model into the table immediately.
So in your instance:
$location = UserLocation::firstOrNew(['lat'=>$coords[1],'lng'=>$coords[0]]);
$location will either contain the existing model from the DB or a new instance with the attributes lat and lng set to $coords[1] and $coords[0] respectively, which you can then save or set more attribute values if needed.
Another example:
$location = UserLocation::firstOrCreate(['lat'=>$coords[1],'lng'=>$coords[0]]);
$location will either contain the existing model from the DB or a new model with the attributes set again, except this time the model will have already been written to the table if not found.

Add element to doctrine ArrayCollection by Id

I find very annoying to have to fetch an object by id from database every time I want to add it to a relationship. Is there a way to add an object to a a relationship by id instead of adding the whole object?
This is my actual code:
...
$person = $em->getRepository("Person")->findOneById($id);
$me->getPersons()->add($person);
...
I would like to have something like this:
...
$me->getPersons()->add($id);
...
Then I would be saving one trip to the database! Which I like better! Is it possible?
You don't have to do that actually. You can get reference object like so:
$person = $em->getReference("Person", $id);
$me->getPersons()->add($person);
Doctrine will not make a query for Person but will instead return an reference proxy object for person with that id. If you, however do:
$person = $em->getReference("Person", $id); // 0 queries
$person->getId(); // Still 0 queries
$person->getSomeField(); // query fired
Doctrine will trigger lazy load if you try to get some field that has to be fetched from database.
See docsEntityManager::getReference method

Categories