Упрощенные контроллеры

Laravel — упрощая контроллеры

В этому уроке я дам пару советов, как облегчить ваши контроллеры.

Контроллерам не нужно ничего наследовать

Если вы выполните команду php artisan make:controller то получите:

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class MyController extends Controller
{
    //
}

Контроллер наследует базовый контроллер App\Http\Controllers\Controller. Вот что у того внутри:

namespace App\Http\Controllers;

use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;

class Controller extends BaseController
{
    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}

Этот контроллер наследует еще один: Illuminate\Routing\Controller. Чтобы не раздувать статью, я не буду показывать его содержимое. Просто знайте, что в нём функции для регистрации мидлваров и вызова других методов контроллера.

Принято думать, что для того, чтобы контроллер заработал, он должен наследовать Illuminate-контроллер. Но это не так, контроллеру не нужно ничего наследовать. Вот пример совершенно корректного контроллера:

namespace App\Http\Controllers;

class MyController
{
   // какой-то функционал
}

У нас в Spatie, во всех наших клиентских проектах, контроллеры по умолчанию ничего не наследуют. Если контроллеру нужна валидация или авторизация, то мы подключаем трейты AuthorizesRequests или ValidatesRequests.

Лучше контроллеры без дефолтного пространства имён

В обычном Laravel-приложении контроллеры живут в пространстве имён App\Http\Controllers. Так настроено в RouteServiceProvider.

namespace App\Providers;

use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;

class RouteServiceProvider extends ServiceProvider
{
    /**
     * This namespace is applied to your controller routes.
     *
     * In addition, it is set as the URL generator's root namespace.
     *
     * @var string
     */
    protected $namespace = 'App\Http\Controllers';

    // ..

    protected function mapWebRoutes()
    {
        Route::middleware('web')
             ->namespace($this->namespace)
             ->group(base_path('routes/web.php'));
    }
}

Это позволяет нам просто использовать строку с названием контроллера в файле маршрутов, например, для App\Http\Controllers\MyController:

Route::get('my-url', 'MyController@index');

Конечно дефолтное пространство имён экономит нам некоторое количество нажатий клавиш в файле маршрутов, но только и всего.

Давайте посмотрим, какие же преимущества мы получим, если не будем использовать дефолтный namespace. Если вы удалите protected $namespace и вызов ->namespace в RouteServiceProvider, то в файле маршрутов вам нужно будет указать полное пространство имен для контроллера.

use App\Http\Controllers\MyController;

Route::get('my-url', [MyController::class, 'index']);

Если у вас в контроллере только один метод, то можете использовать метод __invoke(). В таком случае, в файле маршрутов вы можете указать этот контроллер так:

use App\Http\Controllers\MyController;

// разве не прекрасно?
Route::get('my-url', MyController::class);

Замена на полное пространство имён имеет ряд преимуществ. Если вы используете IDE, например, PhpStorm, то теперь он знает, какой класс используется. Когда вы начнёте набирать класс, то он попытается использовать автокомплит. Также вы можете теперь кликнуть на MyController::class. Прекрасно! Когда займётесь рефакторингом контроллера или его пространством имён, то PhpStorm автоматически обновит файл маршрутов. Отличный результат!

Кроме того, если вы теперь захотите использовать другое пространство имен для вашего контроллера, то можете просто сделать так:

// альтернативный namespace
use App\Front\Http\AlternativeNamespace\MyController;

Route::get('my-url', MyController::class);

Выводы

Laravel пытается всё упростить, для лёгкого вхождения новичков, добавляя основные трейты в каркас дефолтных контроллеров и устанавливая дефолтное пространство имён. Но если вы более-менее опытный программист, то я настоятельно рекомендую не не использовать в своих контроллерах дефолтные наследования и пространства имён.

Автор: Freek Van der Herten
Перевод: Алексей Широков

Наш Телеграм-канал — следите за новостями о Laravel.


Задать вопросы по урокам можно на нашем форуме.