Symfony: queryBuilder without mapped field - symfony

it's possible to create a QueryBuilder in Symfony with fields that not appear in the Entity Class.
Something like this:
MyEntity Class:
id, name, color
DB Table: id, name, color, number
And then, I'm triying to do this:
$filterBuilder = $this->get('doctrine.orm.entity_manager')
->getRepository('XXXXBundle:MiEntity')
->createQueryBuilder('o')
->select('o.number')
->..........
;
But I get this error:
Error: Class XXXXX has no field or association named number

In your case, you should still add an unmapped "number" proporty to your class, but if you insist, you can use a native query to fetch whatever you want from the DB.
Here is an example that selects all users with an age > 20 :
$query = $em->createQuery('SELECT u FROM MyProject\Model\User u
WHERE u.age > 20');
$users = $query->getResult();
As seen on Doctrine Query Language documentation page

Related

How to insert value in the table having it primary key in symfony

I want to insert a value having already defined id in the table which have auto increment column id(PK) in doctrine symfony.
You can change the ID generator temporarily to store given primary ids like:
use App\Entity\YourEntity;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Id\AssignedGenerator;
use Doctrine\ORM\Mapping\ClassMetadata;
$entity = new YourEntity();
$entity->setId(101);
$entity->setSomething('foo');
$entityManager->persist($entity);
// change the ID generator temporarily before flushing
$metadata = $entityManager->getClassMetaData(YourEntity::class);
$metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_NONE);
$metadata->setIdGenerator(new AssignedGenerator());
$entityManager->flush();
Note : generally you should not update the id of an existing row in the dataBase.
But However.. Assuming that your entity look like has fields : ID and nameValue :
$car = $carsRepository->find(10); // select a car which the id is 10
$car->setId(1025); // note that : by default your entity DOES NOT have a built method setID() so you have to write it.
$car->setNameValue("Opel");
$manager->flush();

How can i select extra fields and map them to entity via doctrine query builder in symfony?

I have two entities: Category and Product. Category entity has not link to Product (protected $products // ArrayColection). I need to calculate total amount of product prices inside each category, and i need to do it ONLY IN SINGLE request via query builder.
Can i do something like this:
$categories = $categoryRepository->createQueryBuilder('c')->join('AppBundle:Product', 'p')->addSelect('SUM(p.price) as c.totalPrice')->addGroupBy('c.id')->getQuery()->getResults();
And then map attribute totalPrice to entity, to have access to it somehow like this:
$categories->get(0)->totalAmount
I CAN'T build extra query, and i CAN'T add relationsip field to Category ($products) to calculte totalSum in entity method by adding price of each product. I should done it only with single query...
What you are talking about is possible with Doctrine > 2.4
Check out their docs for more details on joins: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html
Meanwhile - this is what should work for you:
$query = $this->createQueryBuilder('c')
->leftJoin('AppBundle:Product', 'p', 'WITH', 'p.category = c.id')
->select('SUM(p.price) as totalPrice')
->groupBy('c.id');
Note how we use the leftJoin method parameters - this is what allows you to run the query despite there is no relation between tables.
Hope that works for you

Getting custom getter values from Entity with DQL in symfony2

I'm using FOSUserBundle and FOSRestBunldle with Symfony 2.8 and have to get a short user List with age, however there is no field 'age' in the user database, which is why my User entity class has this custom getter to calculate the age from the birthdate field
public function getAge()
{
$now = new \DateTime('now');
$age = $this->birthdate->diff($now);
return $age->format('%y');
}
Getting my user list with "u.age" and serializing it to json however, does not work, as there is no real field associated with u.age
$query = $em->createQuery('SELECT u.username, u.age FROM AppBundle:User u');
$users = $query->getResult();
Using the Repository with ->findAll() would get the ages, but also loads a lot of other related entities (posts, comments by the user) which are not needed here and would be a bit of an overload.
How can i get a list of my users with just their username and respecive age?
thank you for your help!
I have found the solution. Using the Annotation #VirtualProperty tells the serializer to get the value.
use JMS\Serializer\Annotation\VirtualProperty;
has to be included into Entity class, so annotation works.
/**
* #VirtualProperty
*/
public function getAge()
{
You don't have age field in DB, which also means you don't have it in Doctrine mapping, therefore you can't select it. Doctrine doesn't know anything about it.
You need to select data that is required to calculate it inside entity instance. In this case in order to calculate user's age you probably want to select birthday date.
E.g.:
$query = $em->createQuery('SELECT u.username, u.birthday FROM AppBundle:User u');
$users = $query->getResult();
Then you should be able to get age from your entity in PHP code.

How do I setup up Doctrine's Class Inheritance in Symfony?

My issue is, I'm having trouble grasping DiscriminatorColumn and DiscriminatorMap in Doctrine's Class Inheritance.
I have a products entity that is considered the parent class / table.
There are several child entities that inherit the product entity. (models, parts, and options)
I feel like I should be able to use the primary key to link both tables... But how do I do that with DiscriminatorColumn?
Here is the general idea of what I want to happen...
Fetch all model objects from database while inheriting product parent entity
SELECT object
FROM parts_object parts
LEFT JOIN products_object po
ON parts.product_fk = po.product_id
Or... Fetch all part objects from database while inheriting product parent entity
SELECT object
FROM parts_object parts
LEFT JOIN products_object po
ON parts.product_fk = po.product_id
Ideally I want this done using Doctrine instead of some custom SQL.
Do I need to setup a "type" column for the parent table so each row defines whether it's a part, model, or option?
Doctrine inheritance docs
Okay, I'll try to explain this as simple as possible.
Let's start with DiscriminatorColumn
Discriminator column is basically, as it says, a column in your database. Its used to store, a key, if you like which helps to identify what kind of object you're currently querying, based on your DiscriminatorMap configuration.
DiscriminatorMap is the way you map each of those keys to an entity. You said you have the following
Product [parent]
Model [child of parent]
Part [child of parent]
Option [child of parent]
Then, your discriminator map should look something like this, for example:
#DiscriminatorMap({
"model" = "AppBundle\Entity\Model",
"Part" = "AppBundle\Entity\Part",
"Option" = "AppBundle\Entity\Option"
})
Always pay attention to your last definition in your mapping. The last line must end without a comma!
As of InheritanceType I would suggest you to use #InheritanceType("JOINED") because this will let you have single table for each of your child classes.
Every child class must extend your Product entity class, which is obviously the parent. Each child class must not define $id property, because of the inheritance mapping.
Then querying for records by specific type comes with the following query:
"SELECT product FROM AppBundle\Entity\Product product WHERE product INSTANCE OF AppBundle\Entity\Part"
The query will search only for records mapped to this entity only.
If you have any questions, don't hesitate to ask.
Edit as of new comment
-----------------------
A little bit more explanation. You do not need to create any extra property/column in your entity mappings. The moment you add this annotation #DiscriminatorColumn(name="discr", type="string") doctrine will create that column automatically for you. The column from this example would be named discr with type of VARCHAR.
I still don't understand what is used to join the tables. How does doctrine know to link the ids between the product and model
About this part. If you use #InheritanceType("JOINED") this would mean that your GeneratedValue ID would be set in your main entity - Product. Then each of the child entities that extend Product would automatically get the same ID, which is why you don't need to specify $id property in your child entities.
Lastly, how can you check which entity type you're currently viewing for example. Consider the following scenario, each of your child entities extends Product and we will perform a dummy search for a record:
$product = $entityManager->find('AppBundle:Product', 1); // example
Now, if you actually go and do a var_dump($product) you will notice something interesting. The object would be an instance of either Model,Part or Option because each of these entities are defined in your discriminator map and Doctrine automatically maps your records based on that.
Later, this can come handy in situations like this:
if( $product instanceof \AppBundle\Entity\Part ) {
// do something only if that record belongs to part.
}
If you want to use DiscriminatorMap for Doctrine, so you should use Doctrine, but not SQL.
Basic setup is:
/**
* #ORM\Table(name="product")
* #ORM\Entity(repositoryClass="MyApp\ProductBundle\Repository\ProductRepository")
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="productType", type="string")
* #ORM\DiscriminatorMap({
* "Product" = "Product",
* "Model" = "Model",
* "Part" = "Part",
* "Option" = "Option",
* })
*/
class Product
{
...
}
MyApp\ProductBundle\Entity\Model
/**
* #ORM\Entity(repositoryClass="MyApp\ProductBundle\Repository\ModelRepository")
*/
class Model extends Product
{
}
MyApp\ProductBundle\Entity\Part
/**
* #ORM\Entity(repositoryClass="MyApp\ProductBundle\Repository\PartRepository")
*/
class Part extends Product
{
}
MyApp\ProductBundle\Entity\Option
/**
* #ORM\Entity(repositoryClass="MyApp\ProductBundle\Repository\OptionRepository")
*/
class Option extends Product
{
}
Then if you need to get all products at controller
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository("MyAppProductBundle:Product");
$products = $repo->findAll();
Then if you need select all models, just setup proper repository
$repo = $em->getRepository("MyAppProductBundle:Model");
$models = $repo->findAll();

Doctrine DQL Delete from relation table

Using Doctrine 2 and Symfony 2.0.
I have two Doctrine entities (let's suppose EntityA and EntityB).
I have a ManyToMany relation between them. So a EntityA_EntityB table has been created in database.
Using DQL or QueryBuilder, how can I delete from that relation table EntityA_EntityB?
Docrtine offers something like this to perform something similar:
->delete()
->from('EntityA a')
->where('a.id', '?', $id);
But I don't really get how to perform the deletion of row from the relation table.
$em = ...; // instance of `EntityManager`
// fetch both objects if ID is known
$a = $em->getRepository("YourProjectNamespace:EntityA")->find($id_of_A);
$b = $em->getRepository("YourProjectNamespace:EntityB")->find($id_of_B);
// suppose you have `EntityA::getObjectsOfTypeB` which retrieves all of linked objects of type `EntityB`.
// This method return instacne of ArrayCollection
$a->getObjectsOfTypeB()->removeElement($b);
$em->flush();
Something like this?
Basically, you need to remove related object from collection rather than delete relation itself. you want to remove relation directly you can always use pure SQL, but in DQL that is not possible.
Raw DELETE SQL statement via DBAL Connection object
$conn = $this->getDoctrine()->getManager()->getConnection();
$stmt = $conn->prepare("DELETE FROM EntityAEntityB WHERE id_b IN (:ids_of_b)");
$stmt->bindParam('ids_of_b', $to_delete_ids); // BEWARE: this array has to have at least one element
$stmt->executeUpdate();

Resources