I'm using Doctrine ORM in a project that I am working on. Although the idea of providing an object interface to the db is nice, I have a question about the implementation of the entity classes.
Let's consider this example of a User entity:
<?php
/**
* #Entity #Table(name="users")
**/
class User
{
/**
* #Id #GeneratedValue #Column(type="integer")
* #var int
**/
protected $id;
/**
* #Column(type="string")
* #var string
**/
protected $name;
/**
* #OneToMany(targetEntity="Bug", mappedBy="reporter")
* #var Bug[]
**/
protected $reportedBugs = null;
/**
* #OneToMany(targetEntity="Bug", mappedBy="engineer")
* #var Bug[]
**/
protected $assignedBugs = null;
// .. (other code)
}
Now, its all fine and dandy, but I was wondering what would happen if I make a spelling mistake in one of the comments e.g. I write:
#Table(name="users)
instead of
#Table(name="users")
the IDE will not complain since its a comment, and I'll only get an error when I run the "generate entities" command (that does the magic in the background of generating code, creating tables, columns and relationships).
So my question is: Aren't entity definitions for ORM error prone? since there really is no check on the syntax if its valid, and errors are generated only at 'generate' time. Is there a way to automate / check for mistakes earlier on while development?
Thanks!
IMO, The issue that you highlighted can be compared to using wrong variables in PHP ($var1 instead of $var2). For that matter, in all dynamic languages.
But you can avoid the problem highlighted by you, if you write unit tests.
Related
In Javadoc I can represent a hyperlink as #see http://google.com. How can I do this in Kotlin?
Well, actually, hyperlinks and #see tags are two separate matters in KDoc, meaning that #see is only limited to API references:
/**
* #see [Object.toString]
*/
class C
Hyperlinks per se use the regular Markdown syntax (but, unlike JavaDoc, can't be mixed with #see tags):
/**
* **See Also:** [Google](http://google.com)
*/
class C
I'm looking for a way to set up code formatting to keep javadoc in enums in separate blocks. Right now wrapping of enum members works as intended, but for some reason javadoc comments start/end on the same line as the members
I'd keep getting this:
public enum FormatTest {
FOO, /**
* some description
*/BAR, BAZ;
}
but I want it to look something like this:
public enum FormatTest {
FOO,
/**
* docs either like this
*/
BAR,
/** or like this */
BAZ;
}
It works perfectly well for class members strangely enough...
try changing the Code Style settings.
In IntelliJ, go to: Settings -> Code Style -> Java -> Wrapping and Braces tab.
Scroll down untill you see Enum constants, and change the value to: Wrap always.
See screenshot
I'm attempting to have an Fileable trait that will give provide an Entity with methods to CRUD Files based on the File Entity mentioned below.
After reading the documentation on Doctrine and searching the internet, the best I could find is Inheritance Mapping but these all require the subclass to extend the superclass which is not ideal as the current Entities already extend other classes. I could have FileFoo entity and a FileBar entity but this gets too messy and requires an extra join (super -> sub -> entity).
Alternatively, I could have a File Entity which has many columns for Entities (so foo_id for the Foo object, bar_id for the bar object and so on) but this gets messy and would require a new column for every entity that I'd want to add the Fileable trait too.
So to the questions:
Am I thinking about how I want to hold data incorrectly?
Is there some features/functions in Doctrine/Symfony that I've missed?
Do you think I feature like this would be added if I were to fork Doctrine to add this feature, also where should I look?
<?php
/**
* File
*
* #ORM\Table()
* #ORM\Entity()
* #ORM\HasLifecycleCallbacks()
*/
class File
{
/**
* #var integer
*
* #ORM\Column(type="integer")
* #ORM\Id()
* #ORM\GeneratedValue()
*/
protected $id;
/**
* #var string
*
* #ORM\Column(type="string")
*/
protected $entityName;
/**
* #var string
*
* #ORM\Column(type="string")
*/
protected $entityId;
...
I accomplished a similar thing using Inheritance defined in traits, which alongside interfaces, basically gave me what a multiple extend would give.
Take a look at embeddables or you could use traits.
This is classic method for the entity relationship;
/**
* #ORM\OneToMany(targetEntity="Product", mappedBy="category")
*/
protected $products;
and other entity;
/**
* #ORM\ManyToOne(targetEntity="Category", inversedBy="products")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
protected $category;
But, when I use this method, I can't use limit function. All results are taken. But, I should use sql limit function. So, I use a repository class. I wrote all sql code again. I used join function again. Is the relationsip annotation necessary in this situation? Do I still need to add this annotation?
Unfortunately, there is no way of doing what are you asking. You are gonna have to write a custom DQL, preferably inside a custom repository in order to fetch exactly what you want. Of course you still need the annotation itself, as is required by Doctrine to do many things under the hood and, in general, to keep a good relationship model between your entities.
The most close annotation you have to control the way in which relationships are joined when using automatic method is the OrderBy one:
/*
* #OneToMany(...)
* #OrderBy({"name" = "ASC"})
*/
protected $relation;
I am using JMSSerializerBundle to serialize my entities to json and deserialize json into entities, but I think this question applies for any deserialization techniques.
For example, this schema:
class Order
{
private $id;
/**
* #Serializer\Type("ArrayCollection<MyBundle\Entity\Order\Item>")
* #ORM\OneToMany(targetEntity="\MyBundle\Entity\Order\Item", mappedBy="order", cascade={"persist"})
*/
private $items;
}
class Item
{
private $id;
/**
* #ORM\ManyToOne(targetEntity="\MyBundle\Entity\Order", inversedBy="items")
*/
private $order;
/**
* #var integer $amount
* #Serializer\Type("integer")
* #ORM\Column(name="amount", type="integer")
*/
private $amount;
}
Maps to this json: {"id":1,"items":[{"id":1,"amount":100}, {"id":2,"amount":200}]} and the same json is properly deserialized into an object of type MyBundle:Order that has a colletion of two MyBundle:Order/Item objects.
The problem is that when I try to persist this object, new entries are created in the database, rather than updating existing, ignoring the ids. How do I tell entity manager that theses objects should be updated, rather that created?
Update. Generally EntityManager::merge solution (as suggested by DaveM) is fine. But you must only merge existing objects. For example, if you have a json that represents a new Order entity that is connected to existing Order\Item entities
{"id":null,"items":[{"id":1,"amount":100}, {"id":2,"amount":200}]}
In this case you cannot just merge an Order object like this:
$em->merge($order), because order is a new entity and entity manager will attempt to find an Order object with id = null and you will end up with a new Order and empty items array. So the solution is to loop the Order::$items array and merge each item individually. Then a new order will be created and connected with existing items.
You need to use the merge() method on the EntityManager as merging entities refers to the merging of entities into the context of an EntityManager so that they can become managed again. In order to merge the state of an entity into an EntityManager use the EntityManager#merge($entity) method. The state of the passed entity will be merged into a managed copy of this entity and this copy will subsequently be returned.
$detachedEntity = unserialize($serializedEntity);
$entity = $em->merge($detachedEntity);
Also be sure to note when you want to serialize/unserialize entities you have to make all entity properties protected, never private. The reason for this is, if you serialize a class that was a proxy instance before, the private variables won’t be serialized and a PHP Notice is thrown.
More information can be found in the doctrine documentation here:
http://doctrine-orm.readthedocs.org/en/2.0.x/reference/working-with-objects.html#merging-entities
I know this question is three years old, but it mislead me to think the only answer was using the merge operation. I'd like to add my two cents:
The JMSSerializerBundle includes an object constructor for Doctrine entities. When you enable this constructor, the deserialized entities are managed entities that can be persisted(with $em->persist($entity)).
Please check this comment to understand other benefits from this.
And here is how you can enable it.