How specify parameter's format in Nelmio ApiDocBundle - symfony

I use input property of #ApiDoc annotation for specifieng of parameters of my api that are form's fields.
* #ApiDoc(
* section="User",
* resource=true,
* input={
* "class"="Nik\UserBundle\Form\UserType",
* },
* ....
data_class of form is a entity that have constraint validation for properties.
I expect that nelmio api doc specify parameter format as validation constraints of entity, but format are empty.
How can i specify parameter formats in nelmio ApiDocBundle?
EDIT:
maybe i write a bad question.
we can specify parsers for input & output, if we no specify parser for these, it call all parser for input & output, then all parser are called for UserType.
nelmio have a parser named ValidationParser that have a method named parseConstraint that set format for input & output, but this method is not called for my document, why?

Format column is designed only for datetime, date and choice types.
For datetime and date it represents the date format like Y-m-d H:i:s and the array of choices for choice.
I haven't found any documentation about it, so I had to look through the source code. This is FormTypeParser class, the place where FormType is actually parsed and and you can see how format field is set.
In FormTypeParserTest class you can see how to use it. Just pass the string parameter with format name for one of the available types and the parser will handle it.
UPDATE: You are to define your constrains inside your FormType class.
For example:
class TestType extends AbstractType
{
/**
* #Assert\Type("string")
* #Assert\Length(min="10", max="255")
* #Assert\Regex("/^[^<>]+$/i")
*/
private $title;
/**
* #Assert\Type("string")
* #Assert\Length(min="10", max="255")
* #Assert\Regex("/^[^<>]+$/i")
*/
private $content;
/**
* #Assert\Date()
*/
private $created;
public function getName()
{
return 'test';
}
}
will be parsed into:
ValidationParser in
doParse() method finds all constrains defined in your FormType class and then executes parseConstraint() method for each of them.
You can also use FormTypeParser as I described above. For example:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('created', 'date', array('label' => 'Created', 'format' => 'yyyy-MM-dd'))
->add('color', 'choice', array('label' => 'Color', 'choices' => array('grey' => '#CCCCCC', 'red' => '#FF0000')))
->add('save', 'submit');
}
will be parsed as:
Hope it helps now!

i submit a pull request that use validation metadata for format property.
you can see this PR here

As you can see here you can specify filter in annotation like it done documentation example.
Here part of this example:
/**
* This is the documentation description of your method, it will appear
* on a specific pane. It will read all the text until the first
* annotation.
*
* #ApiDoc(
* resource=true,
* description="This is a description of your API method",
* filters={
* {"name"="a-filter", "dataType"="integer"},
* {"name"="another-filter", "dataType"="string", "pattern"="(foo|bar) ASC|DESC"}
* }
* )
*/
public function getAction()
{
}

Related

Symfony Form - sorting data by changing sort option in dropdown list

I'm sorry for the title but I don't know how to define it good. I'd like my app to sort data (in Doctrine) depending on the sort option which user select it in form dropdown list.
The data I mentioned above are stored inside my Doctrine Entity which I called it Flashcards and the Flashcards Entity contains properties which them must be sorted by option that user select in dropdown. Flashcards Entity looks like the following (I gave only a few properties for simplicity):
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Words", inversedBy="flashcards")
* #ORM\JoinColumn(nullable=false)
*/
private $words;
/**
* #ORM\Column(type="datetimetz")
*/
private $creation_date;
Now the controller's code for form is usual, like the Symfony Doc say:
// code for form inside FlashcardController
$flashcard = new Flashcards();
$form = $this->createForm(FlashcardType::class, $flashcard);
And inside FlashcardController render() method I call createView() method on $form object.
The form code is placed inside FlashcardType class and contains code for mentioned above dropdown list and its options. It looks like this (for simplicity I gave only the methods):
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('sortBy', ChoiceType::class, [
'label' => 'Sort by',
'choices' => [
'Date increase' => 1,
'Date decrease' => 2,
'Word alphabetically' => 3,
'Word not alphabetically' => 4
]
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Flashcards::class
]);
}
So as you see the dropdown options include sorting by: date increase, date decrease, word alphabetically, word not alphabetically. User choose one of them in view. So manipulating data by user does NOT change value of this data represented by properties. Changing sort option in dropdown should change Doctrine query to sort by user-changed value. I have no idea how to achieve this in Symfony. Could you give me plese some tips how to make it?
Thank you in advance for answers!
If I understood correctly you have a few options:
First: wire javascript / jquery to select input and submit the form when user changes order(it should reload the form applying the filter, you can set any data user used in the 'previous' page using RequestStack to get the form fields from request / query depending on the method)
Second: get all the nodes you display record and try to manipulate the order based on the select value every time user changes the value
Tell me if this is what you meant else correct me and I'll try to provide the answer

Symfony parameters Routes (Easy to answer)

I try to pass my user id in parameter because I wanted to use it in an other function to link them but don't know why that don't work (I think that I do a mistake and will be easy to answer thx :)
return $this->redirect('/profile/new/', array(
'id' => $user->getId(),
));
My receiver :
/**
* Creates a new profile entity.
*
* #Route("/new/{id}", name="profile_new")
*/
public function newProfileAction(Request $request)
{
when I do /profile/new/8 for example it works! But when I click in the button submit that don't redirect with the id ... (of course the routes are good and when I do - it works :
return $this->redirect('/profile/new');
my receiver (when it works) :
/**
* Creates a new profile entity.
*
* #Route("/new", name="profile_new")
*/
public function newProfileAction(Request $request)
{
You should use $this->redirectToRoute('ROUTENAME',[PARAMETERS]) means:
$this->redirectToRoute('profile_new',['id'=>$ID])
If you use $this->redirect('URL') you have to parse the URL so you need to "/profile/new/ID"

Unable to deal with MySQL column of type "SET" in Sonata Admin

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!

Symfony2 form component - date widget not working with mongodb

Form field declaration:
$builder->add('birthday', 'date', array('label' => 'Data urodzenia:', 'years' => range(date('Y'), date('Y')-100)), 'required' => false);
Corresponding document field declaration:
/**
* #ODM\Field(type="date")
*/
protected $birthday;
/**
* Set bitrhday
*
* #param \DateTime $birthday
*/
public function setBirthday(\DateTime $birthday)
{
$this->birthday = $birthday;
}
/**
* Get bitrhday
*
* #return \DateTime $birthday
*/
public function getBirthday()
{
return $this->birthday;
}
When I set data in form value is saved to database correctly, but widget isn`t populated with data form database field when I visit form page after saving.
Other fields in form works as expected.
It`s sf2 bug or my mistake?
First, birthday seems to be misspelled. Setbitrhday & Getbitrhday
Second, ODM does not support the DateTime field type. ODM only supports the field type Date. See ODM Field Type Reference
ORM, on the otherhand does support the DateTime field type. See ORM Field Type Reference

Entity form field and validation in Symfony2?

In my form I have field of type entity. How to disable validation of that entity when the form is submitted? This entity is already persisted in database, so there is no point for validator to validate this entity from my point of view.
EDIT:
Code looks like this:
class SearchRequest
{
/**
* #ORM\ManyToOne(targetEntity="ArticlePattern")
* #ORM\JoinColumn(name="article_pattern_id", onDelete="CASCADE")
* #Assert\NotBlank
*/
private $articlePattern;
}
form field:
$builder
->add('articlePattern', 'entity', array('class' => 'LonbitItssBundle:ArticlePattern')
Validation groups won't work because what I want to accomplish is for validator to check the constraint #Assert\NotBlank on $articlePattern field, but I don't want him to check the constraints defined in class ArticlePattern. So in other words, I want prevent validator from descending inside the $articlePattern object, but I want the constraint placed on $articlePattern field itself to be validated.
Any idea how to do that?
EDIT2:
Validation groups will work. So the final solution is to add groups={"search_request"} constraint option (name of the group is arbitrary) to every field assertion in SearchRequest class, like this:
/**
* #Assert\NotBlank(groups={"search_request"})
*/
private $articlePattern;
That way, validation won't descend to associated objects (assuming they don't belong to - in this case - "search_request" group).
1) If you want to disable this field, just don't use it in your class form ! (and remove it from the template)
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('content')
->add('username')
//->add('yourEntity')
;
}
2) Or better, use validation groups. You create a validation_group which don't call your validator entity and then you use this group in your class form:
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'Sybio\BuzzBundle\Entity\SearchRequest',
'csrf_protection' => true,
'csrf_field_name' => '_token',
'intention' => '865c0c0b4ab0e063e5caa3387c1a8741',
'validation_groups' => array('without_article_pattern_ckecking'),
);
}
In your Entity class:
/**
* #ORM\ManyToOne(targetEntity="ArticlePattern")
* #ORM\JoinColumn(name="article_pattern_id", onDelete="CASCADE")
* #Assert\NotBlank(
* groups={"without_article_pattern_ckecking"}
* )
*/
private $articlePattern;
Your form will only validate validators that refer to without_article_pattern_ckecking group, so it should not test validators inside your ArticlePattern entity if they don't have this validation group.
I hope this helps you !

Resources