No route found for PUT /api/users/id - symfony

I'm trying to update a record in my mysql database by calling the put method from my sencha touch 2 frontend. I'm calling this url /api/users/id but I keep getting a Symfony error:
No route found for "PUT /api/users/1
This is what I have in my routing.yml file
users:
resource: "Acme\MainBundle\Controller\UsersController"
prefix: /api
type: rest
Also, I have the putUsersAction setup in my User*s*Controller
public function putUsersAction($id, Request $request)
{
$values['birthdate'] = $request->get('birthdate');
$values['clubid'] = $request->get('clubid');
$em = $this->getDoctrine()->getEntityManager();
$user = $this->getDoctrine()
->getRepository('AcmeMainBundle:User')
->find($id);
$club = $this->getDoctrine()
->getRepository('AcmeMainBundle:Club')
->find($values['clubid']);
$user->setBirthdate($values['birthdate']);
$user->addClub($club);
$em->flush();
$view = View::create()
->setStatusCode(200)
->setData($user);
return $this->get('fos_rest.view_handler')->handle($view);
}
Why is Symfony telling me there's no PUT /api/users/id route?
EDIT 1: router:debug output
[router] Current routes
Name Method Pattern
_wdt ANY /_wdt/{token}
_profiler_search ANY /_profiler/search
_profiler_purge ANY /_profiler/purge
_profiler_info ANY /_profiler/info/{about}
_profiler_import ANY /_profiler/import
_profiler_export ANY /_profiler/export/{token}.txt
_profiler_phpinfo ANY /_profiler/phpinfo
_profiler_search_results ANY /_profiler/{token}/search/results
_profiler ANY /_profiler/{token}
_profiler_redirect ANY /_profiler/
_configurator_home ANY /_configurator/
_configurator_step ANY /_configurator/step/{index}
_configurator_final ANY /_configurator/final
get_users GET /api/users.{_format}
post_users POST /api/users.{_format}
get_clubs GET /api/clubs.{_format}
post_clubs POST /api/clubs.{_format}
put_users PUT /api/users.{_format}

At first you should debug your routing and see if the route is being registered correctly. Your posted routing snipped lacks correct intendation. It should read:
user:
resource: "Acme\MainBundle\Controller\UserController"
prefix: /api
type: rest
Afterwards you can debug your routing with the console command:
php app/console router:debug
Furthermore you can use grep ( Unix ) or findstr ( Windows ) to search the output for your route:
php app/console router:debug | grep /api
or
php app/console router:debug | findstr /api
Next make sure for the automatic routing of FOSRestBundle to work as expected to name your controller User*s*Controller and the file User*s*Controller.php.
See: FOSRestBundle Documentation
Please note that you have forgotten to call persist($user) before flushing and that you cannot call flush on your User entity but on your EntityManager. See my example below.
You can slim down your controller a lot by using DependencyInjection , the symfony2 ParamConverter, implicit resource name definition and the #View Annotation provided by the FOSRestBundle.
Your Controller would then read something like this:
<?php
namespace Acme\MainBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use JMS\DiExtraBundle\Annotation as DI;
use Acme\MainBundle\Entity\User;
use FOS\RestBundle\Controller\Annotations\View;
/**
* #DI\Service
*/
class UserController
{
/** #DI\Inject("doctrine.orm.entity_manager") */
private $em;
// ...
/**
* #View()
*/
public function putAction(User $user, Request $request)
{
$club = $this->em
->getRepository('AcmeMainBundle:Club')
->findOneById($request->get('clubid'));
$user
->setBirthdate($request->get('birthdate')
->addClub($club);
// you should add some validation here
$this->em->persist($user);
$this->em->flush();
return $user;
}
// ...
}
Explanations:
I have used the JMSDiExtraBundle's annotations. You need this bundle to make them work.
Otherwise you should declare your controller as a service and inject the EntityManager manually ( for example in your bundle's Resources/config/services.xml ) in the service container.
Declare your controller as Service with #DI\Service annotation.
Inject your EntityManager here to be be able to access it throughout the class with $this->em with the #DI\Inject annotation.
Use FOSRest's #View annotation.
Don't forget to set sensio_framework_extra.view: { annotations: false } before using this if you have the SensioFrameworkExtraBundle's in your application.
Make sure you have return $this; at the end of your User entity's setBirthdate(...) and addClub(...) functions.
Please not that i have used [JMSDiExtraBundle's property injection][3] in the example.
The bundle has to be installed in order to be used.
You might be able to slim down the controller further by using the NoxLogicMultiParamBundle.
I cannot post more than 2 links because im new over here...
please look for the following resources on google:
NoxLogicMultiParamBundle
FOSRestBundle documentation
JMSDiExtraBundle documentation

user:
pattern: /api/user/{id}
defaults: { _controller: AcmeMainBundle:User:putUsers, id: 1 }
or you could use the FQCN:
defaults: { _controller: Acme\MainBundle\Controller\UserController::putUsersAction, id: 1 }
and to match only PUT request use the below code, although some browsers don't support PUT and DELETE see this link
user:
pattern: /api/user/{id}
defaults: { _controller: Acme\MainBundle\Controller\UserController::putUsers, id: 1 }
requirements:
_method: PUT
...and of course to see all of your routes, run this from your project folder:
php app/console router:debug

Related

Symfony - Route 404

I have a Symfony (4.1) project. In this project i need to create new route, like this.
Controller
/**
*
* #Route("/search-user", name="search-user")
*/
public function searchUser(Request $request)
{
dd("Search user");
return $this->render("XXX");
}
Routes.yaml
controllers:
resource: '../src/Controller/'
type: annotation
prefix: '/'
The problem: When i go to endpoint/search-user returns 404 not found.
I´m some new in Symfony, so somebody can see what's wrong?
You can launch
php bin/console debug:router
to have a list of all your existing routing.
Can you add your controller declaration?
check that is in the src/Controller folder
check that there is no routing prefix in your controller (#route before class declaration)

use SessionLogoutHandler to add data in database

i have a symfony application where a logout () is not manually :
( in file routing.yml)
logout:
pattern: /logout
and i would like when i click on /logout we must be able to record information in the database and for that i use :
SessionLogoutHandler class
here is my code :
namespace Symfony\Component\Security\Http\Logout;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Compta\MyappliBundle\Entity\LogTache;
use Compta\MyappliBundle\Entity\User;
use Doctrine\ORM\EntityManager;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class SessionLogoutHandler implements LogoutHandlerInterface
{
public function logout(Request $request, Response $response, TokenInterface $token)
{
$em = $this->getDoctrine()->getEntityManager();
$user= $this->get('security.context')->getToken()->getUser();
$u = new LogTache();
$u->setDate(new \DateTime());
$u->setUser($user->getUsername());
$u->setActioneffectue('Déconnexion');
$em->flush($u);
$request->getSession()->invalidate();
} }
when i click on /logout i get an error :
Fatal error: Call to undefined method
Symfony\Component\Security\Http\Logout\SessionLogoutHandler::getDoctrine()
in
C:\wamp\www\MyAppli\vendor\symfony\src\Symfony\Component\Security\Http\Logout\SessionLogoutHandler.php
on line 46
how to solve it ?
thank in advance
excuse my english
You don't have access to the container from that class. The $this->getDoctrine()... and $this->get() is more likely to be found in a controller action.
You can add a constructor and pass in '#doctrine' and '#security.context' as arguments from the service definition, or with Symfony 3.3 type-hint the appropriate classes (for Doctrine - Doctrine\Common\Persistence\ObjectManager) and use them within the class.
Symfony 2.6 deprecated the security.context service, so it's also quote likely you are running a older version of the framework. Upgrading may bring additional benefits, such as the v3.3+ auto-wiring of services.

Can't post to symfony2

I'm using Symfony2 and i'm trying to POST a form to my controller, but my controller take it as a GET request everytime... Even when i'm using restclient, i put POST for the request but when i use $request->getMethod(), the answer is always GET :/
The source code is really simple :
<?php
namespace TC\UserBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class UserController extends Controller
{
/**
* #Route("/user/register")
* #Method({"POST"})
*/
public function registerAction(Request $request)
{
echo $request->getMethod();
return new Response();
}
}
And when i add the requirements _method: POST like this :
tc_user_register:
path: /user/register/
defaults: { _controller: TCUserBundle:User:register }
requirements:
_method: POST
I got this :
No route found for "POST /user/register"
Whatever i do, Symfony2 take it as a GET request, any idea ?
Thanks !
Couple of things #Xtroyer:
1 If you use routing.yml file, requirements: _method is not recognised since Symfony 2.2, it is now:
tc_user_register:
path: /user/register/
defaults: { _controller: TCUserBundle:User:register }
methods: [POST]
2 If you use Annotations. #Method is not recognised if you don't mention the following use statement in your controller:
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
3 You can check what route is exactly registered with the following command?
php app/console router:debug | grep tc_user_register
You should have:
Name Method Scheme Host Path
tc_user_register POST ANY ANY /user/register/

How can I make routing case insensitive in Symfony2?

Is there any configuration in Symfony2 that allow use of case Insensitive routing?
For example, routes below should be treated as they are the same:
www.exmaple.com/all
www.exmaple.com/ALL
There is a pull request about this, but no reference how to make it happen.
As of Symfony2.4, you can now define condition to your route and use the expression language to do complexe check. See Router: Completely Customized Route Matching with Conditions documentation.
Another solution would be to override the route compiler class to change/extend the php compilation of your route matcher:
contact:
path: /{media}
defaults: { _controller: AcmeDemoBundle:Main:contact, media: organic }
requirements:
media: email|organic|ad
options:
compiler_class: MyVendor\Component\Routing\CaseInsensitiveRouteCompiler
See Symfony\Component\Routing\RouteCompiler class.
Or, as fabpot said in the pull request comment, your could override Request::getPathInfo[1] method to always return a lowercase string (use the setFactory[2] to override default request class).
*1 github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpFoundation/Request.php#L866
*2 github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpFoundation/Request.php#L402
I found a nifty way to do this in pure symfony (no apache mod_rewrite) without having to create a case-insensitive forwarding rule for every route.
This utilizes the twig ExceptionController. Because this occures after the routing has failed to match (or a 404 exception has been thrown for some other reason) it won't break any existing routing urls that use capitals (though that would still be a bad idea).
namespace Application\Symfony\TwigBundle\Controller;
use Symfony\Component\HttpKernel\Exception\FlattenException;
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Bundle\TwigBundle\Controller\ExceptionController as BaseExceptionController;
/**
* ExceptionController.
*/
class ExceptionController extends BaseExceptionController
{
/**
* Redirects 404s on urls with uppercase letters to the lowercase verion,
* then uses it's parent class to
* Convert an Exception to a Response.
*
* #param Request $request The request
* #param FlattenException $exception A FlattenException instance
* #param DebugLoggerInterface $logger A DebugLoggerInterface instance
*
* #return Response
*
* #throws \InvalidArgumentException When the exception template does not exist
*/
public function showAction(Request $request, FlattenException $exception, DebugLoggerInterface $logger = null)
{
if ( (string) $exception->getStatusCode() === '404' && preg_match('/[A-Z]/', $request->getPathInfo())) {
$lowercaseUrl = strtolower($request->getPathInfo());
if ($request->isMethod('POST')) {
return new RedirectResponse(
$lowercaseUrl,
'307'//307 status code preserves post information.
);
}
$queryString = $request->getQueryString();
return new RedirectResponse(
$lowercaseUrl.( strlen($queryString)>0 ? '?'.$queryString : '' ),
'301'//301 status code plays nice with search engines
);
}
return parent::showAction($request, $exception, $logger);
}
}
The only other trick is that you need to configure this controller as a service you can inject the correct arguments into the parent class's constructor:
in services.yml
services:
application.custom.exception_controller:
class: Application\Symfony\TwigBundle\Controller\ExceptionController
arguments: [ "#twig", "%kernel.debug%" ]
in config.yml:
twig:
exception_controller: application.custom.exception_controller:showAction
Of course, you can stick this controller and service definition anywhere
As far as I know, this isn't possible with Symfony 2. However, you should be able to accomplish it with Apache's mod_rewrite. See this blog post for details.
Make sure to read the comments, as there are some errors with the initial post.

Symfony 2.1 Doctrine filters (enable/disable)

I'm currently implementing Doctrine filters in my Symfony2.1 project with the following setup:
<?php
namespace Acme\Bundle\Entity;
class Article {
/**
* #ORM\Column(type="string")
*/
private $status;
...
}
//app/config/config.yml
doctrine:
orm:
filters:
status:
class: Acme\Bundle\Filter\StatusFilter
enabled: false
....
//src/Acme/Bundle/Filter/StatusFilter.php
namespace Acme\Bundle\Filter;
use Acme\Bundle\Entity\Status;
class StatusFilter extends SQLFilter {
public function addFilterConstraint(ClassMetadata $target, $alias)
{
$filter =
$target->reflClass->implementsInterface('Acme\Bundle\Entity\Status')?
$alias . '.status = ' . Status::PUBLISHED : '';
return $filter;
}
}
Where Acme\Bundle\Entity\Status is just an interface.
The code is working as expected when the filter is enabled in config.yml.
The problem is that I cannot retrieve all articles for administration!
Is there a way to enable this filter for a certain bundle?
p.s. I know how to enable and disable the filter with the EntityManager,
I just cannot find the proper place to do it for the frontend Bundle.
my admin section is accessible by route prefix myadmin
www.example.com/myadmin/ -> admin section = disable filter (disabled by default in config)
www.example.com/... -> anything else = enable filter.
Looking at the Doctrine code, there are methods to enable and disable filters.
Once you have defined your filter in the config.yml file, you can enable/disable in a controller or service:
// 'status' is the unique name of the filter in the config file
$this->getDoctrine()->getManager()->getFilters()->enable('status');
$this->getDoctrine()->getManager()->getFilters()->disable('status');
Note: this was taken from Symfony 2.3. You would need to test this with previous versions of Symfony/Doctrine.
there is no notion of bundle at Doctrine level. The only way I see would be to detect which controller is used, by parsing its className (reflection, ...) during a kernel.request event, or a kernel.controller event.
Then, if you detect that your controller is in FrontendBundle, just disable/enable your doctrine filter.
If you prefer using routing to detect when to disable/enable, just use kernel.request event. You will have access to all request parameters, via $event->getRequest()->attributes->get('_controller') for example.

Resources