Configuring the Translatable Doctrine2 extension with Symfony2 using YAML - symfony

In a nutshell
I'm writing a Symfony2 / Doctrine2 app and have installed and configured the Translatable extension provided by StofDoctrineExtensionsBundle using YAML, however no additional translation table(s) are generated and the following exception is thrown when attempting to work with entities that have translatable properties:
No mapping file found named '/var/www/my-project/vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity/Translation.orm.yml' for class 'Gedmo\Translatable\Entity\Translation'.
In more detail
I'm trying to get the Translatable extension working in my Symfony2 / Doctrine2 application that is provided by the StofDoctrineExtensionsBundle, however most of the available documentation I can find mainly targets the usage of annotations for configuration, but I'm going with YAML because that's how I have configured everything else.
My configuration
I have added the following to my composer.json file and have ran the composer update command: "stof/doctrine-extensions-bundle": "dev-master" and the bundle is registered in my app/AppKernel.php file.
My app/config/config.yml file has the following configuration:
doctrine:
orm:
auto_generate_proxy_classes: %kernel.debug%
auto_mapping: true
mappings:
gedmo_translatable:
type: yml
prefix: Gedmo\Translatable\Entity
dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity"
alias: GedmoTranslatable
is_bundle: false
stof_doctrine_extensions:
default_locale: en_GB
translation_fallback: true
orm:
default:
timestampable: true
translatable: true
I have then defined an entity in YAML:
Foo\ContentBundle\Entity\Article:
type: entity
repositoryClass: Foo\ContentBundle\Repository\ArticleRepository
table: article
gedmo:
translation:
locale: locale
id:
id:
type: integer
generator: { strategy: AUTO }
fields:
name:
type: string
length: 64
gedmo:
- translatable
content:
type: text
gedmo:
- translatable
# ... #
oneToMany:
# ... #
I have then ran the console command php app/console doctrine:generate:entities FooContentBundle to generate the entity classes, and have manually added the locale property and setter:
class Article
{
/* ... */
private $locale;
public function setTranslatableLocale($locale)
{
$this->locale = $locale;
}
/* ... */
}
After running php app/console doctrine:schema:update --force, my article table is created along with its associations, but nothing relating to translations (I'm assuming a table is supposed to be created for this...)
Then, when working with an entity that is translatable, I'm getting the exception:
No mapping file found named '/var/www/my-project/vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity/Translation.orm.yml' for class 'Gedmo\Translatable\Entity\Translation'.
The YAML file that the exception is referencing does not exist in the path that it's looking for it within, neither could I find it anywhere else.
Does anyone have any ideas as to where I'm going wrong?
Update: After further investigation...
Running php app/console doctrine:mapping:info displays all of my entities and nothing relating to translations, however, if I update the gedmo_translatable: part of my app/config/config.yml file and change type: yml to type: annotation then run the command again, I get the following listed:
[OK] Gedmo\Translatable\Entity\MappedSuperclass\AbstractTranslation
[OK] Gedmo\Translatable\Entity\Translation
[OK] Gedmo\Translatable\Entity\MappedSuperclass\AbstractPersonalTranslation
At which point, I can update my schema, and I have a new ext_translations table. However, nothing is being inserted into it when working with my entities, presumably because it's now expecting configuration by annotation rather than YAML, changing my config back to type: yml starts throwing the exception again, as expected.

After trying things that the documentation suggests will not work, i.e. mixing both annotation and YAML configurations in the same bundle, it would appear I have things working. The whole thing feels like a bug or an incomplete implementation, however I may be doing something incorrectly. Here's what's working...
Setting the following in app/config/config.yml: doctrine.orm.mappings.gedmo_translatable.type: annotation
Setting the translatable configuration in my YAML schema definition as outlined in my original question, as well as as an annotation in my class file:
/* ... */
use Gedmo\Mapping\Annotation as Gedmo;
/* ... */
class Article
{
/* ... */
/**
* #Gedmo\Translatable
* #var string $name
*/
private $name;
/**
* #Gedmo\Locale
*/
private $locale;
public function setTranslatableLocale($locale)
{
$this->locale = $locale;
}
/* ... */
}
After doing this, the additional table is created and translations are being inserted into it when persisting the entity.

Related

Kayue\WordpressBundle with Symfony 4.4.1: The class XXX was not found in the chain configured namespaces App\Entity

I'm trying to work with kayue/KayueWordpressBundle installed with composer as composer require kayue/kayue-wordpress-bundle in my Symfony 4.4.1 project but I'm unable to.
This is what I'm trying to do:
<?php
namespace App\Service\WordPress;
use Doctrine\ORM\EntityManagerInterface;
use Kayue\WordpressBundle\Entity\Post;
class PostCollection
{
protected $postRepository;
public function __construct(EntityManagerInterface $entityManager)
{
$this->postRepository = $entityManager->getRepository(Post::class);
}
}
The error I get:
The class 'Kayue\WordpressBundle\Entity\Post' was not found in the chain configured namespaces App\Entity
At first I blamed my dual-database configuration (Symfony is on a different DB from Wordpress) but then I put the DBs together and the issue persists:
doctrine:
dbal:
url: '%env(resolve:DATABASE_URL)%'
# Only needed for MySQL (ignored otherwise)
charset: utf8mb4
default_table_options:
collate: utf8mb4_unicode_ci
orm:
auto_generate_proxy_classes: true
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: true
mappings:
App:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
I've been fiddling for the past 2hrs, but now I'm fresh out of ideas. I wonder if ANYONE actually got this to work with Symfony 4.
Thanks!
Edit: other tries:
Direct post injection:
use Kayue\WordpressBundle\Entity\Post;
public function index(Post $post){}
Result:
Cannot autowire argument $post of "App\Controller\IndexController::index()": it references class "Kayue\WordpressBundle\Entity\Post" but no such service exists.
As per documentation: outdated Symfony 2 way
$repo = $this->get('kayue_wordpress')->getManager()->getRepository('KayueWordpressBundle:Post');
Result:
Service "kayue_wordpress" not found: even though it exists in the app's container, the container inside "App\Controller\IndexController" is a smaller service locator that only knows about the "doctrine", "form.factory", "http_kernel", "parameter_bag", "request_stack", "router", "security.authorization_checker", "security.csrf.token_manager", "security.token_storage", "serializer", "session" and "twig" services. Try using dependency injection instead.
The "best way" to do this would actually be:
public function index(EntityManagerInterface $entityManager)
{
$entityManager->getRepository('KayueWordpressBundle:Post');
}
Result:
The class 'Kayue\WordpressBundle\Entity\Post' was not found in the chain configured namespaces App\Entity
Although you found a solution to this, there is a chain of issues I would like to explain.
The error
The class 'Kayue\WordpressBundle\Entity\Post' was not found in the chain configured namespaces App\Entity
means that in the entity manager provided, whose config is defined at:
orm:
...
mappings:
App:
...
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
the entity type Kayue\WordpressBundle\Entity\Post was not found.
Usually this type of error is solved by:
include the path Kayue\WordpressBundle\Entity in the entity manager or
use another entity manager which includes this path
In your case the default entity manager is autowired, based on the service alias of Doctrine\ORM\EntityManagerInterface as explained here. The alias is defined in the doctrine bundle `s config which points to the default doctrine entity manager.
You want to use Kayue\WordpressBundle `s entity manager, not the default one.
Solution
To solve this you can
1) Bind Arguments By type, as you find out, creating an alias of Kayue\WordpressBundle\Wordpress\ManagerRegistry to the service kayue_wordpress, as:
services:
# pass this service for any ManagerRegistry type-hint for any
# service that's defined in this file
Kayue\WordpressBundle\Wordpress\ManagerRegistry: '#kayue_wordpress'
or
2) use Binding Arguments by Name, in this case the "$wpManagerRegistry", as:
services:
# default configuration for services in *this* file
_defaults:
...
bind:
$wpManagerRegistry: '#kayue_wordpress'
and then
public function index($wpManagerRegistry)
{
$postRepository = $wpManagerRegistry->getManager()->getRepository('KayueWordpressBundle:Post');
so that any argument with name "$wpManagerRegistry" is autowired to this service.
References
The Symfony 3.3 DI Container Changes Explained (autowiring, _defaults, etc)
My collegue found a solution. You must configure the autowire like this:
// config/packages/kayue_wordpress.yaml
services:
Kayue\WordpressBundle\Wordpress\ManagerRegistry: '#kayue_wordpress'
After that, you can autowire:
use Kayue\WordpressBundle\Wordpress\ManagerRegistry;
public function __construct(ManagerRegistry $wpManagerRegistry)
{
$this->wpPostRepository = $wpManagerRegistry->getManager()->getRepository('KayueWordpressBundle:Post');
}
public function getPosts()
{
$post = $this->wpPostRepository->findOneBy(array(
'slug' => 'hello-world',
'type' => 'post',
'status' => 'publish',
));
}

Deprecation: Doctrine\ORM\Mapping\UnderscoreNamingStrategy without making it number aware is deprecated

I'm using Symfony 4.3.8 and I can't find any information about thoses deprecations :
User Deprecated: Creating Doctrine\ORM\Mapping\UnderscoreNamingStrategy without making it number aware is deprecated and will be removed in Doctrine ORM 3.0.
Creating Doctrine\ORM\Mapping\UnderscoreNamingStrategy without making it number aware is deprecated and will be removed in Doctrine ORM 3.0.
I searched in stacktrace and found this :
class UnderscoreNamingStrategy implements NamingStrategy
{
private const DEFAULT_PATTERN = '/(?<=[a-z])([A-Z])/';
private const NUMBER_AWARE_PATTERN = '/(?<=[a-z0-9])([A-Z])/';
/**
* Underscore naming strategy construct.
*
* #param int $case CASE_LOWER | CASE_UPPER
*/
public function __construct($case = CASE_LOWER, bool $numberAware = false)
{
if (! $numberAware) {
#trigger_error(
'Creating ' . self::class . ' without making it number aware is deprecated and will be removed in Doctrine ORM 3.0.',
E_USER_DEPRECATED
);
}
$this->case = $case;
$this->pattern = $numberAware ? self::NUMBER_AWARE_PATTERN : self::DEFAULT_PATTERN;
}
In this class, the constructor is always called without params, so $numberAware is always false.
This class is called in file which has been auto generated by the Symfony Dependency Injection, so I can't "edit" it ...
I thought maybe it was in doctrine.yaml :
doctrine:
orm:
auto_generate_proxy_classes: true
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: true
mappings:
App:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
But I have not found any option to allow the number aware :(
In most cases I would just answer this sort of question with a comment but I suspect other developers might run into this issue. I poked around a bit and could not find any explicit documentation on this issue. Perhaps because the DoctrineBundle is under the control of the Doctrine folks and not the Symfony developers. Or maybe I am just a bad searcher.
In any event, between 4.3 and 4.4 the service name for the underscore naming strategy was changed.
# doctrine.yaml
orm:
# 4.3
naming_strategy: doctrine.orm.naming_strategy.underscore
# 4.4
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
And a deprecated message was added to warn developers to change the name. Would have been nice if the message was just a tiny bit more explicit but oh well.
So if you are upgrading an existing app to 4.4 and beyond then you will probably need to manually edit your doctrine.yaml file to make the depreciation message go away.
Some more info (thanks #janh) on why the change was made:
https://github.com/doctrine/orm/blob/2.8.x/UPGRADE.md#deprecated-number-unaware-doctrineormmappingunderscorenamingstrategy
https://github.com/doctrine/orm/issues/7855
Still not really clear on why "they" chose to do things this way but oh well.
You probably want to run "bin/console doctrine:schema:update --dump-sql" just to see if this impacts your database column names and adjust accordingly. The changes has been out for several weeks now and there does not seem to be many howls of outrage over the change so I guess most column names don't have embedded numbers. So far at least.
For those who works with symfony4.3 and still want this warning disapear you can add add new new service defintion in service.yaml
custom_doctrine_orm_naming_strategy_underscore:
class: Doctrine\ORM\Mapping\UnderscoreNamingStrategy
arguments:
- 0
- true
and change the configuration of doctrine.yaml like this:
orm:
naming_strategy: custom_doctrine_orm_naming_strategy_underscore
before going straight forward committing this change I would suggest you to verify that passing true to the Doctrine\ORM\Mapping\UnderscoreNamingStrategy doesn't affect the expected behavior of your code.
// class UnderscoreNamingStrategy
/**
* Underscore naming strategy construct.
*
* #param int $case CASE_LOWER | CASE_UPPER
*/
public function __construct($case = CASE_LOWER, bool $numberAware = false)
{
if (! $numberAware) {
#trigger_error(
'Creating ' . self::class . ' without making it number aware is deprecated and will be removed in Doctrine ORM 3.0.',
E_USER_DEPRECATED
);
}
$this->case = $case;
$this->pattern = $numberAware ? self::NUMBER_AWARE_PATTERN : self::DEFAULT_PATTERN;
}
Quick hint:
passing true to the c'tor will make the class use the NUMBER_AWARE_PATTERN instead of the DEFAULT_PATTERN
private const DEFAULT_PATTERN = '/(?<=[a-z])([A-Z])/';
private const NUMBER_AWARE_PATTERN = '/(?<=[a-z0-9])([A-Z])/';

JMS Serializer Config

I am using this in config.yml:
# JMSSerializer Configuration
jms_serializer:
#parameters:
#jms_serializer.camel_case_naming_strategy.class: JMS\Serializer\Naming\IdenticalPropertyNamingStrategy
metadata:
cache: file
debug: "%kernel.debug%"
file_cache:
dir: "%kernel.cache_dir%/serializer"
auto_detection: true
directories:
AppBundle:
namespace_prefix: "AppBundle"
path: "%kernel.root_dir%/config/serializer/AppBundle"
And this in Entity.Category.yml:
AppBundle\Entity\Category:
exclusion_policy: ALL
But when i try to send request, i receive this error:
Expected metadata for class AppBundle\Entity\Category to be defined
in /var/www/test/app/config/serializer/AppBundle/Entity.Category.yml.
How can I solve this issue?
You forgot about TAB at 2 line.
It looks like you are getting an incorrect path to your project files with %kernel.root_dir%. Make sure that /var/www/test/app is the correct path to your project. Check your PHP __DIR__ constant and try replacing `%kernel.root_dir% with what that says as well as what you think the path should be.
Also, instead of defining your exclusion policy in a config file you should just be able to annotate your entity like so and expose things as needed:
use JMS\Serializer\Annotation as JMS;
/**
* Class ExampleEntity
*
* #JMS\ExclusionPolicy("all")
* #ORM\Entity()
*/
class ExampleEntity
{
}
JMS annotations are found here.

Gedmo loggable working but not storing username

I have got logging working on my entity so that when I make a change to a product field with the #Gedmo\Versioned annotation a new version is created. However the only problem is that the username field remains NULL. There is an authenticated user as the update is performed in Sonata Admin backend.
<?php
namespace MyApp\CmsBundle\Entity\Log;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Loggable\Entity\MappedSuperclass\AbstractLogEntry;
use Gedmo\Loggable\Entity\Repository\LogEntryRepository;
/**
* #ORM\Entity(repositoryClass="Gedmo\Loggable\Entity\Repository\LogEntryRepository", readOnly=true)
* #ORM\Table(
* name="log_product",
* indexes={
* #ORM\Index(name="log_class_lookup_idx", columns={"object_class"}),
* #ORM\Index(name="log_date_lookup_idx", columns={"logged_at"}),
* #ORM\Index(name="log_user_lookup_idx", columns={"username"}),
* }
* )
*/
class ProductLog extends AbstractLogEntry
{
}
So it would appear the log_user_lookup_idx isn't working correctly, is there a particular bit of config I require for this?
It appears I was missing a bit of config, adding the following to the main app/config/config.yml file did the trick.
stof_doctrine_extensions:
default_locale: en
orm:
default:
loggable: true
I did originally have this in my bundles' services.yml config:
gedmo.listener.loggable:
class: Gedmo\Loggable\LoggableListener
tags:
- { name: doctrine.event_subscriber, connection: default }
calls:
- [ setAnnotationReader, [ "#annotation_reader" ] ]
This managed to track the entity being modified but not the user, I have since removed this config and the logging remains to work with just the stof_doctrine_extensions config setting.
If you have both in your code base then everything will be logged twice I found.

JMSSerializer not serializing entity

I am trying to get a serialized entity response using the JmsSerializerBUndle and the FOSRestBundle. unfortunatly i'm unable to do so because i'm having problems
with the response.. i'm not sure the system recognizes the file Entity.SearchEngine.yml
Any Ideas how I could find why its not working?
#src\example\CoreBundle\Resources\config\serializer\Entity.SearchEngine.yml
Example\CoreBundle\Entity\SearchEngine:
exclusion_policy: ALL
properties:
id:
expose: true
groups: [search.list,search.details]
has_product_flight:
expose: true
groups: [search.details]
selfLink:
expose: true
groups: [self.link]
Rest action (using the FOSRestBundle):
/**
* GET /search/engines
*
* #return array
* #Rest\View(serializerGroups={"search.details", "self.link"})
*/
public function getSearchEnginesAction()
{
$searchEngineManager = $this->get('search_manager');
return $searchEngineManager->getSearchEngineList();
}
the response im getting is
{
0: { }
}
First, is SerializerBundle configured correctly? You should supply config for paths to your .ymls and corresponding namespaces, like this:
jms_serializer:
metadata:
auto_detection: true
directories:
ExampleCoreBundle:
namespace_prefix: "Example\\CoreBundle"
path: "#ExampleCoreBundle/Resources/config/serializer/"
Be sure to check that your search.manager service returns instances of SearchEngine. Also, I'm not sure if dots are supported in group names.

Resources