laravel migration add column

Laravel è uno dei framework PHP più popolari, ma anche gli sviluppatori più esperti possono incontrare difficoltà.

In questo articolo, ti guiderò attraverso dieci problemi frequenti che potresti incontrare nello sviluppo con Laravel, e ti fornirò soluzioni pratiche e verificate.

Vulnerabilità dell’assegnazione di massa

Problema: quando si utilizzano metodi create()update() senza un’adeguata protezione, gli utenti possono modificare campi a cui non dovrebbero avere accesso, come i campi is_adminrole.

Soluzione: utilizzare la proprietà $fillable$guarded nel modello Eloquent. La proprietà $fillable è una whitelist di campi che possono essere assegnati in massa:

class User extends Model {
    protected $fillable = ['name', 'email', 'password'];
}

In alternativa, utilizzare $guarded per inserire nella blacklist campi specifici:

protected $guarded = ['id', 'is_admin', 'role'];

Problema di query N+1

Il problema: si recuperano gli utenti e poi si scorre tutto l’elenco in struttura per ottenere i loro post, il che provoca una query per gli utenti e N query aggiuntive per i loro post.

$users = User::all();
foreach ($users as $user) {
    echo $user->posts; // Esegue una query per ogni utente 
}

La soluzione: utilizzare il caricamento eager di Eloquent con il metodo with():

$users = User::with('posts')->get();
foreach ($users as $user) {
    echo $user->posts; // Non ci sono query aggiuntive
}

Problemi di autenticazione con Custom Guards

Problema: devi autenticare diversi tipi di utenti (amministratore, cliente, fornitore), ma la protezione predefinita non è adatta alle tue esigenze.

La soluzione: crea protezioni personalizzate nel file di configurazione config/auth.php:

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],
    'admin' => [
        'driver' => 'session',
        'provider' => 'admins',
    ],
],
'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\Models\User::class,
    ],
    'admins' => [
        'driver' => 'eloquent',
        'model' => App\Models\Admin::class,
    ],
],

Quindi utilizzalo nel tuo middleware: Auth::guard('admin')->check()

Il binding del modello Route non va bene

Problema: si definisce un percorso con un parametro modello, ma viene restituito 404 anche se il record esiste.

Route::get('/posts/{post}', function (Post $post) {
    return $post;
});

La soluzione: assicurati che il nome del parametro di percorso corrisponda al nome della variabile del modello. In caso contrario, utilizza il binding implicito in RouteServiceProvider:

public function boot(): void {
    Route::model('post', Post::class);
}

Oppure utilizzare un binding esplicito:

Route::bind('post', function ($value) {
    return Post::where('slug', $value)->firstOrFail();
});

Middleware non eseguito nell’ordine corretto

Problema: il middleware viene eseguito in un ordine inaspettato, causando il fallimento dell’autenticazione o il mancato controllo delle autorizzazioni.

La soluzione: definire la priorità del middleware nel kernel HTTP. Creare un $middlewarePriorityarray in app/Http/Kernel.php:

protected $middlewarePriority = [
    \Illuminate\Foundation\Http\Middleware\HandlePreconditionRequests::class,
    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    \App\Http\Middleware\Authenticate::class,
    \App\Http\Middleware\CheckAdmin::class,
];

Errori CORS nelle richieste API

Problema: il tuo frontend non riesce a inviare richieste alla tua API Laravel a causa di errori CORS (Cross-Origin Resource Sharing).

La soluzione: configurare CORS in config/cors.php:

'paths' => ['api/*', 'sanctum/csrf-token'],
'allowed_methods' => ['*'],
'allowed_origins' => ['http://localhost:3000'], // Scrivi qui l'URL utilizzato
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => false,

Assicurati che il middleware HandleCors sia registrato nel tuo kernel HTTP.

Seeder non inserisce dati

Problema: esegui php artisan db:seed, ma nel tuo database non vengono scritti i dati.

La soluzione: assicurati che il tuo seeder sia registrato in database/seeders/DatabaseSeeder.php:

public function run(): void {
    $this->call([
        UserSeeder::class,
        PostSeeder::class,
        CommentSeeder::class,
    ]);
}

Quindi esegui: php artisan db:seed

Oppure resetta e inizializza con un unico comando: php artisan migrate:fresh --seed

Le eliminazioni temporanee non funzionano come previsto

Problema: quando si elimina temporaneamente un record, le query lo restituiscono comunque oppure non è possibile ripristinarlo correttamente.

La soluzione: assicurati che il tuo modello utilizzi il SoftDeletes:

use Illuminate\Database\Eloquent\SoftDeletes;
class Post extends Model {
    use SoftDeletes;
    
    protected $dates = ['deleted_at'];
}

Per interrogare solo i record attivi (esclusi quelli eliminati temporaneamente):

$posts = Post::all(); // Esclude implicitamente il softdeletes

Per includere i record eliminati temporaneamente:

$posts = Post::withTrashed()->get();

Per ripristinare un record eliminato temporaneamente:

$post = Post::withTrashed()->find($id);
$post->restore();

La cache non si aggiorna dopo le modifiche ai dati

Il problema: i risultati delle query vengono memorizzati nella cache, ma quando i dati cambiano, la cache non viene invalidata, mostrando informazioni obsolete.

La soluzione: invalidare manualmente la cache quando i dati cambiano. Utilizzare le chiavi della cache e cancellarle durante gli aggiornamenti:

// Nel tuo controller o service
public function updatePost($id, $data) {
    $post = Post::find($id);
    $post->update($data);
    
    Cache::forget("post_{$id}");
    return $post;
}
// Durante il recupero
public function getPost($id) {
    return Cache::remember("post_{$id}", 3600, function () use ($id) {
        return Post::find($id);
    });
}

Oppure utilizzare gli Observer dei modelli per automatizzare questa operazione:

class PostObserver {
    public function updated(Post $post) {
        Cache::forget("post_{$post->id}");
    }
}

La paginazione non funziona con QueryBuilder

Problema: si crea una query con join e filtri, ma la paginazione si interrompe o restituisce risultati errati.

La soluzione: usa il paginate() alla fine della query, e assicurati di selezionare le colonne corrette:

$posts = Post::select('posts.*')
    ->join('users', 'users.id', '=', 'posts.user_id')
    ->where('users.active', true)
    ->distinct()
    ->paginate(15);

Per query complesse, utilizzare una sottoquery:

$posts = Post::whereIn('id', function ($query) {
    $query->select('post_id')
        ->from('posts')
        ->join('users', 'users.id', '=', 'posts.user_id')
        ->where('users.active', true);
})->paginate(15);

Queste dieci soluzioni risolvono alcuni dei problemi più comuni di Laravel. Comprendendole e implementandole, scriverai codice più sicuro, efficiente e manutenibile. Buon lavoro!

Di Ercole Palmeri

Digital Innovator, Executive MBA, InsurTech Specialist, tecnologie innovative: clean code, intelligenza artificiale, analisi big data, blockchain e machine learning. .