Dorokhov.codes
01. About Laravel
I will try to explain how Laravel works and its lifecycle.
The entry point for all requests to a Laravel application is the public/index.php
file.
The index.php
file loads the Composer autoloader:
require __DIR__.'/../vendor/autoload.php';
And then retrieves an instance of the Laravel application from bootstrap/app.php
.
$app = require_once __DIR__.'/../bootstrap/app.php';
Http or Console
Think of the Console
and Http
directories as providing an API into the core of your application. The HTTP protocol and CLI are both mechanisms
to interact with your application, but do not actually contain application logic. In other words, they are two ways of issuing commands
to your application. The Console
directory contains all of your Artisan commands, while the Http
directory contains your controllers, middleware,
and requests.
Here’s how the instance is created:
$app = new Illuminate\Foundation\Application( ... );
$app->singleton( ... );
$app->singleton( ... );
$app->singleton( ... );
return $app;
The $app
instance is in fact a service container. It’s a powerful tool for managing class dependencies and performing dependency injection.
Let’s see how we can use this service container.
Service container
The bind
method is used to bind an abstract type (interface or abstract class) to a concrete implementation.
$app->bind(AbstractType::class, ConcreteImplementation::class);
You can bind a class name directly to itself, and Laravel will automatically resolve it when needed.
$app->bind(ConcreteClass::class);
The singleton
method binds an abstract type to a concrete implementation and ensures that only one instance of the concrete class is created and reused.
$app->singleton(AbstractType::class, ConcreteImplementation::class);
Now it’s very easy to resolve dependencies (automatic dependency resolution):
class SomeClass {
public function __construct(Dependency $dependency) {
// Laravel resolves Dependency class here.
}
}
You can manually resolve a class from the container using the make
method.
$instance = $app->make(SomeClass::class);
Service providers
A service provider is a class that binds services (PHP classes) into the Laravel service container, making them available to the application. It doesn’t contain any service logic. Its task is to make bindings between interfaces and implementations.
One service provider can add as many services as needed, so we can have only one service provider for the whole application.
All service providers extend the Illuminate\Support\ServiceProvider
class.
Let’s create a service provider. For example, we have some interface:
// app/Contracts/Logger.php
namespace App\Contracts;
interface Logger {
public function log($message);
}
And we have an implementation:
// app/Services/FileLogger.php
namespace App\Services;
use App\Contracts\Logger;
class FileLogger implements Logger {
public function log($message) {
// Simulate logging to a file
file_put_contents(storage_path('logs/app.log'), $message . PHP_EOL, FILE_APPEND);
}
}
Now we can create a file for our service provider:
php artisan make:provider LoggerServiceProvider
And now we can add the service to the service container:
// app/Providers/LoggerServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Contracts\Logger;
use App\Services\FileLogger;
class LoggerServiceProvider extends ServiceProvider {
/**
* Register services.
*
* @return void
*/
public function register() {
// Binding the Logger interface to the FileLogger implementation
$this->app->bind(Logger::class, FileLogger::class);
}
/**
* Bootstrap services.
*
* @return void
*/
public function boot() {
// Additional bootstrapping tasks, if needed
}
}
Then we need to register the service provider:
// config/app.php
'providers' => [
// Other providers...
App\Providers\LoggerServiceProvider::class,
],
Now, you have a simple service provider that binds the Logger interface to the FileLogger implementation. You can use dependency injection to access the logger throughout your application.
// Example usage in a controller or another class
use App\Contracts\Logger;
public function logMessage(Logger $logger) {
$logger->log('This message will be logged.');
return 'Message logged successfully!';
}
Core files
The Laravel framework is built using the Illuminate
library components.
Class | Description |
---|---|
Illuminate\Foundation\Application |
Represents the Laravel application instance. |
Illuminate\Foundation\Bootstrap\BootstrapServiceProvider |
Bootstraps the application and its components. |
Illuminate\Foundation\Console\Kernel |
Handles console commands. |
Illuminate\Foundation\Http\Kernel |
Handles HTTP requests and middleware. |
Illuminate\Foundation\ProviderRepository |
Manages service providers. |
Illuminate\Foundation\ComposerScripts |
Scripts executed during Composer events. |
Illuminate\Foundation\ApplicationEvents |
Defines events related to the application’s lifecycle. |
Illuminate\Database\Eloquent\Model |
Base class for Eloquent models. |
Illuminate\Database\Query\Builder |
Query Builder for constructing database queries. |
Illuminate\Routing\Router |
Handles route definition and request handling. |
Illuminate\Routing\Controller |
Base class for controllers. |
Illuminate\Http\Request |
Represents an HTTP request. |
Illuminate\Http\Response |
Represents an HTTP response. |
Illuminate\Http\JsonResponse |
Specialized class for JSON responses. |
Illuminate\Events\Dispatcher |
Manages events and event listeners. |
Illuminate\Events\Listener |
Base class for event listeners. |
Illuminate\Validation\Validator |
Performs data validation. |
Illuminate\Validation\Rule |
Pre-defined validation rules. |
Illuminate\Cache\CacheManager |
Manages various cache stores. |
Illuminate\Cache\Repository |
Represents a cache store. |
Illuminate\Filesystem\Filesystem |
Unified interface for interacting with the filesystem. |
Illuminate\Config\Repository |
Manages configuration settings. |
Illuminate\Session\SessionManager |
Manages session storage and retrieval. |
Illuminate\Session\Store |
Represents a session store. |
Illuminate\Translation\Translator |
Translates messages in the application. |
Kernels
Next, the incoming request is sent to either the HTTP kernel or the console kernel, depending on the type of request that is entering the application.
app/Http/Kernel.php
app/Console/Kernel.php
The HTTP kernel extends the Illuminate\Foundation\Http\Kernel
class, which defines an array of bootstrappers
that will be run before the request is executed. These bootstrappers configure error handling, configure logging, detect the application environment, and perform other tasks that need to be done before the request is actually handled.
It receives a Request
and returns a Response
. Think of the kernel as being a big black box that represents your entire application. Feed it HTTP requests and it will return HTTP responses.
Let’s take a look at the public/index.php
file:
$app = require_once __DIR__.'/../bootstrap/app.php';
$kernel = $app->make(Kernel::class);
$response = $kernel->handle(
$request = Request::capture()
)->send();
$kernel->terminate($request, $response);
Middlewares
Middlewares allow us to perform actions before and after the HTTP request enters the controller.
Middlewares are typically defined in the app/Http/Middleware
directory.
Middleware structure:
// Example Middleware
namespace App\Http\Middleware;
use Closure;
class MyMiddleware {
public function handle($request, Closure $next) {
// Perform actions before the request reaches the controller
return $next($request);
}
public function terminate($request, $response) {
// Perform actions after the response is sent
}
}
A middleware is defined in the $middleware
property of the Kernel
class (app/Http/Kernel.php
).
// Example in Kernel.php
protected $middleware = [
// ...
\App\Http\Middleware\MyMiddleware::class,
];
Views
Views separate your controller logic from your presentation logic and are stored in the resources/views
directory.
Since this view is stored at resources/views/greeting.blade.php
, we may return it using the global view
helper like so:
Route::get('/', function () {
return view('greeting', ['name' => 'James']);
});
Views may also be returned using the View
facade:
use Illuminate\Support\Facades\View;
return View::make('greeting', ['name' => 'James']);
There’s another interesting thing called a view composer. If you have common logic that needs to be shared across multiple views, a view composer allows you to encapsulate that logic in a single location. The data provided by the view composer is automatically bound to the view each time it is rendered, reducing the need to pass data explicitly from controllers.
So if we see that we write the same code for different controllers and views, we can reduce it using a view composer.
A view composer typically resides in a service provider’s boot
method.
View::composer('welcome', function ($view) {
$view->with('key', 'value');
});
Multiple views:
View::composer(
['profile', 'dashboard'],
function ($view) { ... }
);
The composer
method also accepts the *
character as a wildcard, allowing you to attach a composer to all views:
use Illuminate\Support\Facades;
use Illuminate\View\View;
Facades\View::composer('*', function (View $view) {
// ...
});
<!-- Example in a Blade view -->
<p>{{ $key }}</p>