Where should I place my users method in Symfony 4? - symfony

I followed the symfony 4 documentation to make a login form (https://symfony.com/doc/current/security/form_login_setup.html) and I added a registration form in the same controller.
I'm a beginner, and I would like to make an account page where the user will be able to change his informations, but I would like to know if I should create a new Controller who work with the user entity, on just work onthe same controller than the login and registration ?
Or maybe my user controller have to inherit the securityController?
I'm a noob, sorry ^^'
Thank you

You can give a look at https://symfony.com/doc/current/service_container.html#creating-configuring-services-in-the-container
The path is creating your own service(s), for example App\Servie\UserManager that performs every task on a User object
For example, you could have:
App\Service\UserManager
class UserManager
{
// ...
public function handleUpdatePasswordRequest(Request $request) {...}
// or
public function handleUpdatePasswordForm(Form $form) {...}
// or:
public function handleUpdatePassword(User $user, $newPlainPassword) {...}
...
}
as to say, whatever you want to implement, keeping in mind that the thinner the controllers are better it is, while services can grow (and be split) indefinitely

Related

Symfony workaround for using of protected methods

Background: symfony3
I have just stuck in the fact that redirectToRoute and addFlash methods in controller are protected in symfony. I have a separate class for action.
namespace AppBundle\Action;
class Base {
public function __construct($controller) {
$this->controller = $controller;
}
}
As you can see base action class requires a controller. Basically it is logical because action class is part of a controller and should have access to all its methods. However I cannot call $this->controller->addFlash as it is protected. If it is protected then there might be some reason for it. I cannot find it. Can you please hint me how I can change my action class so that it could use controller methods.
The variant about extending action from a controller does not fit me as I have additional functionality in the main controller. It is configured in a proper way.
Update: my goal is to devide controller functionality by responsibility. I invented an action class. My end code look like following:
public function editAction() {
$instance = new \AppBundle\Action\MyController\Edit($this);
return $insance->run();
}
In this case I keep controller clean and not verbose.
Here is a link to Symfony Controller Trait, that you can duplicate, if you really want to work that way.
But since you are injecting a whole symfony controller into your own controllers, you will be better off with extending instead. Injection is used here for injecting separate service by their IDs.

Action requires multiple controllers to execute

I have a UserController that has a Destroy function. It is a rather complex function because it demands to destroy all user's data. I have another action, from the Admin panel that deletes all data from a specific set of users.
Since I don't want to replicate the code from the UserController, I would like to call the Destroy function from UserController for each User to destroy its data.
How should I proceed?
Thanks in advance.
Why not move this functionality to a common class method which can be accessed from both the controllers as needed ?
public class UserManager
{
public void Destroy(List<int> userIdsToDestroy)
{
foreach(var userId in userIdsToDestroy)
{
//Execute code to destroy
}
}
}
and from your action methods, you can call it like
var mgr = new UserManager();
var badUsers = new List<int> { 1,2,3};
mgr.Destroy(badUsers);
Update the badUsers variable value as needed based on from where you are calling it.
Shared functionality like this would ideally be in a business layer, and both controllers would call that code. If it's a little app, you could just create a separate folder structure for shared code. Larger projects would have a business layer dll.
Why not make the Destroy() method as a Non-Action method then like
[Non-Action]
public void Destroy(User user)
{
// code goes here
}
You can as well make this Destroy() function as part of your business layer logic instead of handling this in controller. In that case, you call it from anywhere.
If you want it to be #controller, you can as well consider usig [ChildActionOnly] action filter attribute.

Inheritance - Sharing info between child and parent controllers

Context
I have a custom Event Entity which has several child Entities: Problem and Maintenance (and few others but those two should be enough to describe the problem) entity classes inherit from Event entity class.
The addAction(), seeAction() and modifyAction() of ProblemController and MaintenanceController are (obviously) very similar but with some differences.
I want to have a button to display the see view of an Event, no matter if it is a Problem or a Maintenance. Same for modify.
For the add action it is a bit different: the user has to say (by clicking on child-specific button) what kind of child he want to add.
How I handle this so far
In my seeAction() and modifyAction(), I just forward the "call" depending on the type of the child:
public function seeAction(Event $event)
{
if($event instanceof \Acme\EventBundle\Entity\Problem){
return $this->forward('AcmeEventBundle:Problem:see', array('event_id' => $event->getId()));
}
elseif($event instanceof \Acme\EventBundle\Entity\Maintenance){
return $this->forward('AcmeEventBundle:Maintenance:see', array('maintenance_id' => $event->getId()));
}
}
I have no Event::addAction() but I have a Event::addCommon() which gathers the common parts of the addAction of Problem and Maintenance. Then I call this Event::addCommon() with Controller inheritance.
class ProblemController extends EventController
{
public function addAction(MeasurementSite $measurementSite)
{
$problem = new Problem();
$problem->setMeasurementSite($measurementSite);
$form = $this->createForm(new ProblemType($measurementSite), $problem);
$response = parent::addCommon($problem, $form);
return $response;
}
Problem
All this looks pretty ugly to me. If I want to share common things between Problem::seeAction() and Maintenance::seeAction(), I will have to call an Event function, but Event already forwarded something!! Information jumps from Parent to Child and vice versa...
I would like to know what is the proper way to manage this problem?
I looked a bit at setting Controller as a service, using PHP Traits, Routing inheritance but I couldn't extract anything clear and clean from this research...
I can see how you might end up chasing your tail on this sort of problem.
Instead of multiple controllers, consider have one EventController for all the routes along with individual ProblemHelper and MaintainenceHelper objects. The helper objects would have your add/see/modify methods and could extend a CommonHelper class.
Your controller would check the entity type, instantiate the helper and pass control over to it.

Adding Same FlashBag Code To Every Controller - Symfony2

I need to add a FlashBag code $session->getFlashBag()->add('foo', $bar); to every controller, along with the code required to get $bar. I am wondering if there is a better way then copying+pasting the code into every controller? Would there be some sort of master controller?
I'd recommend you to create a listener that will run before every controller that you indicate. Following this guide will show everything you need to set it up:
http://symfony.com/doc/2.0/cookbook/event_dispatcher/before_after_filters.html
http://symfony2.ylly.fr/symfony2-simulate-preexecute-postexecute-filters-actions-jordscream/
You should try implementing a service and registering it for onCoreController, then do $event->getController()->preAction() (or whatever function name you want...) , then you can implement those methods in the controllers that you need functionality in
something like
src/My/Bundle/RequestListener.php:
public function onCoreController(FilterControllerEvent $event) {
$evntController = $event->getController();
if (method_exists($evntController[0], 'beforeFilter')) {
$evntController[0]->beforeFilter();
}
}
Look here for more info
http://symfony.com/doc/2.0/book/internals.html#the-event-dispatcher
http://symfony.com/doc/2.0/book/internals.html
http://symfony.com/doc/current/cookbook/service_container/event_listener.html

How to contextualize Symfony 2 routes without request parameters

I've been searching high and low for a solution here, but I'm not really finding what I need. It may just be that I'm not searching for the right thing.
For the admin backend of my app, I currently grab a user for a controller like this:
//routing.yml
view_user:
pattern: /user/{id}/
defaults: { _controller: AppBundle:User:view }
//UserController.php
use Sauce\AppBundle\Entity\User;
public function viewAction(User $user)
{
$user->getSauce();
}
For the frontend where a user doesn't fetch themselves at each URL using an id, this doesn't work. Is it possible to do this without having an id in the URL? My first thought of how to make a user easily available is something like:
/**
* A fast way to grab the user throughout this class.
*/
public function getUser() {
return $this->get('security.context')->getToken()->getUser();
}
public function viewAction()
{
$user = $this->getUser();
...
}
But this, to me, seems way below Symfony 2 standards. I must be overlooking something more elegant. Any insights out there?
Yea, creating a helper method is the way to go. You could move it to a base controller to stay DRY. My abstract base controller provides such a method.
There is no “magic” way of doing this I'm aware of.

Resources