Shawn31313
Shawn31313

Reputation: 6062

Organizing Controllers in laravel

I recently dove into the world of laravel (version 5.4). While initially confused, the concept of MVC makes a lot of sense in writing large applications. Applications that you want to be easily understood by outside developers.

Using laravel for this has greatly simplified coding in PHP and has made the language fun again. However, beyond dividing code into its respective models, views, and controllers, what happens if we need to divide controllers to prevent them from growing too large?

A solution that I have found to this is to define one controller each folder and then fill that controller with traits that further add functionalities to the controller. (All-caps = folder):

CONTROLLER
    HOME
        Controller.php
        TRAITS
            additionalFunctionality1.php
            additionalFunctionality2.php
            additionalFunctionality3.php
            ...
    ADMIN
        Controller.php
        TRAITS
            additionalFunctionality1.php
            additionalFunctionality2.php
            additionalFunctionality3.php
            ...

Within routes/web.php I woud initialize everything as so:

Route::namespace('Home')->group(function () {
    Route::get('home', 'Controller.php@loadPage');
    Route::post('test', 'Controller.php@fun1');
    Route::post('test2', 'Controller.php@fun2');
    Route::post('test3', 'Controller.php@fun3');
});
Route::namespace('Admin')->group(function () {
    Route::get('Admin', 'Controller.php@loadPage');
    Route::post('test', 'Controller.php@fun1');
    Route::post('test2', 'Controller.php@fun2');
    Route::post('test3', 'Controller.php@fun3');
});

With me being new to laravel, this seems like a simple and elegant way to organize my logic. It is however something I do not see while researching laravel controller organization.

The Question

Is there an issue, both in the short-run and in the long-run, of organizing my data like this? What is a better alternative?

Example Controller:

<?php

namespace App\Http\Controllers\Message;

use DB;
use Auth;
use Request;
use FileHelper;

use App\Http\Controllers\Message\Traits\MessageTypes;
use App\Http\Controllers\Controller;

class MessageController extends Controller
{   
    // Traits that are used within the message controller
    use FileHelper, MessageTypes;

    /** 
      * @var array $data Everything about the message is stored here
      */
    protected $data = []; // everything about the message

    /** 
      * @var booloean/array $sendableData Additional data that is registered through the send function
      */
    protected $sendableData = false;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
        $this->middleware('access');
    }

    /**
      * Enable sendableData by passing data to the variable
      *
      * @param array $data Addition data that needs to registrered 
      * @return MessageController
      */
    protected function send ($data = []) { 
        // enable sendableData by passing data to the variable
        $this->sendableData = $data;  

        return $this;
    }

    /**
      * Enable sendableData by passing data to the variable
      *
      * @param string $type The type of message that we will serve to the view 
      * @return MessageController
      */
    protected function serve ($type = "message") {
        $this->ss();
        $this->setData(array_merge($this->sendableData, $this->status[$type]));
        $this->data->id = DB::table('messages')->insertGetId((array) $this->data);
    }

    /**
      * Set the data of the message to be used to send or construct a message 
      * Note that this function turns "(array) $data" into "(object) $data"
      *
      * @param array $extend Override default settings 
      * @return MessageController
      */
    protected function setData(array $extend = []) {
        $defaults = [
            "lobby" => Request::get('lobbyid'),
            "type" => "text",
            "subtype" => null,
            "body" => null,
            "time" => date("g:ia"),
            "user" => Auth::User()->username,
            "userid" => Auth::User()->id,
            "day" => date("j"),
            "month" => date("M"),
            "timestamp" => time(),
            "private" => Request::get('isPrivate') ? "1" : "0",
            "name" => Request::get('displayname'),
            "kicker" => null
        ];
        $this->data = (object) array_merge($defaults, $extend);

        // because a closure can not be saved in the database we will remove it after we need it
        unset($this->data->message);

        return $this;
    }

    /**
      * Send out a response for PHP
      *
      * @return string 
      */
    public function build() {
        if($this->data->type == "file") {
            $filesize = @filesize("uploads/" . $this->data->lobby . "/" . $this->data->body);
            $this->data->filesize = $this->human_filesize($filesize, 2);
        }
        // do not send unneccessary data
        unset($this->data->body, $this->data->time, $this->data->kicker, $this->data->name, $this->data->timestamp);

        return $this->data;
    }

    /**
      * Send out a usable response for an AJAX request
      *
      * @return object
      */
    public function json() {
        return json_encode($this->build());
    }

}

?>

Upvotes: 3

Views: 2703

Answers (2)

FULL STACK DEV
FULL STACK DEV

Reputation: 15971

Laravel architecture is simple enough for any size of the application.

Laravel provides several mechanisms for developers to tackle the fatty controllers in your Application.

  • Use Middlewares for authentications.
  • Use Requests for validations and manipulating data.
  • Use Policy for your aplication roles.
  • Use Repository for writing your database queries.
  • Use Transformers for your APIs to transform data.

It depends on your application. if it is too large and have different Modules or functionalities then you should use a modular approach. A nice package is available for making independent modules here

Hope this helps.

Upvotes: 3

ABCrafty
ABCrafty

Reputation: 278

I think you should do a little differently ! First you should use your traits at the same levels as the controllers since traits are not controllers, your tree should look more like :

Http
   Controller
     Controller.php
     Home
       YourControllers
     Admin
       Your admin controllers
   Traits
      Your Traits

Next your routes need to be more like that :

Route::group(['prefix' => 'home'], function()
{
    Route::get('/', 'Home\YourController@index')->name('home.index');
}



Route::group(['prefix' => 'admin',  'middleware' => ['admin']], function()
{
    Route::get('/', 'Admin\DashboardController@index')->name('dashboard.index');
}

You can use many kink or routes like :

Route::post('/action', 'yourControllers@store')->name('controller.store');
Route::patch('/action', 'yourControllers@update')->name('controller.update');
Route::resource('/action', 'yourController');

The Resource route creates automatically the most used your, like post, patch, edit, index.. You just need to write the action and the controller called with its action. You can check out your toutes with this command : php artisan route:list

Laravel also has many automated features, like the creation of a controller with this command : php artisan make:controller YourController.

For the routes the prefix creates portions of url, for example all the routes inside the route group with the prefix 'admin' will lool like : www.yourwebsite.com/admin/theroute, and can also be blocked for some users with a middleware.

To get familiar with laravel i suggest you follow the laravel 5.4 tutorial from scratch by Jeffrey Way on Laracasts, he's awesome at explaining and showing how laravel works. Here is a link : https://laracasts.com/series/laravel-from-scratch-2017

Hope it helps, ask me if you want to know anything else or have some precisions, i'll try to answer you !

Upvotes: 0

Related Questions