0

I made a PHP Symfony project for learning purposes. Now i am stuck, so i have a Controller, which renders a View. But inside that Controller i want to access another Controller and make an object, because i need it's method.

So in short: How can i make a class/object inside another class in Symfony?

This is my code:

<?php

namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;

use AppBundle\Entity\User;
use AppBundle\Controller\LoginController;

class HomeController extends Controller
{

    /**
     * @Route("/", name="home")
     */
    public function renderIndexAction(Request $request)
    {
        $user = new User();

        $form = $this->createFormBuilder($user)
            ->add('username', TextType::class, array('label' => 'username:'))
            ->add('password', PasswordType::class, array('label' => 'password:'))
            ->add('save', SubmitType::class, array('label' => 'login'))
            ->getForm();

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $user = $form->getData();
            $user_username = $user->getUsername();
            $user_password = $user->getPassword();

            $loginController = new LoginController();
            $user = $loginController->checkAction();


            $session = $request->getSession();
            $data = "test";
            $session->set('form_data', $data);


            return $this->redirectToRoute('addressbook');
        }

        return $this->render('home/index.html.twig', array('form' => $form->createView()));
    }
}

So i want to use the LoginController inside my HomeController. But it gives me an error:

Call to a member function has() on null 500 Internal Server Error - FatalThrowableError

PS: Yes i know that my app is not safe, but i am still learning basic OOP. So it might be a weird way to call a LoginController like that. But it's for learning purposes.

ofahchouch
  • 11
  • 5
  • 4
    What method do you need from there? Add it's code here. You might want to extract it into separate service and inject into both controllers instead of trying to create a Controller within another controller. – svgrafov Nov 29 '17 at 09:31
  • If you want to access another endpoint of another controller, look up sub-requests. If you want to re-use another controller's method, make that method into a service and inject use that service in both controllers. – k0pernikus Nov 29 '17 at 09:45
  • You don't want to use another controller's instance in your controller, that's wrong logic; You should read about MVC principle. In your case you probably want to create another class - a service class, and both controllers will use that service. You should also read about dependency injection, for loading the service class. – HTMHell Nov 29 '17 at 09:47
  • Why is it wrong to make a Controller inside another Controller? All i wanted is to make an object from a class inside another class? – ofahchouch Nov 29 '17 at 13:43
  • I am trying to make a service from that Controller. Is it enough to write this in services.yml: services: app.login_controller: class: AppBundle\Controller\LoginController And can i call the LoginController like this: $loginController = app.login_controller; ? – ofahchouch Nov 29 '17 at 14:06
  • NVM, it works now. I am using a service now. This link explains it: https://symfony.com/doc/2.8/service_container.html – ofahchouch Nov 29 '17 at 14:27

2 Answers2

1

It looks like your issue actually stems from the fact, that you are using the controllers wrong. You have managed push the application logic in them, which is causing your current problem.

Instead of creating User instance and doing the authentication in a controller, all of that should be handled by services (like Authentication service). If a controller needs access to a service, said service should be passed as a dependency to that controller.

This would also give you a natural way for sharing logic between multiple controllers, because multiple controller then can depend on same services.

Update

So, the services.yml file would look kinda like this:

services:

    controller.auth:
        class: 'Application\Controller\Authentication'
        arguments: ['@service.recognition', '@service.comunity']

    controller.account:
        class: 'Application\Controller\Authentication'
        arguments: ['@service.comunity']

    service.recognition:
        class: 'Model\Service\Recognition'

    service.community:
        class: 'Model\Service\Community'

In this case the Community service is shared between two unrelated controllers.

P.S. you might find this post useful

tereško
  • 58,060
  • 25
  • 98
  • 150
  • Why is it wrong to make a Controller inside another Controller? All i wanted is to make an object from a class inside another class? – ofahchouch Nov 29 '17 at 13:43
  • I am trying to make a service from that Controller. Is it enough to write this in services.yml: services: app.login_controller: class: AppBundle\Controller\LoginController And can i call the LoginController like this: $loginController = app.login_controller; ? – ofahchouch Nov 29 '17 at 14:05
  • NVM, it works now. I am using a service now. This link explains it: https://symfony.com/doc/2.8/service_container.html – ofahchouch Nov 29 '17 at 14:27
  • @alandibat updated to show an example. And please, do not call the DI container from within a controller class. – tereško Nov 29 '17 at 14:41
  • @alandibat as for "why it is bad idea", there are couple reasons. First of all, it cause a tight coupling between controller (which should be the most lightweight part of an application). It also means, that your controller now has additional responsibility - to "re-execute in a separate context". Aaaand, you would also end up with some "controllers" without consistent methods (as in, in Sf2.x you usually return a `Response` instance from all public methods). – tereško Nov 29 '17 at 15:04
0

The only way you can use a controller from another controller is to define a controller as a service and then use it.

take a look at this answer how-to-access-a-different-controller-from-inside-a-controller-symfony2

here is official doc Define Controllers as Services

habibun
  • 1,552
  • 2
  • 14
  • 29
  • 1
    If you need to call one controller from another, then you have made an architectural mistake. – tereško Nov 29 '17 at 11:27
  • @tereško I agree, just for accuracy if you detect that the request should be handled by another controller, in this case you might forward the request to another controller. It's a specific case don't worry about this, just to know that it exist – Mcsky Nov 29 '17 at 12:35
  • Why is it wrong to make a Controller inside another Controller? All i wanted is to make an object from a class inside another class? – ofahchouch Nov 29 '17 at 13:43
  • I am trying to make a service from that Controller. Is it enough to write this in services.yml: services: app.login_controller: class: AppBundle\Controller\LoginController And can i call the LoginController like this: $loginController = app.login_controller; ? – ofahchouch Nov 29 '17 at 14:05
  • NVM, it works now. I am using a service now. This link explains it: https://symfony.com/doc/2.8/service_container.html – ofahchouch Nov 29 '17 at 14:27
  • Move your code into a service is the good way. Service are very very powerfull. If some code may be reusable into another context, you should directly think about a service :) – Mcsky Nov 29 '17 at 15:54