Find all entities without a relation - doctrine-orm

My question heavily depends on this: Doctrine: Query only where relationship doesn't exist?
I wonder how the very same thing can be accomplished using Doctrine2. I am especially interested in good practices. Do I have to use the QueryBuilder or is it possible to use a findBy on a repository?

Eventually I used QueryBuilder like this (example from the question linked above):
// $entitiyManager: Doctrine EntityManager instance
$qb = $entityManager->createQueryBuilder();
$x = $qb->expr();
$qb->select('article')
->from('Article', 'article')
->leftJoin('article.category', 'category')
->where($x->isNotNull('category.id');

Related

Symfony & Doctrine: Optional foreign key

Without scrutinizing why I want this (it may sound like a bad approach, but I have good reason) I want to know if there is a way in the standard-framework-edition 3.1+ to create a relational association to an entity that may not exist...
Firstly I do realize this determines the schema and that's fine. So if an entity does not exist, it doesn't create a foreign key and the field is always null, or if the target entity does exist, it creates the foreign key and the field works like a normal association...
Secondly, this only changes project to project, and may change down the line as an update to which I realize a manual schema update could be necessary.
Preferably without 3rd party bundle dependencies... hoping for the standard framework to do this,
Anybody?
Thanks in advance
Edit
I am using annotations in my entities with doctrine ORM
Furthermore
The simplest version of why I am doing this is because certain bundles are optional project-to-project, and bundle A may make use of entities in bundle B only if it is present. I have considered using services and if container->has then container->get, or the XML on-invalid="null" approach, but that doesn't address property persistence. I was happy with storing a non-mapped value as a custom relational field, which is fine, just lengthier and wondered if perhaps there was a way Doctrine could ignore a missing targetEntity...
Hm, perhaps I misunderstand your question, but this sounds like a normal 'nullable' association to me?
Create your assocation via annotation:
/**
*
* #var Child
* #ORM\ManyToOne(targetEntity="Child")
*/
private $child;
and use
setChild(Child $child = null)
{
$this->child = $child;
}
as a Setter to allow nullable values.
And your getter might look like:
getChild()
{
return $this->child;
}
In case there isn't any child it will return null.
I will keep the other answer as it responds to the question for a 'nullable association target' live data.
This is the answer for a 'nullable association target' meta data which is a different thing.
OP asks to provide a targetEntity in the metadata which cannot exist in his case, e.g. is not there in a different bundle (or whatever OP's mysterious reason might be).
In that case I recommend to build upon Doctrine's TargetEntityListener which is able to resolve the targetEntity during runtime and targetEntity can be set to an Abstract Class or an Interface:
/**
* #ORM\ManyToOne(targetEntity="Acme\InvoiceBundle\Model\InvoiceSubjectInterface")
* #var InvoiceSubjectInterface
*/
protected $subject;
InvoiceSubjectInterface will then be replaced during runtime by a specific class provided by config e.g.:
# app/config/config.yml
doctrine:
# ...
orm:
# ...
resolve_target_entities:
Acme\InvoiceBundle\Model\InvoiceSubjectInterface: AppBundle\Entity\Customer
So this should be eiter an extendable behaviour for providing no class or implementing an own solution.

Doctrine specify logical name for JoinColumn [duplicate]

I'm working on an events site and have a one to many relationship between a production and its performances, when I have a performance object if I need its production id at the moment I have to do
$productionId = $performance->getProduction()->getId();
In cases when I literally just need the production id it seems like a waste to send off another database query to get a value that's already in the object somewhere.
Is there a way round this?
Edit 2013.02.17:
What I wrote below is no longer true. You don't have to do anything in the scenario outlined in the question, because Doctrine is clever enough to load the id fields into related entities, so the proxy objects will already contain the id, and it will not issue another call to the database.
Outdated answer below:
It is possible, but it is unadvised.
The reason behind that, is Doctrine tries to truly adhere to the principle that your entities should form an object graph, where the foreign keys have no place, because they are just "artifacts", that come from the way relational databases work.
You should rewrite the association to be
eager loaded, if you always need the related entity
write a DQL query (preferably on a Repository) to fetch-join the related entity
let it lazy-load the related entity by calling a getter on it
If you are not convinced, and really want to avoid all of the above, there are two ways (that I know of), to get the id of a related object, without triggering a load, and without resorting to tricks like reflection and serialization:
If you already have the object in hand, you can retrieve the inner UnitOfWork object that Doctrine uses internally, and use it's getEntityIdentifier() method, passing it the unloaded entity (the proxy object). It will return you the id, without triggering the lazy-load.
Assuming you have many-to-one relation, with multiple articles belonging to a category:
$articleId = 1;
$article = $em->find('Article', $articleId);
$categoryId = $em->getUnitOfWork()->getEntityIdentifier($article->getCategory());
Coming 2.2, you will be able to use the IDENTITY DQL function, to select just a foreign key, like this:
SELECT IDENTITY(u.Group) AS group_id FROM User u WHERE u.id = ?0
It is already committed to the development versions.
Still, you should really try to stick to one of the "correct" methods.

How do I remove entities in Doctrine 2?

How do I remove entities in Doctrine 2? I want to know how to do this through the command line and with PHP. Thanks!
Edit:
I'm not sure if I'm asking this question right (I'm new to Doctrine). I want to leave the Entity file in the directory, but I want to delete its table from the database. This stems from Zend based modular architecture where modules can be installed/uninstalled without the module directory being removed. If a module is uninstalled, I want its entities removed. The opposite is also true.
As far as I know, there is no way to do this. You have to manually remove associated database tables.
You can just remove \ORM annotation from entity if you want to exclude it from entity generation process.
I did some looking into Doctrine's API and eventually figured it out:
$classes = array();
$entityManager = ...
$classes[] = $entityManager->getClassMetadata('Entities\MyEntity1');
$classes[] = $entityManager->getClassMetadata('Entities\MyEntity2');
$classes[] = $entityManager->getClassMetadata('Entities\MyEntity3');
$classes[] = $entityManager->getClassMetadata('Entities\MyEntity4');
//Doctrine Schema Tool
$st = new Doctrine\ORM\Tools\SchemaTool( $entityManager );
$st->dropSchema($classes);
This will remove the tables associated with Entities\MyEntity1, 2, 3 and 4 from the database.
Also, using the exact same code above except the last line, the following methods are useful:
$st->createSchema($classes);
AND
$st->updateSchema($classes);
You can find all the info in Doctrine's documentation:
http://www.doctrine-project.org/projects/orm/2.0/api

Doctrine 2 ORM creates classes with hateful CamelCase

I created yaml configuration for Doctrine. When I'm trying doctrine orm:generate-entities, it creates php files with getters and setters in camel case. So, is_public field transforms into setIsPublic and getIsPublic methods. It's owful. How can I get set_is_public and get_is_public? I can manually edit generated php files, but I don't know what will happen when I change the schema.
You can choose a naming strategy that Doctrine will use to generate the items using:
Using a naming strategy you can provide rules for automatically
generating database identifiers, columns and tables names when the
table/column name is not given. This feature helps reduce the
verbosity of the mapping document, eliminating repetitive noise (eg:
TABLE_).
For your specific case, I think you're looking at something like:
$namingStrategy = new \Doctrine\ORM\Mapping\UnderscoreNamingStrategy(CASE_LOWER);
$configuration()->setNamingStrategy($namingStrategy);
The linked topic goes on to show you how you can write your own custom naming strategy.
If you're using Symfony, it's even easier (like most things are with Symfony, but that's just my opinion) via config.yml:
doctrine:
orm:
naming_strategy: doctrine.orm.naming_strategy.underscore
Symfony's coding standards encourage Symfony users to use camelCase:
Naming Conventions
Use camelCase, not underscores, for variable,
function and method names, arguments
Personal advice - do not generate entities by doctrine orm:generate-entities.
Use plain PHP to create class. Why?
Orm uses reflection on privates to communicate with database. You dont need to generate setters and getters. I recomend You to use design patterns such as factory or constructor to achive Your goal. Decorators also should work fine.
<?php
class MyClass
{
private $id;
private $name;
public function __construct(int $id, string $name)
{
$this->id = $id;
$this->name = $name;
}
}
$camelCase is not only Symfony's recomendation for code standard. It's based on PSR2. I highly recomend using PSR2, code gets clean and standarized.
Standard ORM naming strategy is $camelCase private var to snake_case column name. If you want to change it otherwise, consider: other naming stategies

Product of two fields annotation

I currently have a line in my Django app like this:
db.execute("SELECT SUM(price * qty) FROM inventory_orderline WHERE order_id = %s", [self.id])
I'd rather perform this through the models interface provided my Django, but can't find any references.
I'm pretty sure this can be done with an annotation, but the examples only cover a few of them and I can't find a list in the documentation.
I'd like to do something like this:
self.line_items.annotate(lineprice=Product('orderline__price', 'orderline__qty')).aggregate(Sum('lineprice'))
Can anyone suggest an annotation class to use to perform the multiplication? Even better, a link to the API listing all these annotation/aggregation classes?
It's not clearly documented, but this can be done with the F() function:
from django.db.models import F
self.line_items.annotate(lineprice=F('orderline__price') * F('orderline__qty')).aggregate(Sum('lineprice'))
Unfortunately, there aren't enough inbuilt Aggregate functions and specifically, there is not one for Product.
But that doesn't limit you in any way other than having to write a "non-concise" ORM query. Specifically for your case, you should be able to do:
self.line_items.extra(select=("lineprice": "orderline__price*orderline__qty")).aggregate(Sum('lineprice'))