okdewit
okdewit

Reputation: 2566

Traits, helper service or inheritance for eliminating repetitive code in Symfony2

I'm trying to clean up an older Symfony2 project where most of the code is inside controllers. Long, repetitive blocks of code in a controller is not optimal, it makes debugging & development very tedious and error-prone.

There are plenty of things I can easily clean up and move into services, as those blocks of code provide some sort of reusable functionality. I get that any well-defined task should live in a service, and controllers should just be "wiring".

But no matter where I move the code, there are always small repetitive blocks cluttering everything up. Things like initialization/transformation/parsing/filtering patterns for example, which are used extensively in our application.

Take for example the data "kneading" needed for the creation of a DataTable:

class DefaultController extends Controller {

    public function indexAction() {

        $data = array(/* some data */);

        $encoders = array(new JsonEncoder());
        $normalizers = array(new GetSetMethodNormalizer());
        $serializer = new Serializer($normalizers, $encoders);
        $datatable = $this->get('datatables.orders');
        $datatable->buildDatatableView();
        $datatable->setData($serializer->serialize($data, 'json'));

        return array('datatable'=>$datatable);
    }
}

That's a very common, but also very verbose pattern. Our developers tend to store dozens of these kinds of little patterns in text files on their own computers, and often copy/paste them into controllers.

If I try to think of solutions to make the code a bit more concise (and DRY), there are multiple options.

Consider this:

Bundle/Traits/TableTrait.php

Trait TableTrait {
    function serialize($data, $format){
        $encoders = array(new JsonEncoder());
        $normalizers = array(new GetSetMethodNormalizer());
        $serializer = new Serializer($normalizers, $encoders);
        return $serializer->serialize($data, $format);
    }

    function buildTable($table, $data){
        $datatable = $table;
        $datatable->buildDatatableView();
        $datatable->setData($this->serialize($data, 'json'));
    }
}

Bundle/Controller/SomeController.php

class DefaultController extends Controller {

    use \Bundle\Traits\TableTrait;

    public function indexAction() {

        $data = array(/* some data */);
        $datatable = $this->buildTable($this->get('datatables.orders'),$data);

        return array('datatable'=>$datatable);
    }
}

That reduces 6 lines of boilerplate to 1.

Are traits a bad solution for this? If so, which options would be better?

Upvotes: 1

Views: 933

Answers (1)

Cerad
Cerad

Reputation: 48865

You might look at moving some things into services. For example:

$serializer = $this->get('json.getset.serializer');

And maybe make a data table factory service

$dataTable = $this->get('datatable.orders.factory')->create($data);

You could even go one step further, define your controllers as services then inject the needed dependencies. So you would end up with:

$dataTable = $this->dataTableFactory->create($data);

Upvotes: 1

Related Questions