I write my entities in let's say models/ folder.
something like:
namespace Organisation\User;
/**
#Entity
*/
class Customer {
/**
* #Column(type="integer") #GeneratedValue
*/
protected $_id;
}
}
So I'll instantiate my entity with $customer = new \Organisation\User\Customer();
Ok, but if I use doctrine orm:generate-entities library/ it will generate it under the following directory :
library/Organisation/User/Customer.php
ANd that's ok, but if I look at the code, there aren't any of my annotation, and therefore when I try to use it, I get doctrine\ORM\Mapping\MappingException: Class Organisation\User\Customer is not a valid entity or mapped super class. because there aren't any annotation.
So what I need to do is to remove the namespace, generate into the same directory as the entities with metadata inforations are, move to my library folder, and add the namespace to work with.
It looks ugly, do I have missed something?
edit: I forgot to tell that orm:generate-entities doesn't work recursively, then, I can't even use my actual structure within my entities metadata
If you've written your entity classes already, why are you trying to generate them?
They typical way to drive a new project is to write your annotated entity classes, and use orm:schema-tool:create to generate your database schema.
Most examples I've seen do stick the Entities under library/, in some nested directory based on the namespaced name of the class, just as you've described. This is generally a good thing, as it works with the default Doctrine2 autoloader setup.
If you're not trying to fit Doctrine2 onto an already existing database schema, I'd recommend that you simply stick all your entity classfiles someplace like library//Entity/.php, and use orm:schema-tool:update and orm:schematool:update to manage the database for you.
Use the arg --generate-annotations.
Related
Is it considered a bad practice to add fields to Symfony entity in controller? For example lets say that I have a simple entity:
/**
* #ORM\Entity
* #ORM\Table(name="user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
}
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
}
}
And then in UserController.php I want to do the following:
foreach($users as $user){
$user->postsCount = someMethodThatWillCountPosts();
}
So later that postsCount can be displayed in Twig. Is it a bad practice?
Edit:
It's important to count posts on side of mysql database, there will be more than 50.000 elements to count for each user.
Edit2:
Please take a note that this questions is not about some particular problem but rather about good and bad practices in object oriented programming in Symfony.
As #Rooneyl explained that if you have relation between user and post then you can get count easily in your controller, refer this for the same. But if you are looking to constructing and using more complex queries from inside a controller. In order to isolate, reuse and test these queries, it's a good practice to create a custom repository class for your entity.Methods containing your query logic can then be stored in this class.
To do this, add the repository class name to your entity's mapping definition:
// src/AppBundle/Entity/Product.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="AppBundle\Repository\ProductRepository")
*/
class Product
{
//...
}
Doctrine can generate empty repository classes for all the entities in your application via the same command used earlier to generate the missing getter and setter methods:
$ php bin/console doctrine:generate:entities AppBundle
If you opt to create the repository classes yourself, they must extend
Doctrine\ORM\EntityRepository.
More Deatils
Updated Answer
In many cases associations between entities can get pretty large. Even in a simple scenario like a blog. where posts can be commented, you always have to assume that a post draws hundreds of comments. In Doctrine 2.0 if you accessed an association it would always get loaded completely into memory. This can lead to pretty serious performance problems, if your associations contain several hundreds or thousands of entities.
With Doctrine 2.1 a feature called Extra Lazy is introduced for associations. Associations are marked as Lazy by default, which means the whole collection object for an association is populated the first time its accessed. If you mark an association as extra lazy the following methods on collections can be called without triggering a full load of the collection: SOURCE
"rather about good and bad practices in object oriented programming"
If that's the case then you really shouldn't have any business logic in controller, you should move this to services.
So if you need to do something with entities before passing them to twig template you might want to do that in specific service or have a custom repository class that does that (maybe using some other service class) before returning the results.
i.e. then your controller's action could look more like that:
public function someAction()
{
//using custom repository
$users = $this->usersRepo->getWithPostCount()
//or using some other service
//$users = $this->usersFormatter->getWithPostCount(x)
return $this->render('SomeBundle:Default:index.html.twig', [
users => $users
]);
}
It's really up to you how you're going to do it, the main point to take here is that best practices rather discourage from having any biz logic in controller. Just imagine you'll need to do the same thing in another controller, or yet some other service. If you don't encapsulate it in it's own service then you'll need to write it every single time.
btw. have a read there:
http://symfony.com/doc/current/best_practices/index.html
Working with Symfony2 and trying to figure out how best to incorporate Vendor libraries. Calling vendor library methods is very easy using the routing configs: use the appropriate namespace, generate the class name, the method to call, and the arguments from a couple path components and query vars, voila, instant integration.
I'm having trouble with forms, though. My goal seems like it should be very easy. I want to make forms in Symfony2 from vendor classes. As a specific example, consider the google-api-php-client. It seems like ->createForm() would work best, because it bridges to the ORM and validation so nicely. However, it relies on a a MyBundle\Form\ThingType file and class. To create this class, I need an entity within my bundle. I can't (or haven't been able to figure out how to) just use existing "Entities" from vendor libraries. Creating the "Entity" in the Symfony nomenclature when a "Model" already exists in the API lingo seems to be inflexible and very un-D.R.Y.
The other method I've gotten to work is using
$formBuilder = $this->createFormBuilder(new GoogleApi\Contrib\Event);
then
foreach(get_object_vars($event) as $prop) { $formBuilder->add($prop); }
but this does not utilize the seemingly ready-made bridge between the API documentation and the built-in validation tools, and it also means each individual data type is going to have to be declared individual or array to decide whether to include a collection of class-based forms or a single, class-based form.
In short, I want to use the properties and dataType information available in the API, and, if necessary, the Resource representations like this one to create a simple function (like my call function) for creating nested, self-validating forms for the classes in the Google API. I want to accomplish this without creating a bunch of "Entities" and "FormTypes" that simply rewrite what is already written in the library.
Did the vendor library not have any installation details? You should generally calls vendor things from the controller using service calls like $this->get('vendor.name.form_object') rather than calling the class at the service will include any needed dependencies.
Also the entity that you would create in your bundle would only be the basic entity that would then extend their premade abstract classes. For example (taken from https://github.com/FriendsOfSymfony/FOSUserBundle)
<?php
// src/Acme/UserBundle/Entity/User.php
namespace Acme\UserBundle\Entity;
use FOS\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
// your own logic
}
}
If you want to add any of your own entity items then you can do it in this, but still keep the methods and properties from the base entity/model.
I'm trying to practice a good design and extending Doctrine entity.
My extended class, the model basically, will have extra business logic + access to the entity basic data.
I am using Doctrine 2.2.1 & Zend Framework 1.11.4 & php 5.3.8
When I use DQL, doctrine return successfully the Model entity.
When I use Doctrine native find() function, it returns nothing :(.
HELP...
This is how it rolls:
Bootstrap.php:
$classLoader = new \Doctrine\Common\ClassLoader('Entities', APPLICATION_PATH.'/doctrine');
$classLoader->register();
$classLoader = new \Doctrine\Common\ClassLoader('Models', APPLICATION_PATH);
$classLoader->register();
Model in APPLICATION_PATH\models\User.php:
namespace Models;
use Doctrine\ORM\Query;
/**
* Models\User
*
* #Table(name="user")
* #Entity
*/
class User extends \Entities\User {
public function __wakeup() {
$this->tools = new Application_App_Tools();
}
Entity retrieval functions:
DOESN'T WORK:
$userEntity = $registry->entityManager->find('Models\User', $userEntity);
WORKS:
$qry = $qb
->select('u')
->from('Models\User','u');
You shouldn't add the business logic to the entities, you should use models for that instead. One way of doing it would be:
Use models for business logic.
Create custom Doctrine 2 repositories for your all your database queries (DQL or otherwise) [1].
Leave your entities alone.
In practise this means that models are plain PHP classes (or maybe framework extended depending on what your're using) but your models have no relation to your database. Your models do however, instantiate your custom Doctrine 2 repositories. E.g. a UserRepository might contain a method called getUserById. Within your repositories is where your run your actual queries and return entity instances for the models to work with.
[1] http://docs.doctrine-project.org/en/latest/reference/working-with-objects.html#custom-repositories
As I understand Doctrine, entityManager is responsible only for persistent entities, and extending Entities\User entity with Model\User will create another entity (stored in same table as stated in docblock), but not managed by entityManager or in collision with it because you probably didn't mention #InheritanceType("SINGLE_TABLE") in Entities\User docblocks:
Read this docs for more info http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html
What I tried to do was a bad practice.
I coupled my DB entity and tools from zend as #Ivan HuĆĄnjak mentioned.
What should be done is de-coupling.
Business logic should be in services\controller and these should address the entity and it's methods.
you can\should add helper functions to the doctrine entity that only relates to the entity properties.
Regarding my main purpose (to have an entity class that the Doctrine CLI can rewrite & update):
doctrine only searches from changes in the native fields\methods, updates them accordingly and discard all other functions (helpers). so there is no problem when letting doctrine update the php entity!
p.s.
move to symfony2.
doeas anybody use the Query\Builder from Doctrine as Standalone Tool ?
It seems like The Query Manager needs a defined
Class of the requested Document in MongoDB.
If you have a defined Class like:
<?php
namespace Documents;
/** #Document */
class User
{
// ...
/** #Field(type="string") */
private $username;
}
Then you can do the following:
<?php
$user = $dm->createQueryBuilder('User')
->field('username')->equals('jwage')
->getQuery()
->getSingleResult();
Is there a way to do use the Query\Builder without defining the Document Classes ?
Thanks in advance for any help.
You can use the QueryBuilder as soon as you have ClassMetaData.
This class metadata is about mapping class properties to internal information, such as data types, associations, ...
You can define this class metadata without having real classes.
There are different approaches, but one of them would be to use the Doctrine\ODM\MongoDB\Tools\DisconnectedClassMetadataFactory class, and feed related information using yaml or xml mapping.
You will have to configure your DocumentManager with the good classMetadataFactoryName option.
I'm pretty new to Doctrine 2 and am using annotations to do my database mapping. I want to take things a little bit further and use some custom annotations. The aim is to be able to make forms and such that can have settings created through annotations. I'm having trouble reading ANY annotations - even class ones such as #Table aren't being returned from the parser.
I am using Codeigniter 2 and Modular Extensions. In my controller I have:
$reader = new \Doctrine\Common\Annotations\AnnotationReader();
$reader->setDefaultAnnotationNamespace('MyCompany\Annotations');
$reflClass = new ReflectionClass('models\User');
$classAnnotations = $reader->getClassAnnotations($reflClass);
print_r($classAnnotations);
Which returns an empty array.
I then have a file in my libraries/annotations folder, Bar.php:
namespace MyCompany\Annotations;
class Bar extends \Doctrine\Common\Annotations\Annotation
{
public $foo;
}
and lastly, my user model:
/**
* #Entity
* #Table(name="user")
* #MyCompany\Annotations\Bar(foo="bar")
* #MyCompany\Annotations\Foo(bar="foo")
*/
class User {
}
I am trying to follow this example:
http://www.doctrine-project.org/projects/common/2.0/docs/reference/annotations/en#setup-and-configuration
Thanks for your help in advance!
Mark.
use
Doctrine\Common\Annotations\AnnotationRegistry
AnnotationRegistry::RegisterLoader($universalClassLoader);
AnnotationRegistry::RegisterFile(__DIR__ . ' PATH_TO_DoctrineAnnotations.php ');
As you've figured out, you need to include your custom annotation files/classes before you can use them.
Though including them in your controller would work, why not do it the Doctrine way!
Doctrine2's ORM has a file called DoctrineAnnotations.php in the Doctrine/ORM/Mapping/Driver/ folder. It looks like this:
...
require_once __DIR__.'/../GeneratedValue.php';
require_once __DIR__.'/../Version.php';
require_once __DIR__.'/../JoinColumn.php';
require_once __DIR__.'/../JoinColumns.php';
require_once __DIR__.'/../Column.php';
...
So, what I've done is created a similar file in my library and load my annotations by including this "driver" (eg. in your bootstrap).
In my ZF-based app (using Guilherme Blanco's fabulous Zf1-D2 set-up), I just added my "annotations driver" to my application.ini, like this (all on one line):
resources.doctrine.orm.entityManagers.default
.metadataDrivers.annotationRegistry.annotationFiles[]
= APPLICATION_PATH "/path/to/my/library/ORM/Mapping/Driver/MyAnnotations.php"