KnpMenuBundle, extend Builder by ContainerAware and Controller - symfony

I m using KNPMenuBuilder to create a menu. I would like to add query in my Builder.php but I need to extend Builder class by Controller. By default it`s extends by "ContainerAware".
I would like to ask how to extends Builder class by two elements- "ContainerAware" and "Controller"?
Or how can I create a DQL query without extending of Controller?

The Controller class is just a "tool" to easily use controllers (some people even say it's a bad thing to use, as it's somewhat advocating a service locator pattern).
You shouldn't extend Controller in any class other than a controller.
To get access to doctrine (like the Controller#getDoctrine() method), you should request for the doctrine service. Then you just have the same as you have when using the getDoctrine() method.
Since the builder extends ContainerAware, you have access to a $container property and you can get() the doctrine service from it:
$doctrine = $this->container->get('doctrine');
$em = $doctrine->getManager();
$query = $em->createQuery(...);

Related

Symfony - Get Entity from within another entity

I would like to retrieve a record from another entity (or record from the DB) within a entity.
They there are no relationship between the two entities.
I am using #ORM\HasLifecycleCallbacks() and #ORM\PrePersist so when the main entity is created it will also create another entity (save a record to another table)
The above is working fine, there are no issues with this.
What I am having an issue with is I would like to link that entity with another table but I need to retrieve the object based on the value of the first entity.
Usually I would write a function in the entity repository but I am not calling the entity manager within the entity.
An Entity in Doctrine is an object representation of a concept, with attributes and methods. It is meant to be lightweight, a POPO (plain old php object). It must not know anything about its persistence. Therefore if you see reference to the EntityManager in a model, it probably stinks.
Solutions? You could use an entity listener called on entity creation and then use a service dedicated only to properly compose your object(s), maybe something like a Factory. In this way, your entity stays lightweight, the lifecycle management is satisfied and the entity composing is responsibility only of your service.
Entity manager is accessible in an entity repository. You can legally use it to fetch data from other entities and to compose your business logic. This is what entity repositories are made for: Doctrine Custom Repositories, Symfony Custom Repository Classes.
/**
* #ORM\Entity
*/
class Beta {}
/**
* #ORM\Entity
*/
class Alpha {}
class AlphaRepository extends EntityRepository
{
public function getDataFromAnotherEntity($something)
{
$query = 'select * from MyBundle\Entity\Alpha alpha where alpha.id = :something';
return $this->getEntityManager()
->createQuery($query)
->setParameter('something', $something)
->getResult();
}
}
In Symfony 3.1 you can use the entityManager to set a reference. This is still lightweight as it does not instance a complete Doctrine Record.
Example: I have an entity Status which has some states, and it's referenced in another entity. On create i use this method inside EventSubscriber:
public function preAction(LifecycleEventArgs $args)
{
$entity = $args->getObject();
$entityManager = $args->getObjectManager();
if (method_exists($entity, 'setStatus')) {
if ($entity->getStatus() === null) {
$entity->setStatus($entityManager->getReference('AppBundle\Entity\Status', Status::STATUS_REGULAR));
}
}
}

Symfony $this->>createFormBuilder throws notice from controller

I am doing a small project in Symfony to gain some experience with this framework. At the moment I am just following tutorials while making my own tool which is a GUI to make my resume.
In my controller I am calling $this->createFormBuilder($cvBase) which is throwing an "Undefined property" notice which I think is strange because I am calling a method.
Does anyone know what is causing this?
<?php
// My php code
namespace NuiCart\CvToolBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use NuiCart\CvToolBundle\Entity\CvBase;
use Symfony\Component\HttpFoundation\Request;
class DefaultController extends Controller{
public function formAction(Request $request){
$cvBase = new CvBase();
$form = new $this->createFormBuilder($cvBase);
The notice:
Notice: Undefined property:
NuiCart\CvToolBundle\Controller\DefaultController::$createFormBuilder
in
/var/www/devel/cv/public_html/src/NuiCart/CvToolBundle/Controller/DefaultController.php
line 19 500 Internal Server Error - ContextErrorException
createFormBuilder() already returns a newly created FormBuilder object and you therefore don't need to create a new Object. By attempting to use new, it is trying to create a new DefaultController and access a function that is private to the internals of the Controller (or something like that - don't sue me for correctness on this one as it is just an attempt to explain why using new $this is wrong.)
Your solution is to remove the new in $this->createFormBuilder():
$form = $this->createFormBuilder($cvBase);

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

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.

How do I access a repository from the bundle class in symfony2?

So, I'm using the bundle class to do most of my work as I dont need controllers (src\CSFs\QuicklinksBundle\CSFsQuicklinksBundle.php).
From the FrontController of another bundle, I get the quicklinks bundle, inject the container object into the bundle class (above) and then, within the bundle class, extract templating to return HTML, this works fine. However, I'm having trouble with repositories.
/**
* Get the container object, so we can use all the symfony2 fun stuffs
*/
public function injectContainer($cont)
{
// Template
$this->tpl = $cont->get('templating');
// EM
$this->em = $cont->get('doctrine')->getEntityManager();
}
/**
*
**/
public function doStuff()
{
$products = $this->em->getRepository('QuicklinksBundle:Quicklinks')
->getUsersWithQuicklinks();
}
The error I get is:
Unknown Entity namespace alias 'QuicklinksBundle'.
I have both the generated entity file and a repository class with the getUsersWithQuicklinks() method defined.
How do I get the entity manager to know about my repositories?
Thanks,
Mike
Change:
$this->em->getRepository('QuicklinksBundle:Quicklinks')
To:
$this->em->getRepository('CSFsQuicklinksBundle:Quicklinks')
And I'm assuming you have an Entity named 'Quicklinks'

Symfony2 custom annotations for objects

Does anyone know if it's possible to have a bundle use the annotation reader to read new custom annotations for non Doctrine objects? Everything I've seen so far is either for a controller or to extend Doctrine in some way.
What I'd like to be able to do is something like this:
class MyTestClass {
/**
* #MyBundleName\Foo
*/
public $foo_var;
/**
* #MyBundleName\Bar
*/
public $bar_var;
}
And then have some code that when given an instance of MyTestClass could work out which annotation applied to which attribute.
Right, bit more digging into how Doctrine does this and I think I know how to do it. So if anyone else needs to do this here's how I'm doing it (would be appreciative of any feedback)
I have a service that I'm using to read the annotations so in config.yml I've included the annotation_reader service which provides access to the methods to read your annotations.
Each annotation needs to resolve to a class and the class must extend the base Doctrine annotation class, so to do the Foo annotation from my question you'd do something like:
namespace MyBundleName
class Foo extends \Doctrine\Common\Annotations\Annotation {
}
Then you can read the annotations by doing:
$class = get_class($object);
foreach(object_get_vars($object) as $fieldname => $val){
//$this->annotationReader is an instance of the annotation_reader service
$annotations = $this->annotationReader
->getPropertyAnnotations(
new \ReflectionProperty($class, $fieldName)
);
//$annotations will now contain an array of matched annotations, most likely just an instance of the annotation class created earlier
}
Hope that can be of use to someone else!

Resources