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!
Related
So my question is very specific but I couldn't figure out how to make it even after several months of reflection. The following topic will be about Symfony, Doctrine and generating fixtures on-the-go for the tests.
I want to generate fixtures on the go from a test. The goal is to provide a very specific set of fixtures for each tests using helpers without sacrify the readability. That is the goal, so my idea was to create a tests/Resources/EntityProxy which is a mirror of the src/Entity folder, containing the same amount of classes with the exact same name. Each EntityProxy extends from its related Entity, use a custom trait to fill the properties easily.
You guessed it, I want to only use in tests the EntityProxy and use it directly into the functions to tests them. And there is a major issue with that, as Doctrine doesn't recognize the EntityProxy as an entity even if it extends from a real Entity.
Is there a way to say to Doctrine to persist an EntityProxy as its extended Entity?
__
The following code is an example of what I want as en EntityProxy:
namespace Tests\Resources\EntityProxy;
class User extends App\Entity\User
{
use FixtureGenerationTrait;
public function static makeDefault(): self
{
return static::generate([
'username' => self::getFaker()->username,
'email' => self::getFaker()->email,
...
]);
}
public function static make(array $data = []): self
{
$entity = static::makeDefault();
$entity = static::setValues($entity, $data);
return $entity;
}
}
And can be used in the tests like following: User::make(['name' => 'John Wick']);
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.
I am using Symfony version 2.7.6. I have created an entity named EmployeeBasicInfo having fields
firstname
lastname
identificationCode etc
I have created a callback function for validating Identification code in EmployeeBasicInfo entity itself which looks like
/**
* #Assert\Callback(groups={"edit_myinfo"})
*/
public function validateIdentificationCode(ExecutionContextInterface $context)
{
if ($this->getEmployeeFirstName() == 'fakename') {
$context->buildViolation('This name sounds totally fake!')
->atPath('employeeFirstName')
->addViolation();
}
}
and this callback function works properly
Actually I want such a callback functionality which checks identidfication code against database. I have added $em = $this->getDoctrine()->getManager(); inside the callback function and the error is like Attempted to call an undefined method named "getDoctrine" of class "XXX\EmployeeBundle\Entity\EmployeeBasicInfo".. Please advise me the effective way
Do not inject the EntityManager in your Entity. One basic concept of the DataMapper-Pattern is, that your entity does not have to know about your data source and its connectors.
I'd suggest to write a custom validation constraint, in which you inject the dependencies you need.
EntityManager, Repository to query, etc. Whatever service suits you.
Have a look at how to create custom constraint validators with dependencies
I would suggest you use a service to do this
class EmployeeUtility($connection)
{
public function __construct($conn) { $this->connection = $v; }
public function validateIdentificationCode($emloyeeId, $validationCode)
{
// Your code here
}
}
In your controller, you inject the service:
$employeeUtility = $this->get('employee.utility');
$employeeUtility->validateIdentificationCode(1,'GF38883dkDdW3373d');
Alternatively, add the code in a repository class.
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();
}
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'