Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Added the constraint option on the ParamFetcher #700

Merged
merged 1 commit into from
Mar 10, 2014
Merged

[RFC] Added the constraint option on the ParamFetcher #700

merged 1 commit into from
Mar 10, 2014

Conversation

ClementGautier
Copy link
Contributor

Hi friends of Symfony :)

For business needs, I want that my API allows some complex QueryParams like deep array structures. For example I want to be able to query /api/users?filters[0][key]=name&filters[0][operator]=equals&filters[0][value]=Foobar.

I wanted those parameters validated in order to return a BadRequestResponse like its did using the requirements of the QueryParam or RequestParam so I added an option: constraint and this constraint is validated by the Validator component.

requirements and constraint cannot be combined.

@lsmith77
Copy link
Member

lsmith77 commented Mar 5, 2014

ok .. let me know when you have some docs to review

@ClementGautier
Copy link
Contributor Author

@lsmith77 It's ready for review

*/
public function __construct(ParamReader $paramReader, Request $request)
public function __construct(ParamReader $paramReader, Request $request, Validator $validator)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The typehint should be the ValidatorInterface, not the implementation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stof Fixed, thx.

@adrienbrault
Copy link
Contributor

Whether you want nested values or validation, I think you should use a form:

public function fooAction(Request $request)
{
    $form = $this->get('form.factory')->createNamed('', 'acme_foo_filter');
    $form->submit($request->query->all(), false);
}

I also think QueryParam should always be replaced by using a form.

What the FOSRestBundle could do to help is add some kind of ParamConverter to get the bound form as an argument:

/**
 * @SomeFosRestConverter(name = "form", type = "acme_foo_filter", request = {"query", "_attributes"})
 */
public function fooAction(Form $filterForm)
{

}

@ClementGautier
Copy link
Contributor Author

@adrienbrault I disagree. With your proposal we should drop completly the requirements support as the @RequestParam and the @QueryParam. In this PR i'm basicly adding functionalities to the requirements option. With the constraint option we could drop the support of requirements as these 2 things are the same:

/** @QueryParam(name="foo", constraint=@Regex("\d+")) */

and

/** @QueryParam(name="foo", requirements="\d+") */

I'm only extending the functionalities here.

The "problem" with your SomeFosRestFormConverter proposal is that we would not be able to set datas before submiting request datas. As these Query parameters are used for basic purpose like filtering we will not use these form for the rendering process so, for me, it's not a usefull usage of forms.

@stof
Copy link
Member

stof commented Mar 6, 2014

@adrienbrault I disagree as well. The main feature of the Form component is data binding. If all you need is validating data, binding a form is useless overhead (and not negligeable overhead). It is better to run only the validator in such case

@lsmith77
Copy link
Member

lsmith77 commented Mar 6, 2014

Right, I guess this is mostly for cases where it is not really necessary to map things to a model/form type and where an array structure is really sufficient.

@adrienbrault
Copy link
Contributor

I'm not arguing against that change, I'm arguing against the whole @QueryParam concept.

@ClementGautier
Copy link
Contributor Author

Soooo ... Could we merge this as it ? We can discuss of droping QueryParam support in an other PR I guess.

if ('' !== $config->requirements
&& ($param !== $default || null === $default)
if ($param === $default && null !== $default) {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can remove this empty line?

@ClementGautier
Copy link
Contributor Author

I finaly reviewed the code. I hope it will be ok for you.

@lsmith77
Copy link
Member

needs a rebase according to github

}

$constraint = new Regex(array(
'pattern' => '#^'.$config->requirements.'$#xs',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

preg_quote()?

@ClementGautier
Copy link
Contributor Author

Rebased and added preg_quote as @willdurand suggested

@ClementGautier
Copy link
Contributor Author

wait, the annotation does not work:

Attribute "requirements" of @QueryParam declared on method Acme\Bundle\AcmeBundle\Controller\AcmeController::cgetAction() expects a(n) string|\Symfony\Component\Validator\Constraint, but got an instance of Acme\Bundle\AcmeBundle\Validator\Constraints\AcmeConstraint

@ClementGautier
Copy link
Contributor Author

I changed string|Constraint to mixed. It's ok now. Sorry

lsmith77 added a commit that referenced this pull request Mar 10, 2014
[RFC] Added the constraint option on the ParamFetcher
@lsmith77 lsmith77 merged commit 05974ec into FriendsOfSymfony:master Mar 10, 2014
@lsmith77
Copy link
Member

thx!

@ClementGautier
Copy link
Contributor Author

thx ;)

@ClementGautier ClementGautier deleted the feat-validator branch March 10, 2014 12:30
@snc
Copy link

snc commented Mar 11, 2014

It looks like the requirements are not working anymore because of preg_quote. The requirements="\d+" results in 'pattern' => '#^\\d\+$#xsu'.

@lsmith77
Copy link
Member

ok, i guess we need to document that quoting is the responsibility of the user in that case and remove it. can you work on a PR, ideally with a test case?

@stof
Copy link
Member

stof commented Mar 11, 2014

Well, given that the requirement is a regex, applying preg_quote is indeed wrong

@eXtreme
Copy link
Contributor

eXtreme commented Mar 11, 2014

Yup it broke all regexes in my "requirements".

@willdurand
Copy link
Member

Ahm, that was more a question than a suggestion.. Sorry :-(

@lsmith77
Copy link
Member

please test ed28a05

@snc
Copy link

snc commented Mar 11, 2014

Looks good @lsmith77.

@lsmith77
Copy link
Member

ok .. i have released 1.3.1

@eXtreme
Copy link
Contributor

eXtreme commented Mar 12, 2014

BTW it is a funny situation because this should have been covert by unit tests but.. tests have been updated as well. :)

@SilverSting
Copy link

How can I set custom options for the Constraint?
The following doesn't work, the {"message": ...} ends up wrapped by another array.

requirements=@Constraints\NotBlank({"message": "my custom message"})

@mvrhov
Copy link

mvrhov commented May 6, 2014

Oh well. The upcoming sf 2.5 broke the validator implementation.

@stof
Copy link
Member

stof commented May 6, 2014

annotations have never been meant to work as @Constraints\NotBlank({"message": "my custom message"}) but as @Constraints\NotBlank(message="my custom message").

Your syntax is passeing an array as param to the constraint, with a message key in it. This param gets set in the default property of the constraint

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.