I would like to know if it is possible to avoid using getters and setters for a Symfony 2 entity. Although the php app/console doctrine:generate:entities is very helpful, line codes seem to increase a lot for an entity with a lot of fields
You can define the visibility of your properties from protected or private to public so you now have access to them in this way:
// on entity
public $someProp;
// On your code
$someEntity->someProp = someValue;
This is not a good OOP practice and should be avoided, getters and setters are the way to go if you want clean and secure code.
You Code won't work properly if skip getters and setters.
Especially if you have mapping with different Entities.
Doctrine uses getters nad setters to populate various members fields during storing and fetching of information
Its very bad practice to use public for every property in Entity.
and also you will end up wasting lot of time in changing the property to public as doctinr uses proted when it autogenerate the code
Related
Can anyone tell me how to implement Doctrine NotifyPropertyChanged in Symfony?
I have implemented this code in an Entity that will notify about is changes. But how to add listener for these changes in another Entity?
I mean I want to handle this situation: Entity Book has oneToMany to Authors. When something is being changed in a partcular Author, I want to react on it in a Book Entity. So I have implemented NotifyPropertyChanged in Author. In a setter I invoke notifications, but how to add this listener to a Book entity?
It looks like your use case is a little bit different: the ǸotifyPropertyChanged` is usefull to tell Doctrine your entity changed. By default, Doctrine2 will iterate over all properties and compare them (so that's "automatic"). IMO, drop it. Only use case I see for it right now are some very specific cases were using the default policy would cost too much.
Another way to do would be to use some lifecycle events. Changing other entities from a preUpdate or postUpdate is notoriously difficult. Doctrine already started calculting the "changeset", what to persist to DB, and there's no easy way to add another entity to it.
Since you are ok writing some code inside the setters, the easier path is something like this:
class Author
{
public function setName($name)
{
// ...
// for each setter, call onChanged
$this->onChange();
}
private function onChange()
{
foreach ($this->books as $book) {
// maybe call some method on your books, like onAuthorChanged() ?
}
}
}
since I'm quite new to Symfony and Doctrine I got a maybe stupid question ;-)
Can someone use simple words to explain Collections (especially ArrayCollections in entities) to me? What is it and when and how to use them? (Maybe in an simple example)
Couldn't figure it out quite well in the docs...
Thanks in advance.
So the ArrayCollection is a simple class that implements Countable, IteratorAggregate, ArrayAccess SPL interfaces, and the interface Selectable made by Benjamin Eberlei.
Not much information there if you are not familliar with SPL interfaces, but ArrayCollection - permit you to save the object instances in an array like form but in an OOP way. The benefit of using the ArrayCollection, instead of standard array is that this will save you a lot of time and work, when you will need simple methods like count, set, unset iterate to a certain object, and most of all very important:
Symfony2 uses ArrayCollection in his core and is doing a lot of things for you if you configure it well:
will generate the mapping for your relationships "one-to-one, many-to-one ... etc"
will bind the data for you when you create embedded forms
When to use it:
Usually it is used for the object relationship mapping, when using doctrine, it is recommended to just add annotations for your properties and then after the command doctrine:generate:entity the setters and getters will be created, and for relationships like one-to-many|many-to-many in the constructor class will be instantiated the ArrayCollection class instead of just a simple array
public function __construct()
{
$this->orders = new ArrayCollection();
}
An example of use:
public function indexAction()
{
$em = $this->getDoctrine();
$client = $em->getRepository('AcmeCustomerBundle:Customer')
->find($this->getUser());
// When you will need to lazy load all the orders for your
// customer that is an one-to-many relationship in the database
// you use it:
$orders = $client->getOrders(); //getOrders is an ArrayCollection
}
Actually you are not using it directly but you use it when you configure your models when setting setters and getters.
I have two different bundle:
first bundle, OrderBundle , has core logic and functionalities and contains the Order entity.
second bundle, CustomerBundle depends on OrderBundle and contains the Customer entity.
I need to create a oneToMany relation between Customers and Orders (obviously one Customer do many Orders) but I need to keep the first bundle OrderBundle decoupled from the second, because OrderBundle is intended to be reused for other stuff.
I think the correct way could be something like this http://symfony.com/doc/current/cookbook/doctrine/resolve_target_entity.html but I can't figure out how to have a concrete implementation.
How to implement the relation between Order and Customer, if I can't specifically use Customer like targetEntity in the ManyToOne doctrine mapping?
Many thanks, in advance.
UPDATE
I write down the involved code, for better explanation.
\\ Order\Bundle\Entity\Order.php
class Order {
/**
* #ORM\ManyToOne(targetEntity="Order\Bundle\Model\OrderSubjectInterface", inversedBy="orders")
* #var SourceSubjectInterface
*/
protected $subject; // How to define getter ans setter for $subject ? Do I
have to use php app/console doctrine:generate:entities command?
...
\\ Customer\Bundle\Entity\Customer.php
use Order\Bundle\Model\OrderSubjectInterface;
class Customer implements OrderSubjectInterface{
/**
* #ORM\OneToMany(targetEntity="Order\Bundle\Entity\Order", mappedBy="subject")
*/
private $orders;
How to define getters, setters and the interface?
Yes, this is the right way.
As shown in the documentation you mentioned, you can specify something like OrderSubjectInterface as a targetEntity in the ManyToOne mapping.
This way, you know that your Order is related to subjects. Those subjects are, in your case, the Customers, as defined in app/config/config.yml.
It's quite hard to entirely decouple the bundles if you have entity definitions all over the place. The problem is, the Doctrine doesn't allow by default for a related entity to be missing. Let's start from the beginning.
If you want to decouple only Order entity, what you have to do is create interfaces for all its related entities (they need to implement them) and then use the ResolveTargetEntity. So instead of referencing the full entities you reference the interfaces (when you define the relations in your entities). Lastly, you can then set which interface maps to which entity in the configuration.
What this does is it allows you to pick up the Order bundle and put it in an environment which has entirely different entity structure. The important thing is that the entities related to Order must not be missing in the new environment (They can be entirely different, but they must implement the same interfaces as the originals). Then you change the settings so that the interfaces point to the entities from the new environment.
So as you see, this is not "entirely decoupled" code. I can't help you much more without some details. Is the relation bidirectional or unidirectional? What do you exactly mean by "reused for other stuff", can you be more detailed?
I try to use Doctrine casecade feature tu automagicaly save relations between two entities, and it does'nt seem to work.
I've made a demo here : https://github.com/asakurayoh/demo_bug_doctrine
So I use the doctrine fixture to make my demo.
you need to create de database (app/console doctrine:database:create), migrate the tables (app/console doctrine:migrations:migrate) and then, load the fixtures (app/console doctrine:fixtures:load). The third fixture (src/Demo/MyBundle/DataFixtures/ORM/TagsNewsFixtures.php) is adding all tags entities to all the news. And if you go to the database, you will see that no relation was save in the news_tag table... I think my relation are well defined in my mapping (Resources/config/doctrine/News.orm.yml and Tag.orm.yml) and the cascade property is set.
Someone can find the problem with this code? I search everywhere (stackoverflow too) and I've done everythings everyone said... it should work...
Thanks to save my life (and my entities relations, ha!)
AsakuraYoh
The problem is in fixtures loading order - TagNewsFixtures is loaded first, therefore no tag nor news are in database at that time. Try forcing load order using ordere
namespace Acme\HelloBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
class LoadData extends AbstractFixture implements OrderedFixtureInterface
{
public function load(ObjectManager $manager)
{
// ...
}
public function getOrder()
{
return 1; // the order in which fixtures will be loaded
}
}
I found the problem.
The "joinTable" preperty need to be on the News side and news use the "inversedBy" property, no the MappedBy (that's the tag). So it work. And to add news to a tag (do the inverse, then), we need to specify in the Tag entity to add the tag to the news... I don't understand why Doctrine doesn't do that by default... weird...
I'm using Symfony2 and Doctrine, so to create getters and setters methods I do:
php app/console doctrine:generate:entities org/StoreBundle/Entity/Product
That works fine, but I would like to generate the getters and setters without comments. I think they are too obvious and redundant, for example:
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
Five lines !
Is there any option to do that?
Looking at the source for the Doctrine GenerateEntitiesCommand, it doesn't look like there is any way to do that: https://github.com/doctrine/DoctrineBundle/blob/master/Command/GenerateEntitiesDoctrineCommand.php
However, why would you want to remove the comments? It's not like there is a line limit in PHP, and it is barely a blip on your compiling in terms of a performance hit for comments (the different is so small, there is no way you could actually measure it on your computer).
Also, if you use PHPDoc to generate documentation for your code, that #return string is more useful than you might thing, because you'd then know the return types for each of your getters (which isn't always very obvious).
You may generate getter/setter using Netbeans IDE instead of Doctrine command line.