Lets say, I have a class Movie with a Orm\OneToMany relation ship to the class Actors.
I have already a working example of an getter for $movie->getActors(); which will return all actors of that movie.
But how to dynamically modify the query for that? For example, I show a list of all actors of the movie, and allow the user to sort by name, age, gender, whatever.
===== EDIT ======
After learning, that such things belongs to the repository class (thanks to Yoshi, scoolnico), here is the adapted question:
Lets say, I have got a Movie ID 4711. I will fetch the movie:
$movie = $this->getDoctrine()
->getRepository("Movie")
->find(4711);
And now, I need to get all Actors from this movie sorted by name (as an example).
$actorsOfMovie = $this->getDoctrine()
->getRepository("Actor")
->findBy(array("movie_id" => 4711), array('name'=>'asc'));
Is this really the correct way?
With this version, I need to know in the controller, how the relationship between movie and actors work! Thats a thing, doctrine should handle for me!
And how to use it with multiple movies?
// Controller
$movies = $this->getDoctrine()
->getRepository("Movie")
->findfindBy(array());
return $this->render("xyz.html.twig", array("movies": $movies));
// Twig: xyz.html.twig
{% for movie in movies %}
<h1>{% movie.getName() %}</h1>
<p>Actors: {% for actor in movie.getActorsOrderByName() %}{{ actor.getName() }},{% endfor %}
{% endfor %}
You just have to create a specific function in your class Repository:
class MovieRepository extends EntityRepository
{
public function getActoryByGender($gender)
{
/.../
}
}
And in your controller:
/.../
$em = $this->getDoctrine()>getManager();
$repository = $em->getRepository('YourBundle:Movie');
$actors = $repository->getActorByGender('male');
/.../
I think the best solution for this is to use doctrine's Criteria class (http://docs.doctrine-project.org/en/latest/reference/working-with-associations.html#filtering-collections).
Have a look at https://www.boxuk.com/insight/blog-posts/filtering-associations-with-doctrine-2
Based on this, I can do the following:
// In the Movie Class
/**
* Get actors
*
* #param array $options
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getActors($options = array())
{
if(!$options) {
return $this->actors;
}
$criteria = Criteria::create();
if(isset($options["order_by"])) {
$criteria->orderBy($options["order_by"]);
}
if(isset($options["limit"])) {
$criteria->setMaxResults($options["limit"]);
}
if(isset($options["offset"])) {
$criteria->setFirstResult($options["offset"]);
}
// Or I can define other filters or sorting stuff
if(..) {
...
}
return $this->actors->matching($criteria);
}
Related
I am trying to make a QueryBuilder with a join between my entity Product and my entity Store. I'd like to display all products that are related to OneStore. They have a many-to-many relation. I can't figure out how to get the ID's. Welp please. Thanks in advance!
here's a screenshot of my product_store table :
https://imgur.com/a/wUZMEEn
So if I'm clear enough and my english legit, you understood that I'd like to display only the product that are related to one store id.
Let's make an example. If I'm on the /store/detail/{1} page, I'd like to display product id 1,3,6,8,10,13 since they are related to store.id = 1.
So I updated as I have been advised, but it's not working, and I don't get what is wrong. Where am I mistaking? (controller updated)
Here's the error I get :
https://imgur.com/a/q3Uun3E
----------------------my repository function -----------------------------
public function getProductsForStore($sid)
{
return $this->createQueryBuilder('s')
->join('s.product', 'p')
->addSelect('p')
->andWhere('s.id = :sid')
->orderBy('p.name', 'ASC')
->setParameter('sid', $sid)
->getQuery()
->getResult();
}
$produt in store entity :
/**
*
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="App\Entity\Product", mappedBy="store")
* * #ORM\JoinTable(name="product_store",
* joinColumns={#ORM\JoinColumn(name="product_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="store_id", referencedColumnName="id")}
* )
*/
private $product;
$store in product entity :
/**
* * #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="App\Entity\Store", inversedBy="product")
* * #ORM\JoinTable(name="product_store",
* joinColumns={#ORM\JoinColumn(name="store_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="product_id", referencedColumnName="id")}
* )
*/
private $store;
my controller function :
/**
* #Route("stores/detail/{id}", name="detail_store"))
*/
public function getOneStore(StoreRepository $repository, Store $store): Response
{
$store = $repository->findOneBy(array(
'id' => $store->getId(),
));
$products_store = $repository->getProductsForStore(':id');
return $this->render('store.html.twig', array(
'store' => $store,
'product' => $products_store,
));
}
you can better call your properties $stores and $products instead of the singular version to make clear that we talk about an array or collection with possible multiple stores or products. You dont really need the 2nd - 4th rule of your annotations. Just
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Product", mappedBy="store")
*/
and
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Store", inversedBy="product")
*/
will do. It tells us that you use a bidirectional ManyToMany relation. Both Store and Product entities hold a list of the opposite enitity. Therefor you can query Stores with a collection of Products or Products with a collection of Stores.
and what is the correct way to use the $store->getProducts() in my controller?
So exchange store for product and vica versa in the first answer:
public function getStore($sid)
{
return $this->createQueryBuilder('s')
->join('s.product', 'p')
->addSelect('p')
->andWhere('s.id = :sid')
->orderBy('p.name', 'ASC')
->setParameter('sid', $sid);
->getQuery()
->getResult()
;
}
Controller:
/**
* #Route("/{id}", name="store_show", methods={"GET"})
*/
public function show($id): Response
{
$em = $this->getDoctrine()->getManager();
$em->getRepository('App:Store')->getStore($id);
if(null === $store) {
throw $this->createNotFoundException('Store not found.');
}
return $this->render('store/show.html.twig', [
'store' => $store,
]);
}
Twig:
{% extends 'base.html.twig' %}
{% block title %}Store{% endblock %}
{% block body %}
<h1>{{ store.name }}</h1>
<table class="table">
<thead>
<tr>
<th>ProductId</th>
<th>ProductName</th>
</tr>
</thead>
<tbody>
{% for product in store.products %} {# loop through all products in store #}
<tr>
<td>{{ product.id }}</td>
<td>{{ product.name }}</td>
</tr>
{% else %}
<tr>
<td colspan="4">no records found</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
I do wonder why you make a custom query if you want to get all products from one store.
When you made your ManyToMany relation (with maker bundle hopefully), you should also have added in Store entity a getter ($store->getProducts()) to get all products of said store.
Anyway, here is your query...
public function getAllProductsFromOneStore(Store $store) {
$qb=$this->createQueryBuilder('store');
$qb->addSelect('product')
->join('store.product', 'product')
->andWhere('store.id = :storeId')
->setParameters(array(
'storeId'=>$store->getId();
));
return $qb->getQuery->getResult();
}
The above query should return all products from one store.
Also, never use where(), always andWhere(). Read more about it here.
[EDIT]
In response to your edit. As Frank B said, you can do better.
First, as I said, you don't need a custom query.
Instead, make a getter in Store and Product entity.
src/Entity/Store.php
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
class Store {
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Product", inversedBy="stores")
*/
private $products;
public function __construct() {
$this->products=new ArrayCollection();
}
/**
* GETTER
*
* #return Collection|Product[]
*/
public function getProducts(): Collection {
return $this->products;
}
/**
* ADD A PRODUCT TO A STORE
*/
public function addProduct(Product $product): self {
if(!$this->products->contains($product)) {
$this->products[]=$product;
}
return $this;
}
/**
* REMOVE A PRODUCT FROM A STORE
*/
public function removeProduct(Product $product): self {
if($this->products->contains($product)) {
$this->products->removeElement($product);
}
return $this;
}
}
src/Entity/Product.php
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
class Product {
private $stores;
public function __construct() {
$this->stores=new ArrayCollection();
}
/**
* GETTER
*
* #return Collection|Store[]
*/
public function getStores(): Collection {
return $this->stores;
}
/**
* ADD A STORE TO A PRODUCT
*/
public function addStore(Store $store): self {
if(!$this->stores->contains($store)) {
$this->stores[]=$store;
$store->addProduct($this);
}
return $this;
}
/**
* REMOVE A STORE FROM A PRODUCT
*/
public function removeStore(Store $store): self {
if($this->stores->contains($store)) {
$this->stores->removeElement($store);
$store->removeProduct($this);
}
return $this;
}
}
Now in your controller, all you have to do is to call your getter.
Doctrine will handle the query for you :
/**
* #Route("stores/store-{id}", name="index_store"))
*/
public function index(Store $store): Response {
$products=$store->getProducts();
return $this->render('store.html.twig', array(
'store'=>$store,
'products'=>$products,
));
}
And then in your twig view :
{% for product in store.products %}
// Your code here
{% endfor %}
And that is it. Once you have your getter in your entities, you don't need a custom query.
Take note that you can do the same with Product ($product->getStores()) to know in which store you can find your product.
I'm trying to get manyToMany relationship with Doctrine and symfony.
I'm new at Doctrine and Symfony. I came from Zend framework.
I've created the 3 tables:
Post, PostCategory and junction table PostToCategory as you can see below.
My goal is to do inner join and to get for every post its categories.
This is what I've done so far:
//CMS/GBundle/Entity/PostContent
class PostContent
{
/**
* #ORM\ManyToMany(targetEntity="CMS\GBundle\Entity\PostCategory", inversedBy="posts")
* #ORM\JoinTable(name="post_to_category")
*/
protected $categories;
public function __construct()
{
$this->categories = new ArrayCollection();
}
//CMS/GBundle/Entity/PostCategory
class PostCategory
{
/**
* #ORM\ManyToMany(targetEntity="CMS\GBundle\Entity\PostContent", mappedBy="categories")
*/
protected $posts;
public function __construct()
{
$this->posts = new ArrayCollection();
}
I would like now to create function that returns me joined data Post->PostCategories.
Where should I create function ? in PostToCategory Repository ? or somewhere else ? How should my query look like ?
I've tried a lot of options and I passed all the possible questions on Stack but I could not get it done..
Thanks in advance!
Update:
This is what i get when i do findAll method on PostContent repository.
The preferred way to make a relationship is to create your entities like you did, then run a console command to extend your entity with some getters and setters:
$ bin/console doctrine:generate:entities AppBundle
and then let doctrine create your tables:
$ bin/console doctrine:schema:update --force
Now that is everything ready you have to fill some data in your database tables.
$category = new Category();
$categroy->setName('PHP Programming');
$em->persist($category);
$post = new Post();
$post->setTitle('My first Blogpost');
$post->addCategory($category);
$em->persist($post);
$em->flush();
After that can get it out. I just give you an example
public function indexAction($id)
{
$em = $this->getDoctrine()->getManager();
$category= $em->getRepository('AppBundle:PostCategory')->find($id);
// test
foreach($category->getPosts() as $post)
{
echo $post->getTitle() . '<br>';
}
}
To load all the posts immediately instead of lazy loading i suggest to write your own query in the CategoryRepository class and change the find() method-name for your own method-name.
You can create repository class for your entity, for example:
CMS/GBundle/Repository/PostContentRepository.php
<?php
namespace CMS\GBundle\Repository;
use Doctrine\ORM\EntityRepository;
class PostContentRepository extends EntityRepository
{
public function getPostsWithCategories()
{
$qb = $this->createQueryBuilder('post_content')
->select(['post_content', 'post_categories'])
->join('post_content.categories', 'post_categories')
;
return $qb->getQuery()->getResult();
}
}
CMS/GBundle/Entity/PostContent.php
<?php
namespace CMS\GBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Table()
* #ORM\Entity(repositoryClass="CMS\GBundle\Repository\PostContentRepository")
*/
class PostContent
{
/* Your entity properties and methods */
}
And then you can use it in anywhere. For example, in the controller:
<?php
namespace CMS\GBundle\Controller;
use ;
class SomeController extends Controller
{
public function someAction()
{
$posts = $this->getDoctrine()
->getManager()
->getRepository('CMSGBundle:PostContent')
->getPostsWithCategories()
;
/* Your logic */
}
}
As Frankbeen advised me i created my custom query:
public function getPostCategories() {
$data = $this->createQueryBuilder('c')
->select('c.id, pc.name')
->innerJoin('CMSGBundle:PostToCategory', 'ptc', 'WITH', 'ptc.postId = c.id')
->innerJoin('CMSGBundle:PostCategory', 'pc', 'WITH', 'ptc.categoryId = pc.id')
->getQuery()
->getArrayResult();
return $data;
}
In Method above I'm fetching just post.id that is related to post_to_category_post_id category name
In controller I generate two queries one to fetch all Posts second to fetch data using getPostCategories method.
Controller:
$em = $this->getDoctrine()->getManager();
$posts = $em->getRepository('CMSGBundle:PostContent')->findAll();
$postCategories = $em->getRepository('CMSGBundle:PostContent')->getPostCategories();
View:
{% for post in posts %}
{% for category in categories %}
{% if category.id == post.id %}
{{ category.name }}
{% endif %}
{% endfor %}
{% endfor %}
I know that this is not the best solution and please if anyone can suggest me with minifing same code or how to write it better I will be grateful!
I am stuck with a problem please help me with it. Here is the scenarario:
I have an entity "User" and corresponding repository "UserRepository", inside my entity there are only getter and setter methods. All custom queries I have written to UserRepository. Now inside my UserController I am trying to access repository methods which I am not able to do so.
e.g.
User entity:
class User
{
...
public function getId()
{
return $this->id;
}
public function setId($id)
{
return $this->id=$id;
}
public function setProperty($property)
{
$this->property = $property;
}
public function getProperty()
{
return $this->property;
}
....
}
?>
UserRepository:
class UserRepository extends EntityRepository
{
public function findUsersListingById($id)
{
$queryBuilder = $this->getEntityManager()->createQueryBuilder();
$query = $em->createQuery(
"SELECT U
FROM UserEntityPathGoesHere
WHERE U.id IN (".implode(",", $id).")"
);
$users = $query->getResult();
return $users;
}
public function sayHelloWorld(){
echo ' Hello World';
}
}
?>
UserController
class UserController
{
...
$users=$this->getDoctrine()
->getRepository('MyUserEntityPath')
->findUsersListingById($ids);
//now I have multiple users I want to iterate through each user for associating additional data with each user
foreach($users as $user)
{
$temp = array();
//I am able to access getId method which is defined in User entity
$temp['id'] = $user->getId();
//however I am not able to access method from UserRepository, I tried something like below which gives me error call to undefined function sayHelloWorld
$temp['status'] = $user->sayHelloWorld();
....
}
}
....
How can I access repository methods for an entity? Is it possible ? If not then what are the alternatives for the solution?
Everything is possible however you should not access the entity's repository from the entity itself because of the separation of concerns.
See this Stackoverflow answer for more details.
Basically, the whole idea is that you want to have your application organized the following way.
In short:
Controller > Repository > Entities.
It should not go in the other direction otherwise it creates a mess.
If you want to go a bit further into the separation of concerns you could do the following.
Controller > Service > Repository > Entities
Alternative solutions:
Create a Twig extension that access a service (which access a repository) or a repository.
Create a method in your repository, call the method in your controller, map the data to IDs (keys of array are the IDs), pass the array to the template and then pull the data from the array using the entity IDs
Create a method in your repository, call the method in your controller, inject the data into your entities and access the data through the entity in your template.
There are probably others but you would know better how your application is organized.
If the bundle is Acme/DemoBundle, then one would expect at a minimum
User entity
namespace Acme/DemoBundle/Entity
use Doctrine\ORM\Mapping as ORM;
/**
*
* #ORM\Table(name="user")
* #ORM\Entity(repositoryClass="Acme/DemoBundle/Entity/UserRepository")
*/
class User
{
...
}
User repository
namespace Acme/DemoBundle/Entity
use Doctrine\ORM\Mapping as ORM;
class UserRepository extends EntityRepository
{
...
}
It is also true that with an array of ids, one can also do the following in a controller:
...
$em = $this->getDoctrine()->getManager();
$users = $em->getRepository("AcmeDemoBundle:User")->findAllById($idArray);
...
To iterate thru users in a controller, one can then use a foreach loop as in:
foreach ($users as $user) {
//each user is an array
...
$id = $user['id'];
...
}
or in a template:
{% for user in users %}
...
{{ user.firstName }}
...
{% endfor %}
You need to declare the UserRepository as an EntityRepository for your user entity. In your User entity add this annotation:
/**
* #ORM\Entity(repositoryClass="Acme\StoreBundle\Entity\UserRepository")
*/
See the docs for a more detailed description.
You can use the postLoad event from doctrine and inject everything you want into the entity. The event listener looks like:
<?php
namespace AppBundle\EventListener;
use AppBundle\Entity\MyEntity;
use Doctrine\ORM\Event\LifecycleEventArgs;
/**
* Class MyEntityListener
*/
class MyEntityListener
{
public function postLoad(LifecycleEventArgs $eventArgs)
{
/** #var MyEntity $document */
$document = $eventArgs->getEntity();
if(!($document instanceof MyEntity)){
return;
}
$document->setEntityManager($eventArgs->getEntityManager());
}
}
and service.yml:
services:
app.myentity.listener:
class: AppBundle\EventListener\MyEntityListener
tags:
- { name: doctrine.event_listener, event: postLoad }
Of cource your Entity needs the method setEntityManager and your're ready.
I want to create event listener that add some results of db query to all symfony actions
for example:
class BlogController extends Controller
{
/**
* #Route("/blog/")
* #Template()
*/
public function indexAction()
{
....
return array(
'entries' => $posts
);
}
}
This controller is passing entries variable to the view, I want to create listener that take the returned value of all actions and inject another index to the returned array to be (for example)
array(
'entries' => $posts,
'categories' => $categories
);
so I can call the $categories var from any where in my application views
I hope my question is clear to you guys. Thanks in advance.
You should consider creating a global variable or twig extension to make categories available in your templates, you can't do that by using events (since the template is parsed inside the controller, not before/after it)
This approach, although valid and commonly used in some frameworks, is not very common in Symfony as it suits more MVC than HMVC architecture.
I would suggest you a different one with the same result:
Instead of adding parameter to every controller return, render another controller which returns just a subview of what you're trying to show. Simple example:
// article/index.html.twig
<div class="category-bar">{{ render(controller('MyVendorMyBundle:CategoryController:bar')) }}</div>
<div class="article-list">
{% for article in articles %>
{# Print article here #}
{% endfor %}
</div>
// CategoryController
class CategoryController extends Controller
{
/**
* #Template
*/
public function barAction()
{
return ['categories' => $this->fetchCategoriesSomehow()];
}
}
So when you render your article list action, twig will fire a subrequest to render categories bar above it.
Furthermore, if you don't like making subrequests, nothing stops you from creating a twig extension service which would fetch categories and render template for you.
In most cases I would go with #Wouter J's suggestion and create a twig extension or a global variable.
However, what you want to do is actually possible (regardless if that's the right solution or not).
The #Template annotation has a vars attribute, which lets you to specify which atttributes from the request should be passed to the template:
/**
* #ParamConverter("post", class="SensioBlogBundle:Post")
* #Template("SensioBlogBundle:Post:show.html.twig", vars={"post"})
*/
public function showAction()
{
}
Note, that request attributes can be set by you:
$request->attributes->set('categories', []);
So, you could implement a listener which would set the categories attribute on the request and than configure the vars on the #Template annotation:
/**
* #Template("SensioBlogBundle:Post:show.html.twig", vars={"categories"})
*/
public function showAction(Post $post)
{
}
Have a look at the TemplateListener from the SensioFrameworkExtraBundle for more insight. The listener defines template vars on kernel.controller and uses them to render the view on kernel.view.
You could avoid defining vars on the annotation if your listener was registered after the TemplateListener::onController(). It would have to add categories to the _template_vars request attribute.
Use Twig extension to create function that will return list of available categories
<?php
class CategoriesExtension extends \Twig_Extension
{
public function getFunctions()
{
return [
new \Twig_SimpleFunction('getCategories', [$this, 'getCategoriesList'])
];
}
/**
* #return null|string
*/
public function getCategoriesList()
{
return CategoryQuery::create()->find();
}
/**
* Returns the name of the extension.
*
* #return string The extension name
*/
public function getName()
{
return 'list_categories';
}
}
You can pass parameter to function if You would like do some conditions on query.
The trick is to get the twig service in your listener and then use addGlobal to add your categories
namespace Cerad\Bundle\CoreBundle\EventListener;
use Symfony\Component\DependencyInjection\ContainerAware;
use Symfony\Component\HttpKernel\HttpKernel;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class MyEventListener extends ContainerAware implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return array(
KernelEvents::CONTROLLER => array(
array('doCategories', -1100),
);
}
public function doCategories(FilterControllerEvent $eventx)
{
// Query your categories
$categories = array('cat1','cat2');
// Make them available to all twig templates
$twig = $this->container->get('twig');
$twig->addGlobal('categories',$categories);
}
# services.yml
cerad_core__my__event_listener:
class: '%cerad_core__my__event_listener__class%'
calls:
- [setContainer, ['#service_container']]
tags:
- { name: kernel.event_subscriber }
Is it possible (and recommended) to use multiple models for one table?
I have multiple types of "people" (teacher, students, employees, firms) and would like to store them in the same table. They have all personal data in common, but have other relations (for ex. students -> firms, teacher -> rooms and more), additional information (for ex. firms: firm name, teachers: education) and more.
It would be nice to get some best practices for such cases.
It's really simple! You have to make entities like this:
/**
* #ORM\Entity
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="discr", type="string")
* #ORM\DiscriminatorMap({"teacher" = "Teacher"})
*/
class Person
{
/**
* #ORM/Id
**/
private $id;
/**
* #ORM/Column
**/
private $name;
//setters getters and all the stuff
}
And in Teacher.php file:
/**
* #ORM\Table()
* #ORM\Entity()
*/
class Teacher extends Person
{
private $salary;
}
The key to success are those two annotation:
#ORM\DiscriminatorColumn(name="discr", type="string")
#ORM\DiscriminatorMap({"teacher" = "Teacher"})
First is telling ORM what column will be used to verify if person is Teacher or not.
Second is telling what classes are extending base Person class and what to put in column i mentioned before. When you do that you will have two tables, but in Teacher you will have only data you add to Teacher entity :)
Generally speaking when using ORM you have to think on the object abstraction level and don't care about DB (well, that's not entirely true, but it's general idea) :)
It's not recommended. Here are several reasons I can think of why not to do this:
If Teachers and Students share the same set of IDs, what is to stop someone from loading a Teacher using a Student's ID, and adding a value to the "salary" field? Limiting this access can be done, but it may require custom repositories or other modifications.
Let's say that Teachers are required to have a salary. If Students and Teachers share the same table, then the database won't be able to enforce that constraint without giving Students a salary too.
Even though Students will never have a salary, the database may need to allocate space for that field anyway.
IBM has a great post about mapping inheritance in relational databases, and I've referred to it several times when implementing this type of model. They make reference to three methods: (1) using a single table to represent all classes (the method you've proposed), (2) using separate tables for children classes, or (3) using separate tables for all classes. In the end, it comes down to personal preference, but the way I normally do it is a blend between #2 and #3, where I create the model for all classes, but I limit the access to the parent class from the child, and instead write shortcut methods to access the parent data. Consider this:
class Person
{
private $id;
private $name;
public function getId()
{ return $this->id; }
public function getName()
{ return $this->name; }
public function setName($name)
{ return $this->name; }
}
class Teacher
{
private $id;
private $person; // reference to Person table
private $salary;
public function getId()
{ return $this->id; }
private function getPerson()
{ return $this->person; }
public function getSalary()
{ return $this->salary; }
public function setSalary($salary)
{ $this->salary = $salary; }
public function getName()
{ return $this->getPerson()->getName(); }
public function setName($name)
{ $this->getPerson()->setName($name); }
}
I usually choose this method because I can treat a Teacher as simply a Teacher, or as a Person, depending on what the situation requires. So let's say that I have two pages: one that prints out everyone's name (Teachers and Students), and one that prints out just the Teachers and their salaries:
// Assume:
// $people = $this->getDoctrine()->getEntityManager()->getRepository("MyBundle:Person")->findAll()
{% for person in people %}
{{ person.name }}
{% endfor %}
// Assume:
// $teachers = $this->getDoctrine()->getEntityManager()->getRepository("MyBundle:Teacher")->findAll()
{% for teacher in teachers %}
{{ teacher.name }} makes ${{ teacher.salary }}
{% endfor %}