Skip to content

Latest commit

 

History

History
633 lines (451 loc) · 18.4 KB

italian.md

File metadata and controls

633 lines (451 loc) · 18.4 KB

Laravel best practices

You might also want to check out the real-world Laravel example application

Translations:

Nederlands (by Protoqol)

한국어 (by cherrypick)

日本語 (by 2bo)

漢語 (by xiaoyi)

ภาษาไทย (by kongvut sangkla)

فارسی (by amirhossein baghaie)

Português (by jonaselan)

Українська (by Tenevyk)

Русский

Tiếng Việt (by Chung Nguyễn)

Español (by César Escudero)

Français (by Mikayil S.)

Polski (by Karol Pietruszka)

Türkçe (by Burak)

Deutsch (by Sujal Patel)

Italiana (by Sujal Patel)

العربية (by ahmedsaoud31)

اردو (by RizwanAshraf1)

Laravel example app

Contenuto

Principio della sola responsabilità

Modelli grassi, controller skinny

Validazione

La logica aziendale dovrebbe essere nella classe di servizio

Non ripeterti (SECCO)

Preferisco usare Eloquent rispetto a Query Builder e query SQL non elaborate. Preferisce raccolte su array

Assegnazione di massa

Non eseguire query nei modelli Blade e utilizzare il caricamento desideroso (problema N + 1)

Commenta il tuo codice, ma preferisci il metodo descrittivo e i nomi delle variabili rispetto ai commenti

Non inserire JS e CSS nei modelli Blade e non inserire HTML nelle classi PHP

Usa file di configurazione e lingua, costanti anziché testo nel codice

Utilizzare gli strumenti standard Laravel accettati dalla community

Segui le convenzioni di denominazione di Laravel

Utilizzare la sintassi più breve e più leggibile ove possibile

Utilizzare il contenitore o le facciate IoC anziché la nuova classe

Non ottiene direttamente i dati dal file .env

Memorizza le date nel formato standard. Utilizzare accessori e mutatori per modificare il formato della data

Altre buone pratiche

Principio di singola responsabilità

Una classe e un metodo dovrebbero avere una sola responsabilità.

Sbagliato:

public function getFullNameAttribute(): string
{
    if (auth()->user() && auth()->user()->hasRole('client') && auth()->user()->isVerified()) {
        return 'Mr. ' . $this->first_name . ' ' . $this->middle_name . ' ' . $this->last_name;
    } else {
        return $this->first_name[0] . '. ' . $this->last_name;
    }
}

Giusto:

public function getFullNameAttribute(): string
{
    return $this->isVerifiedClient() ? $this->getFullNameLong() : $this->getFullNameShort();
}

public function isVerifiedClient(): bool
{
    return auth()->user() && auth()->user()->hasRole('client') && auth()->user()->isVerified();
}

public function getFullNameLong(): string
{
    return 'Mr. ' . $this->first_name . ' ' . $this->middle_name . ' ' . $this->last_name;
}

public function getFullNameShort(): string
{
    return $this->first_name[0] . '. ' . $this->last_name;
}

🔝Torna ai contenuti

Fat models, skinny controllers

Inserisci tutta la logica legata al DB nei Model Eloquent oppure nei Repository a seconda che tu stia usando il Query Builder o le query SQL raw.

Sbagliato:

public function index()
{
    $clients = Client::verified()
        ->with(['orders' => function ($q) {
            $q->where('created_at', '>', Carbon::today()->subWeek());
        }])
        ->get();

    return view('index', ['clients' => $clients]);
}

Giusto:

public function index()
{
    return view('index', ['clients' => $this->client->getWithNewOrders()]);
}

class Client extends Model
{
    public function getWithNewOrders()
    {
        return $this->verified()
            ->with(['orders' => function ($q) {
                $q->where('created_at', '>', Carbon::today()->subWeek());
            }])
            ->get();
    }
}

Torna ai contenuti

Validazione

Sposta le logiche di validazione dai controller alle Request class.

Sbagliato:

public function store(Request $request)
{
    $request->validate([
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
        'publish_at' => 'nullable|date',
    ]);

    ...
}

Giusto:

public function store(PostRequest $request)
{
    ...
}

class PostRequest extends Request
{
    public function rules()
    {
        return [
            'title' => 'required|unique:posts|max:255',
            'body' => 'required',
            'publish_at' => 'nullable|date',
        ];
    }
}

Torna ai contenuti

La logica di business dovrebbe essere nella classe di servizio

Un controller deve avere una sola responsabilità, quindi sposta la logica di business dai controller alle classi di servizio.

Sbagliato:

public function store(Request $request)
{
    if ($request->hasFile('image')) {
        $request->file('image')->move(public_path('images') . 'temp');
    }
    
    ...
}

Giusto:

public function store(Request $request)
{
    $this->articleService->handleUploadedImage($request->file('image'));

    ...
}

class ArticleService
{
    public function handleUploadedImage($image)
    {
        if (!is_null($image)) {
            $image->move(public_path('images') . 'temp');
        }
    }
}

Torna ai contenuti

Non ripeterti (DRY: Don't Repeat Yourself)

Riutilizzare il codice quando è possibile. Il Principio di Singola Responsabilità (SRP) ti aiuta a evitare la duplicazione. Inoltre, riutilizza i template blade, usa gli eloquenti scopes, ecc.

Sbagliato:

public function getActive()
{
    return $this->where('verified', 1)->whereNotNull('deleted_at')->get();
}

public function getArticles()
{
    return $this->whereHas('user', function ($q) {
            $q->where('verified', 1)->whereNotNull('deleted_at');
        })->get();
}

Giusto:

public function scopeActive($q)
{
    return $q->where('verified', 1)->whereNotNull('deleted_at');
}

public function getActive()
{
    return $this->active()->get();
}

public function getArticles()
{
    return $this->whereHas('user', function ($q) {
            $q->active();
        })->get();
}

Torna ai contenuti

Favorisci l'utilizzo dei Model Eloquent rispetto al Query Builder e alle query SQL raw. Preferisci le Collection agli array

Eloquent ti consente di scrivere codice leggibile e manutenibile. Inoltre, Eloquent ha ottimi strumenti integrati come eliminazioni soft, eventi, scopes, ecc.

Sbagliato:

SELECT *
FROM `articles`
WHERE EXISTS (SELECT *
              FROM `users`
              WHERE `articles`.`user_id` = `users`.`id`
              AND EXISTS (SELECT *
                          FROM `profiles`
                          WHERE `profiles`.`user_id` = `users`.`id`) 
              AND `users`.`deleted_at` IS NULL)
AND `verified` = '1'
AND `active` = '1'
ORDER BY `created_at` DESC

Giusto:

Article::has('user.profile')->verified()->latest()->get();

Torna ai contenuti

Assegnazione di massa

Sbagliato:

$article = new Article;
$article->title = $request->title;
$article->content = $request->content;
$article->verified = $request->verified;

// Add category to article
$article->category_id = $category->id;
$article->save();

Giusto:

$category->article()->create($request->validated());

Torna ai contenuti

Non eseguire query nei template Blade e utilizzare l'eager loading (problema N + 1)

Sbagliato (per 100 utenti, verranno eseguite 101 query DB):

@foreach (User::all() as $user)
    {{ $user->profile->name }}
@endforeach

Giusto (per 100 utenti, verranno eseguite 2 query DB):

$users = User::with('profile')->get();

@foreach ($users as $user)
    {{ $user->profile->name }}
@endforeach

Torna ai contenuti

Commenta il tuo codice, ma cerca anche di rendere autoesplicativi i nomi di metodi e variabili

Sbagliato:

if (count((array) $builder->getQuery()->joins) > 0)

Meglio:

// Determine if there are any joins.
if (count((array) $builder->getQuery()->joins) > 0)

Giusto:

if ($this->hasJoins())

Torna ai contenuti

Non inserire JS e CSS nei templte Blade e non inserire HTML nelle classi PHP

Sbagliato:

let article = `{{ json_encode($article) }}`;

Meglio:

<input id="article" type="hidden" value='@json($article)'>

Or

<button class="js-fav-article" data-article='@json($article)'>{{ $article->name }}<button>

In un file Javascript:

let article = $('#article').val();

Il modo migliore è utilizzare il pacchetto PHP-JS specializzato per trasferire i dati.

Torna ai contenuti

Usa file di configurazione e lingua, costanti anziché testo nel codice

Sbagliato:

public function isNormal()
{
    return $article->type === 'normal';
}

return back()->with('message', 'Your article has been added!');

Giusto:

public function isNormal()
{
    return $article->type === Article::TYPE_NORMAL;
}

return back()->with('message', __('app.article_added'));

Torna ai contenuti

Utilizzare gli strumenti standard Laravel accettati dalla community

Favorisci l'utilizzo delle funzionalità integrate in Laravel e i pacchetti della community anziché utilizzare pacchetti e strumenti di terze parti. Altrimenti, qualsiasi sviluppatore che lavorerà con la tua app in futuro dovrà imparare nuovi strumenti. Inoltre, le possibilità di ottenere aiuto dalla comunità Laravel sono significativamente inferiori quando si utilizza un pacchetto o uno strumento di terze parti. Non far pagare il tuo cliente per quello.

Task Strumenti standard Strumenti di terze parti
Autorizzazione Policies Entrust, Sentinel e altri pacchetti
Compiling assets Laravel Mix, Vite Grunt, Gulp, pacchetti terzi
Ambiente di sviluppo Laravel Sail, Homestead Docker
Distribuzione Laravel Forge Deployer e altre soluzioni
Test unitari PHPUnit, Mockery Phpspec, Pest
Test dal browser Laravel Dusk Codeception
DB Eloquent, Query Builder SQL, Doctrine
Template Blade Twig
Lavorare con i dati Laravel collection Array
Validazione form Form Request Pacchetti di terze parti, convalida nel controller
Autenticazione Incorporato Pacchetti di terze parti, la tua soluzione
Autenticazione API Laravel Passport, Laravel Sanctum Pacchetti JWT e OAuth di terze parti
Creazione dell'API Incorporato API Dingo e pacchetti simili
Lavorare con la struttura DB Migrazioni Lavorare direttamente con la struttura DB
Localizzazione Incorporato Pacchetti di terze parti
Interfacce utente in tempo reale Laravel Echo, Pusher Pacchetti di terze parti e funzionamento diretto con WebSocket
Generazione di dati di test Seeder, Model Factories, Faker Creazione manuale dei dati di test
Pianificazione delle attività Laravel Task Scheduler Script e pacchetti di terze parti
DB MySQL, PostgreSQL, SQLite, SQL Server MongoDB

Torna ai contenuti

Segui le naming convention di Laravel

Seguire Standard PSR.

Inoltre, segui le convenzioni di denominazione accettate dalla comunità Laravel:

Cosa Come Giusto Sbagliato
Controller singolare ArticleController ArticlesController
Route plurale articles/1 article/1
Route name snake_case con notazione punto users.show_active users.show-active, show-active-users
Model singolare User Users
Relazioni hasOne o belongsTo singolare articleComment articleComments, article_comment
Tutte le altre relazioni plurale articleComments articleComment, article_comments
Tabella plurale article_comments article_comment, articleComments
Tabella pivot nomi di modelli singolari in ordine alfabetico article_user user_article, articles_users
Colonna della tabella snake_case senza nome modello meta_title Meta Title; articolo meta_title
Proprietà del Model snake_case $ model->created_at $model->createdAt
Foreign key modello in singolare con un suffisso _id article_id ArticleId, id_article, articles_id
Chiave primaria - id custom_id
Migration - 2017_01_01_000000_create_articles_table 2017_01_01_000000_articles
Metodo camelCase getAll get_all
Metodo nel resource controller resource store saveArticle
Metodo nella test class camelCase testGuestCannotSeeArticle test_guest_cannot_see_article
Variabile camelCase $articolesWithAuthor $articles_with_author
Collection descrittivo, plurale $activeUsers = User::active()->get() $active, $data
Oggetto descrittivo, singolare $activeUser = User::active()->first() $users, $obj
Indice file di configurazione e lingua snake_case articles_enabled ArticlesEnabled; articles-enabled
View kebab-case show-filtered.blade.php showFiltered.blade.php, show_filtered.blade.php
Config snake_case google_calendar.php googleCalendar.php, google-calendar.php
Contratto (interfaccia) aggettivo o sostantivo AuthenticationInterface Authenticatable, IAuthentication
Trait aggettivo Notificabile NotificationTrait
Trait (PSR) adjective NotifiableTrait Notification
Enum singular UserType UserTypes, UserTypeEnum
FormRequest singular UpdateUserRequest UpdateUserFormRequest, UserFormRequest, UserRequest
Seeder singular UserSeeder UsersSeeder

Torna ai contenuti

Utilizzare una sintassi più breve e più leggibile ove possibile

Sbagliato:

$request->session()->get('cart');
$request->input('name');

Giusto:

session('cart');
$request->name;

Più esempi:

Common syntax Shorter and more readable syntax
Session::get('cart') session('cart')
$request->session()->get('cart') session('cart')
Session::put('cart', $data) session(['cart' => $data])
$request->input('name'), Request::get('name') $request->name, request('name')
return Redirect::back() return back()
is_null($object->relation) ? null : $object->relation->id optional($object->relation)->id
return view('index')->with('title', $title)->with('client', $client) return view('index', compact('title', 'client'))
$request->has('value') ? $request->value : 'default'; $request->get('value', 'default')
Carbon::now(), Carbon::today() now(), today()
App::make('Class') app('Class')
->where('column', '=', 1) ->where('column', 1)
->orderBy('created_at', 'desc') ->latest()
->orderBy('age', 'desc') ->latest('age')
->orderBy('created_at', 'asc') ->oldest()
->select('id', 'name')->get() ->get(['id', 'name'])
->first()->name ->value('name')

Torna ai contenuti

Utilizzare il container IoC o i Facades invece di istanziare nuove classi

La sintassi new Class crea un accoppiamento stretto tra le classi e complica i test. Utilizzare invece il container IoC o i Facades.

Sbagliato:

$user = new User;
$user->create($request->validated());

Giusto:

public function __construct(User $user)
{
    $this->user = $user;
}

...

$this->user->create($request->validated());

Torna ai contenuti

Non prelevare direttamente i dati dal file .env

Passa i dati presenti nell'.env file ai file di configurazione e quindi usa l'helper config () per prelevare i dati all'interno dell'applicazione.

Sbagliato:

$apiKey = env('API_KEY');

Giusto:

// config/api.php
'key' => env('API_KEY'),

// Use the data
$apiKey = config('api.key');

Torna ai contenuti

Memorizza le date nel formato standard. Utilizza gli accessors e i mutators per modificare il formato della data

Sbagliato:

{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->toDateString() }}
{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->format('m-d') }}

Giusto:

// Model
protected $casts = [
    'ordered_at' => 'datetime',
];

public function getSomeDateAttribute($date)
{
    return $date->format('m-d');
}

// View
{{ $object->ordered_at->toDateString() }}
{{ $object->ordered_at->some_date }}

Torna ai contenuti

Altre buone pratiche

Non inserire mai alcuna logica nei file di route.

Ridurre al minimo l'utilizzo di vanilla PHP nei template Blade.

Torna ai contenuti