I am currently developing an API and am using FOSRestBundle. I've gone wrong somewhere with the annotation side of my controller.
Please see my code below:
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\Controller\FOSRestController;
class DefaultController extends FOSRestController
{
/**
* #Rest\("/default/{string})
* #param string $string
*/
public function defaultAction($string)
{}
}
I am trying to to pass a parameter to the default action and do something with it. However, the parameter I include in the URL isn't getting passed to the action. Any help will be appreciated.
You're just missing the Get from your first annotation, it should be: #Rest\Get("/default/{string}")
Related
i'm new to Symfony. I'm trying to create dynamic universal route that will pick required controller based on part of url. I've found in docs that there is special param {_controller} that can be used in route pattern, but could not find any examples of usage.
// config/routes.yaml
api:
path: /api/{_controller}
So for example for route /api/product i expect ProductController to be initiated.
But as a result i get error "The controller for URI "/api/product" is not callable: Controller "product" does neither exist as service nor as class."
Can somebody please help me understanding how {_controller] param works? Or maybe there is a better way for specifying universal route that can dynamically chose controller without listing controller names in routes.yaml.
Thanks in advance
This isn't really the cleanest way to do what I think you're trying to do. If I am correct in assuming you want to have a /api/product/ point to methods in your product controller, then something like this is more "symfonyish"
// src/Controller/ProductController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* #Route("/api/product", name="product_")
*/
class ProductController extends AbstractController
{
/**
* #Route("/", name="index")
* --Resolves to /api/product/
*/
public function index(): Response
{
// ...
}
/**
* #Route("/list", name="list")
* --Resolves to /api/product/list
*/
public function list(): Response
{
// ...
}
/**
* #Route("/{productID}", name="get")
* --Resolves to /api/product/{productID}
*/
public function get(string $productID): Response
{
// $productID contains the string from the url
// ...
}
}
Note that this really just scratches the surface of Symfony routing. You can also specify things like methods={"POST"} on the routing directive; so you could have the same path do different things depending on the type of request (e.g. you could have a route /product/{productID} that GETs the product on that request but updates the product on a PATCH request.
Regardless, the takeaway here is that it is unwieldy to have all of your routes defined in routes.yml rather you should define your routes as directives in the controller itself.
In a Symfony 5 project we're using the APi Platform to generate a REST API.
One of the entity classes is called FarmMetadata.
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
/**
* #ApiResource()
* #ORM\Table(... some settings ...)
* #ORM\Entity
*/
class FarmMetadata
{
// properties and methods
}
When I run php bin/console debug:router it shows the following routes for this resource:
api_farm_metadatas_get_collection GET ANY ANY /api/farm_metadatas.{_format}
api_farm_metadatas_post_collection POST ANY ANY /api/farm_metadatas.{_format}
api_farm_metadatas_get_item GET ANY ANY /api/farm_metadatas/{id}.{_format}
api_farm_metadatas_delete_item DELETE ANY ANY /api/farm_metadatas/{id}.{_format}
api_farm_metadatas_put_item PUT ANY ANY /api/farm_metadatas/{id}.{_format}
api_farm_metadatas_patch_item PATCH ANY ANY /api/farm_metadatas/{id}.{_format}
However the word "metadata" is already plural. There's no such thing as metadatas. How can I turn off the pluralisation for this endpoint?
I tried using shortName:
* #ApiResource(
* shortName="FarmMetadata" // also "farm_metadata"
* )
but it doesn't change the output.
If I use:
* #ApiResource(
* shortName="Metadata"
* )
then the route names and paths are changed:
api_metadata_get_collection GET ANY ANY /api/metadata.{_format}
api_metadata_post_collection POST ANY ANY /api/metadata.{_format}
api_metadata_get_item GET ANY ANY /api/metadata/{id}.{_format}
api_metadata_delete_item DELETE ANY ANY /api/metadata/{id}.{_format}
api_metadata_put_item PUT ANY ANY /api/metadata/{id}.{_format}
api_metadata_patch_item PATCH ANY ANY /api/metadata/{id}.{_format}
but that's not what I want.
I know that I can declare a path for every operation, but that would hurt the DRY principle.
How can I achieve the desired behaviour?
You could use "path" option on each operation.
Cf https://api-platform.com/docs/core/operations/#configuring-operations
For example
* shortName="Metadata",
* itemOperations={
* "get"={
* "path"="/metadata/{id}"
I don't think this is possible by configuration: these routes are built in the private method ApiPlatform\Core\Bridge\Symfony\Routing\ApiLoader::addRoute (at least in v2.6 which I'm using), and this uses a static call to a pluralizer - so: decorating the ApiLoader is not easily possible (as the addRoute method is private), and exchanging the ways of generating the route is not possible (due to the usage of a static method call).
Looks like you need to open a feature request ticket in their bug tracker...
you can do easily as you want
api_platform:
...
path_segment_name_generator: App\InfraStructure\ApiPlatform\Core\SingularPathSegmentNameGenerator
create SingularPathSegmentNameGenerator
<?php
declare(strict_types=1);
namespace App\InfraStructure\ApiPlatform\Core;
use ApiPlatform\Core\Operation\PathSegmentNameGeneratorInterface;
use ApiPlatform\Core\Util\Inflector;
final class SingularPathSegmentNameGenerator implements PathSegmentNameGeneratorInterface
{
public function getSegmentName(string $name, bool $collection = true): string
{
return Inflector::tableize($name);
}
}
When I inject the Request class of Simfony it works well for me, but I just created a class called FormRequest that "extends" from Request, I thought this would work, since it is still a Request instance, but it is not, I get an error.
Type error: Argument 1 passed to AppBundle\Http\Controllers\BlogController::validateAction() must be an instance of AppBundle\Http\FormRequest, instance of Symfony\Component\HttpFoundation\Request given, called in /var/www/html/api-erp/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php on line 151
Exception
My class FormRequest.php:
namespace AppBundle\Http;
use Symfony\Component\HttpFoundation\{JsonResponse, Request, Response};
class FormRequest extends Request
{
}
Controller BlogController.php is:
<?php
namespace AppBundle\Http\Controllers;
use AppBundle\Http\FormRequest;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\{Request, JsonResponse};
use Symfony\Component\Routing\Annotation\Route;
class BlogController extends Controller
{
/**
* #Route("/blog", name="blog_index")
*/
public function validateAction(FormRequest $request)
{
return new JsonResponse(['success' => true]);
}
}
Simfony versiĆ³n: 3.4.*
You missing something.
Symfony use the ParamConverter feature to inject the request in your action. If you want to override it you also have to create a custom converter and use the correct priority in the service to avoid the error.
More explanation in symfony documentation
Well, the title says it all. I have a login form which works fine. But what I have to do is to save the timestamp when the user successfully logs in in addition to a field which stores the timestamp when the database record is changed. So these are two different fields. I have found this answer here which does what I want. Unfortunately the class ContainerAware is not present in Symfony3 so I don't know how to get a EntityManager instance into my Handler. I'm pretty sure, that there is a simple solution, but I just can't find it.
With help of the hint from #micguo I got a step further. Here is my code so far:
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
class AuthenticationHandler implements AuthenticationSuccessHandlerInterface{
use ContainerAwareTrait;
/**
* {#inheritDoc}
* #see \Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface::onAuthenticationSuccess()
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token) {
$token->getUser()->setAnmeldat(new \DateTime("now"));
$this->container->get('doctrine')->getEntityManager()->flush();
return new RedirectResponse($this->container->get('router')->generate('/auth/bnme'));
}
}
But when I try to log in, Symfony throws an Exception:
Error: Call to a member function get() on a non-object .
What is wrong here?
Use the ContainerAwareTrait instead
To use ContainerAwareTrait, you need to make a definition in your services.yml file.
Create Service implementing ContainerAwareInterface
I'm working on Laravel framework, I have created a class under controllers/admin/PlacesController.php
I'm placing it in a name space controller/admin;
But as you can see below I can't use standart Laravel classes without "\"
Please see \View
class PlacesController extends \BaseController {
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
$places=\Place::all();
return \View::make('admin.places.index',compact('places'));
}
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create()
{
return \View::make('admin.places.createOrEdit');
}
}
But I would want to use it as View without "\" how can I do this? It is really a problem to fix all View to \View
Thanks all.
You should import View class because it's in other namespace (root namespace).
Add:
use View;
at the beginning of your file, for example:
<?php
namespace yournamespacehere;
use View;
Now you will be able to use in your controllers return View instead of return \View
If you want more explanation you could look at How to use objects from other namespaces and how to import namespaces in PHP