How to handle exceptions inside an entity in symfony2 framework - symfony

I want to get some data from an entity class. I tried to use try/catch to handle problems but it is not working (still gives me the Exception screen).
Error: Call to a member function getGroup() on a non-object in
/var/www/html/system/src/Project/SomeBundle/Entity/MyEntity.php line
139
500 Internal Server Error - FatalErrorException Stack Trace
How can I do something like that in an entity?
Code/Entity:
<?php
namespace Project\SomeBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* MyEntity
*
* #ORM\Table(name="my_entity")
* #ORM\Entity(repositoryClass="Project\SomeBundle\Entity\Repository\MyEntityRepository")
*/
class MyEntity
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
* #Assert\Length(max="255")
*/
private $name;
/**
* #var Item[]|Collection
*
* #ORM\OneToMany(targetEntity="Project\SomeBundle\Entity\Item", mappedBy="itemType", cascade={"remove"}, fetch="EXTRA_LAZY")
*/
protected $items;
// [...]
/**
* Get some data
*
* #return string
*/
public function getSomeData()
{
$result = null;
try {
$result = $this->getName() . ' - ' . $this->getItems()->last()->getGroup()->getCode();
}
catch(\Exception $exception) {
$result = $this->getName();
$logFile = fopen('/tmp/error.log', 'a');
fwrite($logFile, $exception->getMessage());
fclose($logFile);
}
return $result;
}
}
Thanks in advance...

The error message Error: Call to a member function getGroup() on a non-object in... has very little to do with where you're receiving it. It means that you are trying to call a function on something that isn't an object.
It seems likely that $this->getItems()->last() is somehow returning null (because there are no items), and then you're calling getGroup() on null which is a non-object.
Try to debug the object on which you're calling getGroup() and see what value it holds just before you call it.

If you want to catch that error you must write try catch as following
try {
$result = $this->getName() . ' - ' . $this->getItems()->last()->getGroup()->getCode();
}
catch(\Symfony\Component\Debug\Exception\FatalErrorException $exception) {
$result = $this->getName();
$logFile = fopen('/tmp/error.log', 'a');
fwrite($logFile, $exception->getMessage());
fclose($logFile);
}
You can see I have changed \Exception to \Symfony\Component\Debug\Exception\FatalErrorException in above code block

Related

symfony2 - add value to protected object

How can I set the protected object user? After filling the form i have to add user object with current user data (for example like saving comments). I tried something like that:
if ($form->isValid()) {
$comment = $form->getData();
$comment->user = $this->contextSecurity->getToken()->getUser();
$this->model->save($comment);
}
And i've got this error
FatalErrorException: Error: Cannot access protected property AppBundle\Entity\Comment::$user in /home/AppBundle/Controller/CommentsController.php line 184
Here is my Comment entity:
class Comment
{
/**
* Id.
*
* #ORM\Id
* #ORM\Column(
* type="integer",
* nullable=false,
* options={
* "unsigned" = true
* }
* )
* #ORM\GeneratedValue(strategy="IDENTITY")
*
* #var integer $id
*/
private $id;
/**
* Content.
*
* #ORM\Column(
* name="content",
* type="string",
* length=250,
* nullable=false
* )
* #Assert\NotBlank(groups={"c-default"})
* #Assert\Length(min=3, max=250, groups={"c-default"})
*
* #var string $content
*/
private $content;
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="comments")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false)
*/
protected $user;
I'm using Symfony2.3. Any help will be appreciated.
You can't modify protected properties from outside of the object. You need a public property or a setter for that.
class Comment
{
// ...
public function setUser(User $user)
{
$this->user = $user;
}
}
And in a controller you can write:
$comment->setUser($this->getUser());
This question is not related to Symfony2, at first you should read about php types, especially about objects. read here and then here
You should understand how Visibility works. After that you will understand that access to protected/private properties of the object is only available from the object itself, so you need to create public method
setUser($user) {
$this->user = $user;
}
I always use protected, If i want edit variable or take the value, I use the getter and setter:
public function setUser($user) {
$this->user = $user;
}
public function getUser(){
return $this->user;
}

Symfony 2.7 : A new entity was found through the relationship

I have two tables named jobs and attachments.A job may or may not have one or more than one attachments.I have created one to may relation with job and attachment.But when I trying to persist it gives me an error,
A new entity was found through the relationship 'AppBundle\Entity\JotJobs#attachments' that was not configured to cascade persist operations for entity: AppBundle\Entity\JotJobAttachments#000000004d40cceb00000000fe114bdc. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example #ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'AppBundle\Entity\JotJobAttachments#__toString()' to get a clue.
Then I have tried to set cascade persist in jobs entity, after that it always asking for a mandatory attachment for each jobs.Otherwise it will gives an error with job_id can't be null in attachment table.I were trying to correct it for the last few hours.Please help.
My entities are,
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* JotJobs
*
* #ORM\Table(name="jot_jobs")
* #ORM\Entity
*/
class JotJobs
{
/**
* #var \JotJobAttachments
*
* #ORM\OneToMany(targetEntity="JotJobAttachments" ,mappedBy="jotJobs")
* #ORM\JoinColumn(name="ID", referencedColumnName="job_id")
*/
private $attachments;
/**
* Constructor
*/
public function __construct()
{
$this->attachments = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get subTechnologies
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getSubTechnologies()
{
return $this->subTechnologies;
}
/**
* Add attachments
*
* #param \AppBundle\Entity\JotJobAttachments $attachments
* #return JotJobs
*/
public function addAttachment(\AppBundle\Entity\JotJobAttachments $attachments=null)
{
$this->attachments[] = $attachments;
return $this;
}
/**
* Remove attachments
*
* #param \AppBundle\Entity\JotJobAttachments $attachments
*/
public function removeAttachment(\AppBundle\Entity\JotJobAttachments $attachments)
{
$this->attachments->removeElement($attachments);
}
}
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* JotJobAttachments
*
* #ORM\Table(name="jot_job_attachments")
* #ORM\Entity
*/
class JotJobAttachments
{
/**
* #var \JotJobs
*
* #ORM\ManyToOne(targetEntity="JotJobs", inversedBy="attachments")
* #ORM\JoinColumn(name="job_id", referencedColumnName="ID", nullable=true)
*/
private $jotJobs;
/**
* Set jotJobs
*
* #param \AppBundle\Entity\JotJobs $jotJobs
* #return JotJobAttachments
*/
public function setJotJobs(\AppBundle\Entity\JotJobs $jotJobs = null)
{
$this->jotJobs = $jotJobs;
return $this;
}
/**
* Get jotJobs
*
* #return \AppBundle\Entity\JotJobs
*/
public function getJotJobs()
{
return $this->jotJobs;
}
}
In my controller,
$newJob = new JotJobs();
$newJob->setJobName($data->getJobName());
.
.
.
$attachments = $data->getAttachments();
$jobDir = $this->container->getParameter('uploads_directory').'/jobs';
foreach ($attachments as $key => $value) {
if($value->getAttachment()!=null)
{
/** #var Symfony\Component\HttpFoundation\File\UploadedFile $file */
$file = $value->getAttachment();
$fileName = md5(uniqid()).'.'.$file->guessExtension();
$file->move($jobDir, $fileName);
$jobAttachment = new JotJobAttachments();
$jobAttachment->setAttachment($fileName);
$jobAttachment->setAttachmentName($file->getClientOriginalName());
$newJob->addAttachment($jobAttachment);
}
}
$entityManager->persist($newJob);
$entityManager->flush();
$lId = $newJob->getId();
You have two things going on here.
The first, as mentioned before, is that you need cascade={"all"} on your OneToMany relation. Use all instead of persist snce if you delete a job you almost certainly want the attachments to be deleted as well.
The second is that you need to set the job reference in your attachment. That is why you getting those null errors.
public function addAttachment(\AppBundle\Entity\JotJobAttachment $attachment=null)
{
$this->attachments[] = $attachment;
$attachment->setJotJob($this); // ADD THIS
return $this;
}
You might also consider changing thing like JotJobAttachments to JotJobAttachment. Makes your code easier to understand.
And don't pay much attention to the down voters. This cross referencing requirement catches many developers and is not easy to search for.

FOSUserBundle add properties

i've extended FOSUserBundle with my custom User Entity in this way:
<?php
namespace Hu\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Entity\User as BaseUser;
use Symfony\Component\Validator\Constraints as Assert;
/**
* User
*
* #ORM\Table(name="user")
* #ORM\Entity
*/
class User extends BaseUser
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="fname", type="string", length=255)
* #Assert\NotBlank()
*/
private $fname;
// other fields...
/**
* Set fname
*
* #param string $fname
* #return UserEntity
*/
public function setFname($fname)
{
$this->fname = $fname;
return $this;
}
/**
* Get fname
*
* #return string
*/
public function getFname()
{
return $this->fname;
}
public function __construct()
{
parent::__construct();
// ...
$this->fname = setFname($fname);
}
}
But when i try to load the /register route or to add a new user by:
php app/console fos:user:create
Symfony returns me:
FatalErrorException: Error: Call to undefined function Hu\UserBundle\Entity\setFname() in /Library/WebServer/Documents/sfprojects/quattro/src/Hu/UserBundle/Entity/User.php
What's wrong in the constructor? What i miss?
Thanks a lot,
setFname isn't function, but it is method in your class.
so to execute it you need use $this->setFname($fname).
Also in constructor you shouldn't run methods like setters or getters (if they don't do anything except set variable or get variable)
Your constructor should look like:
public function __construct()
{
parent::__construct();
$this->fname = $fname;
}
the commande " php app/console fos:user:create " uses the setters of the entity User to affect data inputs from the terminal ( in the same way that Forms uses them to affect the data to an object from the < input ... > tag ) .
You can add setters for all the fields you added to your User class to solve this problem
exemple :
/**
* #var string
*
* #ORM\Column(name="fname", type="string", length=255)
* #Assert\NotBlank()
*/
private $fname;
public function setFname($fname) {
$this->fname = $fname;
}

Notice: Trying to get property of non-object in vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php line 481

I have a really strange case related to doctrine, loggable (DoctrineExtension) and listeners.
I will explain the situation I am having here and below is all the code I think is related to the problem.
I have two entities (Agreement and Template) where an agreement is based on a specific Template version. Template entity has the DoctrineExtension Loggable annotation. So I can revert an Agreement template to the specific version using the LogEntryRepository->revert() method. (I am using a postLoad listener to do that, so each time an agreement is retrieved, the right Template version is loaded for that Agreement).
If I get a controller action where an agreement is retrieved using a ParamConververter annotation, everything works ok and my agreement is retrieved with the right Template.
If I try to retrieve the very same agreement in the first line of the controller action using a query builder, I get the following exception
Notice: Trying to get property of non-object in /home/administrator{dir}/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php line 481
Any help would be appreciated.
Thanks.
Just copying the parts that are related to the problem:
Entities
/**
* Agreement
*
* #ORM\Table(name="agreement")
* #ORM\Entity
* #Gedmo\Loggable
*/
class Agreement
{
/**
* #var integer
* #ORM\Column(name="id", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var integer
* #ORM\Column(name="template_version", type="bigint", nullable=false)
* #Gedmo\Versioned
*/
private $templateVersion;
/**
* #var \Template
* #ORM\ManyToOne(targetEntity="Template")
* #ORM\JoinColumn(name="template_id", referencedColumnName="id")
*/
private $template;
}
/*
* Template
*
* #ORM\Table(name="template")
* #ORM\Entity
* #ORM\ChangeTrackingPolicy("DEFERRED_EXPLICIT")
* #Gedmo\Loggable
*/
class Template
{
/**
* #var integer
* #ORM\Column(name="id", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
* #ORM\Column(name="name", type="string", length=255, nullable=false)
* #Gedmo\Versioned
*/
private $name;
}
Doctrine Subscriber
*(services.yml)*
services:
ourdeal.listener.loggable:
class: App\Bundle\Listener\LoggableSubscriber
tags:
- { name: doctrine.event_subscriber }
class LoggableSubscriber implements EventSubscriber
{
public function getSubscribedEvents()
{
return array(
'prePersist',
'postLoad',
);
}
public function prePersist(LifecycleEventArgs $args)
*...Code omitted...*
public function postLoad(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
$entityManager = $args->getEntityManager();
if ($entity instanceof Agreement)
{
$agreement = $entity;
$repo = $entityManager->getRepository('Gedmo\Loggable\Entity\LogEntry');
$repo->revert($agreement->getTemplate(), $agreement->getTemplateVersion());
}
}
}
Actions
With this action, I get the desired agreement without problems.
/**
* #Route("/agreement/send/{id}", name="agreement/send")
* #ParamConverter("agreement", class="Bundle:Agreement")
* #Template()
*/
public function sendAction(Request $request, Agreement $agreement) {
*...Code omitted...*
}
Using this code, I get the exception (the hardcoded id and this code is just for test)
/**
* #Route("/agreement/send", name="agreement/send")
* #Template()
*/
public function sendAction(Request $request) {
$em = $this->get('doctrine')->getManager();
$qb = $em->createQueryBuilder()->select('a')->from('AppBundle:Agreement', 'a')->where('a.id=1378');
$agreements = $qb->getQuery()->getResult();
}
use setParameter()
$em->createQueryBuilder()
->select('a')
->from('AppBundle:Agreement', 'a')
->where('a.id = :id')
->setParameter('id', $request->get('id'));
There is a known bug #52083 that affects PHP versions before 5.3.4, which fails randomly with "Notice: Trying to get property of non-object".
If that is your case, try upgrading PHP will solve your issue. Hope that helps

Syntax error on a doctrine query (Symfony2)

Im getting a syntax error on this query:
protected function _getimsg($id)
{
$imsgRepository = $this->getDoctrine( )->getRepository( 'DonePunctisBundle:Imsg' );
$imsg = $imsgRepository->findOneBy(array('to' => $id, 'read' => 0 ));
if($imsg) {
$em = $this->getDoctrine()->getEntityManager();
$imsg->setRead('1');
$em->persist( $imsg );
$em->flush( );
return $imsg->getContent();
} else {
return '';
}
}
imsg Entity
<?php
namespace Done\PunctisBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Imsg
*
* #ORM\Table(name="imsg")
* #ORM\Entity
*/
class Imsg
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="to", type="string", length=25)
*/
private $to;
/**
* #var string
*
* #ORM\Column(name="content", type="string", length=255)
*/
private $content;
/**
* #var integer
*
* #ORM\Column(name="read", type="integer", length=1)
*/
private $read;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set To
*
* #param string $to
* #return Page
*/
public function setTo($to)
{
$this->to = $to;
return $this;
}
/**
* Get to
*
* #return string
*/
public function getTo()
{
return $this->to;
}
/**
* Set content
*
* #param string $content
* #return Page
*/
public function setContent($content)
{
$this->content = $content;
return $this;
}
/**
* Get content
*
* #return string
*/
public function getContent()
{
return $this->content;
}
/**
* Set read
*
* #param integer $read
* #return Imsg
*/
public function setRead($read)
{
$this->read = $read;
return $this;
}
/**
* Get read
*
* #return integer
*/
public function getRead()
{
return $this->read;
}
}
The error output
An exception occurred while executing 'UPDATE imsg SET read = ? WHERE
id = ?' with params {"1":"1","2":1}:
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an
error in your SQL syntax; check the manual that corresponds to your
MySQL server version for the right syntax to use near 'read = '1'
WHERE id = 1' at line 1
Any ideas?
From the MySQL manual: http://dev.mysql.com/doc/refman/5.5/en/reserved-words.html - READ is a reserved word. I'm guessing that's why you're getting the syntax error.
Doctrine can automatically quote the column names for you:
<?php
/** #Column(name="`number`", type="integer") */
private $number;
Add backticks to the colum's name - taken from http://docs.doctrine-project.org/en/latest/reference/basic-mapping.html#quoting-reserved-words
if you use yaml, you can do this
Number:
type: entity
table: `number `

Resources