PHP 7 and Doctrine Group Uses - symfony

I want to use some features of PHP 7 but I'm kinda struggling with it.
I have a Symfony-Project using Doctrine to map some Entities. New in PHP 7 are the GROUP USE-Statemens, which I wanted to try. But it seems I'm doing something wrong, since Symfony / Doctrine can't resolve the Annotations in the Entity-Object.
Use-Statement:
use Doctrine\ORM\Mapping\{Entity, Id, Table, Column, GeneratedValue, JoinColumn, OneToOne, ManyToMany, JoinTable};
Entity
/**
* #Entity
* #Table(name="expansion")
*/
class Expansion {
..
}
Exception
[Semantical Error] The annotation "#Entity" in class AppBundle\Entity\Expansion was never imported. Did you maybe forget to add a "use" statement for this annotation?
If I use the single USE-Statements, the import works perfectly...
What am I doing wrong? Versions are correct. Also PHPStorm is saying that 'Alias XY' is never used.
Thanks for your support!

I'm not 100% sure but I bet that the Doctrine\Common\Annotations component cannot handle PHP7 grouped use statements yet. I could not find any written statement that confirms this assumption but Doctrine\Common\Annotations\TokenParser::parseUseStatement does not seem to handle grouped namespaces at all.

Related

How to rename Entity and attribute in symfony

I just want to rename "EntityName" to something else the most easily possible, with the database entry. Also how can I rename an Attribute?
So, I have an Entity called "EntityName" (for exemple) in /appname/src/Entity/EntityName.php like this:
<?php
namespace App\Entity;
use App\Repository\EntityNameRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=EntityNameRepository::class)
*/
class EntityName
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
[...]
When I try to rename the name of the class and try php bin/console doctrine:schema:update --dump-sql or --force I get this error:
In EntityName.php line 11:
Compile Error: Cannot declare class App\Entity\NewName, because the name is already in use
(I think I cannot rename beaucause it check itself if it already exist.)
I'd advise caution, specially if it's a production environment.
doctrine:schema:update --force (or doctrine:migrations:diff or make:migration, for that matter) doesn't detect changes so it will drop your existing table (along with all your data) and create a new one.
The safest way to preserve data would be to hand-create a migration with the ALTER TABLE ... RENAME. You can also use the #Table(name="old_table_name") annotation to preserve the original name, although this might be a bit confusing when looking at the database alone.
Depending on your IDE you might need more or less elbow grease. Chances are that the following will be handled correctly:
Both the entity and repository class name and file name, making them match (even in the caseName).
The entity class name in the repository constructor.
The repository class name in the repositoryClass annotation of the entity.
targetEntity annotations in relations.
There will be the property names themselves in the related classes (and JoinTableand mappedBy / inversedBy if applicable) left to change, if you wish to keep things consistent. If so, you would have to add the needed statements to the migration as well, and you might need to disable the constraints in the process. --dump-sql might be helpful on hinting what tables need renaming, but you won't be able to use the sql straight up.
The easiest way, if you don't care about your data, would be doctrine:schema:update --force indeed.
If you want to rename the entity means you have to change both Entity and Repository Class name and file name too. Then have to change Both classes import statements properly. After that just run this comment bin/console c:c.
If you want to rename an entity, you only need to change its class name AND file name to make it match. Also make sure the namespace match file path.
If all these things are right, then make sure you don't have another file which would contain the same namespace and class name you are trying to use for your "NewName" class
If you still get the error message, then you might want to clear you cache by running php bin/console c:c
Lastly, if it still fails, you might want to dump the autoload by running composer dump-autoload (or if you are using Phpstorm: tools > composer > dump autoloader)

Symfony doctrine reverse engineering and Apiplatform

Is there a way to create Apiplatform enabled entities directly from database schemas?
I successfully create the entities using php bin/console doctrine:mapping:import "App\Entity" annotation --path=src/Entity , but now i have to add manually the reference to Apiplatform resources in 120 entities like here. Is there another way?
Thanks in advance.
This feature isn’t supported out of the box (but it would be nice to add it). There is an open issue to add this feature to MakerBundle, but this hasn’t been implemented at time of writing.
However, you can easily achieve the same effect by using the "search and replace" feature of your IDE or by using sed: find every occurrences of #ORM\Entity and replace them with:
#ORM\Entity
#\ApiPlatform\Core\Annotation\ApiResource
You may want to run PHP CS Fixer after that to change the fully qualified class name by a use statement.

Doctrine lifecycleCallbacks strange behaviour

I have defined lifecycleCallbacks in yaml as follows:
lifecycleCallbacks:
prePersist: [setCreatedAtValue]
preUpdate: [setUpdatedAtValue]
The above has generated entities with the respective functions as follows:
/**
* #ORM\PrePersist
*/
public function setCreatedAtValue()
{
if($this->created_at == null)
{
$this->created_at = new \DateTime();
}
}
Which looks all fine, right? However, when I try to open the sonata admin page, I get the following error
[Semantical Error] The annotation "#ORM\PrePersist" in method AppBundle\Entity\Article::setCreatedAtValue() was never imported. Did you maybe forget to add a "use" statement for this annotation?
I have never encountered this before and a bit confused about what to do. I am using symfony 2.7.6, Doctrine ORM version 2.5.1, Sonata Admin 2.3.7
Any help will be greatly appreciated
Since you defined your callbacks using yaml, you don´t need to define them again using annotations. Just remove the comments with the #ORM\PrePersist block before the function and everything will be fine.
If you wanted to use annotations to define your doctrine properties, you would need to import them before you can use them. To do so you would need to add this line at the beginning of your file:
use Doctrine\ORM\Mapping as ORM;
Same issue came with me.
In my case everything worked well until I did not Serialize my object in JsonResponse.
So problem was that previously I was not using that entity class (which was giving error) for sending JsonResponse, as soon as I tried to prepare JsonResponse containing that class, JsonResponse failed to serialize my class as it hadn't implemented Serializable interface.
This will happen if you will fetch objects with methods like findAll or findBy which returns Entity objects instead of php array.
So I just skipped those native methods and write doctrine query for fetching data.
You can also implement Serializable interface.

use generated entities as "base class" in sf2/doctrine2

How can I tell Doctrine2 Entity Manager to use an inherited class by default, instead of the generated one?
In my new sf2 app, I generated all entities from the existing database to /src/Package/Bundle/DataBundle/Entity - of course I'd like to have generated forms as well, so I need for my foreign-key relations __toString() methods, which I don't want to put into those generated files because they get overwritten (yes they also get backuped in an extra file, so my changes aren't lost, but manually merging files is not what I want).
So I added new classes to /src/Package/Bundle/DataBundle/Model inheriting all from the entities, but with a __toString() method and surely some other tweaks in the future as well. But now, when I call $entity = $em->getRepository('PackageDataBundle:Customer')->find($id); - I get an instance of /src/Package/Bundle/DataBundle/Entity/Customer instead of /src/Package/Bundle/DataBundle/Model/Customer ..
I'd like to have the behaviour from sf1, where all custom work is done in the inherited classes and the generated ones are the "base" Classes, which can be updated any time on a schema update and aren't touched otherwise..
I hope there is some configuration for this..
Maybe as a bonus, I'd like to have my naming convention turned around: to have Model as the "abstract" generated one and Entity as the actual used one
Thanks.
I'd like to have the behaviour from sf1, where all custom work is done in the inherited classes and the generated ones are the "base" Classes, which can be updated any time on a schema update and aren't touched otherwise..
For purposes you described you should use Propel ORM - it was so in Symfony-1.4, and became even more flexible for Symfony-2.0 with Propel 1.6. It is well documented, easily installed and naturally used within Symfony-2.0
Perhaps I misunderstood your problem, but going from Propel to Doctrine i was also disappointed that there is no way to keep that "dirty" auto-generated code out of my logic.
I do not know how much it is now important to you, but I currently writing a simple bundle that implements such generation style.
$ app/console doctrine:generate:entities СompanySomeBundle --propel-style=true
Generating entities for bundle "СompanySomeBundle"
> backing up User.php to User.php~
> generating Сompany\SomeBundle\Entity\Base\User
> generating Сompany\SomeBundle\Entity\User
https://github.com/madesst/MadesstDoctrineGenerationBundle
PS: Sorry for my english =/

Configurable parameters in Symfony2 entity annotation

I'm trying to create a join across multiple databases (one of them belonging to a legacy application) as described in the Doctrine blog. However, the example suggests hardcoding the name of the database right into the schema, which I'd like to avoid for obvious reasons.
Is there a way to read parameters defined in parameters.ini or config.yml and use them as a value for the annotations, like this?
/**
* #ORM\Table(name="%legacy_db_name%.%legacy_table_name%")
*/
No, it's impossible. The "%key%" form is only available in the DIC.
Why would you put these data in a yml file? Would it be useful?

Resources