How should I organize my controllers using the SOLID methodology?

Asked

Viewed 450 times

5

I am currently developing a project and noticed that my controllers are responsible for more than one activity.

Thinking about it I remembered about the Hangout of the Laravel Brazil Community about SOLID.

The problem is that I don’t know the best way to organize the controllers... currently there is the following case:

Contactoscontroller

Responsibilities:

  • CRUD (index, create, store, Edit, update, Destroy)
  • Import contacts from another system by CSV (3 methods)
  • Export contacts to other systems in CSV (2 methods)
  • Search for contacts through simple or complex filters (2 methods)

How should I organize this controller?

  • Contactoscontroller
  • Contactmportacoescontroller or Contactocontroller
  • Contactosfiltroscontroller

Something like that?


If something hasn’t been explained well or you need more details, let me know.

Thanks in advance.

  • Relevant: http://qualityisspeed.blogspot.com.br/2014/08/why-i-dont-teach-solid.html

1 answer

5


There is a very subtle difference in the One Responsibility Principle that causes this kind of questioning.

Having Sole Responsibility is not restrict the object to do a single thing and yes prevent it from doing things hereafter of the closest context intended to begin coding.

In your case, you have the context of Contacts. A Controller Contacts should control everything about Contacts and only.

But controlling everything about Contacts includes everything you mentioned, from CRUD to search and import/export.

However, it will not be the Controller who will import/export the data, for example. It will only enter the user’s choice made in the GUI (View) and the final product through the Request made.

In that case, the Importer is a separate class yes, but is not a Controller, at least not in the conventional definition, as an Importer should be able to import not only contacts, but any kind of information.

I’m not sure if with methods you have actually referred to class methods or import forms, but assuming it has been as to import forms, this is not even the responsibility of the Importer itself.

The Importer in turn offer an interface (not visual, of course) to the Controller work, but the actual import routines, or better the strategies input analysis classes (CSV, TXT, XML...) are other more classes, all under a regulatory interface.

In code, we’d have something like this:

class ContactsController {

    // GUIs

    public function index() {}
    public function create() {}
    public function edit() {}
    public function delete() {}

    public function search() {}

    public function import() {}
    public function export() {}

    // Actions

    public function indexAction() {}
    public function createAction() {}
    public function editAction() {}
    public function deleteAction() {}

    public function searchAction() {}

    public function importAction() {

        $file   = ( isset( $_POST['file'] ) ? $_POST['file'] : NULL );
        $method = ( isset( $_POST['method'] ) ? $_POST['method'] : 'CSV' );

        try {

            $importer = new Importer( $file, $method );

            $data = $importer -> import();

            // Do something with $data

        } catch( ImporterException $e ) {

            die( $e -> getMessage() );
        }
    }

    public function exportAction() {}
}

class Importer {

    private $strategy;

    public function __construct( $strategy, $file ) {

        $strategyClass = sprintf( '%sStrategy.php', $strategy );

        if( ! class_exists( $strategyClass ) {

            throw new ImporterException(

                sprintf( 'Importer Strategy %s does not exist', $strategy )
            );
        }

        $this -> strategy = new $strategyClass( $file );
    }

    public function import() {
        return $this -> strategy -> import();
    }
}

class CSVStrategy implements ImporterInterface {

    private $file;

    public function __construct( $file ) {

        $this -> file =& $file;
    }

    public function import() {

        // Do something with $this -> file and return
    }
}

interface ImporterInterface{

    public function import();
}

The code fragment above is for educational purposes only and therefore has not been properly tested or even optimized, and may even present syntax errors

  • Right. So I can keep what I already have inside the controller, the difference is that it will use other resources to continue the request. That would be about it?

  • To answer that for sure I’d need to know if Laravel has any kind of coding standards among them organization and structuring. Normally, if it is not (M)Odel, (C)ontroller or (V)iew, it is not part of the main directories of the application. These, from the root of the site, usually stay in a separate directory, often called vendor and subdivided by developer (ZF, Symfony, Smarty...), including its own.

  • Right. I need to understand this better... I’ll wait for other points of view and do some research before closing the question. Anyway, thank you very much.

  • I saw some Jeffrey Way videos on Laracasts and their logic matches some points that he presented. Thanks in advance.

  • Glad I could help :)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.