Overriding Default FOSUserBundle Controller in Symfony 3.4 - php

I'm using the Fosuserbundle to manager members in my project { SF::3.4.8 },
when trying to override the controller of the registrationController by following the Symfony documentation
<?php
namespace TestUserBundle;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use FOSUserBundle\Controller\RegistrationController as BaseController;
class RegistrationController extends BaseController {
public function registerAction(Request $request)
{
die("Hello");
}
}
but the system ignore that controller and still use The original controller, so if there any way to override my controller by

First, overriding the controller is probably not the best way to process. You should consider to hook into controller. Here is the related documentation: https://symfony.com/doc/master/bundles/FOSUserBundle/controller_events.html
Then if you still want to override the controller, you should act in the dependency injection. The service name of the controller is fos_user.registration.controller.
To replace the service you can simply use:
services:
fos_user.registration.controller:
class: YourController
arguments:
$eventDispatcher: '#event_dispatcher'
$formFactory: '#fos_user.registration.form.factory'
$userManager: '#fos_user.user_manager'
$tokenStorage: 'security.token_storage'
You can also override it in a CompilerPass. Which is probably the best solution for you because you do this inside another bundle.
Here is how it should look:
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class ReplaceRegistrationController extends CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$container
->getDefinition('fos_user.registration.controller')
->setClass(YourController::class)
;
}
}
Don't forget to register it inside your bundle:
$container->addCompilerPass(new ReplaceRegistrationController());

Related

add service to my parent of BaseController

as you know controllers in symfony extends AbstractController i want to add some usual methods in base controller and simply use in my method in controller like $this->validate for example so i created a BaseController that extends AbstractController . the issue is how can i use my ValidationService in BaseController? i have to add construct in BaseController and so again pass parent Constructor. another solution is get my ValidationService in BaseController like $this->container->get("my.validation.service") that gives me error like this :
Service "my.validation.service" not found: even though it exists in the app's container, the container inside "App\Controller\VendorController" is a smaller service locator that only knows about the "form.factory", "http_kernel", "parameter_bag", "request_stack", "router", "security.authorization_checker", "security.csrf.token_manager", "security.token_storage", "serializer" and "twig" services. Try using dependency injection instead.
what is the best practice for this?
It sounds like you should be using constructor injection and standard PHP inheritance here (this uses property promotion from php 8)
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use App\Service\ValidationService;
class MyCustomBaseController extends AbstractController
{
public function __construct(private readonly ValidationService $validationService)
{
}
}
namespace App\Controller;
use App\Controller\MyCustomBaseController;
class MyNormalController extends MyCustomBaseController
{
public function foo()
{
$this->validationService->foo();
}
}

Extending my own controller in Symfony

I am creating a webapp that has some common functions. So I figured the easiest way to do this would be to make a base controller and just extend that. So in the base controller I have (similar to):
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class BaseController extends Controller
{
protected function dosomething($data)
{
return $data;
}
}
And then in the default controller:
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class DefaultController extends BaseController
{
/**
* #Route("/", name="homepage")
*/
public function indexAction()
{
$data = "OK";
$thedata = $this->dosomething($data);
}
}
And then for the Admin Controller:
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class AdminController extends BaseController
{
/**
* #Route("/", name="homepage")
*/
public function indexAction()
{
$data = "OK";
$thedata = $this->dosomething($data);
}
}
However, I am getting errors like "Compile Error: Access level to AppBundle\Controller\AdminController::dosomething() must be protected (as in class AppBundle\Controller\BaseController) or weaker", not just when I load the admin controller function, but default as well. When I stop the admin controller extending base controller, this error goes (seems to work on default but not admin).
I'm guessing somewhere I have to let Symfony know that the admin controller is safe or something?
It has nothing to do with Symfony, it's PHP.
Obviously, you're trying to redefine dosomething method in your Admin Controller, and trying to make this method private.
It's not allowed. It may be either protected or public.
It's principle of OOP. Because if you would have a class SubAdminController, then instance of it would be also instance of both AdminController and BaseController. And PHP must definitely know if the method dosomething from parent class is accessible from SubAdminController.

How to create Facades in Laravel 5.0 without using composer?

Thanks to all in advance.
I am trying to create Facades for my custom and common functions in laravel 5.0 also I don`t want to create controller for that so I am using Facades.
I have tried almost every tutorial but it do not help me.
Please help me to create facade without using Composer in Laravel 5.0.
Thanks again.
First of all you're creating a class of facade like this:
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class SomeFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'someService';
}
}
then You create a service class that hold your functionalities:
namespace App\Services;
class SomeService { ... }
Finally you have to register it and set an alias (not required) for it:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProivider extends ServiceProvider
{
(...)
public function register()
{
$this->app->singleton('someService', function () {
return new \App\Services\SomeService();
});
$this->app->alias('SomeServiceFacade', \App\Facades\SomeFacade::class);
}
}
Now you can call your methods from SomeService with:
SomeServiceFacade::someMethhod();
or
app('someService')->someMethhod();

Undefined property exception when trying to instantiate dependency from IOC container

I'm trying to deepen my knowlade in laravel architecture.
I have a search engine (elastic search for the sake of the example), but this search engine might change in the future. So im trying to write a container for this, so in case i'll change the engine in the future, i will have to change only the container. (I believe the termenology is factory design?)
I have created a provider app/providers/DataFromSearchEngine.php that looks like this:
use Illuminate\Support\ServiceProvider;
class DataFromSearchEngine extends ServiceProvider {
public function boot()
{
//
}
public function register()
{
$this->app->singleton('SearchEngine', function($app) {
return new elasticSearch;
});
}
}
Then i registered it in the providers array in config/app.php .
'providers' => [
// providers...
'App\Providers\DataFromSearchEngine'
],
The next step is to call SearchEngine from my controller:
namespace App\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class SearchController extends Controller {
protected $searchEngine;
public function __construct() {
$this->searchEngine = $this->app->make('SearchEngine');
}
}
But all these yields: Undefined property: App\Http\Controllers\SearchController::$app
Can someone explain what i'm missing?
Instead of using $this->app try using app().
This is because non of the inherited controller classes, i.e. App\Http\Controllers\Controller or Illuminate\Routing\Controllers\Controller have an app property on them.
As a note you can use app('SearchEngine') which is the equivalent of app()->make('SearchEngine') as a shortcut to making your object.
I had this issue when trying to create a service provider. I registered my service provider in AppServiceProvider.php but was still getting this same error. The issue was that in my ServiceProvider I needed to add extends ServiceProvider to my class. Seems simple but is often forgotten.

Symfony2 dependecy injection doesn't work with controller

According to Symfony2 Cookbook I'm trying to secure controller via dependecy injection, but I'm getting error Catchable Fatal Error: Argument 1 passed to Acme\ExampleBundle\Controller\DefaultController::__construct() must implement interface Symfony\Component\Security\Core\SecurityContextInterface, none given, called in /var/www/example/app/cache/dev/classes.php on line 4706 and defined in /var/www/example/src/Acme/ExampleBundle/Controller/DefaultController.php line 13
Here is my services.yml
parameters:
acme_example.default.class: Acme\ExampleBundle\Controller\DefaultController
services:
acme_example.default:
class: %acme_example.default.class%
arguments: [#security.context]
and controller:
namespace Acme\ExampleBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
class DefaultController extends Controller {
public function __construct(SecurityContextInterface $securityContext)
{
if(false === $securityContext->isGranted('IS_AUTHENTICATED_FULLY'))
{
throw new AccessDeniedException();
}
}
public function indexAction()
{
return new Response('OK');
}
}
If you configure your controllers as services you need to use a slightly different syntax when referencing them in your routes. Instead of AcmeExampleBundle:Default:index you should use acme_example.default:indexAction.
Make sure you use Symfony\Component\Security\Core\SecurityContextInterface; in your controller. Without it, the SecurityContextInterface type hint in the constructor won't resolve.
Also, make sure your controller is actually being called as a service. The error you posted is complaining that nothing was sent to the constructor, which sounds to me like you're using your controller the 'default' way. See this cookbook page on how to setup a controller as a service.
The class Symfony\Bundle\FrameworkBundle\Controller\Controller extends ContainerAware base class. This class ha whole the container accessible via $container local property, so you should not inject any services to a controller service, because you can access SecurityContext via $this->container->get('security.context').

Categories