I have entities like this :
Request.php (parent)
/**
* #ORM\Entity(repositoryClass=RequestRepository::class)
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="type", type="string")
* #ORM\DiscriminatorMap({
* "requestA" = "RequestA",
* "requestB" = "RequestB"
* })
*/
abstract class Request
{
/*...*/
}
RequestA.php (child A)
/**
* #ORM\Entity(repositoryClass=DemenagementRepository::class)
*/
class RequestA extends Request implements AddressEntityInterface
{
/**
* #ORM\OneToOne(targetEntity=Address::class, inversedBy="request")
* #ORM\JoinColumn(nullable=false)
*/
private $address;
// +others...
}
RequestB.php (child B)
/**
* #ORM\Entity(repositoryClass=DemenagementRepository::class)
*/
class RequestB extends Request implements AddressEntityInterface
{
/**
* #ORM\OneToOne(targetEntity=Address::class, inversedBy="request")
* #ORM\JoinColumn(nullable=false)
*/
private $address;
// +others...
}
AddressEntityInterface.php
interface AddressEntityInterface
{
public function getAddress(): ?Address;
public function setAddress(Address $address): self;
}
Address.php
/**
* #ORM\Entity(repositoryClass=AddressRepository::class)
*/
class Address
{
/**
* #ORM\OneToOne(targetEntity=??????, mappedBy="address")
*/
private $request;
public function getRequest() { /* ... */ }
}
I want to use getRequest() revert relationship how can i do for make targetEntity dynamically ?
Thanks
I believe you need polymorphic relationships or as they like to call them from docrine 'Inheritance Mapping'
I leave you some sites to view on which you can find everything you need
Official Documentation (Doctrine)
Stackoverflow Practical example
Youtube tutorial
Stackoverflow, discussion <-
personally I advise you to read all this so you get a concrete idea of what you need
I hope my little routing will help you.
I use Loggable to backup changes in Entities.
The default AbstractLogEntry does not have enough columns for my needs.
Thats why i extended the class and added extra getters and setters.
See the code below
/**
* EmployeeBackup
*
* #ORM\Table(name="employee_backup")
* #ORM\Entity(repositoryClass="Gedmo\Loggable\Entity\Repository\LogEntryRepository")
*
*/
class EmployeeBackup extends AbstractLogEntry
{
/**
* #var int
*
* #ORM\Column(name="division_id", type="integer", unique=true)
*/
private $divisionId;
/**
* #return int
*/
public function getDivisionId(): int
{
return $this->divisionId;
}
/**
* #param string $divisionId
*/
public function setDivisionId(string $divisionId): void
{
$this->divisionId = $divisionId;
}
}
The extension is using the class above. So it works.
But now i need to set the divisionId when a new version is stored.
I tried the code below
$loggable = new LoggableListener();
$loggable->setDivision($division);
$evm->addEventSubscriber($loggable);
And this is what i get:
Attempted to call an undefined method named "setDivision" of class "Gedmo\Loggable\LoggableListener".
And thats true because LoggableListener does not have a setDivision function. My question is: Do i need to override the listener and if so, how do i do that?
Thanks ;)
I'm following the tutorial : "How to customize a translatable Model?" in Sylius doc.
When I run the command : php bin/console doctrine:migrations:diff I got this error :
Fatal error: Declaration of AppBundle\Entity\ShippingMethod::createTranslation(): Sylius\Component\Shipping\Model\ShippingMethodTranslation must be compatible with Sylius\Component\Shipping\Model\ShippingMethod::createTranslation(): Sylius\Component\Shipping\Model\ShippingMethodTranslationInterface in C:\wamp64\www\acme7\src\AppBundle\Entity\ShippingMethod.php on line 8
Here is my class :
<?php
namespace AppBundle\Entity;
use Sylius\Component\Core\Model\ShippingMethod as BaseShippingMethod;
use Sylius\Component\Shipping\Model\ShippingMethodTranslation;
class ShippingMethod extends BaseShippingMethod
{
/**
* #var string
*/
private $estimatedDeliveryTime;
/**
* #return string
*/
public function getEstimatedDeliveryTime(): string
{
return $this->estimatedDeliveryTime;
}
/**
* #param string $estimatedDeliveryTime
*/
public function setEstimatedDeliveryTime(string $estimatedDeliveryTime): void
{
$this->estimatedDeliveryTime = $estimatedDeliveryTime;
}
/**
* {#inheritdoc}
*/
protected function createTranslation(): ShippingMethodTranslation
{
return new ShippingMethodTranslation();
}
}
Any idea on how to solved this ?
I got some help form the slack of sylius.
As I'm using Sylius v1.0.4
I had to replace :
use Sylius\Component\Shipping\Model\ShippingMethodTranslation;
by
use Sylius\Component\Shipping\Model\ShippingMethodTranslationInterface;
and
/**
* {#inheritdoc}
*/
protected function createTranslation(): ShippingMethodTranslation
{
return new ShippingMethodTranslation();
}
by
/**
* {#inheritdoc}
*/
protected function createTranslation(): ShippingMethodTranslationInterface {
return new ShippingMethodTranslation();
}
I have several classes using a Taggable trait to set up a tag system common to several doctrine entities (Project, Note, ...).
The relationship between these entities and these tags is a ManyToMany relationship that I can not make multi-directional.
My problem: When I delete a Project entity, it is removed from the project table, but the relationships in the project_tag table between this project and the tags are not deleted. Then, if I create a new Project entity, an exception is thrown.
An exception exists while executing 'INSERT INTO project_tag (project_id, tag_id) VALUES (?,?)' With params [2, 4]:
SQLSTATE [23000]: Integrity constraint violation: 19 UNIQUE constraint failed: project_tag.project_id, project_tag.tag_id
Entities :
Tag
/**
* Tag
*
* #ORM\Table(name="tag")
* #ORM\Entity(repositoryClass="AppBundle\Repository\TagRepository")
*/
class Tag
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255, unique=true)
*/
private $name;
/**
* #ORM\Column(name="last_use_at", type="datetime", nullable=false)
* #var \DateTime
*/
private $lastUseAt;
public function __construct()
{
$this->lastUseAt = new \DateTime();
}
public function __toString()
{
return $this->name;
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Tag
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName(): string
{
return $this->name;
}
/**
* #return \DateTime
*/
public function getLastUseAt(): \DateTime
{
return $this->lastUseAt;
}
/**
* #param \DateTime $lastUseAt
*/
public function setLastUseAt(\DateTime $lastUseAt)
{
$this->lastUseAt = $lastUseAt;
}
}
Taggable
trait Taggable
{
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Tag", cascade={"persist"})
*/
protected $tags;
/**
* Add tag
*
* #param Tag $tag
*
* #return $this
*/
public function addTag(Tag $tag)
{
$tag->setLastUseAt(new \DateTime());
$this->tags[] = $tag;
return $this;
}
/**
* Remove tag
*
* #param Tag $tag
*/
public function removeTag(Tag $tag)
{
$this->tags->removeElement($tag);
}
/**
* Get tags
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getTags()
{
return $this->tags;
}
}
Project
/**
* Project
*
* #ORM\Table(name="project")
* #ORM\Entity(repositoryClass="AppBundle\Repository\ProjectRepository")
*/
class Project
{
use Taggable;
}
Note
class Note
{
use Taggable;
}
Is this the only solution or is my annotation incomplete / incorrect?
I tried with JoinColumns, JoinTable and onDelete = "cascade" but nothing works.
In the meantime, I dodged the problem with this instruction placed before the suppresion.
$project->getTags()->clear();
Full code of the action in the controller :
/**
* #Route("/project/{id}/delete", name="project_delete")
*/
public function deleteAction($id) {
$em = $this->getDoctrine()->getManager();
$project = $em->getRepository('AppBundle:Project')->find($id);
if(!$project) {
return $this->redirectToRoute('index');
}
$project->getTags()->clear();
$em->remove($project);
$em->flush();
return $this->redirectToRoute('index');
}
I think I found a better solution: you can set the PRAGMA within Doctrine configuration. Like:
doctrine:
dbal:
# configure these for your database server
driver: 'pdo_sqlite'
#server_version: '5.7'
#charset: utf8mb4
#default_table_options:
#charset: utf8mb4
#collate: utf8mb4_unicode_ci
url: '%env(resolve:DATABASE_URL)%'
options:
'PRAGMA foreign_keys': 'ON'
I just tried it on my Symfony 4 application, re-created the database and tested using DB Browser for SQLite and it works as I expected.
Hope this helps
I managed to fix the problem. Here's my solution working for SQLite conections.
Create an eventListener listening on the kernel.request event :
namespace AppBundle\EventListener;
use Doctrine\Bundle\DoctrineBundle\Registry;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
class RequestListener
{
/**
* #var Registry
*/
private $doctrine;
public function __construct(Registry $doctrine)
{
$this->doctrine = $doctrine;
}
public function onKernelRequest(GetResponseEvent $event)
{
$this->doctrine->getConnection()->exec('PRAGMA foreign_keys = ON');
}
}
Service declaration
app.event_listener.request_listener:
class: AppBundle\EventListener\RequestListener
arguments:
- '#doctrine'
tags:
- { name: kernel.event_listener, event: kernel.request }
I think the problem is that you have your trait Taggable set as the owning side of the ManyToMany relationship but your are deleting the inverse side and expecting something to happen as a result. Doctrine will only check the owning side of the relationship in order to persist any changes. See here for docs on this.
You can solve by making the Taggable the inverse side of each of your relationships, or by manually telling doctrine to delete the owning side.
The first solution will probably not work for you since you won't (easily) specify multiple inverse sides. (Are you sure a trait is the right way to go for this??)
The second solution is easy. In your entities like Project for your deleteTag($tag) function, call a delete function on the owning side (e.g., deleteProject($project). You will have to create if one does not exist.
class Project
{
use Taggable;
public function deleteTag($tag)
{
$this->tags->removeElement($tag);
// persist on the owning side
$tag->deleteProject($this);
}
}
EDIT:
After seeing full code, it looks like you are deleting correctly. Now you need to tell doctrine to carry that through. See this post for full details, but basically you can change your trait to this:
trait Taggable
{
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(
* targetEntity="AppBundle\Entity\Tag",
* cascade={"persist"},
* onDelete="CASCADE"
* )
*/
protected $tags;
// ...
}
I'm learning how to work with Neo4j and Doctrine OGM, and I'm having problems with my source code. I don't know how to use manytomany because I'm just starting learn. When I save I see:
Catchable fatal error: Argument 1 passed to Entity\Empresas::setTelefone() must be an instance of Entity\Entity\Telefones, string given, called in /Applications/MAMP/htdocs/neo4j/n4j/save.php on line 17 and defined in /Applications/MAMP/htdocs/neo4j/n4j/Empresas.php on line 50
My Empresas.php entity
namespace Entity;
use HireVoice\Neo4j\Annotation as OGM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* All entity classes must be declared as such.
*
* #OGM\Entity(labels="Empresas")
*/
class Empresas
{
/**
* The internal node ID from Neo4j must be stored. Thus an Auto field is required
* #OGM\Auto
*/
protected $id;
/**
* #OGM\Property
* #OGM\Index
*/
protected $nome;
/**
* #OGM\Property
*/
protected $keywords;
/**
* #OGM\ManyToOne(relation="tem_telefone")
*/
protected $telefone;
function getID(){
return $this->id;
}
function setNome($nome){
$this->nome = $nome;
}
function setKeywords($keywords){
$this->keywords = $keywords;
}
public function getTelefone() {
return $this->telefone;
}
public function setTelefone(Entity\Telefones $telefone) {
$this->telefone = $telefone;
}
}`
My Telefones.php Entity
<?php
namespace Entity;
use HireVoice\Neo4j\Annotation as OGM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* All entity classes must be declared as such.
*
* #OGM\Entity(labels="Empresas")
*/
class Telefones
{
/**
* The internal node ID from Neo4j must be stored. Thus an Auto field is required
* #OGM\Auto
*/
protected $id;
/**
* #OGM\Property
* #OGM\Index
*/
protected $telefone;
function getID(){
return $this->id;
}
}
And my Save.php Entity
<?php
require 'bootstrap.php';
require 'Empresas.php';
require 'Telefones.php';
$repo = $em->getRepository('Entity\\Empresas');
$empresa_container = $em->find('Entity\\Empresas', "22");
$telefones = new Entity\Telefones();
$empresa = new Entity\Empresas;
$empresa->setNome("nome");
$empresa->setKeywords("keywords");
$empresa->setTelefone("telefone");
$em->persist($telefones);
$em->persist($empresa);
$em->flush();
echo $empresa->getId();
Error