doctrine/DoctrineBundle

Symfony Flex - Generating entity

kironet opened this issue ยท 63 comments

Hey,

Please update this bundle. I'm trying to generate new entity with this bundle, but I'm getting errors that App or AppBundle does not exist...

commands:

php bin/console doctrine:generate:entity
php bin/console doctrine:generate:entities App

My temporary fix for generating new Entities is:

Create new App class that extends Bundle in src/App.php.
Register it in the bundles.php

Unfortunately not working for php bin/console doctrine:generate:entities App not generating getters and setters.

I have the same issue when executing doctrine:mapping:import, since symfony4 is bundle-less there is no destination bundle to specify.

stof commented

Well, none of the Doctrine maintainers is in favor of using these generation commands (they tend to create more harm than good in most cases). So I suspect this is the reason why they were not spotted as broken in a Flex context yet (none of the Symfony or Doctrine maintainers trying Flex early were using them)

Well, thats nice(I don't see what harm can generating entity cause), at this point I don't see why I should stay with Symfony, I can just switch to Laravel, if since flex it looks like I will have to do everything manually...

We will support the generation commands, but in a different bundle... so stay tuned :). Remember, Symfony 4 isn't even out yet - we're still (and will continue) polish things. But, thanks for the issue!

In DoctrineBundle, I think we should deprecate any commands that you don't want to support. However, I know the doctrine:mapping:import (though imperfect by design because it's doing an impossible task) is used by a lot of developers.

The problem exists in 3.4 too when using flex.
Trying to generate getters and setters with command failed
A way to fix it in #723

@stof, so you basically offer to use public properties for doctrine?

Hi all! DisconnectedMetadataFactory not suitable for Symfony 4 also

For example, doesn't work for PSR-4:

    /**
     * Get a base path for a class
     *
     * @param string $name      class name
     * @param string $namespace class namespace
     * @param string $path      class path
     *
     * @return string
     * @throws \RuntimeException When base path not found
     */
    private function getBasePathForClass($name, $namespace, $path)
    {
        $namespace = str_replace('\\', '/', $namespace);
        $search = str_replace('\\', '/', $path);
        $destination = str_replace('/'.$namespace, '', $search, $c);

        if ($c != 1) {
            throw new \RuntimeException(sprintf('Can\'t find base path for "%s" (path: "%s", destination: "%s").', $name, $path, $destination));
        }

        return $destination;
    }

Yes. I see. We can find out path from

/** @var Composer\Autoload\ClassLoader $loader */
$loader = require __DIR__.'/../vendor/autoload.php';
$loader->getPrefixesPsr4();

This is the place for a little magic))

Hi @weaverryan any news on this? I'm still getting the same error reported in #723 with Symfony 4

Hi all! I have the same issue..
My way to (hope) temporary fix it:

  1. create a symfony 3.3 installation
  2. doctrine:mapping:import from existing database
  3. copy and paste Entity files in my new symfony 4 project (after change "AppBundle" with "App" in each one)
  4. doctrine:schema:update --force in new symfony 4 project
seydu commented

@Ocramius
I would agree with you on doctrine:mapping:import. Four to 5 years ago I used it when migrating existing applications to Symfony 2. I stopped using it because it required so much work to fix the generated mappings that writing the mappings from scratch was more efficient.

But doctrine:generate:entities is very useful and does not lead to anemic data model. I use it to generate entity classes from YAML or XML mapping and it does not cause any harm. It really shines in this use case as it handles all the boring, repetitive and error prone process of converting XML or YAML mapping into entity classes.

Symfony is used by a wide range of shops, we cannot assume that the author of the mapping is the developer and suggest they just write the mapping in annotations to begin with (you did not say that but that argument is frequently raised).

I know that using pre-Symfony 4 doctrine:generate:entity + doctrine:generate:entities + doctrine:schema:update made prototyping very fast.

as a developer, you answered a few basic questions that were prompted on the screen and everything was created on your behalf. no more of similar code written by hand over and over again...

and coupled with an EasyAdmin with low customization, it provided out of the box functionality by using basically only config files.

you could have an up and running PoC application in 30 minutes, having the rest of the time for doing the real coding for the more relevant business layer.

My 5 cents:

  • actually, generators are Rails - style legacy. Don't trust autogenerated code, unless you don't see it (like container)
  • still current generator works bad when adding $blabla = new ArrayCollection in constructor
  • any recent IDE (including de-facto PHPStrom) can generate fluid getters and setters for you faster and in more controlled way than Doctrine does

@andrewtch I haven't been able to make PHPStorm generate methods for collections properties (addElement, removeElement + constructor initialization). hence, relied on the generator to do this instead of me.

to generate entities of tables in symfony 4, try it:

php bin/console doctrine:mapping:convert --from-database annotation ./src/Entity

Yeah, I was using command doctrine:generate:entities only because of relationships. It was easy and fast.

you can use a text editor plugin to generate the setters and getters
for exmaple

https://github.com/francodacosta/atom-php-getters-setters

@martinezvictor84 For simple getters and setters you can just use phpstorm
CMD + N on MacOS
CTRL + N on Windows(I guess).

@martinezvictor84 With Phpstorm, when you are in an inversed entity, Generate Getters & Setters doesn't work properly, cause it does'nt generate the 'add'/'remove' methods

Just a heads-up here: support for codegen tools, including EntityGenerator, EntityRepositoryGenerator, orm:generate:entities, orm:generate-repositories and doctrine:convert-mapping, has been dropped and they will not be part of Doctrine 3.0 (ref doctrine/orm#6870).
It'd be awesome if Symfony started phasing them out, the sooner the better, and teach its users good manners - i.e. how to write entities properly, not by generating anemic 1:1 table copy.

Woohoo let's spend weeks just by writing entities from scratch. ๐Ÿ‘

Not much of a joke: if you generate anemic entities, enjoy maintaining the stateful spaghetti mess for years.

Last but not least, if someone really wants this functionality, feel free to extract these commands to a separate bundle or create a pull-request to add them to the Symfony MakerBundle if you want to maintain them. Doctrine is not breaking code generation - we're just no longer maintaining/providing the tools to do so.

If you don't want people to use anemic entities, maybe it's good idea to update docs?

Lets collect experience.
I use gen:entities for generating getters/setters and "new ArrayCollection"

Good documentation about design/modelling is indeed needed apart from just removing generator-related chapters. Keep in mind that entity generator has not yet been officially deprecated or removed so there is still time to improve documentation. I've opened an issue on symfony-docs repo.

Woohoo let's spend weeks just by writing entities from scratch.

Actually, why not? If you put enough time in designing your domain model, you won't regret. Entity with bunch of getters and setters is not a good example, but entity with some getters, (almost no/zero) setters and business methods is. For example, $article->release($reviewer, $date) will definitely be better than $article->setReleaseDate($date) + $article->setReviewer($reviewer) + $article->setState($article::RELEASED).

Lets collect experience.
I use gen:entities for generating getters/setters and "new ArrayCollection"

Then please stop. Please read some articles about anemic domain model.
https://www.martinfowler.com/bliki/AnemicDomainModel.html


As already stated in the PR doctrine/orm#6870, if anyone wants to take over, that PR is a good reference of all the needed code if you read it inversely.

I ran into this issue today in Symfony 4 while trying to generate the usual getters/setters on a class. For anybody looking to actually make the current software work, you do need to make changes to both the DoctrineBundle and the ORM itself as outlined in #723 (and below).

Regardless of the long term solution, this should be fixed in what is out there today so as to behave as documented. When the entity generator is deprecated in the new Doctrine and eventually removed in 3.0, new documentation should exist somewhere in the Symfony ecosystem describing the proper best practice (the Martin Fowler article is nice at a conceptual level, but is rather vague from a "what to do next when these commands stop existing" perspective). In my case, I wouldn't call my models anemic, but generating these on a large model is a good starting point and easy to do, and my IDE doesn't generate what I need without spending a good bit of time playing with the recipe.

The root cause of the problem at hand is that the new Symfony structure removes the "App" directory (or whatever you call your project), so for example if your company is "Example" then your entities are probably namespaced to "Example\Entity" but your directory structure is likely just "src/Entity". The same is true if you use the default "App\Entity" and so on.

I solved this by making the following change to Mapping\DisconnectedMetadataFactory.php in DoctrineBundle on line 124 (1.8.1):

        if (class_exists($all[0]->name)) {
            $r = new \ReflectionClass($all[0]->name);
            $ns = substr($r->getNamespaceName(), strpos($r->getNamespaceName(), '\\') + 1);
            $path = $this->getBasePathForClass($r->getName(), $ns, dirname($r->getFilename()));
        } elseif ($path) {

And in Doctrine\ORM\Tools\EntityGenerator.php in the ORM on line 363 (2.5.13):

        $namespace = substr($metadata->name, strpos($metadata->name, '\\') + 1);
        $path = $outputDirectory . '/' . str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . $this->extension;

These changes just strip the leading namespace element out of the path since it is no longer present in the new structure.

Is it worth putting out PRs for these to get them merged, or is another solution favored?

For anybody looking to follow the new entity generation for Symfony Flex, it seems to be here (also referenced above): symfony/maker-bundle#83

I completely disagree with @Ocramius. I exactly know how my domain-model must be designed!
I used to copy necessary methods from generated entities, remove some methods and redesign some of them. Writing all this from scratch (because beginners users abuse it) is insane idea.

@Majkl578 You said: "It'd be awesome if Symfony started phasing them out, the sooner the better, and teach its users good manners - i.e. how to write entities properly, not by generating anemic 1:1 table copy." So lets consider simple example to prove you are wrong:

Now I am struggling with import of several GB of data to more than 100 tables. All data must be imported with little reorganization of relation names etc... I created my new database scheme with MysqlWorkbench - fastest way. Please tell me who is going to pay for time I will be wasting on writing everything from scratch? It will take me about one 10 days to do all the job. I think that you forget that writing applications isn't always a hobby when you have infinite time and you can spent to concerning good manners only.

After my import will be done I am going use DDD to write my target application where persistent layer will be complete decoupled from domain. But for now my client wont allow me to just skip import of some data because lack of time or because you don't like it. You can't put all people to one bag and say that they need to be more educated.

If you don't like generation entities inside doctrine3 project just move it and maintain it in separate branch or project but don't kill feature that my be really helpful for many people. If you're unable understand it I hope there will people that will do and will have 10000 of stars on github with new generator project!

Now I am struggling with import of several GB of data to more than 100 tables. All data must be imported with little reorganization of relation names etc... I created my new database scheme with MysqlWorkbench - fastest way.

You are importing an entire schema without changing anything, yet you had to do design the new schema manually in MySQL Workbench? I cannot see where this could possibly go wrong!

Jokes apart, you will likely incur in:

  • data loss due to asymmetrical data structures (yours and the original one)
  • data integrity issues at import time
  • broken assumptions when first working with the data at application/domain-level

Please tell me who is going to pay for time I will be wasting on writing everything from scratch? It will take me about one 10 days to do all the job. I think that you forget that writing applications isn't always a hobby when you have infinite time and you can spent to concerning good manners only.

Importing the entire schema into a "new" application without inspecting manually each scenario and each business rule that couldn't be coded into a DB-level constraint is gonna be more trouble.

You will hit issues, you will corrupt the data and the migration will just lead to misunderstanding by consumers of the generated model.

I've gone through the same scenario you described above multiple times, and it is generally a waste of money to abstract away existing data models, since you do not know everything that the existing data model is supposed to do.

After my import will be done I am going use DDD to write my target application where persistent layer will be complete decoupled from domain. But for now my client wont allow me to just skip import of some data because lack of time or because you don't like it. You can't put all people to one bag and say that they need to be more educated.

Then you likely don't need Doctrine ORM: you probably want a Table-Data-Gateway or an Active-Record implementation, or even something more lightweight than that if applicable. You'd just end up writing something quite complex that:

  • doesn't use the ORM up to its potential
  • is actually slowed down massively by the ORM (typical scenario of "ORMs suck" after using them incorrectly for years)

If you don't like generation entities inside doctrine3 project just move it and maintain it in separate branch or project but don't kill feature that my be really helpful for many people. If you're unable understand it I hope there will people that will do and will have 10000 of stars on github with new generator project!

This train has left the station over 2 years ago, and it is just going to happen now.

We're not in a popularity contest here: if people like shooting themselves in the foot, so be it, but we'll provide as little assistance (before AND after) as possible to focus on more relevant problems.

To recap:

  • entity generator is going away
  • we did it exactly to prevent people from doing exactly what you are doing: designing anemic domains with a "database-first" approach. That's a bad fit for this ORM and it will hurt you down the line.
  • if you really need to go down that path, you can write your own throw-away entity generator in a couple hours - it really isn't that hard if you don't have weird requirements. We no longer want to provide the foot-gun out of the box.

http://docs.doctrine-project.org/en/latest/tutorials/getting-started.html

When creating entity classes, all of the fields should be protected or private (not public), with getter and setter methods for each one (except $id).

  1. "You are importing an entire schema without changing anything, yet you had to do design the new schema manually in MySQL Workbench? I cannot see where this could possibly go wrong!"

I disagree. I am importing data from different source types (not just doing copy of existing schema):

  • some data from 2 existing MySQL database schema like You said
  • some data from .csv files
  • some data from Excel files
  • some data from XML files
    This import needs to be done only once to collect all data from different sources (so import time doesn't matter). This data already suffer integrity issues, so import is intended to put them together and fix those integrity issues. Only after that I will be able use this data - probably reimport it to proper designed database. Only MySQL Workbench allow me to create in a small manner of time this temporary database.
  1. "Then you likely don't need Doctrine ORM: you probably want a Table-Data-Gateway or an Active-Record implementation, or even something more lightweight than that if applicable. You'd just end up writing something quite complex that (...)"
  • I agree. But I am going to use ORM only after good redesign, reimport those data. Without initial import and putting data together non type of implementation will good.
  1. "We're not in a popularity contest here: if people like shooting themselves in the foot, so be it, but we'll provide as little assistance (before AND after) as possible to focus on more relevant problems."
  • If considering this as a cost of time that won't allow you to focus on more important problems and my scenario is really rare: I agree. But if it is not a popularity contest why to put so effort to remove tools which can be useful in some unpopular use-cases like mine.
  1. "we did it exactly to prevent people from doing exactly what you are doing: designing anemic domains with a "database-first" approach. That's a bad fit for this ORM and it will hurt you down the line."
  • This is not database-first approach, without putting this data together tere will be no domain and no future approach.

Ok, You may say that Doctrine is not tool designed as a some kind of tool/helper to import data from junk sources like those i have ..and I agree with that, I also agree and understand why removing generators will prevent people of saying "ORM sucks" because they put whole database to it. But you must admit that there are scenarios when generator can be useful. Maybe there is some approach to kill to birds with one stone and save generators for cases like mine and also save people from abusing it.
It is up to you.

Thanks for answer
Best Regards.

It is up to you.

Precisely the opposite, which is why they are being removed here.

Just want to say this that for me this is "Volstead Act" approach like in USA in 1919. Instead of educating people you just want to put all people to the same bag and ban all generators, its exactly like prohibition did with alkohol in United States.
Maybe better way is to change documentation, try to educate people (see what happen and after that decide should we remove generators or not). Like @kironet mention Doctrine documentation is teaching developers to create anemic domains in the first place not generators itself.

No prohibition: make your own generator.

Prohibition is when I lock the thread, which is really close.

As for the docs: doctrine/orm#6902

@pawellen

who is going to pay for time I will be wasting on writing everything from scratch?

Perhaps consider who's paying the maintainers of this project to do your job for you?

Guys, I've experienced generate:entity and mapping:import a dozen times since 2013, as I also wanted to migrate an old data source to Symfony & Doctrine.

First I was like:

Neat! I can use my old db structure again!

Then I was:

Damn, it's been 3 weeks and I'm still handling errors in my entities

And after the first year:

I think my structure's not OK

And today, it's more than four years after the birth of this "V2" project. Still not on production (it's a personal project so I don't mind, in the beginning it was just for fun), and by the way it's the same for all other non-personal projects on which I used these features:

Hell, how could the v1 possibly work with such structure? My objects are now thousands, and I cannot manage to handle importing the old data in the new structure. I shouldn't have used import at all in the first place.

The same goes for generate:entity but @Ocramius said enough about anemic models. If you like anemic models, it's up to you, but just don't ask Doctrine maintainers to support an idea that themselves would've never used because it's bad design in the first glance. It's like saying Hey, Symfony devs, I need the sfContext class like in Symfony1 because I design my whole project using this class, it's so cool and shiny and furry, but it's hell of a bad practice so it's been removed.

Even though my entities are still a mix between anemic and rich, I tend to think every model should be rich, so no setters, but getters are fine.

That's why I created doctrine/orm#6902 and will take time in the next weeks to update it, unless someone more clever than me wants to participate.

And that's also why I agree on the fact that generate:entity and mapping:import were removed and are not coming back.

That's my 2 cents

So here are my 2 cents to this discussion. Is it really doctrine or symfony task to teach people DDD, i think so. Doctrine is only one tool to practice DDD. You can also use eloquent, propelorm or just dbal to do it. Should each of this project do document DDD?

And for all people who want to have this feature: I see many comments here, but no one extract this feature into his own library bundle. You can also create a PR and say "Hey i want to maintain this feature". Then this is how open source should work.

The guys form doctrine do a great job and instead of blame this people they do bad work, think about this: How many time (and money) do you save with doctrine and you pay nothing for it.

See this as a chance to give them something back and be constructive.

There's no need to discuss about this :) Doctrine maintainers have removed all the generator tools because they think it's the best for their project ... and we're working on adding new and modern generator tools to Symfony's Maker bundle because we think it's the best for Symfony.

So we both get what we want, nobody is "doing it wrong", everybody should be happy ... and there's no need to discuss about this. Cheers!

"Perhaps consider who's paying the maintainers of this project to do your job for you?"
@ciaranmcnulty good point!

@javiereguiluz You right!

@Ocramius After reading whole discussion I admit that generators inside doctrine project are bad idea and their are causing to many problems and most of my arguments I wrote earlier sucks! :)

I never used this tool after pass 2-3 months in Doctrine, try to go RDBMS and some IDE like Phpstorm so now about 5+ years life is easy.

tvogt commented

Half of you are insane, right? Don't tell me how to write my code. If I want all my entities to have getters and setters for all their variables, and access to the very convenient relation add, remove, etc. methods then I want it and it's not your place to tell me what I want.

Symfony used to be perfect for banging out a quick prototype exactly because of this. Especially if you use XML or Yaml for entity mapping, the getter/setter code generation is a gift from heaven.

I just started a new project on Flex, after using Symfony 2 and 3 for older ones, and the missing entity generator is the reason I'm shelving it for the weekend until I figure out how to proceed without wasting hours on writing extremely repetitive code.

Just make properties public and you have the same behaviour: no need for generators or "extremely repetitive code" (which is quite the code smell again, and leads to extremely repetitive maintenance work).

We're not telling you how to write your code, we just stop writing code for you.

So, will it solve? When I am using MySQL Workbench, it (doctrine:mapping:import) is was good for me.

tvogt commented

@Ocramius - public properties doesn't solve the problem for relations.

Repetitive code - well yes, we can have a discussion about getters and setters if you want, I'm not much of a fan of the concept, but I would much rather have one concept and use it consistently then mix.

Your call if you don't want to provide functionality anymore. I'm just pointing out that users rely on this functionality and value it.

@BerkhanBerkdemir by moving to other libraries doing that.

@tvogt agree, every developer values quick scaffolding until it is clear that it is just generating legacy code even before the developer has touched it.

If people want to have all their choices made for them, they can move to Laravel.. lol..

Hey there,

I'm adding my 2 cents opinion about this topic. Having a getters/setters generator in Doctrine is really up to @Ocramius and other Doctrine core maintainers. The thing is if this feature is depreciated and doesn't work properly, it should be removed. As Ocramius said you can use public attribute and avoid getters/setters all together, that's how we deal with it in other ORM like SQLAlchemy or in Python in general. By the way, it's been a while I didn't write any PHP/Doctrine/Symfony code, but is it normal that no error is raised when an entity has no getters/setters and all it's attributes are private? Because if I remember well it used to throw an error like "Can't access to attribute" or something like that.

Because if I remember well it used to throw an error like "Can't access to attribute" or something like that.

That must've been a long time ago. These days, Doctrine access your properties using reflection and doesn't care about accessors. If you have used Doctrine entities in combination with the Symfony Form framework, the error may have come from there as the PropertyAccess component used by the form framework indeed requires public accessors for any properties mapped in the form.

Yeah Symfony can't stop using getter and setters, because of forms, etc...

Just now realized I inadvertently closed the issue this morning. After internal discussion, we decided to keep the issue closed: code generation tools have been removed from Doctrine 3.0 and are considered deprecated in the current release; this will not be updated.

If you want to keep using these features, use the MakerBundle.

code generation tools have been removed from Doctrine 3.0 and are considered deprecated in the current release; this will not be updated.

Are XML and YAML configurations also to be deprecated? Most of my projects have the following setup: schema defined in XML and PHP entity files generated based on those XML files. Without the code generation tools, this is going to be a lot more work. The MakerBundle does not seem to be a replacement for this.

Are XML and YAML configurations also to be deprecated?

Yaml mapping is being deprecated, XML and Annotations are staying.

It does not generate the setters and getters.

php bin/console doctrine:generate:entities App:Cars

error:

Can't find base path for "App\Entity\Cars" (path: "/www/crm/src/Entity", destination: "/www/crm/src/Entity").

Someone, please close the comments already ) The feature is gone now.