Hi,
I have an entity A :
id
att1
att2
Now, I'd like to add a new Bundle (which will add new functionality) and here especially I'd like to add an attribute to A. A must be like :
id
att1
att2
newAtt3
newAtt4
In order to do that, I was thinking to create a new entity which will extend A and add the new attribute.
But then, what I don't know is how can I prepare the first bundle to use the 2nd entity (and controller/view) if the 2nd bundle is installed?
I guess I need to add configuration in the first bundle, but I have no idea what to add...
Thanks !
Please read Best Practices for Reusable Bundles
and Doctrine Inheritance Mapping
You can also think about Traits but often the best way is to use Interfaces. With the help of interfaces you can make your bundle highly configurable on a clean way like this:
make a configuration variabele that tells the bundle what class should be used. This can be the default class A from the Bundle but may also be class A from your AppBundle.
$rootNode
->children()
->scalarNode('a_entity')
->defaultValue('AppBundle\\Entity\\A')
->end()
->end()
;
Then make a interface for class A with all the functions that are mandatory:
interface AInterface
{
public function setVariable($name, $var);
public function getHtml($template);
}
and implement the interface in the class:
class A implements AInterface
{
// ...
}
Every time if you pass the class as a paramter use AInterface instead of A:
class B
{
private $a;
public function __construct(AInterface $a)
{
$this->a = $a;
}
}
Right now you can change the configuration variabele a_entity to another class. This other class still needs to implement the interface AInterface.
Related
I pass all the day reading, testing, re-reading and re-testing, I can't find a proper solution to my problem.
Let say you have a file entity, which switch type, go to a different block. (I mean, in the database i only have 1 file table, but in the display, i have a block "images", another "documents" and another "map"). All 3 are files with a different value for the field "type".
I know that the simplest should be to have 3 tables but i don't want to ruin my architecture because of using sonata.
I totally figure out how to do it in practice with preupdate and prepersist events and the initialisation phase. But even when i try to give the option "admin_code" to my unmapped property $images. It's always saying that it need an admin class. As the admin class is mapped by the annotation #ORM\OneToMany, i can't use it otherwise doctrine generates me another table.
Is there any way to achieve this ?
Is the admin_code option bugged ?
Or should i pass by a front-end solution? (i totally prefer back-end, but i will do with what is possible)
Did you try to use Doctrine inheritance
I think you'll be able to create an abstract File class and 3 other classes that extend File :
/**
* #ORM\Entity
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="type", type="string")
* #ORM\DiscriminatorMap({"image" = "Image", "document" = "Document", "map" = "Map"})
*/
abstract class File {
...
}
Then you'll have to create the 3 classes:
class Image extends File {
...
}
class Document extends File {
...
}
class Map extends File {
...
}
After, you'll be able to create 3 differents admin class to display in Sonata.
I'm developping a symfony2 application with the DatatableBundle (https://github.com/AliHichem/AliDatatableBundle)
I need to override the DoctrineBuilder class in the Util Directory
I've created a DtatableBundle in my src directory with all the structure of the Alidatatable Bundle
I've write a getParentMethod in the newBundle, and create my new DoctrineBuilde class
Symfony always use the vendor class and not the new one
Here,s the Bundle Structure and then class i want to override :
DatatableBundle
Util
Factory
Query
DoctrineBuilder.php
and the bundle's service definition:
parameters:
datatable.class: Ali\DatatableBundle\Util\Datatable
services:
datatable:
class: "%datatable.class%"
arguments: [ #service_container ]
scope: prototype
datatable.twig.extension:
class: Ali\DatatableBundle\Twig\Extension\AliDatatableExtension
arguments: [ #service_container ]
tags:
- { name: twig.extension }
Any Ideas ?
Thansk a lot!
In normal (extendable) bundles you always have ability to override every part of it just by replacing one parameter with your value (default class name to your class name). But the bundle that you want to extend is not intended to be extended. So to extend it properly and override some parts you will need to do many manipulations.
In your particular case to use your own query builder you need to override __construct() of Datatable.php in your class and replace in it:
//from
$this->_queryBuilder = new DoctrineBuilder($container);
//to
$this->_queryBuilder = new YourDoctrineBuilder($container);
Also to make application to use your Datatable class you need to replace default class to yours in your parameters.yml:
datatable.class: Your\Path\To\Datatable
It is not necessary to implement the same directory structure in your bundle to override some parts of bundle. It has no effect! The only thing that you need is to define your own classes and set up bundle to use yours instead of original.
getParent() for bundle only works for cases when you need to override some Resources. They need to have the same structure as in original bundle. But your case is not about Resources.
For this you cannot directly override the builder class.
You could, however, override the Datatable class and call your own version of the builder in the __construct like so..
namespace Acme\DatatableBundle\Util;
use Ali\DatatableBundle\Util\Datatable as BaseDatatable;
use Acme\DatatableBundle\Util\Factory\Query\DoctrineBuilder;
class Datatable extends BaseDatatable
{
/**
* class constructor
*
* #param ContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
parent::__construct($container);
// This would change the default for your version of the builder
$this->_queryBuilder = new DoctrineBuilder($container);
}
}
And then just set your version of the datatable class as the %datatable.class% parameter like..
datatable.class: Acme\DatatableBundle\Util\Datatable
I have a one-to-many relationship Cart-SendingMethod. I would like to set a default SendingMethod for new Carts. So I have tried this:
<?php
/**
* #ORM\ManyToOne(targetEntity="MetodoEnvio", inversedBy="metodoEnvios")
* #ORM\JoinColumn(name="metodo_envio_id", referencedColumnName="id")
**/
private $metodoEnvio = 1;
but doesn't work... I get:
Impossible to access an attribute ("id") on a integer variable ("1") when I call Cart.SendingMethod.id from a view file
So how to set a default SendingMethod for new Products?
I could do it in the controller, but I would like to know if it is possible from the entity Product.
Note: I didn't know exactly if this is a symfony or doctrine question.
You don't want to introduce dependencies into your entity.
The obvious and cleaner way to do it would be to create a CartFactory service, and inject that into any controller (or other class) that needs to create carts. Inject your EntityManager and other dependencies into the factory. That way you DRY up your cart-initialization code, and avoid bulking up your controller.
Just set the property's default value inside the constructor like this:
public function __construct(..)
{
$this->property = new OtherObject();
}
I'm using Doctrine 2 in a Symfony 2 environment.
I've created a custom data type which extends \Doctrine\DBAL\Types\Type. This data type should map an integer value stored in database to a specific string (like ENUM, but integer and string must be accessible).
At the moment the mapping of these values is hardcoded within the doctrine type using a class variable which holds and array.
class xyType extends \Doctrine\DBAL\Types\Type {
public static $messageTypes = array(
10 => "Wareneingang",
20 => "Polstern",
.
.
.
}
.
.
}
Now I want to put this array into the config.yml of this bundle. But I don't know how to use Dependency Injection in this type class, to be able to access my config parameters in any way...
I hope you can help me. I'm also open for other ideas to implement this.
Thx in advance
Yes, you cannot access DI in your type class, but there is bundle initialization stage where you can save your types from config to your static property. So i suggest using YourBundleExtension to solve this.
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!