Class LogEntry not found - symfony

In my app developed with Symfony 4.2 and API Platform,
I install DoctrineExtensions bundle to use Loggable extension,
and I follow instructions in Symfony documentation and Loggable extension.
When I only use one EntityManager, everything works.
But I wanna move the LogEntry entity table to another database.
So I created a second EntityManager as described in the Symfony doc.
After, I modify in my app an entity that has the annotation #Gedmo\Loggable
and I get this error:
The class 'Gedmo\Loggable\Entity\LogEntry' was not found in the chain configured namespaces 'App\Entity'.
My config/packages/doctrine.yaml file:
parameters:
env(DATABASE_URL): ''
doctrine:
dbal:
connections:
default:
driver: 'pdo_mysql'
server_version: '%env(resolve:SERVER_VERSION)%'
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
url: '%env(resolve:DATABASE_URL)%'
log:
driver: 'pdo_mysql'
server_version: '%env(resolve:SERVER_VERSION)%'
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
url: '%env(resolve:LOG_DATABASE_URL)%'
orm:
auto_generate_proxy_classes: '%kernel.debug%'
entity_managers:
default:
naming_strategy: doctrine.orm.naming_strategy.underscore
mappings:
App:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
log:
naming_strategy: doctrine.orm.naming_strategy.underscore
connection: log
mappings:
gedmo_loggable:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/vendor/gedmo/doctrine-extensions/lib/Gedmo/Loggable/Entity'
prefix: 'Gedmo\Loggable\Entity'
alias: GedmoLoggable
Example of Entity that I want to watch:
<?php
namespace App\Entity;
...
use Gedmo\Mapping\Annotation as Gedmo;
...
/**
* #ApiResource
* #Gedmo\Loggable
* #ORM\Table(name="patients")
*/
class Patient
{
/**
* #ORM\Id
* #ORM\Column(type="guid", unique=true)
* #ORM\GeneratedValue(strategy="UUID")
* #Assert\Uuid
*/
private $id;
/**
* #ORM\Column(length=50)
* #Assert\NotBlank()
* #Assert\Length(max=50)
* #Gedmo\Versioned
*/
public $familyName;
/**
* #ORM\Column(length=50)
* #Assert\NotBlank()
* #Assert\Length(max=50)
* #Gedmo\Versioned
*/
public $firstName;
...
}
I tried to add and remove some properties in the doctrine.yaml but I always get the same error...
Thanks for your time.

Related

Loggable doesn't write in the table

I want to use loogable extension, but it doesn't write anything in ext_log_enties table.
I'm using symfony 5.4 and Api-platform 2.6.8 in my project.
My configuration:
doctrine.yaml
doctrine:
dbal:
...
orm:
auto_generate_proxy_classes: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: true
mappings:
gedmo_loggable:
type: annotation
prefix: Gedmo\Loggable\Entity
dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Loggable/Entity"
alias: GedmoLoggable # (optional) it will default to the name set for the mapping
is_bundle: false
...
stof_doctrine_extensions.yaml
stof_doctrine_extensions:
default_locale: fr_FR
orm:
default:
...
loggable: true
User.php
#[Gedmo\Loggable]
class User implements UserInterface
{
/**
* #ORM\Column(type="string", length=128, nullable=false)
*/
#[Gedmo\Versioned]
private ?string $firstName = null;
/**
* #ORM\Column(type="string", length=128, nullable=false)
*/
#[Gedmo\Versioned]
private ?string $lastName = null;
}
service.yaml :
services:
...
gedmo.listener.loggable:
class: Gedmo\Loggable\LoggableListener
tags:
- { name: doctrine.event_subscriber, connection: default }
What's wrong in my configuration ?

Why does Doctrine tries to insert new entities through relationships?

I have the following Doctrine entities where EntityA is the owning side:
<?php
class EntityA
{
/**
* #ORM\ManyToOne(targetEntity="EntityB" , inversedBy="propertyA")
*/
private $propertyB;
// ....
public function setEntityB(EntityB $entBRef)
{
$this->propertyB = $entBRef;
}
}
class EntityB
{
/**
* #ORM\OneToMany(targetEntity="EntityA", mappedBy="propertyB")
*/
private $propertyA;
// ....
}
I do also have a RepositoryB class:
<?php
class RepositoryB extends \Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository
{
public function __construct(\Doctrine\Common\Persistence\ManagerRegistry $registry)
{
parent::__construct($registry, EntityB::class);
}
}
Then in my class I am trying to persist an EntityA object:
<?php
class SomeService
{
/** #var RepositoryB */
private $repositoryB;
/** #var EntityManagerInterface */
private $entityManager;
public function __construct(RepositoryB $repositoryB, EntityManagerInterface $entityManager)
{
$this->repositoryB = $repositoryB;
$this->entityManager = $entityManager;
}
public function testSomething()
{
$entBRef = $this->repositoryB->find(1);
$newEnt = (new EntityA());
$newEnt->setEntityB($entBRef);
$this->entityManager->persist($newEnt);
$this->flush();
}
}
But I've got the following error:
A new entity was found through the relationship 'EntityA#propertyB'
that was not configured to cascade persist operations for entity:
EntityB. To solve this issue: Either explicitly call
EntityManager#persist() on this unknown entity or configure cascade
Here is how my doctrine.yaml file looks like:
parameters:
env(DATABASE_URL_WRITE): ''
services:
gedmo.listener.timestampable:
class: Org\CompBundle\Gedmo\Timestampable\TimestampableListener
tags:
- { name: doctrine.event_subscriber, connection: default }
calls:
- [ setAnnotationReader, [ "#annotation_reader" ] ]
gedmo.listener.loggable:
class: Gedmo\Loggable\LoggableListener
tags:
- { name: doctrine.event_subscriber, connection: default }
calls:
- [ setAnnotationReader, [ "#annotation_reader" ] ]
gedmo.listener.deleteable:
class: Gedmo\SoftDeleteable\SoftDeleteableListener
tags:
- { name: doctrine.event_subscriber, connection: default }
calls:
- [ setAnnotationReader, [ '#annotation_reader' ] ]
doctrine:
dbal:
default_connection: default
types:
microseconds: Org\CompBundle\DBAL\Types\DateTimeMicrosecondsType
connections:
read_only:
url: '%env(resolve:DATABASE_URL_READ)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
default:
url: '%env(resolve:DATABASE_URL_WRITE)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
orm:
auto_generate_proxy_classes: '%kernel.debug%'
default_entity_manager: default
entity_managers:
filters:
filters:
softdeleteable:
class: Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter
enabled: true
read_only:
connection: read_only
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
mappings:
gedmo_loggable:
type: annotation
prefix: Gedmo\Loggable\Entity
dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Loggable/Entity"
alias: GedmoLoggable
is_bundle: false
App:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/vendor/org/comp-bundle/Entity'
prefix: 'Org\CompBundle\Entity'
alias: Drm
dql:
datetime_functions:
timetosec: DoctrineExtensions\Query\Mysql\TimeToSec
timediff: DoctrineExtensions\Query\Mysql\TimeDiff
now: DoctrineExtensions\Query\Mysql\Now
numeric_functions:
rand: DoctrineExtensions\Query\Mysql\Rand
default:
connection: default
filters:
softdeleteable:
class: Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter
enabled: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: true
mappings:
gedmo_loggable:
type: annotation
prefix: Gedmo\Loggable\Entity
dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Loggable/Entity"
alias: GedmoLoggable
App:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/vendor/org/comp-bundle/Entity'
prefix: 'Org\CompBundle\Entity'
alias: Drm
dql:
datetime_functions:
timetosec: DoctrineExtensions\Query\Mysql\TimeToSec
timediff: DoctrineExtensions\Query\Mysql\TimeDiff
now: DoctrineExtensions\Query\Mysql\Now
numeric_functions:
rand: DoctrineExtensions\Query\Mysql\Rand
Last but not least I do have the following setup at org\compbundle\Resources\services.yaml:
services:
_defaults:
autowire: true
autoconfigure: true
public: false
bind:
$logger: '#Psr\Log\LoggerInterface'
Org\CompBundle\Repository\:
resource: '../../Repository/{Case,Main}'
exclude: ['../../Repository/**/*Interface.php']
tags: ['doctrine.repository_service']
Org\CompBundle\Interfaces\Queues\QueueRepositoryInterface:
class: Org\CompBundle\Repository\DrmCase\QueueRepository
Org\CompBundle\Interfaces\Cases\CasesRepositoryInterface:
class: Org\CompBundle\Repository\DrmCase\CasesRepository
Doctrine\Common\Persistence\ManagerRegistry: '#doctrine'
What I have done so far?
Read a lot of post here on SO leading to the same solution add cascade={"persist"} to the owning side which I did and I must say did not work.
Read Doctrine docs looking for mistakes on my entities definition but so far everything looks fine to me.
I did found this which is helpful but I keep questioning myself why would Doctrine tries to insert and existent entity just because of the reference? Is there any way to get this working?
I do not want the EntityB persisted nor updated, it already exists. I do want the new EntityA have a FK to an existent record in EntityB.
During the weekend a work colleague did work very hard to find out what was causing the issue and after a lot of hours debugging how Doctrine and the UoW works he found where the problem was: how Doctrine and the Repository pattern works. Let me explain a little bit.
If you check this closer and go deep inside Doctrine you will notice how the following code leads to two different entities manager:
public function __construct(RepositoryB $repositoryB, EntityManagerInterface $entityManager)
{
$this->repositoryB = $repositoryB; // spin his own EM
$this->entityManager = $entityManager; // this is a new EM object
}
So:
$entBRef = $this->repositoryB->find(1);
Is being fetched through another EM and since I am using $this->entityManager to persist/flush the recently created entityA object then Doctrine sees $entBRef as a new entity that has to be persisted.
Our solution was to fetch everything through the same repository class which I do not like so much because we are querying things that does not belongs there and we had to ever persist/flush using the same EM.
If you have any other solution it is more than welcome.

Functional Testing Symfony with mulitple Doctrine EntityManagers

In a Symfony 4 application I have configured multiple entity managers.
I want my functional tests to automatically create DB tables for both managers.
However, when I run my test; PHP unit encounters an error that says
PDOException: SQLSTATE[42S02]: Base table or view not found: 1146
Table 'test.example' doesn't exist
config/packages/doctrine.yaml:
doctrine:
dbal:
connections:
default:
url: '%env(resolve:DATABASE_URL)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
custom:
url: '%env(resolve:DATABASE_URL)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
orm:
default_entity_manager: default
auto_generate_proxy_classes: '%kernel.debug%'
entity_managers:
default:
connection: default
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: true
mappings:
Model:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Model'
prefix: 'App\Entity\Model'
alias: Model
custom:
connection: custom
naming_strategy: doctrine.orm.naming_strategy.underscore
mappings:
Custom:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Custom'
prefix: 'App\Entity\Custom'
alias: Custom
To create tables and load Fixtures I'm currently using the Liip Functional Test Bundle.
A simple test looks like this:
tests\Functional\GeneralControllerTest.php:
class GeneralControllerTest extends WebTestCase
{
/**
* {#inheritdoc}
*/
protected function setUp()
{
$this->loadFixtures([
SomeFixtures::class,
MoreFixtures::class,
]);
}
/**
* #dataProvider providePageUris
* #test
* #param string $uri
*/
public function checkThatPageLoads($uri)
{
$client = static::createClient();
/* ... more code ... */
$client->request(Request::METHOD_GET, $uri);
static::assertEquals(Response::HTTP_OK, $client->getResponse()->getStatusCode());
}
/**
* #return array
*/
public function providePageUris()
{
return [
["/dashboard"],
];
}
}
How can I make my Test Case create database tables for the other custom Doctrine EntityManagers?
I have tried adding:
$this->loadFixtures([], true, "custom");
and also:
$this->runCommand("doctrine:schema:create --env=test --em=custom");
to the setUp() method of the Test Case, but this did not result in what is needed. The database tables all need to be created before any Fixture is loaded into the database.
To not have tables in a different entity manager and connection removed when loading data fixtures I changed the doctrine configuration with distinct environment variables.
config/packages/doctrine.yaml:
doctrine:
dbal:
connections:
default:
url: '%env(resolve:DATABASE_URL)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
custom:
url: '%env(resolve:DATABASE_URL_CUSTOM)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
According to the code for the WebTestCase on GitHub the second argument should contain the name of the object manager. I am not sure if specifying custom is enough or if you have to specify the full name doctrine.entity_manager.custom though.

Using Doctrine extension softdeleteable with api-platform

I'm building an API with Symfony 3.4 and api-platform. I want to use soft delete on my entity. I've installed DoctrineExtensions and StofDoctrineExtensionsBundle.
config.yml:
doctrine:
dbal:
connections:
default:
[…]
orm:
entity_managers:
default:
naming_strategy: doctrine.orm.naming_strategy.underscore
connection: default
mappings:
[…]
filters:
softdeleteable:
class: Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter
enabled: true
And my entity :
<?php
namespace AppBundle\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* MyEntity
*
* #ORM\Table(name="MyEntity", schema="MyEntity")
* #ORM\Entity(repositoryClass="AppBundle\Repository\MyEntityRepository")
* #Gedmo\SoftDeleteable(fieldName="deletedAt")
* #ApiResource
*/
class MyEntity
{
/**
* #var \DateTime
* #ORM\Column(name="deleted_at", type="datetime")
*/
private $deletedAt;
[…]
This is not working. I'm aware that I need to configure something (namely the EventManager), but I don't know how.
Here is the error I get when I try to create an entity
Listener "SoftDeleteableListener" was not added to the EventManager!
I think I've done everything that page explains : StofDoctrineExtensionsBundle documentation
Any help would be greatly appreciated.
Try the following configuration at your config.yml
doctrine:
orm:
entity_managers:
default:
naming_strategy: doctrine.orm.naming_strategy.underscore
connection: default
mappings:
[…]
filters:
softdeleteable:
class: Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter
enabled: true
stof_doctrine_extensions:
default_locale: %locale%
orm:
default:
softdeleteable: true
Note: My configuration looks like:
orm:
auto_generate_proxy_classes: "%kernel.debug%"
entity_managers:
default:
auto_mapping: true
filters:
softdeleteable:
class: Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter
enabled: true
Seems that you're customizing your mappings so be sure you're autoloading the SoftDeleteable classes properly.

How can I log username and email address with StofDoctrineBundle?

I am running a Symfony2 app with Symfony2 and I'm using the FOSUserBundle to manage my users.
Now I implemented the StofDoctrineExtensionsBundle to use the loggable extensions. Unfortunately I cannot log the username and the email. If I try to activate logging via YML:
Acme\MyBundle\Entity\User:
type: entity
gedmo:
loggable: true
fields:
id:
...
username:
type: string
gedmo:
- versioned
email:
type: string
gedmo:
- versioned
I get a
Duplicate definition of column 'username' on entity in a field or discriminator column mapping.
So I tried to activate the logging in annotations (note that I define all my other entities via YML):
use FOS\UserBundle\Model\User as BaseUser;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* #Gedmo\Loggable
*/
class User extends BaseUser {
...
/**
* #var string
* #Gedmo\Versioned
*/
protected $username;
/**
* #var string
* #Gedmo\Versioned
*/
protected $email;
But: Nothing happens. All other properties of my User are logged, but username and email are not.
What do I have to change in order to activate logging for those both properties? Or is this an interdependency between the FOSUserBundle and the StofDoctrineExtensionsBundle that I cannot influence?
Have you added this configuration?:
//app/config/config.yml
orm:
auto_generate_proxy_classes: "%kernel.debug%"
auto_mapping: true
mappings:
translatable:
type: annotation
alias: Gedmo
prefix: Gedmo\Translatable\Entity
dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity"
loggable:
type: annotation
alias: Gedmo
prefix: Gedmo\Loggable\Entity
dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Loggable/Entity"
tree:
type: annotation
alias: Gedmo
prefix: Gedmo\Tree\Entity
dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Tree/Entity"
sluggable:
type: annotation
alias: Gedmo
prefix: Gedmo\Sluggable\Entity
dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Tree/Entity"

Resources