laravel collections

Laravel Collections sono funzionalità incredibili di Laravel, ma sottoutilizzate.

Consentono il concatenamento di operazioni sui dati, in modo estremamente efficiente.

Vediamo insieme alcuni esempi, che evidenziano sia i loro metodi che gli scenari di utilizzo ottimale.

Le Laravel Collections sono uno strumento potente per manipolare gli array. Incapsulano le funzioni native degli array PHP, ne creano di nuove e utili e forniscono un’interfaccia fluida per lavorare con loro.

Sono anche immutabili, il che significa che non modificano la collezione originale. Invece, ne restituiscono una nuova con le modifiche applicate.

Utilizzo map con implode

Innanzitutto, vediamo un esempio semplice in cui concateniamo due metodi. Qui, il nostro scopo è visualizzare i permessi separati da un tag di interruzione HTML.

esempio:

$role = Role::with('permissions')->first();
$displayPermissions = $role->permissions
->map(function($permission) {
return $permission->name;
})
->implode("<br>");

Inizialmente, $role->permissions ci fornisce oggetti di permesso. Tuttavia, vogliamo solo il campo name di ogni oggetto. Utilizzando map, creiamo una nuova collezione con solo questi nomi. Infine, implode ci fornisce una stringa come:

"manage users<br>manage posts<br>manage comments"

Come combinare i metodi map e max

Immagina di avere una serie di punteggi. Il tuo obiettivo è determinare il punteggio più alto della serie.

Esempio:

$hazards = [
    'BM-1' => 8,
    'LT-1' => 7,

    // ... [Other values]

    'NoGS' => 0,
    'Not Screened' => 0,
];

$highestScore = Score::all()
    ->map(function($score) use ($hazards) {
        return $hazards[$score->field];
    })
    ->max();

Inizialmente, hai l’array hazards. Dopo aver usato map, estraiamo solo i valori numerici basati sul campo punteggio. Alla fine, max restituisce quello più alto, che in questo esempio è:

8

Come utilizzare il metodo pluck con il metodo flatten

I file di configurazione di Laravel sono impostati in array, e insieme compongono una struttura multilivello. Vediamo in questo esempio come leggere questi dati, e portarli all’interno di una array semplice da leggere.

Vediamo in questo esempio un file di configurazione come il seguente: config/setting_fields.php):

return [
    'app' => [
        'title' => 'General',
        // ... [Other details]
        'elements' => [
            [
                'type' => 'text',
                'name' => 'app_name',
                'value' => 'Laravel Starter',
                // ... [Other fields]
            ],
            // ...
        ],
    ],
    'email' => [
        'title' => 'Email',
        // ... [Other details]
        'elements' => [
            [
                'type' => 'email',
                'name' => 'email',
                'value' => 'info@example.com',
                // ... [Other fields]
            ],
        ],
    ],
    'social' => [
        'title' => 'Social Profiles',
        // ... [Other details]
        'elements' => [
            [
                'type' => 'text',
                'name' => 'facebook_url',
                'value' => '#',
                // ... [Other fields]
            ],
        ],
    ],
    // ... [Other sections]
];

Per estrarre le informazioni di configurazione procediamo come segue:

  1. Convertiamo l’array config('setting_fields') in una collections Laravel.
  2. Quindi utilizziamo pluck('elements') per acquisire tutti gli elements array.
  3. Infine, flatten(1) viene utilizzato per trasformare la collection multidimensionale in un array a livello singolo.
$elementsArray = collect(config('setting_fields'))
    ->pluck('elements')
    ->flatten(1);

Questo processo ci fornisce una serie semplificata di elementi, senza alcuna complessità multilivello.

Esempio di utilizzo dei metodi filter + first e map + implode

Consideriamo uno scenario in cui vogliamo identificare lo spazio dei nomi di una classe da un elenco e quindi trasformare il nome di quella classe nella lettera maiuscola kebab.

Esempio:

$class = 'App\\Base\\Http\\Livewire\\SomeClass';
$availableNamespaces = [
    'App\Base\Http\Livewire',
    'App\Project\Livewire'
];

$foundNamespace = collect($availableNamespaces)
    ->filter(function($namespace) use ($class) {
        return strpos($class, $namespace) !== false;
    })
    ->first();

$kebabCasedNamespace = collect(explode('.', str_replace(['/', '\\'], '.', $foundNamespace)))
    ->map([Str::class, 'kebab'])
    ->implode('.');

Nell’esempio abbiamo definito una variabile $class con il nome di una classe Livewire, e un array contenente un elenco di namespace.

Utilizziamo il metodo filter(), esaminiamo i namespace per trovare una corrispondenza per la nostra classe. Quindi estraiamo il namespace corrispondente con il metodo first().

L’applicazione di questo filtro, il risultato $foundNamespace sarà:

"App\Base\Http\Livewire"



Procediamo quindi a trasformare lo spazio dei nomi in caso kebab:

  • Sostituiamo le barre con i punti per segmentare lo spazio dei nomi.
  • Suddividiamo lo spazio dei nomi segmentiamo in una raccolta.
  • Utilizziamo map() per applicare il kebab case.

Ecco un trucco interessante: invece di scrivere una callback completa per map(), possiamo puntarla direttamente a un metodo, come Str::kebab.

Infine, utilizzando implode(), uniamo i nostri segmenti kebab-cased di nuovo in una singola stringa. Il risultato sarà:

"app.base.http.livewire"


Quindi, con pochi metodi collections, siamo riusciti a trovare uno spazio dei nomi e a trasformarlo in un kebab case!

Esempio di combinazione di push, map , e implode

Addentriamoci in uno scenario con tre collections method. Immagina di eseguire un comando di giveaway di Twitter in Artisan di Laravel e di voler escludere utenti specifici.

Codice semplificato:

$excludedNames = collect($this->option('exclude'))
    ->push('povilaskorop', 'dailylaravel')
    ->map(function (string $name): string {
        return str_replace('@', '', $name);
    })
    ->implode(', ');

Utilizzo del comando:

php artisan twitter:giveaway --exclude=someuser --exclude=@otheruser

Spiegazione in passaggi:

Punto di partenza: il comando consente di escludere gli utenti con l’ --excludeopzione. $this->option('exclude')Fornirebbe un array di nomi utente che si desidera escludere.

Inizialmente, dopo averlo trasformato in una raccolta, potrebbe apparire così:

["someuser", "@otheruser"]

Utilizzo di push(): Vogliamo aggiungere nomi utente specifici all’elenco di esclusione. Utilizzando push(), aggiungiamo ‘povilaskorop’ e ‘dailylaravel’ alla nostra collezione.

Dopo questo passaggio, la raccolta potrebbe apparire così:

["someuser", "@otheruser", "povilaskorop", "dailylaravel"]

Applicazione map(): vogliamo che i nostri nomi utente siano coerenti. Il simbolo ‘@’ viene rimosso per garantire uniformità. Il map()metodo ci aiuta a scorrere l’elenco e a rimuovere qualsiasi ‘@’ dai nomi utente.

La raccolta, dopo l’utilizzo map, sarebbe:

["someuser", "otheruser", "povilaskorop", "dailylaravel"]

Completamento con implode(): Per una visualizzazione più semplice, vogliamo unire i nomi in un’unica stringa. implode() ci aiuta a raggiungere questo obiettivo separando ogni nome utente con una virgola.

Pertanto, il nostro risultato finale sarebbe:

"someuser, otheruser, povilaskorop, dailylaravel"

Con questi tre metodi abbiamo riordinato e formattato il nostro elenco di nomi utente Twitter esclusi.

Esempio di combinazione di filtermap, e implode

In questo scenario, considera di avere un modello Utente con più link di profili social. Il nostro obiettivo è visualizzare questi link come hyperlink cliccabili e omettere quelli vuoti.

Codice semplificato:

$socialProfileLinks = collect([
    'Twitter' => $user->link_twitter,
    'Facebook' => $user->link_facebook,
    'Instagram' => $user->link_instagram,
])
->filter()
->map(function ($link, $platform) {
    return '<a href="' . $link . '">' . $platform . '</a>';
})
->implode(' | ');

Spiegazione passo dopo passo:

Punto di partenza: iniziamo creando una raccolta di profili sui social media.

Inizialmente potrebbe sembrare:

['Twitter' => 'https://twitter.com/username', 'Facebook' => '', 'Instagram' => 'https://instagram.com/username']

Utilizzo filter(): alcuni link del profilo potrebbero essere vuoti, quindi utilizziamo filter()per rimuoverli. Per impostazione predefinita, filter()ometterà i valori vuoti.

Dopo il filtraggio, la nostra raccolta potrebbe apparire come:

['Twitter' => 'https://twitter.com/username', 'Instagram' => 'https://instagram.com/username']

Applicazione map(): ora vogliamo convertire gli URL in link cliccabili. Il map()metodo ci consente di scorrere ogni link, racchiudendoli in tag di ancoraggio HTML.

Dopo la mappatura, la raccolta si trasformerebbe in:

["<a href='https://twitter.com/username'>Twitter</a>", "<a href='https://instagram.com/username'>Instagram</a>"]

Concludendo con implode(): Per renderlo presentabile, uniamo i singoli collegamenti in un’unica stringa utilizzando implode(), con ogni collegamento separato da una barra verticale (‘|’).

Il risultato finale sarebbe:

"<a href='https://twitter.com/username'>Twitter</a> | <a href='https://instagram.com/username'>Instagram</a>"

Con questo flusso puoi formattare e visualizzare senza sforzo i profili social attivi di un utente nei file blade di Laravel.

Esempio con i metodi rejectreject, e each

Analizziamo una situazione in cui dobbiamo filtrare un elenco di modelli in base a determinate condizioni e poi eseguire un’azione sui modelli rimanenti.

esempio:

Repository::query()
    ->with('owner')
    ->get()
    ->reject(function (Repository $repository) {
        return $repository->owner instanceof User && $repository->owner->github_access_token === null;
    })
    ->reject(function (Repository $repository) {
        return $repository->owner instanceof Organization && !$repository->owner->members()->whereIsRegistered()->exists();
    })
    ->each(function (Repository $repository) {
        UpdateRepositoryDetails::dispatch($repository);
    });

Stiamo estraendo un elenco di repository con i rispettivi proprietari.

All’inizio potrebbe sembrare:

[Repository1 with User without GitHub token, Repository2 with Organization having registered members, ...]

Primo passo con reject(): vogliamo escludere i repository in cui il proprietario è un utente e non ha un token di accesso GitHub.

Dopo le prime esclusioni fatte con la reject, la nostra lista diventa:

[Repository2 with Organization having registered members, ...]

Secondo passo con reject(): ora vogliamo filtrare ulteriormente i repository in cui il proprietario è un’organizzazione e non ha membri registrati. Dopo questa seconda esclusione, il nostro elenco dovrebbe restringersi ulteriormente.

Utilizziamo la each(): con l’elenco filtrato nei passi precedenti, eseguendo un ciclo su ogni repository per aggiornarne i dettagli.

Autore