As the Doctrine tools documentation says, reverse engineering is a one-time process to get started on a project. Doctrine is able to convert approximately 70-80% of the necessary mapping information based on fields, indexes and foreign key constraints. Doctrine can't discover inverse associations, inheritance types, entities with foreign keys as primary keys or semantical operations on associations such as cascade or lifecycle events. Some additional work on the generated entities will be necessary afterwards to design each to fit your domain model specificities.
Below the steps I made to generate entities from existing tables in database:
1. Change current path to home directory of my Symfony installation.
Execute this command:
php app/console doctrine:mapping:import --force CPANAClassifiedsBundle xml
The metadata files are generated under "/src/CPANAClassifiedsBundle/Resources/config/doctrine/". Delete .orm.xml files related to other tables than the ones related to your bundle
2. Once the metadata files are generated, you can ask Doctrine to build related entity classes by executing the following two commands.
php app/console doctrine:mapping:convert annotation ./src/CPANA/ClassifiedsBundle
check if the data was exported into the correct path otherwise copy it to Entity directory.
php app/console doctrine:generate:entities CPANAClassifiedsBundle
NOTE: If you want to have a one-to-many relationship, you will need to add it manually into the entity or to the generated XML or YAML files. Add a section on the specific entities for one-to-many defining the inversedBy and the mappedBy pieces.
http://stackoverflow.com/questions/12493865/what-is-the-difference-between-inversedby-and-mappedby
3. Delete the mapping generated by Doctrine in the directory "/src/CPANA/ClassifiedsBundle/Resources/config/doctrine".
You may need to clear the cache:
php app/console doctrine:cache:clear-metadataAlso you need to modify the Ads entity to correctly point to your User entity. In my case:
/**
* @var \AppBundle\Entity\User
*
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\User")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="id_user", referencedColumnName="id")
* })
*/
private $idUser;
and
public function setIdUser(\AppBundle\Entity\User $idUser = null)
Testing how the model classes (entities) generated by Doctrine work
1. Add a new route to routing.yml
cpana_classifieds_categories_index:
path: /classifieds/categories
defaults: { _controller: CPANAClassifiedsBundle:Categories:index }
2. Add controller class CategoriesController.php:
class CategoriesController extends Controller
{
public function indexAction()
{
$em = $this->getDoctrine()->getEntityManager();
$allCategories = $em->getRepository('CPANAClassifiedsBundle:Category')->findAll();
if (!$allCategories) {
throw $this->createNotFoundException('Unable to find categories.');
}
return $this->render('CPANAClassifiedsBundle:Categories:index.html.twig', array( 'all_cat' => $allCategories ) );
}
}
3. Add the index.html.twig view:
{% extends 'CPANAClassifiedsBundle::layout.html.twig' %}
{% block content %}
<table style="width:100%">
{% for category in all_cat %}
<tr>
<td>{{ category.getIdCategory() }}</td>
<td>{{ category.getCategoryName() }}</td>
{% if category.getIdParent() != false %}
<td>{{ category.getIdParent().getCategoryName() }}</td>
{% else %}
<td>root category</td>
{% endif %}
</tr>
{% endfor %}
</table>
{% endblock %}
--------------------------------------------------------------------------------------------------------------
Some explanations:
The foreign keys from my tables are transformed in objects holding the entire row for that foreign key id. Results from this that category.getIdParent() is returning an object. If you try to display that object you will get an error like "Catchable Fatal Error: "Object of class CPANA\ClassifiedsBundle\Entity\Category could not be converted to string"
So I will be displaying a certain property of that object, let's say CategoryName using the getter: "category.getIdParent().getCategoryName() ".
I had a problem because Doctrine transformed the column "parent_id" into "parent" field which is not good cause "parent" is a key word used by PHP. I had to alter the table and generate again the entities. I suppose Doctrine transformed "parent_id" to "parent" because of the default mapping logic:
5.11. Mapping Defaults
The @JoinColumn and @JoinTable definitions are usually optional and have sensible default values.
The defaults for a join column in a one-to-one/many-to-one association is as follows:
name: "<fieldname>_id"
referencedColumnName: "id"
As an example, consider this mapping:
PHP
<?php
/** @OneToOne(targetEntity="Shipping") **/
private $shipping;
XML
YAML
This is essentially the same as the following, more verbose, mapping:
PHP
<?php
/**
* @OneToOne(targetEntity="Shipping")
* @JoinColumn(name="shipping_id", referencedColumnName="id")
**/
private $shipping;