Doctrine find() returning controller - symfony

I have a method within my controller that takes a deserialized object from JMSSerializerBundle and returns the full object, ready to be persisted. The reason I'm doing this is to return the updated object so, when it's persisted, it doesn't reset everything to the default.
When ran, this method ends up throwing an ErrorException on the indicated line and puts this in my log: Warning: ReflectionProperty::setValue() expects parameter 1 to be object, null given in C:\DevelopmentProjects\keobi-web\vendor\doctrine\lib\Doctrine\ORM\Mapping\ClassMetadata.php line 177 (uncaught exception) at C:\DevelopmentProjects\keobi-web\vendor\symfony\src\Symfony\Component\HttpKernel\Debug\ErrorHandler.php line 65
For some reason, the EntityManager method find is returning (according to get_class) DefaultController, the controller class for this method. And the setFieldValue says it's NULL.
One thing that's confusing me is the Doctrine\ORM\EntityNotFoundException should be thrown if the entity isn't found. It's not being thrown. So, it's obviously finding the entity, not not returning it properly...
Incoming parameter $data is the object deserialized by JSMSerializerBundle. $em is definitely EntityManager and $metadata is definitely ClassMetadata.
I'm at a loss here. No idea how to proceed.
protected function processEntity($data)
{
$em = $this->getDoctrine()->getEntityManager();
$metadata = $em->getClassMetadata(get_class($data));
$fqcn = $metadata->getName();
$blankEntity = new $fqcn();
$id = array();
$this->get('logger')->debug('Incoming object type: ' . get_class($data)); # Keobi\ModelBundle\Entity\User
$this->get('logger')->debug('Blank entity type: ' . get_class($blankEntity)); # Keobi\ModelBundle\Entity\User
$this->get('logger')->debug('FQCN: ' . $fqcn); # Keobi\ModelBundle\Entity\User
foreach ($metadata->getIdentifierFieldNames() as $identifier)
{
$id[$identifier] = $metadata->getFieldValue($data, $identifier);
if (!$id[$identifier])
{
$this->get('logger')->debug(sprintf("Identifer '%s' missing. Assuming the object is new.", $identifier));
return $data;
}
}
$entity = $em->find($metadata->getName(), $id);
$this->get('logger')->debug(get_class($entity)); # Keobi\RestAPIBundle\DefaultController
foreach ($metadata->getFieldNames() as $field)
{
$value = $metadata->getFieldValue($data, $field);
$default = $metadata->getFieldValue($blankEntity, $field);
if ($value <> $default)
{
$metadata->setFieldValue($entity, $field, $value); # <- throws ErrorException
$this->get('logger')->debug(sprintf("Updated field '%s' in %s", $field, get_class($entity)));
}
}
return $entity;
}

Looks like there was an issue with Doctrine2. I updated it to the latest HEAD commit of the Github repo. What puzzles me is that this method actually worked not too long ago.
Couldn't find the exact commit that fixed the issue, but, as of this writing, the commit is 93cef612701b9e8caaf43c745978cd4fbd9d4e4e.

$entity = $em->find($metadata->getName(), $id);
You need to specify Repository in which you search, like:
$entity = $em->getRepository('EntitiesBundle:Entity')->find(...)

Related

I get error on Adding custom action in symfony Warning: array_merge(): Expected parameter 2 to be an array, null given

I have a dating website programmed with symfony. I want to add a function in easyadmin to be able to delete a user and her/his messages and posts. In UserCrudController I followed the instruction in symfony website and write a custom action. But I get an error
Warning: array_merge(): Expected parameter 2 to be an array, null given
public function configureActions(Actions $actions): Actions
{
// this action executes the 'renderInvoice()' method of the current CRUD controller
$delUserAction = Action::new('deleteUser', 'Delete user completely')
->linkToRoute('delete_user', function (User $user){
$id = $user->getId();
$res = $this->getDoctrine()->getRepository(User::class)->find($id);
if ($res) {
$em = $this->getDoctrine()->getManager();
$em->remove($res);
$em->flush();
}
$res = $this->getDoctrine()->getRepository(Message::class)->remove_all_message($id);
$res = $this->getDoctrine()->getRepository(Beziehungen::class)->remove_all_relations($id);
$res = $this->getDoctrine()->getRepository(Album::class)->remove_album_of_user($id);
$res = $this->getDoctrine()->getRepository(Blog::class)->remove_blog_of_user($id);
$res = $this->getDoctrine()->getRepository(Comment::class)->remove_comments_of_user($id);
$res = $this->getDoctrine()->getRepository(Subcomment::class)->remove_subcomments_of_user($id);
$res = $this->getDoctrine()->getRepository(Like::class)->remove_likes_of_user($id);
});
return $actions
// ...
->add(Crud::PAGE_INDEX, $delUserAction)
;
}
Can you please help me?
According to the tutorial, linkToRoute will connect an action to a route (as the name suggests). Similar to other route functions, it expects as first parameter the route name and as second parameter an array or a function that returns an array - the parameters to fill the placeholders of the route.
Your function doesn't return an array but instead IS the action.
So you really should put the deletion code you have and put it into an extra function like ... deleteUserAction, and then define your action as
$delUserAction = Action::new('deleteUser', 'Delete user completely')
->linkToCrudAction('deleteUserAction');

why Update and insert in same method is not working in symfony?

I am using symfony3 with window 7:
This method should work for both action update and add.But its behavior only insertion. while i am setting $id also.
/**
* #Route("entity/entity/{id}", name="entity_entity",defaults={"id" = 0})
*/
public function entityAction(Request $request,$id){
$action = false;
$arr_XYZ_data = array();
$arr_XYZ_prepare_data = array();
$form_title = 'Add New XYZ';
$obj_XYZ = new XYZ();
$form = $this->createForm(XYZType::class, $obj_XYZ);
if($id!=0){
$obj_repo = $this->getDoctrine()->getRepository('AppBundle:XYZ');
$arr_XYZ_data = $obj_repo->find($id);
if($arr_XYZ_data){
$action = true;
$form_title = 'Update XYZ';
$arr_XYZ_data = $obj_repo->findXYZById($id);
$arr_XYZ_prepare_data = $this->_prepareData($arr_XYZ_data);
}
}
$form->handleRequest($request);
if (($form->isSubmitted())) {
$obj_XYZ->setXYZId($id);
$str_hiddenfield_result = $form->get('extraformfield')->getData();
$arr_hiddenfield_result = explode('&',$str_hiddenfield_result);
$obj_XYZ->setDef($obj_XYZ->getDef()->getDefId());
$obj_XYZ->setAbc($arr_hiddenfield_result[3]);
$obj_XYZ->setAuthor(1); //ldap session value
$em = $this->getDoctrine()->getManager();
$em->persist($obj_XYZ);
$em->flush();
$this->addFlash('success', 'Your record has been added successfully!');
return $this->redirectToRoute('XYZ_index', array(), 301);
}
}
anyone can suggest me how can i achieve this ?
Some remarks:
Are you calling the right URL (with $id != 0)?
Check if the form that is submitted is valid before doing anything.
Why are you calling setId() on the entity? Doctrine will set the ID of a new and persisted entity.
Finally, you are using a 301 redirect, which is a Permanent Redirect. This means that the browser will redirect any request to entity/entity/{id} to whichever URL is generated by XYZ_index.
I would recommend the following things:
Use isValid instead of isSubmitted for the form (it might not be valid but you are persisting its data!).
Use the built-in Forms, which you can load with an entity (so that you do not have to process data fields yourself).
Return a $this -> redirectToRoute('...', array(...)) instead of a 301.
After a lot of R&D i got the solution:
use:
$em->merge($obj_XYZ) instead of $em->persist($obj_XYZ);
before
$em->flush();

symfony doctrine find User by Email

ok, with
$user = $this->getDoctrine()
->getRepository('UserBundle:User')
->find($user_id)
I get an User by the given Identifier (ID).
but how can I get him by given email?
$emailCheck = $em->createQueryBuilder('u')
->select('u, r')
->where('u.email = :email')
->setParameter('email','test#email.com')
->getQuery();
Whill it return an array or an object? Is this the right way to handle it?
This will return a User object.
$user = $this->getDoctrine()
->getRepository('UserBundle:User')
->findOneByEmail($email);
You can use either
$user = $this->getDoctrine()
->getRepository('UserBundle:User')
->findBy(array('email' => $email));
To load an array of User entities. (Will always be a list, even with 0 or 1 results.)
Or you can do:
$user = $this->getDoctrine()
->getRepository('UserBundle:User')
->findOneBy(array('email' => $email));
This will return the first found result as a User entity object.
You can use the getOneOrNullResult(), as well, it's the long variant. Note however that you should always use setMaxResults(1) with this, otherwise you'll get an exception if more than one result is found (SF 2.3.x).
Either you use the magic method of Doctrine findOneByyour_field or you can create your own method in your repo
public function findOneByEmailAndStoreId($email, $store_id)
{
$q = $this->createQueryBuilder('c')
->where('c.email = :email')
->andWhere('c.store_id = :store_id')
->setParameter('email', $email)
->setParameter('store_id', $store_id)
->getQuery();
return $q->getOneOrNullResult(); // will return only one result or null 'getResult' will return a collection
}

Symfony2 Delete Record

I am having issues removing a record from my db using Symfony2. Hoping someone can help me out.
Here is my code:
// Get user's account
$account = $this->getUser()->getAccount();
// Get manager
$em = $this->getDoctrine()->getManager();
// Get entity
$entity = $em->getRepository('WICPurchaseOrderLineItemBundle:PurchaseOrderLineItem')->findBy(array('account'=>$account->getId(), 'id'=>$id));
// If not entity
if (!$entity) {
throw $this->createNotFoundException('Unable to find this entity.');
}
// Remove the record...
$em->remove($entity);
$em->flush();
// Go to this url...
return $this->redirect($this->generateUrl('purchaseOrder_view', array('id' => '8')));
When this is run, I get this error:
EntityManager#remove() expects parameter 1 to be an entity object, array given.
My URL look like this:
{{ path('purchase_order_remove_line_item', { 'id': purchaseOrderLineItem.id }) }}
Does my "id" number need to be turned into an object first? Not sure how to fix this, still learning Symfony.
Anyone have any suggestions?
You just need to use the findOneBy method instead of the findBy method.
$entity = $em->getRepository('WICPurchaseOrderLineItemBundle:PurchaseOrderLineItem')->findOneBy(array('account'=>$account->getId(), 'id'=>$id));

Class not found when trying to index documents using Solr with Symfony2

I am very new to Solr and I am probably missing something simple however, having followed Xavier Briand's presentation I have set up Symfony2, Solarium and Nelmio\SolariumBundle.
"nelmio/solarium-bundle": "2.0.*#dev",
"solarium/solarium": "3.0.*"
Having implemented a toSolrDocument method for my doctrine php object.
public function toSolrDocument(\Solarium_Document_ReadWrite $doc)
{
$doc->id = $this->getId();
$doc->description = $this->getTitle();
$doc->path = "path";
return $doc;
}
I am faced with the following error.
Catchable Fatal Error: Argument 1 passed to ::toSolrDocument() must be an instance of Solarium_Document_ReadWrite, instance of Solarium\QueryType\Update\Query\Document given, called in Controller.php
The controller calling this toSolrDocument method has the following function
public function indexItems(){
$client = $this->get('solarium.client');
// get an update query instance
$update = $client->createUpdate();
// create documents
$documents = array();
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('<Bundle>:<Object>');
$items = $repo->findAll();
foreach ($items as $item) {
$documents[] = $item->toSolrDocument($update->createDocument());
}
// add the documents and a commit command to the update query
$update->addDocuments($documents);
$update->addCommit();
// this executes the query and returns the result
$result = $client->update($update);
}
Most of this method again comes directly from Xavier's presentation and it is clear to see that the method $update->createDocument() does not return the correct type. In fact it returns an instance of the my php object. Does anyone know where I am going wrong here? Another thing that might be of help is that even when I try to pass a Solarium Document directly I get an exception.
foreach ($items as $item) {
$rw_item = new \Solarium_Document_ReadWrite();
$documents[] = $item->toSolrDocument($rw_item);
}
The exception is
FatalErrorException: Error: Class 'Solarium_Document_ReadWrite' not found in
I can't seem to find this class in any of the bundles and I am wondering if my setup might be causing the issues. Any help would be very much appreciated.
One additional point to note is that when I am running the solr jar I see the query requests come in from my symfony2 page it is only this indexing action that I can not work out so the config may be alright and I am miss understanding the use of the bundle.
You just need to use the correct class for the argument.
use Solarium\QueryType\Select\Result\AbstractDocument;
...
public function toSolrDocument(AbstractDocument $doc)
{
You could also not type hint it:
public function toSolrDocument($doc)
{

Resources