I want use request parameter in my annotation in Symfony2
I want set $id (it is parameter from request) to MyAnnotation, as it described below
/**
* #MyAnnotation($id)
* #Route('something/{id}')
*
*/
When I set $id in this way, I have an error. How to pass this parameter to annotation?
Other way is:
/**
* #MyAnnotation("id")
* #Route('something/{id}')
*
*/
And I can get value of "id" parameter in annotation class, in constructor:
public function __construct($options)
{
// get key
$key = $options['value'];
// get value of key
$id = $request->get($key);
}
But I dont know its possible to set $id in annotation and dont write code in constructor.
Related
I'm trying to create a relation ManyToMany with doctrine (in symfony) that is depending on a field value.
/**
* #ORM\ManyToMany(targetEntity="Label")
* #ORM\JoinTable(
* name="Item_Label",
* joinColumns={#ORM\JoinColumn(name="item_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="label_id", referencedColumnName="id")}
* )
*/
private $labels;
Here we understand that we have to get data from Label via the table Item_label
We are on table Wine
Wine.id <-> Item_Label.item_id
<<< `WHERE Item_Label.item_type = 'wine'` >>>
`Item_Label.label_id` <-> `Label.id`
So, how can i write the WHERE Item_Label.item_type = 'wine' in annotations ?
Or a SqlFilter (I tried but failed) ?
Thanks for your help =)
So, it seems from this SO answer that it's not possible in doctrine.
My workaround was to add a method to my entity class as follows
public function foo($itemLabelRepo)
{
$found = $itemLabelRepo->findBy(['item_type'=>'wine', 'label_id'=>$this->getId()]);
if(count($found)!=1) {
throw new \Exception("Found non-one object from entity role");
}
return $found[0];
}
where $itemLabelRepo would be the repository to "Item_Label" in your case
I am trying to create an action in my controller that handles a null value for category if it's not passed in.
I've tried annotating 2 routes (one without /{category}) but in every case, when I do not supply a category in the URL, Symfony retrieves the 1st category it can find.
#Route("/accounts/{id}/categories/{category}", defaults={"category" = null})
The action definition looks like this:
public function categoryAction(Request $request, Account $account, Category $category)
I have also tried $category = null in the action, but that does not make a difference.
How can I make this action have a $category with a value of null if the category is not defined in the url?
Update:
To be clear, here is the full annotation and function definition with comments on my xdebug results:
/**
* #Route("/accounts/{id}/categories")
* #Route("/accounts/{id}/categories/{category}, defaults={"category" = null}")
*/
public function categoryAction(Request $request, Account $account, Category $category = null)
{
// When I set a breakpoint here, $category is populated with
// the first category result in the database.
// This is when visiting: http://localhost:8000/accounts/1/categories
You can define multiple routes for same actions, maybe try something like :
/**
* #Route("/accounts/{id}/categories")
* #Route("/accounts/{id}/categories/{category}")
* #Template()
*/
public function categoryAction(Request $request, Account $account, Category $category)
{
And if you try to access /accounts/{id}/categories, $category will be null
I believe this is the change you should make:
/**
* #Route("/accounts/{id}/categories", defaults={"category" = null}")
* #Route("/accounts/{id}/categories/{category})
*/
public function categoryAction(Request $request, Account $account, Category $category)
{
...
Can you try it and let us know? I haven't tested it, but I think it's right.
I have Cases, which also have Attachments. This is coded as a Case entity with the OneToMany association to Attachment entity. The Attachment entity has a ManyToOne association to Case entity. The code:
class Case {
/**
* #var integer
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="Attachment", mappedBy="case",cascade={"persist"})
*/
protected $attachments;
class Attachment
{
/**
* #var integer
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Case", inversedBy="attachments")
* #ORM\JoinColumn(name="case_id", referencedColumnName="id")
*/
protected $case;
}
Im trying the following. I pretend to show/open the whole case into a single page. Inside the page, there will be the attachment list. At the end of that list, I pretend to put a form for new attachment submissions.
So I have written a controller to show the case, and I have created a new attachment form (AttachmentType ) and place it in the middle of the twig template, passing it into the render call of the action as a argument.
// CaseController.php
/**
* #Route("/cases/show/{case}", name="showCase", requirements={ "case" : "\d+" } )
*/
public function showCaseAction(Request $request, $case)
{
$theCase = $this->getDoctrine()->getRepository('AppBundle:Case')->findOneById( $case );
$attachment = new Attachment();
$attachment->setCase( $theCase );
$attachmentForm = $this->createForm(AttachmentType::class, $attachment);
if ( ! $theCase ) {
$this->addFlash('danger', $this->get('translator')->trans('cases.show.case_not_found', [ '%case%' => $case ] ) );
}
return $this->render('cases/caseContainer.html.twig', array( 'case' => $theCase, 'attachmentform' => $attachmentForm->createView() ) );
}
And also I have written a newAttachmentAction into the controller to perform the attachment creation.
I stop writting my code here. I dont want to condition the possible answers.
My problem is that im not able to figure out how to recover the Case object when the newAttachmentAction is called, so I can do the association. I cant figure out if i should place something ( HiddenType,EntityType,etc ) into the Attachment Form Builder to store the Case object, or maybe would be better to use some other Symfony mechanism (Services, Closure, StorageTokens). I have made a wide search along the web, but i have read some many articles, that Im stucked ! Im probably missing the right search keywords.
I hope i have made my self clear, and therefore someone can point me into the right direction to find an example or a tutorial.
Best regards and many many thanks for your time and attention !
For creating a Case, i will add a HiddenType for attachment property inside the CaseformType.
Set data_class to Attachment
When you will create the form, you will pass a new instance of Case with the attachment reference.
After the post, when you will receive the form data, you will have the linked object
I have just installed the doctrine extensions to use Sluggable.
I make this :
composer.json
"stof/doctrine-extensions-bundle": "1.2.*#dev"
AppKernel.php
new Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(),
app/config/config.yml
stof_doctrine_extensions:
orm:
default:
sluggable: true
Djoo\AppliBundle\Entity\Nomenclature.php
namespace Djoo\AppliBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\DBAL\Types\SmallIntType;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* Nomenclature
*
*
* #ORM\Table(name="app_nomenclature")
* #ORM\Entity
*/
class Nomenclature
{
.....
/**
* #var string
*
* #ORM\Column(name="titre", type="string", length=200, nullable=false)
*/
private $titre;
/**
* #var string
*
* #ORM\Column(name="finess", type="string", length=10, nullable=true)
*/
private $finess;
/**
* #Gedmo\Slug(fields={"titre","finess"},suffix=".html")
* #ORM\Column(length=128, unique=true,nullable=true)
*/
private $slug;
public function getSlug() {
return $this->slug;
}
public function setSlug($slug){
$this->slug = $slug;
return $this;
}
}
In my controller i make this to generate slug for old values in my datatable :
$filterBuilder = $this->get('doctrine.orm.entity_manager')>getRepository('DjooAppliBundle:Nomenclature')->createQueryBuilder('e')->orderBy('e.titre', 'asc');
$query = $filterBuilder->getQuery();
$nomenclatures = $query->getResult();
foreach($nomenclatures as $nomenclaturee){
$nomenclature->setSlug(null);
$this->get('doctrine.orm.entity_manager')->persist($nomenclature);
$this->get('doctrine.orm.entity_manager')->flush();
}
I have no error, but my old values are a null slug. I try to create a new element and i have a good slug. Have you and idea ?
Thanks
To change the slug you must change the related property. You can add a space at the end of $titre, save it, change it back and save it again. That will flush the slugs.
$uow = $em->getUnitOfWork();
$uow->propertyChanged($entity, 'slug', NULL, NULL);
$uow->scheduleForUpdate($entity);
$em->flush();
Why it didn't work for OP, but worked for others (eg. #gregor):
When creating slug, your first instinct is to create slug property with this column configuration:
..
#ORM\Column(unique=true, nullable=false)
private $slug;
..
When running app/console doctrine:schema:update and this will result in 2 sql statements:
ALTER TABLE ... ADD slug ... NOT NULL
CREATE UNIQUE INDEX...`.
By default column slug will be filled with value '' (empty string) which would make 2nd statement to fail with (Duplicate entry '') error. Now you have two choices:
Choice A: Ignore failure of the 2nd statement
If you ignore the error, and later try generating slugs manually using the documented method $entity->setSlug(null) everything would work. It would work because by using $entity->setSlug(null) you would let Doctrine know that propertyslug was changed (from '' to null) and this in turn would trigger internally $uow->propertyChanged() and $uow->scheduleForUpdate() (Thanks to #Sebastian Radu for his example). The Sluggable extension will notice this change as well and will regenerate the slug. Now as all the slugs are unique, next time you run app/console doc:schema:update it will succeed in creating index on slug and your schema will be fully in sync.
Choice B: Modify slug field to be nullable
After noticing error your instinct would be to mark slug field as nullable, so that index creation succeeds:
..
#ORM\Column(unique=true, nullable=true)
private $slug;
..
This would result in slug column having NULL as it's default value. Now as you try using documented $entity->setSlug(null) approach it won't work (just as OP has posted). This happens because when $entity->slug property is already NULL. Thus when you use $entity->setSlug(null) no changes are detected by Doctrine, and thus Sluggable regeneration behaviour is never triggered. In order to trigger the changes there were two answers:
hack with adding space to the slug source properties $entity -> setTitre($titre." "); (but this would result in extra space you would have to trim after)
approach by #Sebastian Radu, where he shows how to tell Doctrine directly that the field was changed (I personally prefer this one and wonder why it was unfairly downvoted)
Hope this helps you understand a bit better the inner workings of Doctrine and extensions.
The sluggable documentation states the following:
In case if you want the slug to regenerate itself based on sluggable
fields, set the slug to null.
<?php
$entity = $em->find('Entity\Something', $id);
$entity->setSlug(null);
$em->persist($entity);
$em->flush();
It does work for me.
I have a column in MySQL table defined as follows:
`fuel_type` set('gasoline','diesel','LPG','CNG','ethanol','bio-diesel','hydrogen') DEFAULT NULL,
I generated entities usingn doctrine's database introspection feature. The generated code in the entity in question is this:
/**
* #var simplearray
*
* #ORM\Column(name="fuel_type", type="simplearray", nullable=true)
*/
private $fuelType;
/**
* Set fuelType
*
* #param \simplearray $fuelType
* #return NomEngine
*/
public function setFuelType(\simplearray $fuelType)
{
$this->fuelType = $fuelType;
return $this;
}
/**
* Get fuelType
*
* #return \simplearray
*/
public function getFuelType()
{
return $this->fuelType;
}
In my sonata admin class the configureFormsFields method is thefined this way:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('name')
->add('fuel_type', 'choice', array(
'choices' => array(
'gasoline' => 'Gasoline',
'diesel' => 'Diesel',
'LPG' => 'LPG',
'CNG' => 'CNG',
'ethanol' => 'Ethanol',
'bio-diesel' => 'Bio Diesel',
'hydrogen' => 'Hydrogen'
),
'multiple' => true,
'required' => false
));
;
}
The problem is that after I try to save record in the database I get this exception:
Unknown column type "simplearray" requested. Any Doctrine type that you use has to be registered with \Doctrine\DBAL\Types\Type::addType(). You can get a list of all the known types with \Doctrine\DBAL\Types\Type::getTypesMap(). If this error occurs during database introspection then you might have forgot to register all database types for a Doctrine Type. Use AbstractPlatform#registerDoctrineTypeMapping() or have your custom types implement Type#getMappedDatabaseTypes(). If the type name is empty you might have a problem with the cache or forgot some mapping information.
500 Internal Server Error - DBALException
I tried a couple of things to resolve this issue:
I noticed, that the generated type is 'simplearray', but in doctrine this type is 'simple_array'. I thought there was a typo.
Without success I tried to map simplearray to simple_array in config.yml :
doctrine:
dbal:
mapping_types:
simplearray: simple_array
After that I tried to change simplearray to simple_array in the entity. I got this error:
Catchable Fatal Error: Argument 1 passed to Acme\AdminBundle\Entity\Engine::setFuelType() must be an instance of simple_array, array given,
I thought that the admin class was passing array, and the entity was expecting simple_array, so I changed simple_array to array in the entity.
Now the error was this:
Could not convert database value "" to Doctrine Type array 500 Internal Server Error - ConversionException
Any insights about dealing with set columns in Sonata Admin will be greatly appreciated!
Your entity setter & getter are wrong too and should deals with a PHP array as Doctrine is converting it, I think you must change them to:
/**
* Set fuelType
*
* #param array $fuelType
*
* #return NomEngine
*/
public function setFuelType(array $fuelType)
{
$this->fuelType = $fuelType;
return $this;
}
/**
* Get fuelType
*
* #return array
*/
public function getFuelType()
{
return $this->fuelType;
}
It seems that Doctrine doesn't handle well the set syntax in MySQL. I see 2 ways you could solve your issue:
Change your MySQL schema to put in a json array or a varchar instead of your set. Probably the fastest way.
You might not have the luxury to change your schema. In that case, define a custom Doctrine type to suit your needs as described there: http://docs.doctrine-project.org/en/2.0.x/cookbook/mysql-enums.html#solution-2-defining-a-type ; you'll need then to register it to Symfony as explained there: http://symfony.com/doc/current/cookbook/doctrine/dbal.html#registering-custom-mapping-types
Hope it helps!