Laravel Astuces
5 min de lecture 378 vues

Laravel Tips Clean Code: Rendez votre code Laravel plus propre et plus sûr #2

mckenziearts

Arthur Monney

@mckenziearts

Laravel Tips Clean Code: Rendez votre code Laravel plus propre et plus sûr #2

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

Arthur Monney

@mckenziearts

Fullstack Designer - Laravel & React Developer. Laravel Cameroon Organizer @laravelcm | @shopperlabs

Vous aimez cet article ? Faite le savoir en partageant