Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Symfony 2 CLI tools, how can I generate getters and setters with correct type hinting for sub-classes?

Background

I am developing an application using Symfony 2 that is structured such that a "Core" bundle defines entities, relationships and fields. Other bundles are then be able specialise the core functionality by inheritance, so-called "child" bundles.

Doctrine 2 annotations have been used to define a core entity called "Package". A "Package" links together an architectural design and a piece of land - essentially a house-and-land package. I've cut the examples back to a more basic form, so you won't find definitions for Land and ChildLand in the examples below, but you can assume they have been implemented in a similar fashion.

Update

According to users on FreeNode's #symfony channel, this is a doctrine issue as the app/console command simply invokes the doctrine console. I am using doctrine 2.3.

Here is a diagram showing the general situation that causes the issue which should help visualise the scenario:

(imgur link to full-size image) Type hinting contract breaking

Also, here is a link to a bug report on doctrine's issue tracker: http://www.doctrine-project.org/jira/browse/DDC-2605

Update 2 - More detailed ERD

The structure of the relationships between entities has been questioned, so below is a better example of the data structure we are implementing.

The main requirement is again to have core classes that provide a shared set of entities and fields. Child classes in company bundles extend these core classes.

We did consider EAV at length, but in that approach we will spend a lot more time creating a platform and the tools to manage EAV data rather than satisfying the present business requirements, we won't be able to use doctrine to manage the entities as they will be defined in the database, etc etc.

As time passes and I come to understand this issue better, it appears the only issue is with the getters and setters generated by doctrine's CLI tool as they break the type hinting contracts as mentioned below. This structure works perfectly when these issues are manually corrected.

(imgur link to full-size image) Detailed data structure

Generating Entities with CLI Tool

So, initially I used the command line tool...

> app/console doctrine:generate:entity

...to generate the entity stubs with basic field mappings, then manually added the relationship to land (as the tool doesn't seem to support relationships):

This is the resulting code:

core Package entity: http://pastebin.com/3ujPT1mJ

child Package entity: http://pastebin.com/sjAB0XJ2

Generating Getters and Setters

Next, I generate the getters and setters by executing:

> app/console doctrine:generate:entities CompanyCoreBundle

> app/console doctrine:generate:entities CompanyChildBundle

Which automatically modifies the core and child entity definitions:

core Package entity: http://pastebin.com/kfQRxcnm

child Package entity: http://pastebin.com/UdiPP9xX

The problem!

So, the crux of the issue is this: If you compare the setLand function in the Core and Child bundle, you can see the declarations are different:

public function setLand(\Company\CoreBundle\Entity\Land $land = null)
public function setLand(\Company\ChildBundle\Entity\ChildLand $land = null)

Errors :(

Unfortunately, the different type hints cause PHP strict errors to occur, for example:

PHP Fatal error:  Class 'Symfony\Component\Debug\Exception\ContextErrorException' not found in ... Company/ChildBundle/Entity/ChildPackage.php on line ...

And

Runtime Notice: Declaration of ... should be compatible with ... in ... line ...

The cause of the errors

After doing some research as to why this was a problem, I read in several places that changing type hinting in subclasses breaks type hinting contracts (see this post: Is there a way to redefine a type hint to a descendant class when extending an abstract class?).

Options?

There are some obvious but less-than-ideal options:

  • I can suppress strict notices quite easily, but my development manager baulks at the prospect of having to create snowflake exceptions in our CI processes.
  • I can manually edit the code that doctrine generates to remove all type hinting, or to ensure the child class type hints are the same as the parent classes. Doing this makes the code work, but I can see it being tedious unless I write some scripts to manage this for me.
  • I can just not use the command line tools and hand-craft my entities and sub-entities manually. I would rather be able to automate this with scripts :(

My question!!! (finally)

My question is, is it possible to use the command line tools to do what I am trying to do here? Ideally, I'd love to be able to execute the doctrine console commands to generate entity stubs and getters and setters without manual intervention to fix up type hints in sub-classes. If this isn't easily achievable, what's the next-best option?

Gratitude

Thanks!

like image 819
Alex Parker Avatar asked Aug 07 '13 08:08

Alex Parker


1 Answers

I'm not exactly sure what process you'll use in order to define the entities, but in order to usefully create persistable entities with Doctrine such as GenericEngine and FordEngine, you want @MappedSuperclass

http://docs.doctrine-project.org/en/latest/reference/inheritance-mapping.html#mapped-superclasses

It's the Doctrine equivalent of an abstract class.

There are some other interesting inheritance tricks on that page linked above. They might help you.

As far as generating this stuff automatically, it could be doable but above my pay grade at +50 reputation points. :-) Doctrine can help you generate code templates for your entities, but really, time designing the entities and their relationships is better spent than time coming up with a magic command line combination.

(Myself, I'd have a Manufacturer entity and then have one-to-many relationship between the Engine and the Manufacturer. But that's not what you asked. :-)

like image 159
paul-m Avatar answered Oct 20 '22 00:10

paul-m