Creating a new entity in Symfony2 with Doctrine by using the "namespace" - symfony

You know that in Symfony2 a new entity can be defined as in the following example:
use Acme\StoreBundle\Entity\Product;
public function defaultController() {
$product = new Product();
$product->setName('Pippo');
$product->setPrice(19.99);
....
// Use Doctrine EntityManager to store the Product object
}
Suppose that you know that the Product class has the following namespace: "AcmeHomeBundle:Product". It would by nice to create the $product object by using the namespace (e.g. by using the EntityManager or something similar).
public function defaultController() {
$item = createObjectFromNamespace("AcmeHomeBundle:Product");
$item->setName('Pippo');
$item->setPrice(19.99);
....
// Use Doctrine EntityManager to store the Item object
}
Do you know if this is possible?
Suppose that you have a string that provides the entity type

You should do this...
$entityInfo = $this->em->getClassMetadata("entityNameSpace:entityName");
$entityMember = $entityInfo->newInstance();
If you wanna use a setter method by string:
$entitySetMethod = "set".\ucfirst("entityDataMemberName");
\call_user_func(array($entityMember, $entitySetMethod), $parameter);

If you really want to, you can do this:
$product = new Acme\JournalBundle\Entity\Product();
$article = new Acme\JournalBundle\Entity\Article();
But you'd have to type it out every time you wanted to create a new entity in that namespace. If you simply used a use statement at the top of you class:
use Acme\JournalBundle\Entity\Product,
Acme\JournalBundle\Entity\Article;
You could then create new articles and products with a simple:
$product = new Product();
$article = new Article();
They do the same thing.

Acme\StoreBundle\Entity\Product IS the namespace of your entity. AcmeStoreBundle:Product is just an alias for the namespace to be used in DQL as a shorter alternative to the real namespace.
Why would you want to create objects with aliased namespace? I suppose you could create some kind of a factory using alias to map it to a real namespace, create an object and return it. But what's the point?
Entity aliases are defined via Configuration: http://www.doctrine-project.org/api/orm/2.2/source-class-Doctrine.ORM.Configuration.html#153
you can not only set them but also retrieve, so if you really need this functionality you should be able to do this with Configuration instance.
It's hard to find anything about entity aliases in Doctrine docs. Symfony docs explain the purpose of it a little:
alias - Doctrine offers a way to alias entity namespaces to simpler, shorter names to be used in DQL queries or for Repository access. When using a bundle the alias defaults to the bundle name.

Related

Create new element with doctrine entity manager?

I use doctrine entity manager in my script, select and update works always, so entity manager is initialized correctly:
$article = $entityManager->find('Models\Article', 5);
echo $article->getTitle();
or:
$article->setTitle('Updated!');
but when I try to create/save new element then the page breaks, the code is:
$item = new Article();
$item->setAuthorId(1);
$item->setTitle('Created item!');
$entityManager->persist($item);
$entityManager->flush();
It's created like on official documentation page
What I do wrong here?
Seems you can't specify the relation of the object with the Author entity:
$item->setAuthorId(1);
Probably your entity Article Have a relation with the entity Author. In this case you should have a proper setter method (simple setAuthor(Author $author) ) that assign the reference of an Author object. In this case you could use the following:
$item->setAuthor($entityManager->find('Models\Author', 1););
Or Better
$item->setAuthor($entityManager->getReference('Models\Author', 1););
You could also use a short way of reference the class object with the class keyword, as example:
$item->setAuthor($entityManager->getReference(Author::class, 1););
Hope this help

Set up non-persistent relation in Doctrine 2

I have an object $user that has a one to many relation with $establishment. I can use:
$user->getEstablishments();
The user can select a stablishment to work on. I have this method that I call in the controller:
$user->setCurrentEstablishment($establishment);
And this one that I call in the view:
$establishment = $user->getCurrentEstablishment();
I want to be able to call:
$user->setCurrentEstablishmentBy Slug($establishment_slug);
where the slug is a string, and let the user object look for the establishment.
Doctrine discourages the practice of accessing the Entity Manager inside the Entity object, but I think that using it in the controller is even worse.
I suspect that some special Doctrine annotation exists that takes care of non persistent relations like this, or some method other than serving the Entity Manager through a service should be used here. Some easy way of referencing other entities from inside the model.
¿Is there any? ¿How could I do that?
There is no Annotation in Doctrine which could convert slug into object.
What can help You is ParamConverter, with it you can automatically convert slug from query into object. But it still must be used in Controller.
Example usage:
/**
* #Route("/some-route/{slug}")
* #ParamConverter("object", class="AppBundle:Establishment", options={"id" = "slug", "repository_method" = "findEstablishmentBySlug"})
*/
public function slugAction(Establishment $object)
{
...
Docs about param converter: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html

Add data when running Symfony migrations

I have a Symfony project that is using the DoctrineMigrations bundle, and I have a really simple question: When I run a migration (e.g., when I'm pushing an update to production), how can I insert data to the database?
For example: I have an Entity which is the type of an add. The entity is:
private $addType; // String
private $type1; // Boolean
private $type2; // Boolean
private $type3; // Boolean
I add another field ($type4), and I want to add a new record to the database, with this values:
$addType = 'Type number 4';
$type1 = false;
$type2 = false;
$type3 = false;
$type4 = true;
How can this be done with DoctrineMigrations? Is it possible?
Using the Entity Manager as suggested in another answer is not a good idea, as it leads to troubles later.
In the first migration, I created a table with users and populated some users via $em->persist($user); which seemed fine at the beginning.
But after a month, I added a phone column to my User model. And Doctrine generates INSERT statements with this column within the first migration, which fails due to the non-existing column phone. Of course it doesn't exist yet in the first migration. So it is better to go with pure SQL INSERTs.
I just asked a related related question.
It is possible to use the migrations bundle to add data to the database. If you add a new property and use the doctrine mapping then the
php app/console doctrine:migrations:diff
command will generate a new migration file. You can just put your insert statements inside this file using the syntax:
$this->addSql('INSERT INTO your_table (name) VALUES ("foo")');
Make sure you put it after the auto-generated schema changes though. If you want to separate your schema changes and your data changes then you can use
php app/console doctrine:migrations:generate
to create an empty migrations file to put your insert statements in.
Like I said in my related question, this is one way to do it, but it requires manually creating these if you want to change this data in the database.
Edit:
Since this answer seems to get a few views I think it's worth adding that to more clearly separate the data changes from the schema changes there is a postUp method that can be overridden and that will be called after the up method.
https://www.doctrine-project.org/projects/doctrine-migrations/en/3.0/reference/migration-classes.html#postup
I've "found" the correct way to solve my problem (insert data after running migrations, using my entity classes).
Here is: https://stackoverflow.com/a/25960400
The idea is to declare the migration as ContainerAware, and then, from the postUp function, call the DI to get the EntityManager. It's really easy, and you can use all your entities and repositories.
// ...
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class Version20130326212938 extends AbstractMigration implements ContainerAwareInterface
{
private $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
public function up(Schema $schema)
{
// ... migration content
}
public function postUp(Schema $schema)
{
$em = $this->container->get('doctrine.orm.entity_manager');
// ... update the entities
}
}
when you make the new field you need to enter this annotation "options={"default":1}" and it should work.
/**
* #var boolean
* #ORM\Column(name="type4", type="boolean", options={"default":1})
*/
private $type4 = true;
Took me some time to figure this out :)
It does, if you know how to format the array;
$this->connection->insert('user', ['id' => 1, 'gender' => 'Male']);
this is good solution for me. Just use bin/console make:migration and when migration is generated just edit if and add "DEFAULT TRUE":
$this->addSql('ALTER TABLE event ADD active TINYINT(1) NOT NULL DEFAULT TRUE');
It doesn't sound a good idea to fill date in migration, not its responsibility, symfony has a way of doing that. https://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html

Doctrine: how to add a if statement in an order by condition?

I try to write this kind of query :
$qb = $this
->createQueryBuilder()
->select('gh')
->orderBy("IF(gh.language = 'en', 1, 0)", 'desc')
->getQuery();
How can it work ?
Short answer: You can't.
Long answer:
Doctrine only supports a limited subset of SQL functions because it was built to be flexible and not SQL engine specific. Therefore, things like IF statements are not implemented into doctrine, and won't be implemented because the way MySQL handles IF, for example, is different from what PostgreSQL does it (it does not even exist).
However, Doctrine 2 is so powerful that allows you to write your own functions, and extend its functionality, however I wouldn't recommend this unless it's really really necessary to do so.
You can find more details about user defined functions and Doctrine in their documentation:
http://doctrine-orm.readthedocs.org/en/latest/cookbook/dql-user-defined-functions.html
What I would do, is to write raw SQL to query your database. You will have to create a custom repository to keep your code clean and organized.
The custom repositories are an "extension" of your entities.
For example, if you have an entity GH, then your entity class looks like this:
<?php
namespace YourNamespace\ProjectName\WhateverBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* GH
*
* #ORM\Table(name="GH")
* #ORM\Entity(repositoryClass="YourNamespace\ProjectName\WhateverBundle\GHRepository")
*/
class Category {}
Note the repositoryClass statement added to your annotations, that indicates where your customer repository is.
Then create a repository class in the same folder where your entity class is. The convention is to name it "Repository", so in your case it would be: GHRepository and extend the parent class EntityRepository, your custom repository class would look like this:
<?php
namespace YourNamespace\ProjectName\WhateverBundle\Entity;
use Doctrine\ORM\EntityRepository;
use PDO;
class GH Repository extends EntityRepository {
}
Then you can just create public functions inside your class that use raw SQL to query your database. The convention is to name your functions starting with findBy or findAllBy but it's not necessary.
For example, one of my functions look like this:
public function findAllProductsByCategory($categoryId) {
$pdo = $this->getEntityManager()->getConnection();
$findProductsQuery =
"SELECT
P.*
FROM
Products P
LEFT JOIN Types_Products TP ON TP.product_id = P.id
LEFT JOIN Types T ON TP.type_id = T.id
LEFT JOIN Categories_Types CT ON CT.type_id = T.id
LEFT JOIN Categories C ON CT.category_id = C.id
WHERE
C.id = :categoryId
GROUP BY
P.id";
$stmt = $pdo->prepare($findProductsQuery);
$stmt->bindParam(':categoryId', $categoryId, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
and I can use this function, in any controller this way:
$doctrine = $this->getDoctrine();
$em = $doctrine->getManager();
$categoryRepository = $em->getRepository('MyBundle:Category');
$products = $categoryRepository->findAllProductsByCategory($category->getId());
Asfar as I know you cannot do this in doctrine. In MySQL you would use CASE and is a vendor specific keyword.

When to use Entity Manager in Symfony2

At the moment I am learning how to use Symfony2. I got to the point where they explain how to use Doctrine.
In the examples given they sometimes use the entity manager:
$em = $this->getDoctrine()->getEntityManager();
$products = $em->getRepository('AcmeStoreBundle:Product')
->findAllOrderedByName();
and in other examples the entity manager is not used:
$product = $this->getDoctrine()
->getRepository('AcmeStoreBundle:Product')
->find($id);
So I actually tried the first example without getting the entity manager:
$repository = $this->getDoctrine()
->getRepository('AcmeStoreBundle:Product');
$products = $repository->findAllOrderedByName();
and got the same results.
So when do i actually need the entity manager and when is it OK to just go for the repository at once?
Looking at Controller getDoctrine() equals to $this->get('doctrine'), an instance of Symfony\Bundle\DoctrineBundle\Registry. Registry provides:
getEntityManager() returning Doctrine\ORM\EntityManager, which in turn provides getRepository()
getRepository() returning Doctrine\ORM\EntityRepository
Thus, $this->getDoctrine()->getRepository() equals $this->getDoctrine()->getEntityManager()->getRepository().
Entity manager is useful when you want to persist or remove an entity:
$em = $this->getDoctrine()->getEntityManager();
$em->persist($myEntity);
$em->flush();
If you are just fetching data, you can get only the repository:
$repository = $this->getDoctrine()->getRepository('AcmeStoreBundle:Product');
$product = $repository->find(1);
Or better, if you are using custom repositories, wrap getRepository() in a controller function as you can get auto-completition feature from your IDE:
/**
* #return \Acme\HelloBundle\Repository\ProductRepository
*/
protected function getProductRepository()
{
return $this->getDoctrine()->getRepository('AcmeHelloBundle:Product');
}
I think that the getDoctrine()->getRepository() is simply a shortcut to getDoctrine()->getEntityManager()->getRepository(). Did not check the source code, but sounds rather reasonable to me.
If you plan to do multiple operations with the entity manager (like get a repository, persist an entity, flush, etc), then get the entity manager first and store it in a variable. Otherwise, you can get the repository from the entity manager and call whatever method you want on the repository class all in one line. Both ways will work. It's just a matter of coding style and your needs.

Resources