We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Inject a component in a controller action without dispatch events

Hello all,

I am trying to use laravel way to inject a component in a controller action, see this example from laravel:

class UserController extends Controller {

    /**
     * Store a new user.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        $name = $request->input('name');

        //
    }

}

They use something called "service container" to resolve action params, is this applicable in Phalcon ?

I did try to make it manually but with no luck!

Sorry, it may be because it's early, but I'm not seeing any injection here - just passing a parameter to a function.

Controllers in Phalcon do automatically extend DiInjectable (or something similarly named) which allows you to access everything in your DI directly like:

class UserController extends Controller {
    /**
     * Store a new user.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        $name = $request->input('name');
        // "config" is set in the DI
        $age = $this->config->user->defaults->age;
    }
}

You can also directly access the request object with $this->request

class UserController extends Controller {
    /**
     * Store a new user.
     */
    public function storeAction()
    {
        $name = $this->request->getPost('name');
    }
}

If neither of these answer your question, can you please reword it?

edited Mar '20

Thanks for sharing such info, but this is not my question.

If you define a user-defined typed parameter in a controller action, Laravel will inject an instance of this parameter, so you can use it directly in the action. It maybe any object and not exclusive for request objects.

I need this functionality to avoid defining each component as a service in Phalcon DI.

Sorry, it may be because it's early, but I'm not seeing any injection here - just passing a parameter to a function.

Controllers in Phalcon do automatically extend DiInjectable (or something similarly named) which allows you to access everything in your DI directly like:

class UserController extends Controller {
   /**
    * Store a new user.
    *
    * @param  Request  $request
    * @return Response
    */
   public function store(Request $request)
   {
       $name = $request->input('name');
      // "config" is set in the DI
      $age = $this->config->user->defaults->age;
   }
}

You can also directly access the request object with $this->request

class UserController extends Controller {
   /**
    * Store a new user.
    */
   public function storeAction()
   {
      $name = $this->request->getPost('name');
   }
}

If neither of these answer your question, can you please reword it?

edited Mar '20

I'm not too familiar with Laravel, but it sounds like you're describing the "Container" concept in Laravel, as described here: https://stackoverflow.com/a/42817767/251859

That sounds just like a dependency injector, with each thing the Container supplies being a service.

Laravel certainly does more automated actions that Phalcon will, and I think this is an example of that. If you have a custom component you'd like to use in a controller action, you have 2 choices:

  1. Instantiate it as a service in the DI. In reality, this isn't that much work, it could be as simple as:

    DI

    $DI->set('customComponent',function(){ return new \Namespace\Component\Custom(); }

    Controller action

    $this->customComponent->doTheThing()
  2. Put the component in a Component namespace, then configure the auto-loader to automatically load classes in that namespace:

    Controller action

    $MyCustomComponent = new \Namespace\Component\Custom();
    $MyCustomComponent->doTheThing()


7.0k
Accepted
answer
edited Mar '20

Thanks @quasipickle for your answer, is helpful somewhat.

I came with a solution described in Phalcon docs, but with some tweaks to match my needs.

The solution I came with is to add new dispatch event listener to the servise container to handle the action depedencies, example:

$di->setShared('dispatcher', function() {
    $evManager->attach("dispatch:beforeDispatch", function (Event $event, Dispatcher $dispatcher) {
        try {
            $methodReflection = new ReflectionMethod(
                $dispatcher->getControllerClass(),
                $dispatcher->getActiveMethod()
            );
            foreach ($methodReflection->getParameters() as $parameter) {
                $parameterClass = $parameter->getClass();
                if ($parameterClass instanceof ReflectionClass) {
                    $dispatcher->setParam($parameter->name, new $parameterClass->name);
                }
            }
        } catch (Exception $exception) {
            throw new \Exception('', Dispatcher::EXCEPTION_HANDLER_NOT_FOUND);
        }
    });
    $dispatcher = new Dispatcher();
    $dispatcher->setEventsManager($evManager);
    return $dispatcher;
}

Even if it is not fully capable which laravel can do but it is doing the job as expected for now. Each framework has it's own mechanism, so if you need to make something special, you have to make it manually.