FOSuserBundle override controller - symfony

What is the right way to pass more variables to FOSUserBundle settings twig template (Profile/show_content.html.twig) in Symfony 3.4?
I basically want to rewrite showAction() method and pass more than user variable ti twig template.
I tried to following this tutorial. It seems it does no longer work with Symfony 3.4

The way I do it (and there might be better methods) is simply create a new controller with a route to the original 'show route', together with the variables I want to pass. Here is an example of the showAction() with an extra variable rendered_address:
namespace App\Controller;
use FOS\UserBundle\Model\UserInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
class ProfileController extends Controller
{
/**
* Show the user.
* #Route("/profile/show")
*/
public function showAction()
{
$user = $this->getUser();
if (!is_object($user) || !$user instanceof UserInterface) {
throw new AccessDeniedException('This user does not have access to this section.');
}
$address = $this->getUser()->renderAddress(); // here is get my variable
return $this->render('#FOSUser/Profile/show.html.twig', array(
'user' => $user,
'rendered_address' => $address // here is pass my variable
));
}
}

Related

Convert POST Request to Doctrine Entity

Coming from a NodeJS environment, this seems like a nobrainer but I somehow did not figured it out.
given the function:
/**
* #Route("/", name="create_stuff", methods={"POST"})
*/
public function createTouristAttraction($futureEntity): JsonResponse
{
...
}
Let futureEntity have the same structure as my PersonEntity.
What is the best way of mapping that $futureEntity to a PersonEntity?
I tried to assign it manually, and then run my validations which seems to work, but i think this is cumbersome if a model has more than 30 fields...
Hint: Im on Symfony 4.4
Thank you!
Doc: How to process forms in Symfony
You need to install the Form bundle: composer require symfony/form (or composer require form if you have the Flex bundle installed)
Create a new App\Form\PersonType class to set the fields of your form and more: doc
In App\Controller\PersonController, when you instanciate the Form, just pass PersonType::class as a first parameter, and an new empty Person entity as a second one (the Form bundle will take care of the rest):
$person = new Person();
$form = $this->createForm(PersonType::class, $person);
The whole controller code:
<?php
namespace App\Controller;
use App\Entity\Person;
use App\Form\PersonType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class PersonController extends AbstractController
{
private $entityManager;
public function __construct(EntityManagerInterface $entityManager) {
$this->entityManager = $entityManager;
}
/**
* #Route("/person/new", name="person_new")
*/
public function new(Request $request): Response
{
$person = new Person(); // <- new empty entity
$form = $this->createForm(PersonType::class, $person);
// handle request (check if the form has been submited and is valid)
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$person = $form->getData(); // <- fill the entity with the form data
// persist entity
$this->entityManager->persist($person);
$this->entityManager->flush();
// (optional) success notification
$this->addFlash('success', 'New person saved!');
// (optional) redirect
return $this->redirectToRoute('person_success');
}
return $this->renderForm('person/new.html.twig', [
'personForm' => $form->createView(),
]);
}
}
The minimum to display your form in templates/person/new.html.twig: just add {{ form(personForm) }} where you want.

symfony 4 dynamic route with array

I'm quiet new to symfony and spend hours trying to find a solution.
I'm building a multilingual website where page slugs are differents.
For example :
www.mywebsite.com/products EN will be www.mywebsite.com/produits FR but both use the same controller
I have to build a dynamic route and here is the way I did I'm pretty sure I can do better, could you help me?
<?php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class websiteController{
public function __construct(){
$this -> route = array(
'about' => 'page_about',
'contact' => 'page_contact',
);
}
/**
* #Route("/{page}", name="page")
*/
public function pageAction($page)
{
if($page == $this -> route['about']){
return new Response('<html><body>page about</body></html>');
}
if($page == $this -> route['contact']){
return new Response('<html><body>page contact</body></html>');
}
}
}
?>
There is a bundle for routing internationalization called BeSimpleI18nRoutingBundle but it is not available for symfony 4 right now.
Core symfony implementation
With core symfony you could use multiple routes for each controller, that would have a {_locale} parameter with default value, here the problem would be that two different URLs would be returning the same page.
e.g /test would be the same as /test/en
This might cause problems with SEO
here how the annotations would look like if you wish to implement this method
/**
* #Route("/test/{_locale}", defaults={"_locale"="en"}, requirements={"_locale":"en"}, name="default_en")
* #Route("/δοκιμή/{_locale}", defaults={"_locale"="el"}, requirements={"_locale":"el"}, name="default_el", options = {"utf8": true})
* #Route("/tester/{_locale}", defaults={"_locale"="fr"}, requirements={"_locale":"fr"}, name="default_fr")
*/
public function test($_locale)
{
return new Response("Your current locale is : $_locale");
}
Dynamic Route
Another option is to create a Routing Service that would apply your logic.
Here is an example.
this would be the controller that handles all the paths
Controller
namespace App\Controller;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use App\Service\Router;
class RouterController extends Controller {
/**
* #Route("/{path}", name="router", requirements={"path" = ".+"})
*/
public function router($path,Request $request,Router $router) {
$result=$router->handle($path);
if($result){
$result['args']['request']=$request;
return $this->forward($result['class'], $result['args']);
}
throw $this->createNotFoundException('error page not found!');
}
}
This Controller Action depends on a service called Router so you will have to create a Router service that would return the an array (you can change it to return a custom object) with keys class and args that would be used to forward the request to a controller action.
Service
/src/Service/Router.php
Here you should implement a function called handle and you can apply any logic to it
here is a basic example
namespace App\Service;
class Router
{
public function handle($path)
{
switch ($path) {
case "test":
return [
"class" => "App\Controller\TestController::index",
"args" => [
"locale" => 'en'
]
];
case "tester":
return [
"class" => "App\Controller\TestController::index",
"args" => [
"locale" => 'fr'
]
];
default:
return false;
}
}
}
The code above would forward the request to TestController::index function and will add as parameter to that function the locale variable and also it will include the Request object
You could store the routes in a yaml file or database or any other location you like. You can manipulate the $path variable to extract information about id, page etc.

Extending Controller - Nothing Happens

I'm trying to figure that problem for a long day.
I have Sonata User Bundle installed and I use it to manage users and profile edition and so on.
BUT, I a need to override Sonata Profile Controller.
If I understood correctly (I'm a perfect beginner in Symfony), I have to extend SonataUserBundle (which has been done using the easy extend bundle).
So, when I declare a new controller, nothing happens. Not even an error message.
Any ideas ?
Here are my files
[ BUNDLE EXTENSION FILE ]
// ApplicationSonataUserBundle.php
namespace Application\Sonata\UserBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class ApplicationSonataUserBundle extends Bundle
{
/**
* {#inheritdoc}
*/
public function getParent()
{
return 'SonataUserBundle';
}
}
[ CONTROLLER FILE ]
namespace Application\Sonata\UserBundle\Controller;
use Sonata\UserBundle\Controller\ProfileFOSUser1Controller as BaseController;
class ProfileFOSUser1Controller extends BaseController {
public function editProfileAction() {
die('toto');
$user = $this->getUser();
if (!is_object($user) || !$user instanceof UserInterface) {
throw new AccessDeniedException('This user does not have access to this section.');
}
$form = $this->get('sonata.user.profile.form');
$formHandler = $this->get('sonata.user.profile.form.handler');
$process = $formHandler->process($user);
if ($process) {
$this->setFlash('sonata_user_success', 'profile.flash.updated');
return $this->redirect($this->generateUrl('sonata_user_profile_edit'));
}
return $this->render('SonataUserBundle:Profile:edit_profile.html.twig', array(
'form' => $form->createView(),
'breadcrumb_context' => 'user_profile',
));
}
}
You have die('toto'); as first line in the controller method, isn't that going to terminate all code below?
Ok so I have found the answer by myself :)
I forgot to specify the classes I needed
use FOS\UserBundle\Model\UserInterface;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Sonata\UserBundle\Controller\ProfileFOSUser1Controller as BaseController;
I cleared the cache and everything was ok !
Thanks all !

overriding ChangePasswordFOSUser1Controller prints code on login page

I'm curently developing an app on Symfony 2.5.0 using FOSUSerBundle, SonataAdminBundle and SonataUserBundle.
I've extended FOSUserbundle so my AppKernel.php has new Sonata\UserBundle\SonataUserBundle('FOSUserBundle') and I also generated my own Application\Sonata\UserBundle using Easy Extends.
In my Application\SonataUserBundle, i've overriden the ChangePasswordFOSUser1Controller as so:
use Symfony\Component\DependencyInjection\ContainerAware;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\Request;
use FOS\UserBundle\Model\UserInterface;
use Sonata\UserBundle\Controller\ChangePasswordFOSUser1Controller as BaseController;
class ChangePasswordFOSUser1Controller extends BaseController
{
public function changePasswordAction()
{
$user = $this->container->get('security.context')->getToken()->getUser();
if (!is_object($user) || !$user instanceof UserInterface)
{
throw new AccessDeniedException('This user does not have access to this section.');
}
$form = $this->container->get('fos_user.change_password.form');
$formHandler = $this->container->get('fos_user.change_password.form.handler');
$process = $formHandler->process($user);
if ($process)
{
$this->setFlash('fos_user_success', 'change_password.flash.success');
if ($user->getFirstConnection())
$user->setFirstConnection(false);
return new RedirectResponse($this->getRedirectionUrl($user));
}
return $this->container->get('templating')->renderResponse('SonataUserBundle:ChangePassword:changePassword.html.'.$this->container->getParameter('fos_user.template.engine'),
array('form' => $form->createView()));
}
/**
* {#inheritdoc}
*/
protected function getRedirectionUrl(UserInterface $user)
{
return $this->container->get('router')->generate('front_home');
}
/**
* #param string $action
* #param string $value
*/
protected function setFlash($action, $value)
{
$this->container->get('session')->getFlashBag()->set($action, $value);
}
}
The problem is: Whenever I go to my login page I see my controller's code printed twice in the "header section", right before the login form.
I've tried clearing my cache and VOILA ! cache is cleared but the same code gets printed twice in my shell. (yeah, I work with a shell)
I get the "bug" over and over again when clearing cache but on my login page it disappears after two page refresh.
Have anyone tried overriding that controller or got a similar error ? (would be a shame no one had)
Thx for the help !
<?php
Missing on ChangePasswordFOSUser1Controller.php
The code was defined as interpretable and so printed as plain text on every html page.

How to override the FOSUserBundle's profile controller correctly?

I would like to override the ProfileController's edit action of FosUserBundle. I've created the controller in my own UserBundle, copied the edit action into it and made some changes. In this controller there is a check if the logged in user is an instanceOf UserInterFace. Apparently it's not because it throws an access denied exception when I go to /profile/edit
Why isn't the logged in user an instanceOf UserInterFace anymore?
Controller:
namespace Tennisconnect\UserBundle\Controller;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use FOS\UserBundle\Controller\ProfileController as BaseController;
class ProfileController extends BaseController
{
/**
* Edit the user
*/
public function editAction()
{
$user = $this->container->get('security.context')->getToken()->getUser();
if (!is_object($user) || !$user instanceof UserInterface) {
throw new AccessDeniedException('This user does not have access to this section.');
}
$form = $this->container->get('fos_user.profile.form');
$formHandler = $this->container->get('fos_user.profile.form.handler');
$process = $formHandler->process($user);
if ($process) {
$user->upload();
$this->setFlash('fos_user_success', 'profile.flash.updated');
return new RedirectResponse($this->container->get('router')->generate('fos_user_profile_show'));
}
return $this->container->get('templating')->renderResponse(
'FOSUserBundle:Profile:edit.html.'.$this->container->getParameter('fos_user.template.engine'),
array('form' => $form->createView(), 'theme' => $this->container->getParameter('fos_user.template.theme'))
);
}
}
Reading your code snippet, I would say it's simply because you don't match the full qualified namespace of UserInterface.
Either import the class with:
use Symfony\Component\Security\Core\User\UserInterface;
or modify your code like this:
if (!is_object($user) || !$user instanceof Symfony\Component\Security\Core\User\UserInterface) {
The cleaner solution is to create a new Bundle "MyFOSBundle", in the bundle class :
getParent()
{
return "FosBundle";
}
Then you write the file you want override on the same location.
http://symfony.com/doc/master/cookbook/bundles/inheritance.html

Resources