Helpers

Les funcions helpers de Laravel: strings, arrays, paths, URLs, dates, depuració, respostes HTTP i utilitats diverses.

Què són els helpers?#

Els helpers de Laravel són funcions i classes disponibles globalment que proporcionen dreceres per a operacions comunes. No cal importar res per utilitzar funcions com dd(), now() o collect(): estan disponibles a qualsevol lloc del codi de la teva aplicació. Laravel inclou centenars d'helpers que cobreixen des de la manipulació de strings i arrays fins a la generació d'URLs, la depuració i la gestió de respostes HTTP.

Aquests helpers no són simplement funcions de conveniència: molts d'ells encapsulen patrons que resolen problemes recurrents de manera elegant i segura. Per exemple, Str::slug() no només converteix un text a minúscules i substitueix espais per guions: també gestiona caràcters especials, accents, caràcters Unicode i casos límit que un strtolower() + str_replace() manual no cobriria. De la mateixa manera, Arr::get() amb notació de punt simplifica l'accés a dades niuades que amb arrays nadius requereix comprovacions d'existència a cada nivell.

Helpers de strings (classe Str)#

La classe Illuminate\Support\Str és una de les més extenses de Laravel, amb desenes de mètodes estàtics per manipular cadenes de text. A més, la funció helper str() retorna una instància de Stringable que permet encadenar operacions de manera fluida.

Transformacions de format#

Aquests mètodes converteixen strings entre els diferents formats de nomenclatura habituals en programació. Són essencials quan necessites generar noms de variables, URLs amigables, noms de classes o identificadors a partir de text lliure:

use Illuminate\Support\Str;
 
// slug() - ideal per a URLs amigables
Str::slug('Laravel Andorra: Guia Completa');
// 'laravel-andorra-guia-completa'
 
// camelCase, snake_case, kebab-case, StudlyCase
Str::camel('user_profile_image');    // 'userProfileImage'
Str::snake('userProfileImage');      // 'user_profile_image'
Str::kebab('UserProfileImage');      // 'user-profile-image'
Str::studly('user_profile_image');   // 'UserProfileImage'
 
// Capitalització
Str::title('hola món, benvinguts');   // 'Hola Món, Benvinguts'
Str::headline('user_profile_image'); // 'User Profile Image'
Str::lower('HOLA MÓN');             // 'hola món'
Str::upper('hola món');              // 'HOLA MÓN'
Str::ucfirst('hola món');            // 'Hola món'
Str::lcfirst('Hola món');            // 'hola món'

El mètode headline() és especialment útil per generar títols llegibles a partir de noms de variables o constants: converteix qualsevol format (camelCase, snake_case, kebab-case) en paraules separades amb cada inicial en majúscula.

Truncament#

Quan necessites limitar la longitud d'un text per a la interfície d'usuari, com ara llistes d'articles, metadescripcions o cards de productes:

// limit() - tallar per caràcters
Str::limit('Aquesta és una descripció molt llarga del producte', 25);
// 'Aquesta és una descripc...'
 
Str::limit('Text curt', 25);
// 'Text curt' (no talla si és més curt)
 
// Personalitzar el sufix
Str::limit('Descripció llarga del producte', 20, ' [...]');
// 'Descripció llarga de [...]'
 
// words() - tallar per paraules (respecta paraules senceres)
Str::words('Aquesta és una descripció molt llarga del producte', 5);
// 'Aquesta és una descripció molt...'
 
Str::words('Aquesta és una descripció molt llarga', 3, ' →');
// 'Aquesta és una →'

La diferència entre limit() i words() és important per a la UX: limit() talla a mitja paraula si cal, mentre que words() sempre respecta paraules senceres, generant textos truncats més naturals.

Cerca i comprovació#

Aquests mètodes permeten cercar substrings, comprovar patrons i validar el contingut d'un string:

// Comprovar contingut
Str::contains('Laravel Andorra', 'Andorra');           // true
Str::contains('Laravel Andorra', ['Vue', 'Andorra']);  // true (qualsevol)
Str::containsAll('Laravel Andorra', ['Laravel', 'Andorra']); // true (tots)
 
// Comprovar inici i final
Str::startsWith('Laravel Andorra', 'Laravel');  // true
Str::endsWith('foto.jpg', ['.jpg', '.png']);    // true
 
// Validar formats
Str::is('user.*', 'user.profile');  // true (patró wildcard)
Str::isUuid('550e8400-e29b-41d4-a716-446655440000'); // true
Str::isUrl('https://laravelandorra.com');  // true
Str::isJson('{"key": "value"}');           // true

Extracció i manipulació#

Aquests mètodes permeten extreure parts d'un string o manipular-ne el contingut:

// Extreure parts
Str::before('admin@laravelandorra.com', '@');
// 'admin'
 
Str::after('admin@laravelandorra.com', '@');
// 'laravelandorra.com'
 
Str::between('[important]', '[', ']');
// 'important'
 
Str::beforeLast('app/Http/Controllers/UserController.php', '/');
// 'app/Http/Controllers'
 
Str::afterLast('app/Http/Controllers/UserController.php', '/');
// 'UserController.php'
 
// Substituir
Str::replace('Laravel', 'Symfony', 'Laravel és genial');
// 'Symfony és genial'
 
Str::replaceFirst('a', 'A', 'abracadabra');
// 'Abracadabra'
 
Str::replaceLast('a', 'A', 'abracadabra');
// 'abracadabrA'
 
// Repetir
Str::repeat('ab', 3);
// 'ababab'
 
// Omplir
Str::padLeft('42', 5, '0');   // '00042'
Str::padRight('Hola', 10, '.'); // 'Hola......'

Generació de valors únics#

Laravel proporciona mètodes per generar identificadors únics, strings aleatoris i contrasenyes de manera segura:

// UUIDs (Universally Unique Identifier)
Str::uuid();         // '550e8400-e29b-41d4-a716-446655440000'
Str::orderedUuid();  // UUID ordenable per temps (útil com a clau primària)
 
// ULIDs (Universally Unique Lexicographically Sortable Identifier)
Str::ulid();         // '01H5N3FWGA8PKZR4F7YGXQJ6E9'
 
// Strings aleatoris
Str::random(32);     // 'kHGp9vN2xR...' (32 caràcters alfanumèrics)
 
// Contrasenyes segures
Str::password();     // 'jT9$kN!mP2@wQ5' (16 caràcters per defecte)
Str::password(32);   // Contrasenya de 32 caràcters
 
// Amb opcions específiques
Str::password(
    length: 20,
    letters: true,
    numbers: true,
    symbols: true,
    spaces: false
);

Str::orderedUuid() genera UUIDs que es poden ordenar cronològicament perquè incorporen el timestamp. Això els fa ideals com a claus primàries de base de dades, ja que mantenen l'ordre d'inserció i funcionen millor amb índexs B-tree que els UUID v4 aleatoris.

Pluralització i singularització#

Aquests mètodes treballen amb la gramàtica anglesa per defecte, però són extremadament útils per a la generació dinàmica de noms de taules, rutes i missatges:

Str::plural('article');     // 'articles'
Str::plural('child');       // 'children'
Str::plural('person');      // 'people'
 
Str::singular('articles');  // 'article'
Str::singular('children');  // 'child'
 
// Pluralització condicional basada en quantitat
Str::plural('article', 1);  // 'article' (singular perquè n=1)
Str::plural('article', 5);  // 'articles' (plural perquè n>1)

Emmascarament de dades sensibles#

El mètode mask() és útil per mostrar dades parcialment ocultes, com ara números de telèfon, correus electrònics o números de targeta de crèdit:

Str::mask('joan@exemple.com', '*', 3);
// 'joa**************'
 
Str::mask('+376 123 456', '*', 5, 3);
// '+376 ***456'
 
Str::mask('4111 1111 1111 1234', '*', 0, -4);
// '************** 1234'

Fluent Strings#

Les Fluent Strings permeten encadenar múltiples operacions sobre un string de manera expressiva. La funció helper str() o Str::of() retornen una instància de Stringable que suporta la concatenació de mètodes:

use Illuminate\Support\Str;
 
// Crear una Fluent String
$result = Str::of('  Laravel Andorra - Guia de Laravel en Català!  ')
    ->trim()
    ->lower()
    ->slug()
    ->toString();
// 'laravel-andorra-guia-de-laravel-en-catala'
 
// Equivalent amb la funció helper str()
$result = str('  User Profile Image  ')
    ->trim()
    ->snake()
    ->toString();
// 'user_profile_image'

L'avantatge sobre els mètodes estàtics de Str és la llegibilitat: en lloc d'anar niuant crides estàtiques (Str::snake(Str::lower(trim($text)))), escrius una cadena de transformacions de dalt a baix.

Operacions condicionals#

Les Fluent Strings inclouen mètodes when* per aplicar transformacions només quan es compleix una condició, evitant sentències if addicionals:

$title = str('article sobre laravel')
    ->title()
    ->when(
        $addPrefix,
        fn ($str) => $str->prepend('Blog: ')
    )
    ->toString();
// 'Blog: Article Sobre Laravel' (si $addPrefix és true)
// 'Article Sobre Laravel' (si $addPrefix és false)
 
// whenContains - aplicar si conté un substring
$text = str('Error: connexió fallida')
    ->whenContains('Error', fn ($str) => $str->upper())
    ->toString();
// 'ERROR: CONNEXIÓ FALLIDA'
 
// whenStartsWith
$path = str('/admin/users')
    ->whenStartsWith('/admin', fn ($str) => $str->append('?verified=1'))
    ->toString();
// '/admin/users?verified=1'
 
// whenEmpty - aplicar si el string és buit
$name = str($input)
    ->whenEmpty(fn ($str) => $str->append('Anònim'))
    ->toString();

Expressions regulars#

Les Fluent Strings proporcionen mètodes per treballar amb expressions regulars de manera més còmoda:

// match() - extreure la primera coincidència
$version = str('Laravel 11.2.3')->match('/(\d+\.\d+\.\d+)/');
// '11.2.3'
 
// matchAll() - extreure totes les coincidències
$numbers = str('preu: 10€, descompte: 3€, total: 7€')
    ->matchAll('/(\d+)/');
// ['10', '3', '7']
 
// test() - comprovar si coincideix
$isEmail = str('joan@exemple.com')->test('/^[\w.-]+@[\w.-]+\.\w+$/');
// true
 
// scan() - extreure grups amb un patró
$parts = str('2024-03-15 14:30:00')
    ->scan('/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/');
// [['2024', '03', '15', '14', '30', '00']]

pipe() i transformacions personalitzades#

El mètode pipe() permet passar el string a qualsevol funció personalitzada dins de la cadena:

$result = str('hola món')
    ->title()
    ->pipe(fn ($str) => base64_encode($str))
    ->toString();
// base64 de 'Hola Món'
 
// Combinar amb funcions PHP noves
$clean = str('<p>Hola <b>món</b></p>')
    ->pipe('strip_tags')
    ->trim()
    ->toString();
// 'Hola món'

wrap(), prepend() i append()#

$tag = str('important')
    ->wrap('<span class="tag">', '</span>')
    ->toString();
// '<span class="tag">important</span>'
 
$url = str('laravelandorra.com')
    ->prepend('https://')
    ->append('/guia')
    ->toString();
// 'https://laravelandorra.com/guia'

Exemple pràctic de Fluent Strings#

// Processar un títol d'article per generar un slug únic
$slug = str($request->input('title'))
    ->trim()
    ->lower()
    ->slug()
    ->when(
        Article::where('slug', str($request->input('title'))->trim()->lower()->slug()->toString())->exists(),
        fn ($str) => $str->append('-' . Str::random(5))
    )
    ->limit(80, '')
    ->toString();
 
// Netejar i formatar un nom d'usuari
$displayName = str($rawInput)
    ->trim()
    ->replaceMatches('/\s+/', ' ')  // Múltiples espais a un sol espai
    ->title()
    ->when(
        fn ($str) => $str->length() > 30,
        fn ($str) => $str->limit(30)
    )
    ->toString();

Helpers d'arrays (classe Arr)#

La classe Illuminate\Support\Arr proporciona mètodes per treballar amb arrays PHP de manera més expressiva. La seva característica més potent és el suport de notació de punt (dot notation), que permet accedir a dades niuades profundament sense comprovacions d'existència a cada nivell.

Notació de punt per a dades niuades#

La notació de punt és una manera intuïtiva d'accedir a dades niuades utilitzant punts com a separadors de nivell. Això és especialment útil quan treballes amb configuracions, respostes d'API o qualsevol estructura de dades niuada:

use Illuminate\Support\Arr;
 
$config = [
    'database' => [
        'connections' => [
            'mysql' => [
                'host' => 'localhost',
                'port' => 3306,
                'database' => 'laravel_app',
            ],
            'redis' => [
                'host' => '127.0.0.1',
                'port' => 6379,
            ],
        ],
    ],
];
 
// get() - accedir amb notació de punt
Arr::get($config, 'database.connections.mysql.host');
// 'localhost'
 
// Amb valor per defecte si la clau no existeix
Arr::get($config, 'database.connections.mysql.password', 'secret');
// 'secret' (no existeix, retorna el valor per defecte)
 
// has() - comprovar existència
Arr::has($config, 'database.connections.mysql');       // true
Arr::has($config, 'database.connections.sqlite');      // false
Arr::has($config, ['database.connections.mysql', 'database.connections.redis']); // true
 
// set() - establir un valor
Arr::set($config, 'database.connections.mysql.password', 'secret123');
 
// forget() - eliminar una clau
Arr::forget($config, 'database.connections.redis');

Sense notació de punt, accedir a $config['database']['connections']['mysql']['host'] requereix comprovar l'existència de cada nivell intermedi per evitar errors. Amb Arr::get(), si qualsevol nivell no existeix, simplement retorna null (o el valor per defecte).

Selecció i exclusió#

$user = [
    'name' => 'Joan',
    'email' => 'joan@test.com',
    'password' => 'hashed_password',
    'role' => 'admin',
    'api_token' => 'abc123',
];
 
// only() - seleccionar claus específiques
Arr::only($user, ['name', 'email']);
// ['name' => 'Joan', 'email' => 'joan@test.com']
 
// except() - excloure claus específiques
Arr::except($user, ['password', 'api_token']);
// ['name' => 'Joan', 'email' => 'joan@test.com', 'role' => 'admin']

Aquests mètodes són extremadament útils per filtrar dades sensibles abans de retornar-les en respostes d'API o per limitar els camps que es passen a un formulari.

Cerca i filtratge#

$items = [
    ['name' => 'Portàtil', 'price' => 999, 'active' => true],
    ['name' => 'Teclat', 'price' => 79, 'active' => true],
    ['name' => 'Monitor', 'price' => 450, 'active' => false],
];
 
// first() - primer element que compleix la condició
$first = Arr::first($items, fn ($item) => $item['price'] > 100);
// ['name' => 'Portàtil', 'price' => 999, 'active' => true]
 
// last() - últim element que compleix la condició
$last = Arr::last($items, fn ($item) => $item['active']);
// ['name' => 'Teclat', 'price' => 79, 'active' => true]
 
// where() - filtrar per condició
$active = Arr::where($items, fn ($item) => $item['active']);
// Portàtil i Teclat
 
// pluck() - extreure una columna
$names = Arr::pluck($items, 'name');
// ['Portàtil', 'Teclat', 'Monitor']
 
// pluck() amb claus
$priceMap = Arr::pluck($items, 'price', 'name');
// ['Portàtil' => 999, 'Teclat' => 79, 'Monitor' => 450]

Aplanament i transformació#

// flatten() - aplanar arrays niuats
Arr::flatten([[1, 2], [3, [4, 5]]]);
// [1, 2, 3, 4, 5]
 
// collapse() - fusionar arrays d'arrays
Arr::collapse([[1, 2], [3, 4], [5]]);
// [1, 2, 3, 4, 5]
 
// wrap() - garantir que un valor sigui un array
Arr::wrap('hello');      // ['hello']
Arr::wrap(['hello']);    // ['hello'] (ja és un array, no canvia)
Arr::wrap(null);         // []
 
// undot() - convertir notació de punt en array niuat
Arr::undot([
    'user.name' => 'Joan',
    'user.email' => 'joan@test.com',
    'user.address.city' => 'Andorra la Vella',
]);
// [
//     'user' => [
//         'name' => 'Joan',
//         'email' => 'joan@test.com',
//         'address' => ['city' => 'Andorra la Vella'],
//     ],
// ]
 
// map() i mapWithKeys()
Arr::map([1, 2, 3], fn ($value) => $value * 2);
// [2, 4, 6]
 
Arr::mapWithKeys($users, fn ($user) => [$user['id'] => $user['name']]);
 
// sortRecursive() - ordenar tots els nivells
Arr::sortRecursive([
    'z' => 'last',
    'a' => ['c' => 3, 'a' => 1, 'b' => 2],
]);
// ['a' => ['a' => 1, 'b' => 2, 'c' => 3], 'z' => 'last']

data_get(), data_set() i data_fill()#

Aquestes funcions globals treballen com Arr::get() i Arr::set() però suporten wildcards (*) per accedir a múltiples elements dins d'arrays niuats:

$data = [
    'users' => [
        ['name' => 'Joan', 'email' => 'joan@test.com', 'address' => ['city' => 'Andorra la Vella']],
        ['name' => 'Maria', 'email' => 'maria@test.com', 'address' => ['city' => 'Escaldes']],
        ['name' => 'Pere', 'email' => 'pere@test.com', 'address' => null],
    ],
];
 
// Wildcard per accedir a tots els elements d'un nivell
$names = data_get($data, 'users.*.name');
// ['Joan', 'Maria', 'Pere']
 
$cities = data_get($data, 'users.*.address.city');
// ['Andorra la Vella', 'Escaldes', null]
 
// data_set() - establir valors amb wildcard
data_set($data, 'users.*.verified', true);
// Afegeix 'verified' => true a tots els usuaris
 
// data_fill() - establir NOMÉS si no existeix
data_fill($data, 'users.*.address.country', 'Andorra');
// Afegeix 'country' => 'Andorra' només on address existeix i no té 'country'

La diferència entre data_set() i data_fill() és crucial: data_set() sobreescriu qualsevol valor existent, mentre que data_fill() només estableix el valor si la clau no existeix o és null. data_fill() és ideal per aplicar valors per defecte sense sobreescriure configuracions personalitzades.

Helpers de paths#

Laravel proporciona funcions per generar paths absoluts als directoris principals de l'aplicació. Aquestes funcions retornen el camí complet al directori, i opcionalment accepten un subpath que s'afegeix al final:

// Path a l'arrel del projecte
base_path();                           // /var/www/app
base_path('vendor/autoload.php');      // /var/www/app/vendor/autoload.php
 
// Path al directori app/
app_path();                            // /var/www/app/app
app_path('Models/User.php');           // /var/www/app/app/Models/User.php
 
// Path al directori config/
config_path();                         // /var/www/app/config
config_path('app.php');                // /var/www/app/config/app.php
 
// Path al directori database/
database_path();                       // /var/www/app/database
database_path('migrations');           // /var/www/app/database/migrations
 
// Path al directori public/
public_path();                         // /var/www/app/public
public_path('css/app.css');            // /var/www/app/public/css/app.css
 
// Path al directori resources/
resource_path();                       // /var/www/app/resources
resource_path('views/welcome.blade.php');
 
// Path al directori storage/
storage_path();                        // /var/www/app/storage
storage_path('logs/laravel.log');      // /var/www/app/storage/logs/laravel.log
 
// Path al directori lang/ (Laravel 11)
lang_path();                           // /var/www/app/lang
lang_path('ca/messages.php');          // /var/www/app/lang/ca/messages.php

Utilitza sempre aquestes funcions en lloc de construir paths manualment amb concatenació de strings. Garanteixen que els paths siguin correctes independentment de l'entorn de desplegament, i gestionen automàticament els separadors de directori del sistema operatiu.

Helpers d'URLs#

Les funcions d'URL generen URLs absolutes per a la teva aplicació, respectant la configuració de APP_URL i el protocol HTTPS:

// url() - generar URL absoluta
url('/users/profile');
// 'https://laravelandorra.com/users/profile'
 
url()->current();    // URL actual completa
url()->full();       // URL actual amb query string
url()->previous();   // URL anterior (referrer)
 
// route() - generar URL a partir del nom d'una ruta
route('users.show', ['user' => 1]);
// 'https://laravelandorra.com/users/1'
 
route('users.index');
// 'https://laravelandorra.com/users'
 
// Amb query string
route('products.index', ['category' => 'electronics', 'sort' => 'price']);
// 'https://laravelandorra.com/products?category=electronics&sort=price'
 
// action() - generar URL a partir d'un controlador
use App\Http\Controllers\UserController;
action([UserController::class, 'show'], ['user' => 1]);
// 'https://laravelandorra.com/users/1'
 
// asset() - generar URL a fitxers públics
asset('images/logo.png');
// 'https://laravelandorra.com/images/logo.png'
 
// secure_asset() - forçar HTTPS
secure_asset('css/app.css');
// 'https://laravelandorra.com/css/app.css'
 
// secure_url() - forçar HTTPS
secure_url('/api/v1/users');
// 'https://laravelandorra.com/api/v1/users'

Utilitza sempre route() amb noms de ruta en lloc d'URLs hardcoded amb url(). Si canvies l'estructura d'URLs de l'aplicació, les rutes amb nom continuaran funcionant automàticament, mentre que les URLs hardcoded s'hauran d'actualitzar manualment.

Helpers de dates#

Laravel integra la biblioteca Carbon per a la manipulació de dates. Els helpers now() i today() són les dreceres més comunes:

use Carbon\Carbon;
 
// Funcions helper globals
now();                                // Carbon::now() - data i hora actuals
today();                              // Carbon::today() - avui a les 00:00:00
 
// Crear dates
Carbon::parse('2024-03-15');          // Des d'un string
Carbon::parse('next monday');         // Llenguatge natural
Carbon::parse('+3 days');             // Relatiu
 
Carbon::createFromFormat('d/m/Y', '15/03/2024');
 
// Manipular dates
now()->addDays(7);                    // D'aquí a 7 dies
now()->subHours(3);                   // Fa 3 hores
now()->startOfMonth();                // Primer dia del mes a les 00:00
now()->endOfMonth();                  // Últim dia del mes a les 23:59:59
now()->startOfWeek();                 // Dilluns d'aquesta setmana
 
// Formatar
now()->format('d/m/Y H:i');          // '15/03/2024 14:30'
now()->toDateString();                // '2024-03-15'
now()->toDateTimeString();            // '2024-03-15 14:30:00'
now()->diffForHumans();               // 'fa 3 hores'
 
// Comparar
now()->isWeekend();                   // true/false
now()->isFuture();                    // true/false
now()->isPast();                      // true/false
now()->isToday();                     // true/false
 
$deadline = Carbon::parse('2024-12-31');
$deadline->diffInDays(now());         // Dies restants
now()->gt($deadline);                 // true si avui és posterior
now()->lt($deadline);                 // true si avui és anterior

Configuració i entorn#

Aquests helpers permeten accedir a la configuració de l'aplicació i a les variables d'entorn:

// config() - llegir configuració
config('app.name');                   // 'Laravel Andorra'
config('app.timezone');               // 'Europe/Andorra'
config('database.default');           // 'mysql'
 
// config() amb valor per defecte
config('services.stripe.key', 'default_key');
 
// config() per establir valors en runtime (amb array)
config(['app.debug' => true]);
 
// env() - llegir variables d'entorn
env('APP_KEY');
env('DB_HOST', '127.0.0.1');         // Amb valor per defecte
 
// app() - accedir al contenidor de serveis
app();                                // Instància de l'aplicació
app('cache');                         // Resolre un servei
app()->environment();                 // 'local', 'production', etc.
app()->isProduction();                // true/false
 
// resolve() - àlies per app()
resolve(UserRepository::class);

La funció env() només s'hauria d'utilitzar dins dels fitxers de configuració (config/*.php). Fora d'aquests fitxers, utilitza sempre config(). El motiu és que env() no funciona correctament quan la configuració està cacheada (php artisan config:cache), ja que Laravel deixa de llegir el fitxer .env i utilitza la cache en lloc seu.

Helpers de resposta#

Aquests helpers simplifiquen la generació de respostes HTTP des dels controladors:

// abort() - llançar una excepció HTTP
abort(404);                           // Not Found
abort(403, 'No tens permís');         // Forbidden amb missatge
abort(500, 'Error intern');
 
// abort_if() - abortar condicionalment
abort_if(! $user->isAdmin(), 403);
abort_if($order->isPaid(), 400, 'La comanda ja està pagada');
 
// abort_unless() - abortar tret que...
abort_unless(auth()->check(), 401);
abort_unless($user->can('edit', $article), 403);
 
// redirect() - redirigir
redirect('/dashboard');
redirect()->route('users.index');
redirect()->back();
redirect()->back()->with('success', 'Guardat correctament');
redirect()->intended('/dashboard');   // On volia anar abans del login
 
// back() - drecera per redirect()->back()
back();
back()->withInput();                  // Conservar els valors del formulari
back()->withErrors($validator);       // Retornar amb errors de validació
 
// response() - crear respostes personalitzades
response('Hola', 200);
response()->json(['status' => 'ok']);
response()->json(['error' => 'No trobat'], 404);
response()->download($pathToFile);
response()->file($pathToFile);
response()->noContent();              // 204 No Content
 
// view() - retornar una vista
view('users.index', ['users' => $users]);
view('errors.custom')->with('message', 'Alguna cosa ha fallat');

Helpers d'autenticació#

La funció auth() proporciona accés ràpid al sistema d'autenticació sense necessitat d'importar facades:

// Comprovar l'estat d'autenticació
auth()->check();                      // true si l'usuari està autenticat
auth()->guest();                      // true si és un visitant (no autenticat)
 
// Obtenir l'usuari autenticat
auth()->user();                       // Model User o null
auth()->id();                         // ID de l'usuari o null
 
// Guard específic
auth('api')->user();                  // Usuari del guard 'api'
auth('admin')->check();               // Autenticat com a admin?
 
// Autenticar/desautenticar programàticament
auth()->login($user);                 // Iniciar sessió
auth()->loginUsingId(1);              // Per ID
auth()->logout();                     // Tancar sessió
 
// Comprovar contra un guard específic
if (auth()->guard('admin')->check()) {
    // L'usuari està autenticat com a admin
}

Helpers de depuració#

Aquests helpers són essencials durant el desenvolupament per inspeccionar variables, registrar informació i diagnosticar problemes:

// dd() - Dump and Die: mostra la variable i atura l'execució
dd($user);
dd($user, $order, $request->all()); // Múltiples variables
 
// dump() - mostra la variable SENSE aturar l'execució
dump($variable);
dump('Punt de control 1', $data);
 
// logger() - escriure al fitxer de log
logger('Usuari ha iniciat sessió', ['user_id' => $user->id]);
logger()->info('Processant comanda', ['order_id' => $order->id]);
logger()->error('Error de pagament', ['exception' => $e->getMessage()]);
 
// info() - drecera per logger()->info()
info('Comanda processada correctament');
info('Dades rebudes', $request->all());
 
// report() - reportar una excepció sense aturar l'execució
try {
    // Operació arriscada
} catch (\Exception $e) {
    report($e); // Envia al sistema de logs i handlers d'excepcions
    // L'execució continua normalment
}

La diferència entre dd() i dump() és crítica: dd() atura l'execució del script (die), mentre que dump() mostra la informació i continua. Durant el desenvolupament, dd() és útil per inspeccionar un punt concret, mentre que dump() és millor quan vols veure múltiples punts sense aturar el flux.

Mai deixis crides a dd() o dump() al codi de producció. Utilitza logger() o Log::info() per a registrar informació que necessitis en producció. Eines com Laravel Pint o PHPStan poden detectar crides a dd() que s'han quedat per error.

Utilitats diverses#

Laravel inclou un conjunt de funcions d'utilitat general que resolen patrons recurrents de manera elegant:

retry()#

El mètode retry() reintenta una operació un nombre determinat de vegades amb una pausa entre intents. És ideal per a operacions que poden fallar temporalment, com crides a APIs externes o operacions de xarxa:

// Reintentar fins a 3 vegades amb 100ms entre intents
$response = retry(3, function () {
    return Http::get('https://api.exemple.com/data');
}, 100);
 
// Amb backoff exponencial
$result = retry(5, function (int $attempt) {
    logger("Intent {$attempt} de connexió a l'API");
    return ExternalService::connect();
}, function (int $attempt) {
    return $attempt * 200; // 200ms, 400ms, 600ms, 800ms, 1000ms
});
 
// Reintentar només per a excepcions específiques
$response = retry(
    3,
    fn () => Http::get('https://api.exemple.com/data'),
    100,
    fn ($exception) => $exception instanceof ConnectionException
);

throw_if() i throw_unless()#

Aquestes funcions llancen excepcions de manera condicional, fent el codi més concís:

// throw_if() - llançar si la condició és certa
throw_if(
    $user->isBanned(),
    new AuthorizationException('Usuari bloquejat')
);
 
throw_if(! $order->canBeCancelled(), 'L\'operació no és vàlida');
 
// throw_unless() - llançar tret que la condició sigui certa
throw_unless(
    auth()->check(),
    AuthenticationException::class
);
 
throw_unless($product->inStock(), 'Producte sense estoc');

optional()#

La funció optional() permet accedir a propietats o cridar mètodes sobre un objecte que pot ser null sense llançar errors. Si l'objecte és null, retorna null en lloc de causar un error fatal:

// Sense optional(): pot llançar "Trying to get property of non-object"
$city = $user->address->city; // Error si address és null
 
// Amb optional(): retorna null de manera segura
$city = optional($user->address)->city; // null si address és null
 
// Amb callback
$result = optional($user->profile, function ($profile) {
    return $profile->bio . ' - ' . $profile->website;
});
// null si profile és null, o el resultat del callback si existeix

A partir de PHP 8.0, l'operador nullsafe (?->) fa una feina similar: $user->address?->city. No obstant això, optional() amb callback ofereix més flexibilitat per a transformacions complexes.

with() i value()#

// with() - passar un valor a un callback i retornar el resultat
$result = with($data, function ($data) {
    return process($data);
});
 
// value() - retornar el valor d'un callback o el valor directe
$val = value(fn () => expensive_calculation());
// Executa el callback i retorna el resultat
 
$val = value('hello');
// 'hello' (retorna el valor directament si no és un callback)

blank() i filled()#

Aquestes funcions comproven si un valor és "buit" o "ple" amb una definició més útil que l'empty() de PHP:

// blank() - comprova si un valor és "buit"
blank('');        // true
blank('   ');     // true (només espais)
blank(null);      // true
blank(collect()); // true (collection buida)
blank(0);         // false (0 NO és blank!)
blank(false);     // false
 
// filled() - invers de blank()
filled('Hola');   // true
filled(0);        // true
filled('');       // false
filled(null);     // false

La diferència clau amb empty() de PHP és que blank() considera 0 i false com a valors vàlids (no buits), mentre que empty(0) retorna true en PHP. Això fa que blank() sigui molt més útil per validar inputs de formularis on el valor 0 és legítim.

rescue()#

La funció rescue() executa un callback dins d'un try-catch i retorna un valor per defecte si hi ha una excepció, sense aturar l'execució:

// Executar amb valor per defecte si falla
$price = rescue(fn () => ExternalApi::getPrice($productId), 0);
// Retorna 0 si l'API falla
 
$name = rescue(
    fn () => $user->profile->display_name,
    'Usuari anònim'
);
 
// Amb report automàtic de l'excepció
$data = rescue(
    fn () => riskyOperation(),
    'default',
    report: true  // Registra l'excepció als logs
);

tap()#

La funció tap() passa un valor a un callback, executa el callback i retorna el valor original (no el resultat del callback). Això és útil per fer operacions secundàries sense trencar la cadena de valors:

// tap() executa el callback i retorna el valor original
$user = tap(User::find(1), function ($user) {
    $user->update(['last_login' => now()]);
});
// $user és el model User, no el resultat de update()
 
// Exemple amb create
$user = tap(User::create($data), function ($user) {
    $user->assignRole('editor');
    event(new UserRegistered($user));
});
 
// Sense arguments al callback, retorna un proxy
$user = tap($user)->update(['last_login' => now()]);
// Equivalent a: $user->update(...); return $user;

once()#

La funció once() memoritza el resultat d'un callback i retorna sempre el mateix valor en crides posteriors. Això és útil per a càlculs costosos que es fan múltiples vegades durant una petició:

class UserService
{
    public function getSettings(): array
    {
        // Només executa la consulta la primera vegada
        return once(function () {
            return DB::table('settings')
                ->where('user_id', auth()->id())
                ->get()
                ->keyBy('key')
                ->map->value
                ->toArray();
        });
    }
}
 
// Les crides posteriors retornen el valor cached
$service->getSettings(); // Executa la consulta
$service->getSettings(); // Retorna el resultat cached
$service->getSettings(); // Retorna el resultat cached

Helper de números (classe Number)#

La classe Number, introduïda a Laravel 11, proporciona mètodes per formatar números de maneres útils per a la interfície d'usuari. Resol el problema habitual de presentar números crus de manera llegible i localitzada:

use Illuminate\Support\Number;
 
// format() - formatat amb separadors de milers
Number::format(1234567.89);           // '1,234,567.89'
Number::format(1234567.89, locale: 'ca'); // Format català
 
// percentage() - formatar com a percentatge
Number::percentage(75.5);             // '75.50%'
Number::percentage(75.5, precision: 0); // '76%'
 
// currency() - formatar com a moneda
Number::currency(1500);               // '$1,500.00'
Number::currency(1500, 'EUR');        // '€1,500.00'
Number::currency(1500, 'EUR', 'ca');  // Format català amb euros
 
// fileSize() - mida de fitxer llegible
Number::fileSize(1024);               // '1 KB'
Number::fileSize(1073741824);         // '1 GB'
Number::fileSize(1536, precision: 2); // '1.50 KB'
 
// abbreviate() - abreviar números grans
Number::abbreviate(1000);             // '1K'
Number::abbreviate(1500000);          // '1.5M'
Number::abbreviate(2000000000);       // '2B'
 
// forHumans() - format llegible per a humans
Number::forHumans(1000);              // '1 thousand'
Number::forHumans(1500000);           // '1.5 million'
 
// ordinal() - números ordinals
Number::ordinal(1);                   // '1st'
Number::ordinal(2);                   // '2nd'
Number::ordinal(3);                   // '3rd'
Number::ordinal(21);                  // '21st'
 
// spell() - escriure el número en paraules
Number::spell(42);                    // 'forty-two'
Number::spell(100);                   // 'one hundred'

La classe Number utilitza l'extensió intl de PHP per a la localització. Assegura't de tenir-la instal·lada si vols formatar números amb locales específics. La majoria d'instal·lacions de PHP la inclouen per defecte.

Crear helpers personalitzats#

Si necessites funcions auxiliars pròpies que estiguin disponibles a tot el projecte, pots crear un fitxer de helpers i carregar-lo automàticament a través de Composer. Això és útil per a funcions específiques del teu domini que no existeixen a Laravel.

Primer, crea el fitxer de helpers:

// app/helpers.php
 
if (! function_exists('format_price')) {
    /**
     * Formatar un preu amb el símbol de l'euro.
     */
    function format_price(float $amount, int $decimals = 2): string
    {
        return number_format($amount, $decimals, ',', '.') . ' €';
    }
}
 
if (! function_exists('is_andorra_phone')) {
    /**
     * Comprovar si un número de telèfon és d'Andorra.
     */
    function is_andorra_phone(string $phone): bool
    {
        $clean = preg_replace('/\D/', '', $phone);
        return preg_match('/^(376)?\d{6}$/', $clean) === 1;
    }
}
 
if (! function_exists('active_class')) {
    /**
     * Retornar una classe CSS si la ruta actual coincideix.
     */
    function active_class(string $routeName, string $class = 'active'): string
    {
        return request()->routeIs($routeName) ? $class : '';
    }
}

Després, registra el fitxer a composer.json perquè es carregui automàticament:

{
    "autoload": {
        "files": [
            "app/helpers.php"
        ],
        "psr-4": {
            "App\\": "app/"
        }
    }
}

Finalment, regenera l'autoloader:

composer dump-autoload

Ara les funcions estan disponibles a tot el projecte:

// A qualsevol lloc del codi
echo format_price(29.99);  // '29,99 €'
 
if (is_andorra_phone('+376 321 654')) {
    // Telèfon d'Andorra
}
 
// A Blade
<a href="/dashboard" class="{{ active_class('dashboard') }}">Dashboard</a>

Envolta cada funció amb if (! function_exists(...)) per evitar errors de redeclaració si el fitxer es carrega més d'una vegada, i per permetre que altres paquets sobreescriguin les funcions si cal.

Exemples pràctics#

Processar dades d'un formulari#

use Illuminate\Support\Str;
use Illuminate\Support\Arr;
 
public function store(Request $request)
{
    $validated = $request->validated();
 
    $user = User::create([
        'name' => Str::title($validated['name']),
        'email' => Str::lower($validated['email']),
        'username' => Str::slug($validated['name']) . '-' . Str::random(4),
        'phone' => Str::of($validated['phone'] ?? '')
            ->replaceMatches('/\D/', '')
            ->whenNotEmpty(fn ($str) => $str->prepend('+376 '))
            ->toString() ?: null,
    ]);
 
    return redirect()
        ->route('users.show', $user)
        ->with('success', "Usuari {$user->name} creat correctament");
}

Generar una resposta d'API normalitzada#

use Illuminate\Support\Arr;
use Illuminate\Support\Number;
 
public function show(Order $order)
{
    $data = [
        'id' => $order->id,
        'status' => Str::headline($order->status),
        'total' => Number::currency($order->total, 'EUR'),
        'items_count' => $order->items->count(),
        'created' => $order->created_at->diffForHumans(),
        'customer' => Arr::only(
            $order->customer->toArray(),
            ['name', 'email']
        ),
        'items' => $order->items->map(fn ($item) => [
            'name' => $item->product->name,
            'quantity' => $item->quantity,
            'unit_price' => Number::currency($item->price, 'EUR'),
            'subtotal' => Number::currency($item->quantity * $item->price, 'EUR'),
        ])->all(),
    ];
 
    return response()->json($data);
}

Combinar múltiples helpers per a tasques complexes#

use Illuminate\Support\Str;
use Illuminate\Support\Arr;
 
// Generar un excerpt intel·ligent per a SEO
function generateMetaDescription(string $content): string
{
    return str($content)
        ->pipe('strip_tags')
        ->replaceMatches('/\s+/', ' ')
        ->trim()
        ->words(25, '')
        ->append('...')
        ->limit(160)
        ->toString();
}
 
// Processar una resposta d'API externa amb gestió d'errors
function fetchAndTransform(string $url): array
{
    return rescue(function () use ($url) {
        $response = retry(3, fn () => Http::get($url), 500);
 
        return collect(data_get($response->json(), 'data.*'))
            ->map(fn ($item) => [
                'title' => Str::title(data_get($item, 'attributes.name', 'Sense títol')),
                'slug' => Str::slug(data_get($item, 'attributes.name', '')),
                'price' => Number::currency(
                    data_get($item, 'attributes.price', 0) / 100,
                    'EUR'
                ),
                'available' => filled(data_get($item, 'attributes.stock')),
            ])
            ->filter(fn ($item) => filled($item['slug']))
            ->values()
            ->all();
    }, []);
}

Els helpers de Laravel no són simplement funcions de conveniència: són eines que encapsulen bones pràctiques, gestionen casos límit i fan que el codi sigui més expressiu. Combinar-los de manera intel·ligent pot reduir significativament la quantitat de codi boilerplate i fer que la lògica del negoci sigui més clara i mantenible.