I'm using annotation to set my routes and method types. Is there a way to only allow certain types of post data. Currently I'm doing the following:
/**
* #Route("/myurl", requirements={"varID" = "\d+"} )
* #Method({"POST"})
* #Template()
*/
But if a varID gets submitted with a string value then it goes through anyway... I'm guessing due partly to there being no {varID} in the route? Is there a way to validate POST data like this in Symfony?
Change annotation into this:
/**
* #Route("/myurl/{varID}", requirements={"varID" = "\d+"} )
* #Method({"POST"})
* #Template()
*/
You must tell symfony wich part of url is yours varID variable to allow engine to check datatype. Than you get an exception:
No route found for "GET /myurl/somestring"
404 Not Found - NotFoundHttpException
1 linked Exception:
Related
I am using the #Security annotation to control which roles have access to certain routes in my Symfony 3.4 application, it works when I am logged in however when the user object doesn't exist such as when the session times out I get the following exception thrown.
Unable to get a property on a non-object.
vendor/symfony/symfony/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php:78
at
Symfony\Component\ExpressionLanguage\ExpressionLanguage->evaluate('\'ROLE_MANAGER\'
in user.getRoles()',
My method definition looks like this:
/**
* #Route("/club/{id}/trophies", name="club_trophies", methods={"GET","POST"})
* #IsGranted("IS_AUTHENTICATED_FULLY")
* #Security("'ROLE_MANAGER' in user.getRoles()")
* #param Club $club
* #return Response
*/
public function trophies(Club $club): Response
{
Is there a way using the Symfony Expression Language, or similar, that I can check that user exists. Or is there a better way?
When you are not authenticated, the value of user is null, so it's normal that your check is throwing an exception (as you're trying to access the method getRoles() of a null object).
The proper ways to check if a user has a given role using annotations are :
#IsGranted("ROLE_MANAGER")
Or :
#Security("is_granted('ROLE_MANAGER')")
You can see more here : https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/security.html
I have created a custom endpoint using API Platform. Here is the annotation I have used:
/**
* We only want the POST option for now.
*
* #ApiResource(
* itemOperations={},
* collectionOperations={"post"={
* "method"="POST",
* "controller"=PairingController::class,
* "path"="/devices/pairing",
* "defaults"={"_api_receive"=false}
* }},
* )
*
*
*/
class Pairing
{
...
The controller I am calling executes some custom logic. I am happy with how things are working so far. But the documentation generated by API Platform is now inaccurate. It says:
/devices/pairing Creates a Pairing resource.
... which is no longer true, since my controller does not generate a pairing. (It calls out to a different API instead, asking that API to do some stuff.)
So here's my question: How do I change my annotation to allow me to write a custom piece of documentation for this endpoint?
You can use the swagger_context key to change any Swagger field, including description (the one you are looking for): https://api-platform.com/docs/core/swagger/#changing-operations-in-the-swagger-documentation
It didn't works for me, here is how I did it with openapi_context:
"openapi_context"={
"summary"="test",
},
I am using request object in twig extension class to get the current route. For instance, having the following url:
http://www.localhost/project/user/page/2
Inside of the twig extension I'm able to get user/page/2 string and do something with it.
The problem arises when I wanna get the default route using the same method, which I have to do. For example, accessing the following url:
http://www.localhost/project/user
I want to get user/page/1 string inside the twig extension class, and not just user.
The controller looks like this:
/**
* #Route(name="user",
* default="user/page/1")
*/
Is there a way to achieve that? Or do I have to stop using default routes?
Write a comment if you need more explanation, it's 9AM here in Poland and I'm sleeping yet.
The #Route documentation explains that you can do this for set a default page number:
/**
* #Route("/project/user/page/{page}",
* name="user",
* defaults={"page" = 1},
* requirements={"page" = "\d+"}
* )
*/
When retrieving models from database and sending them to the client I want to include for each model the url to that resource.
Let's take as example this Article model, with:
id
title
content
etc.
Storing the url to an article in the DB doesn't make sense, because it can be easily made up from id and title:
ex: http://www.example.com/articles/article_id/article_title
So, this is what I am doing now:
I use the $appends array:
/**
* Additional attributes
*
* #var array
*/
protected $appends = array('article_url');
and created a getter for article_url:
/**
* Get the article url attribute
*
* #return string
*/
protected function getArticleUrlAttribute()
{
return $this->exists
? url('articles', $parameters = array(
$this->getKey(),
Str::title(Str::limit($this->title, 100))
))
: null;
}
This works just fine. The problem is, that probably the model should not include any logic for creating urls. What is a good approach for this problem? Where should I create the
url to the article before sending it to the client?
That sort of logic would usually go in whatever your framework's routing engine is. For instance, since it sounds like you're using Laravel, you'd probably make a Named Route -- call it, say, "canonical_article".
Then you can use the link_to_route helper to have your framework generate the URL.
I have created a RESTful API that has an optional parameter passed in as a URL variable. It seems to work correctly when executing from the browser directly but when trying it in the API Explorer it lists the parameter but ignores it when executing it. I have no idea where to start to look in solving this. Any help would be greatly appreciated.
The class definition is as follows:
class actions {
/**
* LIST available Actions
*
* List all the actions that a user (or app) can choose from. The response list
* will include [name],[slug/id], and [description] attributes. If you want a more complete set of
* meta attributes for the actions then you can specify "meta=all" in the request url. For full spec of
* response please review LG_actions_list.json.
*
* #url GET /available
*
* #param $meta {#from url} Optional parameter to control the amount of meta-data passed back. Values are "none","normal", and "all"
**/
public function available ($meta="normal")
{
return "list actions (meta level set to $meta)";
}
}
In this case I can type "all" as the value of $meta in the API explorer but the response is still "list actions (meta level set to normal)".
UPDATE:
In order to clarify this behaviour I am adding the API Explorers output and the output I get when I call the service directly:
In comparison, when actually using the API I get the correct results. Typing this into Chrome:
http://[domain]/api/actions/available?meta=foobar
I get the desired output of:
"list actions (meta level set to foobar)"
There are few problems with what you are doing with the above code
Optional Parameters are better left to query string
When you add a manual route using #url no auto routes will be added for that method
Do the following to make it work.
Changed the method name to get to map it to root of the class
Turned off smart auto routing
Now in the explorer there will be two operations listed
actions.json
actions.json/{meta}
.
class actions {
/**
* LIST available Actions
*
* List all the actions that a user (or app) can choose from. The response list
* will include [name],[slug/id], and [description] attributes. If you want a more complete set of
* meta attributes for the actions then you can specify "meta=all" in the request url. For full spec of
* response please review LG_actions_list.json.
*
* #smart-auto-routing false
* #param $meta Optional parameter to control the amount of meta-data passed back. Values are "none","normal", and "all"
**/
public function get ($meta="normal")
{
return "list actions (meta level set to $meta)";
}
}