I'm using EasyAdmin Bundle. When I'm trying to add a new element in Entity named "Company" which have 'ManyToMany' relation with "Service" entity I'm getting an error:
Error: Method AppBundle\Entity\Service::__toString() must not throw an exception
But when I'm going to add a new element in "Service" entity, everything works fine and the field with "Company" entities is displaying correctly.
I was trying to catch the exception implementing this workaround, but It doesn't take effect.
The Service class:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Company
*
* #ORM\Table(name="company")
* #ORM\Entity(repositoryClass="AppBundle\Repository\CompanyRepository")
*/
class Company
{
/**
* #var
*
* Many Companys have Many Services.
* #ORM\ManyToMany(targetEntity="Service", inversedBy="companys")
* #ORM\JoinTable(name="companys_services")
*/
private $services;
public function __construct() {
$this->services = new ArrayCollection();
}
public function __toString()
{
return $this->name;
}
}
And the Service class:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Service
*
* #ORM\Table(name="service")
* #ORM\Entity(repositoryClass="AppBundle\Repository\ServiceRepository")
*/
class Service
{
/**
* Many Services have Many Companys.
* #ORM\ManyToMany(targetEntity="Company", mappedBy="services")
*/
private $companys;
public function __construct()
{
$this->companys = new ArrayCollection();
}
public function __toString()
{
return (string) $this->name;
}
}
What is wrong?
The error message is so specific (Service::__toString() must not throw an exception) that the problem must be in the $this->name property of Service. Is it defined? Is a "normal" property or some advanced object which fails when casting it into a string?
Related
Symfony 5.3
Doctrine bundle ^2.4 ORM ^2.9
MariaDB 10.6.4
This has been rather difficult to diagnose especially as I was dealing with some complicated layered code. If I was sure, I would have filed a bug with Doctrine, but I want to first make sure I'm not making some glaring mistake or such, in implementation.
I have painstakingly tried to reduce the code to a simplified working example. On my test database tables, there are additional columns that are not referred to in the demo code.
// src/Entity/Record.php
declare(strict_types = 1);
namespace App\Entity;
use App\Repository\RecordRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=RecordRepository::class)
* #ORM\Table(name="Records")
*/
class Record {
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
protected $id;
public function getId(): ?int {
return $this->id;
}
/**
* #ORM\OneToOne(targetEntity="App\Entity\RecordStatus", mappedBy="record", cascade={"persist"})
* #ORM\JoinColumn(name="Id")
*/
private ?RecordStatus $recordStatus = NULL;
public function getRecordStatus(): ?RecordStatus {
return $this->recordStatus;
}
public function setRecordStatus(RecordStatus $value): void {
$value->setRecord($this);
$this->recordStatus = $value;
}
}
// src/Entity/RecordStatus.php
declare(strict_types = 1);
namespace App\Entity;
use App\Repository\RecordStatusRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=RecordStatusRepository::class)
* #ORM\Table(name="Record_Statuses")
*/
class RecordStatus {
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
protected $id;
public function getId(): ?int {
return $this->id;
}
/**
* #ORM\OneToOne(targetEntity="App\Entity\Record", inversedBy="record")
* #ORM\JoinColumn(name="RecordId")
*/
private Record $record;
public function getRecord(): Record {
return $this->record;
}
public function setRecord(Record $value): void {
$this->record = $value;
}
}
// src/Controller/DefaultController.php
declare(strict_types = 1);
namespace App\Controller;
use App\Entity\Record;
use App\Entity\RecordStatus;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class DefaultController extends AbstractController {
/**
* #Route("/")
*/
public function home(): Response {
$doctrine = $this->getDoctrine();
$entityManager = $doctrine->getManager();
$recordRepository = $doctrine->getRepository(Record::class);
$recordStatus = new RecordStatus;
$item = $recordRepository->find(1);
$item->setRecordStatus($recordStatus);
$entityManager->flush();
return new JsonResponse(['id' => $item->getId()]);
}
}
When this route ("/") is triggered, the record is updated and the old Id is displayed. But after the update, checking the database shows that the record now has a newly Auto-Generated Id, that comes after the last previous record in the table. Note that this is on UPDATE and not INSERT.
My current partial workaround is to load the currently mapped relation if one exists and update it instead of using new RecordStatus, but it should also be possible to use a new Related instance if required (especially if there was no Relation assigned on first insert).
Im trying to change an old arraycolection of $linhas for a new one by using the method
setLinhas(Arraycollection $linhas)
but what happens when it does the changes is that internally he creates a new object with the new lines and dont update the old object with the new lines. It creates a new instance with the same values as the old object. It was suppose to update the same object and not create a new one!
Entity's Property :
/**
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="AppBundle\Entity\LinhasPrecos", mappedBy="preco",orphanRemoval=true,cascade={"persist","merge"})
*/
protected $linhas;
/**
* #param $linhas
*/
public function setLinhas($linhas)
{
$this->linhas = new ArrayCollection($linhas);
}
In the service:
$oldObject->setLinhas($newObectWithNewLinhas->getLinhas());
$this->em->persist($oldObject);
but if I do the change manually it will work:
$oldLinhas = $oldObject->getLinhas()->getValues();
foreach($oldLinhas as $oldLinha)
{
$oldObject->removeLinha($oldLinha);
}
$linhaToCopy = $newObectWithNewLinhas->getLinhas()->getValues();
foreach($linhasCopyNew as $linhaCopyNew)
{
$oldObject->addLinha($linhaCopyNew);
}
thanks in advance!
You are doing it wrong!
use this constructor and setter instead:
Preco
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Preco
{
//...
/**
* #var Collection
*
* #ORM\OneToMany(targetEntity="AppBundle\Entity\LinhasPrecos", mappedBy="preco", orphanRemoval=true, cascade={"persist","merge"})
*/
protected $linhas;
//...
public function __construct()
{
$this->linhas = new ArrayCollection();
}
public function setLinhas($linhas)
{
$this->linhas = $linhas;
}
}
Notice
You should pass a doctrine collection into setLinhas.
This way you are totally replacing an old collection, with the new collection (and not adding an element to the old collection).
I'm making my first small app in symfony, a simple blog.
Now I have been using the documentation for both symfony and doctrine and want to preform a simple, beginner task: display a json encoded simple table
Yet somehow I cant seem to get along with doctrine.
Here is my data (apart form the view which does nothing but display the value):
//AppBundle/Controller/DefaultController.php
<?php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use AppBundle\Entity\Post;
use Doctrine\Common\Persistence;
class DefaultController extends Controller
{
/**
* #Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
$database = new Post();
$output = $database->findAll();
return $this->render('default/index.html.twig', [
'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR,
'x' => json_encode($output)
]);
}
}
<?php
//AppBundle/Entity/Post.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\EntityRepository;
/**
* #ORM\Entity
* #ORM\Table(name="sqltest")
*/
class Post extends EntityRepository
{
//The post for now uses data from a temponary test table
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=100)
*/
private $name;
/**
* #ORM\Column(type="integer", scale=2)
*/
private $number;
/**
* Get id
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
* #param string $name
* #return Post
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set number
* #param integer $number
* #return Post
*/
public function setNumber($number)
{
$this->number = $number;
return $this;
}
/**
* Get number
* #return integer
*/
public function getNumber()
{
return $this->number;
}
}
Problem is when I try to display the website i get this exception
Warning: Missing argument 1 for
Doctrine\ORM\EntityRepository::__construct(), called in
C:\Users\Alan\Desktop\symf-blog\src\AppBundle\Controller\DefaultController.php
on line 19 and defined
Problematic line being the one with $database = new Post();
I am very new in this and am aware that the response is very simple and I just don't see it. When answering please provide and explanation which even a dead rabbit could understand.
Pretty thanks for your patience.
PS: Also an explanation about what the $em variable I've seen so much about is for and from where do I get it would be nice
If you're want a repository class for custom DB functions then this is the right way to do it:
namespace AppBundle\Entity;
use Doctrine\ORM\EntityRepository;
class PostRepository extends EntityRepository
{
public function findAll()
{
return $this->findBy(array(), array('id' => 'DESC', 'createdAt' => 'DESC'));
}
....
}
Then in your controller:
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository("AppBundle:Post")->findAll();
Remove the annotations (them belongs to the entity). Also pay attention to what #james_bond told you. Try that!
As stated in the documentation, you access custom repository classes through doctrine entity manager.
$em = $this->getDoctrine()->getManager();
$posts = $em->getRepository('YourBundle:Post')->findAll();
Also you're mixing your entity definition with your repository definition, which is not a good idea.
Please refer to the doctrine documentation in symfony for proper usage.
I'm using the BeSimple SoapBundle to create a SOAP server but i'm having troubles with the following piece of code:
namespace AppBundle\Entity;
use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap;
/**
* #Soap\Alias("Item")
*/
class Item
{
/**
* #Soap\ComplexType("AppBundle\Entity\Item[]")
*/
protected $items;
/**
* #Soap\ComplexType("string")
*/
protected $name;
What i need to get is a tree of complextype items but i'm getting a circular reference error when using the annotation #Soap\ComplexType("AppBundle\Entity\Item[]").
Any idea of how can i deal with this situation?
I finally found a workaround for this issue. I think that it shouldn't be necessary but is the best and only way i found.
namespace AppBundle\Entity;
use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap;
/**
* #Soap\Alias("ComplexItem")
*/
class ComplexItem extends Item
{
/**
* #Soap\ComplexType("AppBundle\Entity\Item")
*/
protected $item;
public function setItem($item)
{
$this->item = $item;
}
namespace AppBundle\Entity;
use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap;
class Item
{
/**
* #Soap\ComplexType("string")
*/
protected $name;
Controller usage example:
/**
* #Soap\Method("getItem")
* #Soap\Result(phpType = "AppBundle\Entity\ComplexItem")
*/
public function getItem()
{
$item = new ComplexItem();
$complexItem = new ComplexItem();
$complexItem->setItem($item);
return $complexItem;
}
Hope it helps someone. If you know a better way to solve this, please, let me know.
Im working with Symfony 2.4 im getting this exception when i came to run the code
doctrine:generate:entities
Class "Entity\ClientClass" is not a valid entity or mapped super class
How to resolve it.
Here is the code in Entity
namespace category\CategoryBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* category
*/
class category
{
/**
* #var integer
*/
private $id;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
We can't help you without details :
- check the namespace of the Entity/ClientClass and the file path according to doctrine configuration, by default : src/BundleName/Entity
does your class have the annotation #ORM\Entity or #ORM\MappedSuperClass ?