Laravel Tips Clean Code: Rendez votre code Laravel plus propre et plus sûr #2
Arthur Monney
@mckenziearts
Après le premier épisode de Laravel Tips Clean Code nous ouvrons l'épisode ✌🏾. Si vous n'avez pas lu la première partie nous vous invitons à vous rendre sur cet article
Éviter les classes d'aide (Helper Class)
Parfois, les dévéloppeurs mettent des helpers dans une classe.
Attention, cela peut devenir désordonné. Ceci est une classe avec uniquement des méthodes statiques utilisées comme fonctions d'aide. Il est généralement préférable de placer ces méthodes dans des classes ayant une logique connexe ou de les conserver comme fonctions globales.
❌ Mauvais
class Helper { public function convertCurrency(Money $money, string $currency): self { // We're converting from current currency, to base currency and finally to the new currency $newCurrencyConfig = config("shop.currencies.$currency"); $mathDecimalDifference = $newCurrencyConfig['math_decimals'] - config("shop.currencies." . config('shop.base_currency') return new static( (int) round($money->baseValue() * $newCurrencyConfig['value'] * 10**$mathDecimalDifference, 0), $currency ); }} // Usage:use App\Helper; Helper::convertCurrency($total, 'EUR');
✅ Correct
class Money { // the other money/currency logic public function convertTo(string $currency): self { // We're converting from current currency, to base currency and finally to the new currency $newCurrencyConfig = config("shop.currencies.$currency"); $mathDecimalDifference = $newCurrencyConfig['math_decimals'] - config("shop.currencies." . config('shop.base_currency') return new static( (int) round($this->baseValue() * $newCurrencyConfig['value'] * 10**$mathDecimalDifference, 0), $currency ); }} // Usage$EURtotal = $total->convertTo('EUR');
Consacrez un week-end à l'apprentissage de la POO
Connaissez la différence entre les méthodes et les variables statiques/instance
et la visibilité privée/protégée/publique
. Apprenez également comment Laravel utilise les méthodes magiques.
Vous n'en avez pas besoin en tant que débutant, mais à mesure que votre code se développe, c'est crucial.
Ne vous contentez pas d'écrire du code procédural dans des classes
Cela relie le tip précédent avec les autres conseils ici. La POO existe pour rendre votre code plus lisible, utilisez-la. N'écrivez pas seulement du code procédural de 400 lignes dans les actions du contrôleur.
Utilisez des objets de transfert de données (DTO)
Plutôt que de passer une quantité énorme d'arguments dans un ordre spécifique, envisagez de créer un objet avec des propriétés pour stocker ces données.
Des points bonus si vous trouvez que certains comportements peuvent être déplacés dans cet objet.
❌ Mauvais
public function log($url, $route_name, $route_data, $campaign_code, $traffic_source, $referer, $user_id, $visitor_id, $ip, $tim){ // ...}
✅ Correct
public function log(Visit $visit){ // ...} class Visit { public string $url; public ?string $routeName; public array $routeData; public ?string $campaign; public array $trafficSource = []; public ?string $referer; public Carbon $timestamp; // ... }
Créer des objets fluent (chainage)
Vous pouvez également créer des objets avec des API fluent. Ajoutez progressivement des données par le biais d'appels distincts, et n'exigez que le strict minimum dans le constructeur.
Chaque méthode renvoie $this
, vous pouvez donc vous arrêter à n'importe quel appel.
Visit::make($url, $routeName, $routeData) ->withCampaign($campaign) ->withTrafficSource($trafficSource) ->withReferer($referer)// ... etc
Utiliser des collections personnalisées
La création de collections personnalisées peut être un excellent moyen d'obtenir une syntaxe plus expressive. Prenons cet exemple avec les totaux des commandes.
❌ Mauvais
$total = $order->products->sum(function (OrderProduct $product) { return $product->price * $product->quantity * (1 + $product->vat_rate);});
✅ Correct
$order->products->total(); class OrderProductCollection extends Collection{ public function total() { $this->sum(function (OrderProduct $product) { return $product->price * $product->quantity * (1 + $product->vat_rate); }); }}
N'utilisez pas d'abréviations
Ne pensez pas que les longs noms de variables/méthodes sont mauvais. Ils ne le sont pas. Ils sont expressifs.
Il vaut mieux appeler une méthode longue qu'une courte et vérifier le bloc de documentation pour comprendre ce qu'elle fait. Il en va de même pour les variables. N'utilisez pas d'abréviations absurdes de 3 lettres.
❌ Mauvais
$ord = Order::create($data); // ... $ord->notify();
✅ Correct
$order = Order::create($data); // ... $order->sendCreatedNotification();
Créer des traits à usage unique
L'ajout de méthodes aux classes auxquelles elles appartiennent est plus propre que la création de classes d'action pour tout, mais cela peut faire grossir les classes.
Envisagez d'utiliser des traits. Ils sont conçus principalement pour la réutilisation du code, mais il n'y a rien de mal à utiliser des traits à usage unique.
❌ Mauvais
class Order extends Model{ public static function bootHasStatuses() { ... } public static $statusMap = [ ... ]; public static function getStatusId($status) { ... } public function getPaymentStatusAttribute(): OrderPaymentStatus { ... } // ... }
✅ Correct
class Order extends Model{ use HasStatuses; // ... } trait HasStatuses{ public static function bootHasStatuses() { ... } public static $statusMap = [ ... ]; public static function getStatusId($status) { ... } public function getPaymentStatusAttribute(): OrderPaymentStatus { ... } // ...}
Importer des namespaces au lieu d'alias
Parfois, vous pouvez avoir plusieurs classes avec le même nom. Plutôt que de les importer avec un alias, importez les namespaces.
❌ Mauvais
use App\Types\Entries\Visit as VisitEntry;use App\Storage\Database\Models\Visit as VisitModel; class DatabaseStorage{ public function log(VisitEntry $visit) { $visitModel = VisitModel::create([ ... ]); }}
✅ Correct
use App\Types\Entries;use App\Storage\Database\Models; class DatabaseStorage{ public function log(Entries\Visit $visit) { $visitModel = Models\Visit::create([ ... ]); }}
Créer des scopes pour les where()s complexes
Plutôt que d'écrire des clauses where() complexes, créez des scopes avec des noms expressifs. Ainsi, vos contrôleurs par exemple auront moins besoin de connaître la structure de la base de données et votre code sera plus propre.
❌ Mauvais
Order::whereHas('status', function ($status) { $status->where('canceled', true);})->get();
✅ Correct
Order::whereCanceled()->get(); class Order extends Model{ public function scopeWhereCanceled(Builder $query) { return $query->whereHas('status', function ($status) { $status->where('canceled', true); }); }}
Arthur Monney
@mckenziearts
Fullstack Designer - Laravel & React Developer. Laravel Cameroon Organizer @laravelcm | @shopperlabs