Skip to content

Latest commit

 

History

History
636 lines (451 loc) · 19.7 KB

german.md

File metadata and controls

636 lines (451 loc) · 19.7 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 woeichern)

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

বাংলা (by Anowar Hossain)

فارسی (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)

Azərbaycanca (by Maharramoff)

العربية (by ahmedsaoud31)

اردو (by RizwanAshraf1)

Laravel example app

Inhaltsverzeichnis

Single-Responsibility-Prinzip

Fette Models, schlanke Controller

Validierung

Geschäftslogik sollte in einer Serviceklasse sein

Wiederholen Sie sich nicht / Don't repeat yourself (DRY)

Verwenden Sie Eloquent anstelle des Query Builders und rohen SQL-Abfragen. Bevorzugen Sie Collections gegenüber Arrays

Massenzuordnung

Führen Sie keine Abfragen in Blade-Templates aus und verwenden Sie eager loading (N + 1-Problem)

Kommentieren Sie Ihren Code, aber bevorzugen Sie beschreibende Methoden- und Variablennamen gegenüber Kommentaren

Schreiben Sie kein JS und CSS in Blade-Templates und schreiben Sie kein HTML in PHP-Klassen

Verwenden Sie Konfigurations- und Sprachdateien und Konstanten anstelle von Text im Code

Verwenden Sie Standard-Laravel-Tools, die von der Community akzeptiert werden

Befolgen Sie die Namenskonventionen von Laravel

Verwenden Sie nach Möglichkeit eine kürzere und besser lesbare Syntax

Verwenden Sie IoC-Container oder Facades, statt neue Klassen zu instanziieren

Rufen Sie Daten nicht direkt aus der .env-Datei ab

Speichern Sie Datumsangaben im Standardformat. Verwenden Sie Accessoren und Mutatoren, um das Datumsformat zu ändern

Andere gute Praktiken

Single-Responsibility-Prinzip

Eine Klasse und eine Methode sollten nur eine Verantwortung haben.

Schlecht:

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;
    }
}

Gut:

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;
}

🔝 Zurück zum Inhaltsverzeichnis

Fette Models, schlanke Controller

Fügen Sie die gesamte DB-bezogene Logik in Eloquent-Models oder in Repository-Klassen ein, wenn Sie Query Builder oder SQL-Rohabfragen verwenden.

Schlecht:

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

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

Gut:

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();
    }
}

🔝 Zurück zum Inhaltsverzeichnis

Validierung

Verschieben Sie die Validierung von Controllern in Request-Klassen.

Schlecht:

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

    ...
}

Gut:

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',
        ];
    }
}

🔝 Zurück zum Inhaltsverzeichnis

Geschäftslogik sollte in einer Serviceklasse sein

Ein Controller darf nur eine Verantwortung haben, also verschieben Sie die Geschäftslogik von Controllern in Serviceklassen.

Schlecht:

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

Gut:

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');
        }
    }
}

🔝 Zurück zum Inhaltsverzeichnis

Wiederholen Sie sich nicht / Don't repeat yourself (DRY)

Verwenden Sie Code wieder, wenn Sie können. Das Single-Responsibility-Prinzip (SRP) hilft Doppelarbeit zu vermeiden. Verwenden Sie auch Blade Templates, Eloquent Scopes etc. wieder.

Schlecht:

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();
}

Gut:

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();
}

🔝 Zurück zum Inhaltsverzeichnis

Verwenden Sie lieber Eloquent anstelle des Query Builders und rohen SQL-Abfragen. Bevorzugen Sie Collections gegenüber Arrays

Eloquent ermöglicht es, lesbaren und wartbaren Code schreiben. Außerdem verfügt Eloquent über großartige integrierte Tools wie Soft Deletes, Events, Scopes usw.

Schlecht:

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

Gut:

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

🔝 Zurück zum Inhaltsverzeichnis

Massenzuordnung

Schlecht:

$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();

Gut:

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

🔝 Zurück zum Inhaltsverzeichnis

Führen Sie keine Abfragen in Blade-Templates aus und verwenden Sie eager loading (N + 1-Problem)

Schlecht (für 100 Benutzer werden 101 Datenbankabfragen ausgeführt):

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

Gut (für 100 Benutzer werden 2 Datenbankabfragen ausgeführt):

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

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

🔝 Zurück zum Inhaltsverzeichnis

Kommentieren Sie Ihren Code, aber bevorzugen Sie beschreibende Methoden- und Variablennamen gegenüber Kommentaren

Schlecht:

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

Besser:

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

Gut:

if ($this->hasJoins())

🔝 Zurück zum Inhaltsverzeichnis

Schreiben Sie kein JS und CSS in Blade-Templates und schreiben Sie kein HTML in PHP-Klassen

Schlecht:

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

Besser:

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

oder

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

In einer JavaScript-Datei:

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

Am besten verwenden Sie ein spezielles PHP-zu-JS-Paket, um die Daten zu übertragen.

🔝 Zurück zum Inhaltsverzeichnis

Verwenden Sie Konfigurations- und Sprachdateien und Konstanten anstelle von Text im Code

Schlecht:

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

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

Gut:

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

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

🔝 Zurück zum Inhaltsverzeichnis

Verwenden Sie Standard-Laravel-Tools, die von der Community akzeptiert werden

Verwenden Sie vorzugsweise integrierte Laravel-Funktionen und Community-Pakete, anstatt Pakete und Tools von Drittanbietern zu verwenden. Ansonsten muss jeder Entwickler, der in Zukunft an Ihrer App arbeitet, neue Tools erlernen. Außerdem sind die Chancen, Hilfe von der Laravel-Community zu erhalten, erheblich geringer, wenn Sie ein Paket oder Tool eines Drittanbieters verwenden. Lassen Sie Ihren Kunden nicht dafür bezahlen.

Aufgabe Standardwerkzeuge Tools von Drittanbietern
Autorisierung Policies Entrust, Sentinel und andere Pakete
Assets kompilieren Laravel Mix, Vite Grunt, Gulp, 3rd-Party-Pakete
Entwicklungsumgebung Laravel Sail, Homestead Docker
Bereitstellung Laravel Forge Deployer und andere Lösungen
Unit Tests PHPUnit, Mockery Phpspec, Pest
Browsertests Laravel Dusk Codeception
DB Eloquent SQL, Doctrine
Templates Blade Twig
Mit Daten arbeiten Laravel Collections Arrays
Formularvalidierung Request-Klassen Pakete von Drittanbietern, Validierung im Controller
Authentifizierung Integriert Pakete von Drittanbietern, Ihre eigene Lösung
API-Authentifizierung Laravel Passport, Laravel Sanctum JWT- und OAuth-Pakete von Drittanbietern
API erstellen Integriert Dingo API und ähnliche Pakete
Mit DB-Struktur arbeiten Migrationen Direkt mit der DB-Struktur arbeiten
Lokalisierung Integriert Pakete von Drittanbietern
Echtzeit-Benutzeroberflächen Laravel Echo, Pusher Pakete von Drittanbietern und direktes Arbeiten mit WebSockets
Testdaten generieren Seeder-Klassen, Model Factories, Faker Testdaten manuell erstellen
Aufgabenplanung Laravel Task Scheduler Skripte und Pakete von Drittanbietern
DB MySQL, PostgreSQL, SQLite, SQL Server MongoDB

🔝 Zurück zum Inhaltsverzeichnis

Befolgen Sie die Namenskonventionen von Laravel

Folgen Sie den PSR standards.

Befolgen Sie außerdem die von der Laravel-Community akzeptierten Namenskonventionen:

Was Wie Gut Schlecht
Controller singular ArticleController ArticlesController
Route plural articles/1 article/1
Benannte Route snake_case mit Punktnotation users.show_active users.show-active, show-active-users
Model singular User Users
hasOne oder belongsTo Beziehung singular articleComment articleComments, article_comment
Alle anderen Beziehungen plural articleComments articleComment, article_comments
Tabelle Plural article_comments article_comment, articleComments
Pivot-Tabelle singuläre Modellnamen in alphabetischer Reihenfolge article_user user_article, articles_users
Tabellenspalte snake_case ohne Modellname meta_title MetaTitle; article_title_title
Model-Eigenschaft snake_case $model->created_at $model->createdAt
Fremdschlüssel singulärer Modellname mit Suffix _id article_id ArticleId, id_article, articles_id
Primärschlüssel - id custom_id
Migration - 2017_01_01_000000_create_articles_table 2017_01_01_000000_articles
Methode camelCase getAll get_all
Methode im Ressourcencontroller Tabelle store saveArticle
Methode in einer Testklasse camelCase testGuestCannotSeeArticle test_guest_cannot_see_article
Variable camelCase $articlesWithAuthor $articles_with_author
Collection beschreibend, plural $activeUsers = User::active()->get() $active, $data
Objekt beschreibend, singular $activeUser = User::active()->first() $users, $obj
Konfigurations- und Sprachdateien index 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
Vertrag (Interface) Adjektiv oder Substantiv AuthenticationInterface Authenticatable, IAuthentication
Trait Adjektiv Notifiable NotificationTrait
Trait (PSR) adjective NotifiableTrait Notification
Enum singular UserType UserTypes, UserTypeEnum
FormRequest singular UpdateUserRequest UpdateUserFormRequest, UserFormRequest, UserRequest
Seeder singular UserSeeder UsersSeeder

🔝 Zurück zum Inhaltsverzeichnis

Verwenden Sie nach Möglichkeit eine kürzere und besser lesbare Syntax

Schlecht:

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

Gut:

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

Mehr Beispiele:

Gängige Syntax Kürzere und lesbarere 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')

🔝 Zurück zum Inhaltsverzeichnis

Verwenden Sie IoC-Container oder Facades, statt neue Klassen zu instanziieren

Die Syntax new Class erzeugt eine enge Kopplung zwischen Klassen und erschwert dadurch das Testen. Verwenden Sie stattdessen IoC-Container oder Facades.

Schlecht:

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

Gut:

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

...

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

🔝 Zurück zum Inhaltsverzeichnis

Rufen Sie Daten nicht direkt aus der .env-Datei ab

Übergeben Sie die Daten stattdessen an eine Konfigurationsdatei und verwenden Sie dann die Hilfsfunktion config(), um die Daten in ihrer Anwendung zu verwenden.

Schlecht:

$apiKey = env('API_KEY');

Gut:

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

// Verwendung der Daten
$apiKey = config('api.key');

🔝 Zurück zum Inhaltsverzeichnis

Speichern Sie Datumsangaben im Standardformat. Verwenden Sie Accessoren und Mutatoren, um das Datumsformat zu ändern

Strings für Datums sind generell weniger belastbar als Objekte (z.B. Carbon Objekte). Es ist empfehlenswert Carbon-Instanzen zwischen Klassen zu übergeben. Formatierung sollte in den blade Dateien erfolgen:

Schlecht:

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

Gut:

// Model
protected $dates = [
    'ordered_at',
];

// Blade view
{{ $object->ordered_at->toDateString() }}
{{ $object->ordered_at->format('m-d') }}

🔝 Zurück zum Inhaltsverzeichnis

Andere gute Praktiken

Logik sollte nicht in Routes Dateien eingebaut werden.

Minimieren Sie die Verwendung von Vanilla PHP in Blade-Templates.

🔝 Zurück zum Inhaltsverzeichnis