We continue with the bug tracker example by creating the Bug and User classes. All of the properties we've seen so far are of simple types integer, string, and datetime. But now, we'll add properties that will store objects of specific entity types in order to model the relationships between different entities.
At the database level, relationships between entities are represented by foreign keys. But with Doctrine, you'll never have to and never should work with the foreign keys directly.
You should only work with objects that represent foreign keys through their own identities. On the inverse sides of these foreign keys you can have OneToMany associations. Obviously you can have ManyToMany associations that connect two tables with each other through a join table with two foreign keys. Now that you know the basics about references in Doctrine, we can extend the domain model to match the requirements:.
Whenever an entity is created from the database, a Collection implementation of the type PersistentCollection will be injected into your entity instead of an ArrayCollection.
This helps Doctrine ORM understand the changes that have happened to the collection that are noteworthy for persistence. Lazy load proxies always contain an instance of Doctrine's EntityManager and all its dependencies.
Additionally you should be aware that dumping the EntityManager to a Browser may take several minutes, and the Debug::dump method just ignores any occurrences of it in Proxy instances.
Because we only work with collections for the references we must be careful to implement a bidirectional reference in the domain model. The concept of owning or inverse side of a relation is central to this notion and should always be kept in mind. The following assumptions are made about relations and have to be followed to be able to work with Doctrine ORM. Consistency of bi-directional references on the inverse side of a relation have to be managed in userland application code.
Doctrine cannot magically update your collections to be consistent. In the case of Users and Bugs we have references back and forth to the assigned and reported bugs from a user, making this relation bi-directional. We have to change the code to ensure consistency of the bi-directional reference:. I chose to name the inverse methods in past-tense, which should indicate that the actual assigning has already taken place and the methods are only used for ensuring consistency of the references.
This approach is my personal preference, you can choose whatever method to make this work. You can see from User addReportedBug and User assignedToBug that using this method in userland alone would not add the Bug to the collection of the owning side in Bug reporter or Bug engineer. Using these methods and calling Doctrine for persistence would not update the Collections' representation in the database. Only using Bug setEngineer or Bug setReporter correctly saves the relation information.
In a normalized relational model, the foreign key is saved on the Bug's table, hence in our object-relation model the Bug is at the owning side of the relation. You should always make sure that the use-cases of your domain model should drive which side is an inverse or owning one in your Doctrine mapping.
In our example, whenever a new bug is saved or an engineer is assigned to the bug, we don't want to update the User to persist the reference, but the Bug. This is the case with the Bug being at the owning side of the relation.
We are now finished with the domain model given the requirements. Lets add metadata mappings for the Bug entity, as we did for the Product before:. Here we have the entity, id and primitive type definitions.
After the field definitions, the two qualified references to the user entity are defined. They are created by the many-to-one tag. The class name of the related entity has to be specified with the target-entity attribute, which is enough information for the database mapper to access the foreign-table. Since reporter and engineer are on the owning side of a bi-directional relation, we also have to specify the inversed-by attribute.
They have to point to the field names on the inverse side of the relationship. We will see in the next example that the inversed-by attribute has a counterpart mapped-by which makes that the inverse side.
The last definition is for the Bug products collection. It holds all products where the specific bug occurs. Again you have to define the target-entity and field attributes on the many-to-many tag. Here are some new things to mention about the one-to-many tags.
Remember that we discussed about the inverse and owning side. Now both reportedBugs and assignedBugs are inverse relations, which means the join details have already been defined on the owning side. Therefore we only have to specify the property on the Bug class that holds the owning sides. So far, we've seen the most basic features of the metadata definition language. To explore additional functionality, let's first create new User entities:.
Since we only have one user and product, probably with the ID of 1, we can call this script as follows:. See how simple it is to relate a Bug, Reporter, Engineer and Products? Also recall that thanks to the UnitOfWork pattern , Doctrine will detect these relations and update all of the modified entities in the database automatically when flush is called. Using the previous examples we can fill up the database quite a bit. However, we now need to discuss how to query the underlying mapper for the required view representations.
When opening the application, bugs can be paginated through a list-view, which is the first read-only use-case:. The console output of this script is then:. These assumptions are not unique to Doctrine 2 but are best practices in handling database relations and Object-Relational Mapping. Consistency of bi-directional references on the inverse side of a relation have to be managed in userland application code.
Doctrine cannot magically update your collections to be consistent. In the case of Users and Bugs we have references back and forth to the assigned and reported bugs from a user, making this relation bi-directional.
We have to change the code to ensure consistency of the bi-directional reference:. I chose to name the inverse methods in past-tense, which should indicate that the actual assigning has already taken place and the methods are only used for ensuring consistency of the references. This approach is my personal preference, you can choose whatever method to make this work. You can see from User addReportedBug and User assignedToBug that using this method in userland alone would not add the Bug to the collection of the owning side in Bug reporter or Bug engineer.
Using these methods and calling Doctrine for persistence would not update the collections representation in the database. Only using Bug setEngineer or Bug setReporter correctly saves the relation information.
You should always make sure that the use-cases of your domain model should drive which side is an inverse or owning one in your Doctrine mapping.
This is the case with the Bug being at the owning side of the relation. We are now finished with the domain model given the requirements. Lets add metadata mappings for the User and Bug as we did for the Product before:.
Here we have the entity, id and primitive type definitions. After the field definitions the two qualified references to the user entity are defined. They are created by the many-to-one tag.
The class name of the related entity has to be specified with the target-entity attribute, which is enough information for the database mapper to access the foreign-table. Since reporter and engineer are on the owning side of a bi-directional relation we also have to specify the inversed-by attribute.
They have to point to the field names on the inverse side of the relationship. We will see in the next example that the inversed-by attribute has a counterpart mapped-by which makes that the inverse side. The last definition is for the Bug products collection. It holds all products where the specific bug occurs. Again you have to define the target-entity and field attributes on the many-to-many tag.
Here are some new things to mention about the one-to-many tags. Remember that we discussed about the inverse and owning side. Now both reportedBugs and assignedBugs are inverse relations, which means the join details have already been defined on the owning side.
Therefore we only have to specify the property on the Bug class that holds the owning sides. Since we only have one user and product, probably with the ID of 1, we can call this script with:. The UnitOfWork will detect this relations when flush is called and relate them in the database appropriately.
Using the previous examples we can fill up the database quite a bit, however we now need to discuss how to query the underlying mapper for the required view representations. When opening the application, bugs can be paginated through a list-view, which is the first read-only use-case:. The console output of this script is then:.
You may wonder why we start writing SQL at the beginning of this use-case. It does not know the concept of columns and tables, but only those of Entity-Class and property. Using the Metadata we defined before it allows for very short distinctive and powerful queries. There are more details about this in the relevant part of the documentation. As a last resort you can still use Native SQL and a description of the result set to retrieve entities from the database.
To learn more, go to Recovery options in Windows. Windows 10 Windows 8. Need more help? Join the discussion. Was this information helpful? Yes No. Thank you! Any more feedback? The more you tell us the more we can help. Next thing is the console: The console didn't work at all.
Section 2. My overall question is: Why doesn't Doctrine2 has a simple Getting started, where the examples are shown in a standard way, so that even newcomers can understand?
It is a big drawback, when you want to use Doctrine2 and spend two whole hours just getting these simple things done. Perhaps, as more experienced users - you can provide some feedback, and maybe we can improve some things.
Thanks a lot if you read all this :. Benjamin Eberlei. I agree with you that the getting Doctrine 2 setup is a bit cumbersome. That is why we actually switched to recommending installation of Doctrine with Composer, because it handles autoloading and installation of the CLI command.
Which sections of the documentation did you use? To post to this group, send email to doctri To unsubscribe from this group, send email to doctrine-use Jasper N. I think must of your problems will be solved when autoloading is setup correctly.
0コメント