Search code examples
phpfunctioncontrollersilex

Silex call controller within controller


When I receive an API request it routes trough the Application.php to the UserController.

The UserController does his thing with the information and I need to call the EmailController, because that is the controller that manages all the emails.

In the EmailController I have a function (its simplified):

class EmailController { 

   public function getEmail() {
       return 1337 ;
   }
}

In the UserController I have a function:

class UserController {
    public function getUserMail(Request $request, Application $app) {
        $number = ???;
        return $number;
    }
}

What do I have to call within the UserController to get the getEmail function of the EmailController?

If this is not a correct way of doing it, I would love to hear what term I am acutally searching for :)

Edit1: As @lawrence-cherone pointed out, it should have been in a model. It was stuck in my head that I had to use the controller for this task.


Solution

  • You could use the dependency injection to share the class that return number.

    So your controllers will look like:

    class EmailController
    {
      /**
       * @var NumberCalculatorInterface
       */
      private $numberCalculator;
    
      /**
       * @param NumberCalculatorInterface $numberCalculator
       */
      public function __construct(NumberCalculatorInterface $numberCalculator)
      {
          $this->numberCalculator = $numberCalculator;
      }
    
      public function getEmail()
      {
          return $this->numberCalculator->getNumber();
      }
    }
    

    and

    class UserController
    {
      /**
       * @var NumberCalculatorInterface
       */
      private $numberCalculator;
    
      /**
       * @param NumberCalculatorInterface $numberCalculator
       */
      public function __construct(NumberCalculatorInterface $numberCalculator)
      { 
          $this->numberCalculator = $numberCalculator;
      }
    
      public function getUserMail(Request $request, Application $app)
      {
          $number = $this->numberCalculator->getNumber();
          return $number;
      }
    }
    

    Your class that calculate number or other more complex logic will be

    interface NumberCalculatorInterface
    {
       public function getNumber();
    }
    
    class DefaultNumberCalculator implements NumberCalculatorInterface
    {
      public function getNumber()
      {
          return 1337;
      }
    }
    

    Since the number calculation is not a logic proper to your EmailController cause you use the logic in several classes, it make sense to be an external class. You will be able to unit test it properly and to inject in all the classes that need this calculation to be done.

    You will be able to declare it as service:

    class NumberCalculatorProvider implements ServiceProviderInterface {
    
        public function register(Container $pimple)
        {
            $pimple['number_calculator'] = function () {
                return new DefaultNumberCalculator();
            };
        }
    }
    

    And inject it inside your controller easily (in the following example is use the ServiceControllerServiceProvider to declare controller as services):

    class ControllerProvider implements ServiceProviderInterface {
      public function register(Container $pimple)
    {
        $pimple['controller.user'] = function ($pimple) {
            return new UserController($pimple['number_calculator']);
        };
    
    
        $pimple['controller.email'] = function ($pimple) {
            return new EmailController($pimple['number_calculator']);
        };
      }
    }
    

    note: In my example i use silex 2., since its not specified in your question, you may need to adapt it if you use an older version but the logic remain the same.*