Symfony: Handling EntityNotFoundException on Doctrine relation - symfony

When I tried to display a related object in Twig, and that relation is not present because the ID is in the parent entity, but the related entity was not in the current database, Symfony throws a 500 error
// EntityNotFoundException Twig_Error_Runtime
An exception has been thrown during the rendering of a template
("Entity of type 'App\Entity\Location' for IDs id(265) was not
found").
I'd like to be able to ignore this error and instead display something like "Related object missing".
It seemed like this could be solved by some checking in Twig, but checking if the relation is null or not defined does not work - they both still find the relation, but when a property is called on the related entity, the exception is thrown.
Has anyone solved this problem already?

You could check if the entity exists in a Twig extension
Something like:
public function isRelatedEntityDefined($entity)
{
try {
if(isset($entity->getSomeField()) return true;
} catch (EntityNotFoundException $e) {
return false;
}
}

Have a look at this subject
On delete cascade with doctrine2
Isn't the problem from your annotation ?
On your owning side the ID is still defined but the entity doesn't exist anymore.
You should do something like this :
* #JoinColumn(name="locationId", referencedColumnName="id", onDelete="set null")

Related

Receive all kind of Entity as an Argument in Symfony

I have a method to get a change set of Entity from the unit of work (entity manager) in Symfony and I would like it to receive all Entities (Post, User...) instead of specific Entity.
public function getChanges(Post $event): array
{
$uow = $this->entityManager->getUnitOfWork();
$uow->computeChangeSets();
return $uow->getEntityChangeSet($event);
}
Do you have any idea to do it?
One solution is getting the object as the argument but I prefer to get only the Symfony Entity objects in the function.
Look for doctrine entity listener.
https://symfony.com/doc/current/doctrine/events.html#doctrine-entity-listeners
And do not filter entity inside it, remove this part from the example:
// if this listener only applies to certain entity types,
// add some code to check the entity type as early as possible
if (!$entity instanceof Product) {
return;
}
if (!$this->entityManager->contains($entity)) {
throw new Exception('The given object must be doctrine entity');
}

How to use Association field in Symfony EasyAdmin 4

When I use:
public function configureFields(string $pageName): iterable
{
return [
AssociationField::new('XYZ')
];
}`
I get error "Object of class App\Entity\XYZ could not be converted to string"
When I add ->autocomplete() to the AssociationField::new('XYZ'), then it works, but on save it displays error "Expected argument of type "?string", "App\Entity\XYZ" given at property path "XYZ".
Whats the CORRECT way to use this field with many to one relation? Symfony Easy Admin documentation https://symfony.com/doc/current/EasyAdminBundle/fields/AssociationField.html doesn't help at all.
Your entity App\Entity\XYZ will be converted to a string in your association field (which is a standard symfony entity type). Otherwise there is no way to set a label in your entity select.
It will try to convert it using the __toString method, so you need to add it in your entity.
For example:
/**
* #ORM\Entity(repositoryClass=XyzRepository::class)
*/
class Xyz
{
public function __toString(){
return $this->name; //or anything else
}
EasyAdmin should be able to guess the entity class, so you don't have to specify it like you would for a simple EntityType.

Easy admin list modification

I don't get this guys!
At this moment I still have only one entity (User). I manage my users with the FOSUserBundle.
I want to modify the fields displayed in my list. Like this right?
config.yml
easy_admin:
entities:
Users:
class: AppBundle\Entity\User
list:
fields:
- username
- email
- last_login
But I get this error when trying to do it;
An exception has been thrown during the rendering of a template
("Warning: mb_strlen() expects parameter 1 to be string, object
given") in #EasyAdmin/default/field_text.html.twig at line 4.
I've added a __toString() method in my User entity but it still doesn't work;
User.php
public function __toString()
{
return $this->getUsername();
}
I am pretty new to the whole Symfony thing, so can somebody please help me out?
This issue is fixed and will probably be available with the next stable release.
In the meantime you can fix this by manually copy paste this 5 lines into EasyAdminTwigExtention.php at line 269.
try {
$value = (string) $value;
} catch (\Exception $e) {
$value = '';
}
Look here for the same question I asked on Git. And here where the code is modified.

Automatically update created_by and updated_by value in Symfony 2

I'm trying to add the current user_id into a created_by or updated_by field automatically.
But I can't seem to get the current user_id into the entity of the other table.
I'm using FOSUserBundle....
/**
* #ORM\PrePersist
*/
public function setCreatedByValue()
{
if(!$this->getCreatedBy())
{
$user= $this->container->get('security.context')->getToken()->getUser();
$this->created_by = $user->getId();
}
}
This throws a Undefined property: ..... Container error :-(
How do I access the current user id?
Thanks for any help.
Your entity does not have any reference to the container. Where is this $this->container coming from ? From nowhere.
There would many ways to resolve the problems, but it's better to implement what you need than fixing your problems :)
So I would suggest a Doctrine listener, that would modify the createdBy value every time an entity is created.
In fact, it already exist: https://github.com/KnpLabs/DoctrineBehaviors#blameable
Take a look at implementation: https://github.com/KnpLabs/DoctrineBehaviors/blob/master/src/Knp/DoctrineBehaviors/ORM/Blameable/BlameableListener.php#L151

Symfony 2 - flush in postUpdate fire preUpdate event

I detected this problem "thanks" to an exception I got:
Catchable Fatal Error: Argument 3 passed to
Doctrine\ORM\Event\PreUpdateEventArgs::__construct()
must be an array, null given, called in
/.../vendor/doctrine/lib/Doctrine/ORM/UnitOfWork.php on line 804
and defined in
/.../vendor/doctrine/lib/Doctrine/ORM/Event/PreUpdateEventArgs.php line 28
I am working on a project that requieres a specific logic:
When the order field in entity book is modified, I need to update field books_order_modified_at in the parent entity bookstore (this field allows me to know whether the order of books in a bookstore was changed).
I decided to do it in an event listener since there are many places in the code that might change the order of books.
I didn't find any way to update a related entity from preUpdate event, so I have a private field in the listener class which I use to tell the postUpdate event to update the relevant bookstore entity.
My problem is that when I do so the preUpdate event of the book entity is fired.
When I check the change-set it contains only the modified_at field, but it has the same value before and after.
If someone has another idea how to solve the problem - great.
If not - any idea how can I prevent the preUpdate event from being fired when the flush is called in teh postUpdate event??
Actually, this is a problem from doctrine Doctrine Issue DDC-2726. Solved it by adding a clear call on the entity manager after the flush in the listener so the 3-rd argument to that constructor, which is actually the entityChangeSets, will be re-written.
What about updating the modified_at within your entities and let doctrine handle it? You would change your setOrder method in your book to update the BookOrder entity like this:
class Book {
public function setOrder($order) {
// modify book
$this->bookOrder->updateModifiedAt();
}
}
Of course your BookOrder would have to implement modifiedAt:
class BookOrder {
public function updateModifiedAt() {
$this->modifiedAt = new \DateTime();
}
}
If you use other classes for your Datetime, you of course have to change this code!
Doctrine should recognize that BookOrder has changed and should update it without any need to use a event listener.
I can suggest you to use Timestampable extension for Doctrine from DoctrineExtensionsBundle.
By using it you don't need to set created_at or modified_at values. This extension does it automatically. Even it can set modified_at only when specific fields were modified. See example.
I think you are writing something like this extension. So, you don't need to do that because this is already done :)
I had a similar problem to this. Trying to use preupdate to modify child elements caused the same error. In the end, my solution to simply update the children belonging to the parent. No explicit call to flush required.
/**
* Update expiry dates for all runners belonging to a campaign
*
* #param $runners
* #param $expiryDate
*/
private function updateCampaignRunners($runners, $expiryDate){
foreach($runners as $runner){
$runner->setExpiresAt($expiryDate);
$this->getModelManager()->update($runner);
}
}
/**
* Post update and persist lifecycle callback
*
* #param Campaign $campaign
*/
private function postAction(Campaign $campaign)
{
$runnerExpire = $this->getForm()->get("runnerExpire")->getData();
if($runnerExpiryDate && $campaign->getRunners()){
$this->updateCampaignRunners($campaign->getRunners(), $runnersExpiryDate);
}
}

Resources