Translations:
Nederlands (by Protoqol)
한국어 (by cherrypick)
ภาษาไทย (by kongvut sangkla)
فارسی (by amirhossein baghaie)
Українська (by Tenevyk)
Tiếng Việt (by Chung Nguyễn)
Español (by César Escudero)
Français (by Mikayil S.)
Polski (by Maciej Jeziorski)
Deutsche (by Sujal Patel)
Italiana (by Sujal Patel)
Es handelt sich nicht um eine Laravel-Anpassung von SOLID-Prinzipien, Mustern usw. Hier finden Sie die Best Practices, die in echten Laravel-Projekten normalerweise ignoriert werden.
Prinzip der Einzelverantwortung
Fette Models, dünne Controller
Geschäftslogik sollte in der Serviceklasse sein
Führen Sie keine Abfragen in Blade-Vorlagen aus und verwenden Sie das eifrige Laden (N + 1-Problem).
Setzen Sie JS und CSS nicht in Blade-Vorlagen und setzen Sie kein HTML in PHP-Klassen
Verwenden Sie Konfigurations- und Sprachdateien, 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 -Fassaden anstelle der neuen Klasse
Rufen Sie keine Daten direkt aus der ENV-Datei ab
Eine Klasse und eine Methode sollten nur eine Verantwortung haben.
Schlecht:
public function getFullNameAttribute()
{
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()
{
return $this->isVerifiedClient() ? $this->getFullNameLong() : $this->getFullNameShort();
}
public function isVerifiedClient()
{
return auth()->user() && auth()->user()->hasRole('client') && auth()->user()->isVerified();
}
public function getFullNameLong()
{
return 'Mr. ' . $this->first_name . ' ' . $this->middle_name . ' ' . $this->last_name;
}
public function getFullNameShort()
{
return $this->first_name[0] . '. ' . $this->last_name;
}
Fügen Sie die gesamte DB-bezogene Logik in Eloquent-Modelle oder in Repository-Klassen ein, wenn Sie Query Builder oder Raw SQL-Abfragen 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();
}
}
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',
];
}
}
Ein Controller muss nur eine Verantwortung haben. 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');
}
}
}
Code wiederverwenden, wenn Sie können. SRP hilft Ihnen, Doppelarbeit zu vermeiden. Verwenden Sie auch Blade-Vorlagen, eloquente Bereiche usw.
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();
}
Verwenden Sie lieber Eloquent als Query Builder und SQL-Rohdatenabfragen. Ziehen Sie Sammlungen Arrays vor
Mit Eloquent können Sie 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();
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());
Führen Sie keine Abfragen in Blade-Vorlagen aus und verwenden Sie das eifrige Laden (N + 1-Problem).
Schlecht (for 100 users, 101 DB queries will be executed):
@foreach (User::all() as $user)
{{ $user->profile->name }}
@endforeach
Gut (for 100 users, 2 DB queries will be executed):
$users = User::with('profile')->get();
...
@foreach ($users as $user)
{{ $user->profile->name }}
@endforeach
Kommentieren Sie Ihren Code, bevorzugen Sie jedoch beschreibende Methoden- und Variablennamen gegenüber Kommentaren
Schlecht:
if (count((array) $builder->getQuery()->joins) > 0)
Better:
// Determine if there are any joins.
if (count((array) $builder->getQuery()->joins) > 0)
Gut:
if ($this->hasJoins())
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.
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'));
Verwenden Sie vorzugsweise integrierte Laravel-Funktionen und Community-Pakete, anstatt Pakete und Tools von Drittanbietern zu verwenden. Jeder Entwickler, der in Zukunft mit Ihrer App arbeitet, muss 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 |
---|---|---|
Genehmigung | Richtlinien | Entrust, Sentinel und andere Pakete |
Assets zusammenstellen Laravel Mix | Grunzen, Schlucken, 3rd-Party-Pakete | |
Entwicklungsumgebung | Gehöft | Docker |
Bereitstellung | Laravel Forge | Deployer und andere Lösungen |
Einzelprüfung | PHPUnit, Spott | Phpspec |
Browsertests | Laravel Dämmerung | Codezeption |
DB | Eloquent | SQL, Lehre |
Vorlagen | Klinge | Zweig |
Mit Daten arbeiten | Laravel Sammlungen | Arrays |
Formularvalidierung | Klassen anfordern | Pakete von Drittanbietern, Validierung im Controller |
Authentifizierung | Eingebaut | Pakete von Drittanbietern, Ihre eigene Lösung |
API-Authentifizierung | Laravel Passport | JWT- und OAuth-Pakete von Drittanbietern |
API erstellen | Eingebaut | Dingo API und ähnliche Pakete |
Mit DB-Struktur arbeiten | Migrationen | Direkt mit der DB-Struktur arbeiten |
Lokalisierung | Eingebaut | Pakete von Drittanbietern |
Echtzeit-Benutzeroberflächen | Laravel Echo, Drücker | Pakete von Drittanbietern und direktes Arbeiten mit WebSockets |
Testdaten generieren | Sämaschinenklassen, Modellfabriken, Faker | Testdaten manuell erstellen |
Aufgabenplanung | Laravel Task Scheduler | Skripte und Pakete von Drittanbietern |
DB | MySQL, PostgreSQL, SQLite, SQL Server | MongoDB |
Folgen PSR standards.
Befolgen Sie außerdem die von der Laravel-Community akzeptierten Namenskonventionen:
Was | Wie | Gut | Schlecht |
---|---|---|---|
Controller | Singular | ArticleController | |
Route | plural | Artikel / 1 | |
Benannte Route | snake_case mit Punktnotation | users.show_active | |
Modell | Singular | Benutzer | |
hasOne oder Zugehörigkeit zu einer Beziehung Singular | articleComment | ||
Alle anderen Beziehungen plural | articleComments | ||
Tisch | plural | article_comments | |
Schwenktisch | Singuläre Modellnamen in alphabetischer Reihenfolge article_user | ||
Tabellenspalte | snake_case ohne Modellname | meta_title | |
Modelleigenschaft | snake_case | $ model-> created_at | |
Fremdschlüssel | singulärer Modellname mit Suffix _id | article_id | |
Primärschlüssel | - | id | |
Migration | - | 2017_01_01_000000_create_articles_table | |
Methode | camelCase | getAll | |
Methode im Ressourcencontroller | table | Geschäft | |
Methode in der Testklasse camelCase | testGuestCannotSeeArticle | ||
Variable | camelCase | $ articlesWithAuthor | |
Sammlung | beschreibend, Plural | $ activeUsers = User :: active () -> get () | |
Objekt | beschreibend, einzigartig $ activeUser = User :: active ()->first() | ||
Konfigurations- und Sprachdateien index | snake_case | articles_enabled | |
Ansicht | Döner-Etui | show-filtered.blade.php | |
Config | snake_case | google_calendar.php | |
Vertrag (Schnittstelle) | Adjektiv oder Substantiv Authentifizierbar | ||
Merkmal | Adjektiv | Meldepflichtig |
Schlecht:
$request->session()->get('cart');
$request->input('name');
Gut:
session('cart');
$request->name;
Mehr Beispiele:
Gemeinsame 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') |
Die neue Klassensyntax sorgt für eine enge Kopplung zwischen den Klassen und erschwert das Testen. Verwenden Sie stattdessen einen IoC-Container oder Fassaden.
Schlecht:
$user = new User;
$user->create($request->validated());
Gut:
public function __construct(User $user)
{
$this->user = $user;
}
....
$this->user->create($request->validated());
Übergeben Sie die Daten stattdessen an Konfigurationsdateien und verwenden Sie dann die Hilfefunktion config ()
, um die Daten in einer Anwendung zu verwenden.
Schlecht:
$apiKey = env('API_KEY');
Gut:
// config/api.php
'key' => env('API_KEY'),
// Use the data
$apiKey = config('api.key');
Speichern Sie Daten im Standardformat. Verwenden Sie Accessoren und Mutatoren, um das Datumsformat zu ändern
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', 'created_at', 'updated_at'];
public function getSomeDateAttribute($date)
{
return $date->format('m-d');
}
// View
{{ $object->ordered_at->toDateString() }}
{{ $object->ordered_at->some_date }}
Fügen Sie niemals Logik in Routendateien ein.
Minimieren Sie die Verwendung von Vanille-PHP in Blade-Vorlagen.