Tinker

Com utilitzar Laravel Tinker per explorar models, relacions, serveis i depurar l'aplicació des d'un REPL interactiu.

Que es Tinker?#

Laravel Tinker es un REPL (Read-Eval-Print Loop) integrat al framework que et permet interactuar amb tota la teva aplicacio directament des de la linia de comandes. Un REPL es un entorn interactiu on pots escriure expressions de codi, veure'n el resultat immediatament i continuar experimentant sense necessitat de crear fitxers, definir rutes ni obrir el navegador. El concepte es simple pero extraordinariament potent: escrius una linia de PHP, Tinker l'avalua, et mostra el resultat i espera la seguent instruccio.

Tinker esta construit sobre PsySH, una consola interactiva de PHP avancada que afegeix funcionalitats com autocompletat, historial de comandes, documentacio integrada i inspeccion de codi font. Laravel estent PsySH carregant automaticament tot l'entorn de l'aplicacio: models, serveis, facades, helpers, configuracio i qualsevol classe registrada al contenidor de serveis. Aixo significa que quan obres Tinker, tens acces a tot el que tindries dins d'un controlador o un job, pero sense la cerimonia d'escriure codi en un fitxer, guardar-lo i executar-lo.

Per que es tan valuos Tinker durant el desenvolupament? Per tres raons fonamentals. Primera, l'exploracio rapida: pots provar consultes Eloquent, comprovar relacions entre models i verificar que les dades a la base de dades son correctes, tot en segons. Segona, la depuracio agil: quan alguna cosa no funciona com esperes, Tinker et permet aillar el problema executant cada pas individualment i inspeccionant els resultats intermedis. Tercera, el prototipatge instantani: abans d'escriure una consulta complexa en un controlador, pots construir-la incrementalment a Tinker, verificar que retorna el que esperes i despres copiar-la al codi definitiu.

Per iniciar una sessio de Tinker, executa la comanda Artisan corresponent:

php artisan tinker

Veuràs un prompt >>> que indica que Tinker esta llest per rebre instruccions. A partir d'aqui, qualsevol expressio PHP valida sera avaluada immediatament:

>>> 2 + 2
=> 4
 
>>> strtoupper('hola andorra')
=> "HOLA ANDORRA"
 
>>> now()->format('d/m/Y H:i')
=> "14/02/2026 10:30"

Per sortir de Tinker, escriu exit o prem Ctrl+D.

Treballar amb models Eloquent#

L'us mes habitual de Tinker es interactuar amb els models Eloquent de l'aplicacio. Des de Tinker pots crear, llegir, actualitzar i eliminar registres de la base de dades exactament com ho faries dins del codi de l'aplicacio, pero amb la immediatesa d'un entorn interactiu. Cada operacio es real: els canvis s'apliquen directament a la base de dades, cosa que fa de Tinker una eina molt practica pero que requereix atencio, especialment en entorns de produccio.

Crear registres#

Per crear registres nous, pots utilitzar el metode create() del model o les factories. El metode create() accepta un array d'atributs i guarda el registre immediatament a la base de dades. Recorda que els camps que passis han d'estar inclosos a l'array $fillable del model:

>>> use App\Models\User;
 
>>> User::create([
...     'name' => 'Joan Martí',
...     'email' => 'joan@laravelandorra.com',
...     'password' => bcrypt('secret'),
... ])
=> App\Models\User {id: 1, name: "Joan Martí", email: "joan@laravelandorra.com", ...}

Les factories son especialment utils a Tinker perque generen dades realistes automaticament, sense que hagis d'inventar valors per a cada camp. Aixo es ideal quan necessites registres de prova rapids:

>>> User::factory()->create()
=> App\Models\User {id: 2, name: "Maria López", email: "maria@example.com", ...}
 
>>> User::factory()->create(['name' => 'Pere Andorra'])
=> App\Models\User {id: 3, name: "Pere Andorra", ...}
 
>>> User::factory(5)->create()
=> Illuminate\Database\Eloquent\Collection {#1234
     all: [User, User, User, User, User],
   }

El metode factory()->create() guarda el registre a la base de dades, mentre que factory()->make() crea una instancia en memoria sense persistir-la. Aquesta distincio es important: utilitza make() quan nomes necessites un objecte per provar alguna cosa sense contaminar la base de dades.

Llegir registres#

Tinker es perfecte per explorar les dades existents a la base de dades. Pots utilitzar tots els metodes de consulta d'Eloquent que ja coneixes:

>>> User::find(1)
=> App\Models\User {id: 1, name: "Joan Martí", email: "joan@laravelandorra.com", ...}
 
>>> User::where('email', 'like', '%@laravelandorra.com')->get()
=> Illuminate\Database\Eloquent\Collection {#1235
     all: [
       App\Models\User {id: 1, name: "Joan Martí", ...},
     ],
   }
 
>>> User::first()
=> App\Models\User {id: 1, name: "Joan Martí", ...}
 
>>> User::all()
=> Illuminate\Database\Eloquent\Collection {#1236
     all: [User, User, User, ...],
   }
 
>>> User::where('created_at', '>=', now()->subDays(7))->get()
=> Illuminate\Database\Eloquent\Collection {#1237
     all: [...],
   }

Quan Tinker mostra un model, presenta els seus atributs principals en un format llegible. Si el resultat es una col·leccio gran, Tinker la truncara automaticament per no inundar la pantalla.

Actualitzar registres#

Per actualitzar registres, primer recupera el model i despres modifica'l. Pots utilitzar el metode update() per actualitzar multiples camps d'un cop, o assignar propietats individualment i cridar save():

>>> $user = User::find(1)
=> App\Models\User {id: 1, name: "Joan Martí", ...}
 
>>> $user->update(['name' => 'Joan Martí Roca'])
=> true
 
>>> $user->email = 'joan.marti@laravelandorra.com'
=> "joan.marti@laravelandorra.com"
 
>>> $user->save()
=> true
 
>>> $user->refresh()
=> App\Models\User {id: 1, name: "Joan Martí Roca", email: "joan.marti@laravelandorra.com", ...}

El metode refresh() torna a carregar el model des de la base de dades, cosa que es util per verificar que els canvis s'han aplicat correctament.

Eliminar registres#

L'eliminacio de registres a Tinker funciona exactament com al codi de l'aplicacio. Pots eliminar un model individual amb delete() o multiples registres amb destroy():

>>> $user = User::find(3)
=> App\Models\User {id: 3, ...}
 
>>> $user->delete()
=> true
 
>>> User::destroy([4, 5, 6])
=> 3

Si el model utilitza soft deletes, delete() marcara el registre com a eliminat sense treure'l realment de la base de dades. Per forcar l'eliminacio definitiva, utilitza forceDelete().

Scopes i agregacions#

Els scopes locals definits als teus models funcionen perfectament a Tinker. Aixo et permet verificar que els scopes retornen els resultats esperats abans d'integrar-los a la logica de l'aplicacio:

>>> use App\Models\Article;
 
>>> Article::published()->count()
=> 15
 
>>> Article::published()->where('category', 'laravel')->get()
=> Illuminate\Database\Eloquent\Collection {#1238
     all: [...],
   }
 
>>> Article::draft()->count()
=> 3

Les funcions d'agregacio SQL tambe son accessibles directament. Son perfectes per obtenir estadistiques rapides de les dades:

>>> use App\Models\Order;
 
>>> Order::sum('total')
=> "4582.50"
 
>>> Order::where('status', 'completed')->avg('total')
=> "127.29"
 
>>> User::count()
=> 42
 
>>> Order::max('total')
=> "999.99"
 
>>> Order::min('created_at')
=> "2025-01-15 08:30:00"

Pluck i col·leccions#

El metode pluck() es extremadament util a Tinker per obtenir una llista rapida de valors d'una columna especifica. Si passes dos arguments, el segon s'utilitza com a clau de l'array resultant:

>>> User::pluck('name')
=> Illuminate\Support\Collection {#1239
     all: ["Joan Martí", "Maria López", "Pere Andorra"],
   }
 
>>> User::pluck('name', 'id')
=> Illuminate\Support\Collection {#1240
     all: [
       1 => "Joan Martí",
       2 => "Maria López",
       3 => "Pere Andorra",
     ],
   }
 
>>> User::pluck('email')->filter(fn ($e) => str_ends_with($e, '@laravelandorra.com'))
=> Illuminate\Support\Collection {#1241
     all: ["joan@laravelandorra.com"],
   }

Pots encadenar qualsevol operacio de col·leccio sobre els resultats, cosa que fa de Tinker un entorn ideal per experimentar amb pipelines de transformacio de dades.

Explorar relacions#

Una de les coses que mes temps estalvia Tinker es la capacitat d'explorar les relacions entre models de manera interactiva. Quan estàs dissenyant l'esquema de la base de dades o depurant un problema amb les relacions, poder navegar per les relacions en temps real es invaluable.

Accedir a les relacions#

Recorda la distincio fonamental: accedir a una relacio com a propietat (sense parentesis) executa la consulta i retorna el resultat. Accedir-hi com a metode (amb parentesis) retorna el query builder, permetent encadenar condicions addicionals:

>>> $user = User::find(1)
=> App\Models\User {id: 1, name: "Joan Martí", ...}
 
>>> $user->articles
=> Illuminate\Database\Eloquent\Collection {#1242
     all: [
       App\Models\Article {id: 1, title: "Introduccio a Laravel", ...},
       App\Models\Article {id: 2, title: "Eloquent avançat", ...},
     ],
   }
 
>>> $user->articles()->count()
=> 2
 
>>> $user->articles()->where('published', true)->count()
=> 1
 
>>> $user->articles()->latest()->first()
=> App\Models\Article {id: 2, title: "Eloquent avançat", ...}

Eager loading a Tinker#

Quan explores relacions a Tinker, cada acces a una relacio genera una consulta SQL addicional. Si necessites accedir a relacions de multiples models, utilitza eager loading amb with() per carregar-les d'un sol cop i evitar el problema de les N+1 queries:

>>> User::with('articles')->find(1)
=> App\Models\User {id: 1, name: "Joan Martí", ...,
     articles: [
       App\Models\Article {id: 1, title: "Introduccio a Laravel", ...},
       App\Models\Article {id: 2, title: "Eloquent avançat", ...},
     ],
   }
 
>>> User::with(['articles', 'profile'])->get()
=> Illuminate\Database\Eloquent\Collection {#1243
     all: [...],
   }
 
>>> User::with('articles.comments')->find(1)
=> App\Models\User {id: 1, ...,
     articles: [
       App\Models\Article {id: 1, ...,
         comments: [Comment, Comment, ...],
       },
     ],
   }

Crear a traves de relacions#

Pots crear registres associats directament a traves de les relacions. Laravel s'encarrega d'assignar automaticament les claus foranes:

>>> $user = User::find(1)
 
>>> $user->articles()->create([
...     'title' => 'Tinker: la guia completa',
...     'slug' => 'tinker-guia-completa',
...     'body' => 'Contingut de l\'article...',
...     'published' => true,
... ])
=> App\Models\Article {id: 3, user_id: 1, title: "Tinker: la guia completa", ...}

El camp user_id s'assigna automaticament al valor 1 perque estem creant l'article a traves de la relacio $user->articles().

Relacions niuades#

Pots navegar per cadenes de relacions per explorar l'estructura completa de les dades. Aixo es especialment util per verificar que les relacions estan ben configurades i que les dades son coherents:

>>> $user = User::find(1)
 
>>> $user->articles->first()->comments
=> Illuminate\Database\Eloquent\Collection {#1244
     all: [
       App\Models\Comment {id: 1, body: "Molt bon article!", ...},
       App\Models\Comment {id: 2, body: "Gracies per compartir!", ...},
     ],
   }
 
>>> $user->articles->first()->comments->first()->author->name
=> "Maria López"
 
>>> $user->articles->pluck('title')
=> Illuminate\Support\Collection {#1245
     all: ["Introduccio a Laravel", "Eloquent avançat", "Tinker: la guia completa"],
   }

Testejar serveis i classes#

Tinker no es nomes per a models Eloquent. Pots resoldre qualsevol classe del contenidor de serveis de Laravel i cridar els seus metodes directament. Aixo es molt util per verificar que un servei funciona correctament sense haver de fer una peticio HTTP completa o executar un job.

Resoldre des del contenidor#

La funcio app() permet obtenir una instancia de qualsevol classe registrada al contenidor de serveis. Laravel resoldra automaticament les dependencies injectades al constructor:

>>> $service = app(\App\Services\InvoiceService::class)
=> App\Services\InvoiceService {#1246}
 
>>> $service->calculateTotal($order)
=> 127.50
 
>>> $service->generatePdf($order)
=> "/storage/invoices/INV-2026-001.pdf"

Si el servei te dependencies, el contenidor les resoldra automaticament. Per exemple, si InvoiceService depèn d'un repositori i un servei de PDF, Laravel els injectara sense que hagis de fer res:

>>> app(\App\Services\NotificationService::class)->sendWelcome($user)
=> true
 
>>> app(\App\Repositories\UserRepository::class)->findByEmail('joan@laravelandorra.com')
=> App\Models\User {id: 1, ...}

Testejar amb injeccio de dependencies#

Tambe pots instanciar classes manualment per provar escenaris especifics o per passar dependencies mock:

>>> $calculator = new \App\Services\PriceCalculator(taxRate: 0.21)
=> App\Services\PriceCalculator {#1247}
 
>>> $calculator->withDiscount(100, 15)
=> 102.85
 
>>> $calculator->withoutTax(121)
=> 100.0

Testejar correus i notificacions#

Tinker es una manera rapida de verificar que els correus i les notificacions de l'aplicacio funcionen correctament. Pots enviar correus reals o previsualitzar-ne el contingut sense passar per tot el flux de l'aplicacio.

Enviar correus#

Per enviar un correu des de Tinker, utilitza la facade Mail exactament com ho faries al codi:

>>> use Illuminate\Support\Facades\Mail;
>>> use App\Mail\WelcomeEmail;
 
>>> $user = User::find(1)
>>> Mail::to($user)->send(new WelcomeEmail($user))
=> null

Si tens configurat un servei de captura de correus com Mailpit o Mailtrap en l'entorn de desenvolupament, podras veure el correu immediatament a la seva interficie web. Si el driver de correu es log, el contingut apareixera al fitxer storage/logs/laravel.log.

Enviar notificacions#

De manera similar, pots enviar notificacions directament:

>>> use Illuminate\Support\Facades\Notification;
>>> use App\Notifications\OrderShipped;
 
>>> $user = User::find(1)
>>> $order = Order::find(1)
 
>>> $user->notify(new OrderShipped($order))
=> null
 
>>> Notification::send(User::all(), new OrderShipped($order))
=> null

Previsualitzar el contingut d'un correu#

Si nomes vols veure el contingut HTML d'un correu sense enviar-lo, pots renderitzar el Mailable:

>>> $user = User::find(1)
>>> $mailable = new \App\Mail\WelcomeEmail($user)
 
>>> $mailable->render()
=> "<html><body><h1>Benvingut, Joan Martí!</h1>..."

Aixo es util per verificar que les dades es passen correctament a la plantilla i que el contingut es el que esperes.

Helpers i utilitats#

Tinker es un entorn excel·lent per experimentar amb els nombrosos helpers que Laravel posa a la teva disposicio. Pots provar funcions de manipulacio de cadenes, dates, configuracio i molt mes, tot de manera instantania.

Helpers de cadenes#

La classe Str ofereix desenes de metodes per manipular cadenes de text. A Tinker pots provar-los rapidament per trobar el que necessites:

>>> use Illuminate\Support\Str;
 
>>> Str::slug('Bon dia, Andorra!')
=> "bon-dia-andorra"
 
>>> Str::random(32)
=> "a7Bk9mNx3pQrStUv2wXyZ1cDeFgHiJkL"
 
>>> Str::uuid()
=> "550e8400-e29b-41d4-a716-446655440000"
 
>>> Str::headline('eloquent_orm_relations')
=> "Eloquent Orm Relations"
 
>>> Str::limit('Aquesta es una frase molt llarga que volem truncar', 30)
=> "Aquesta es una frase molt lla..."
 
>>> Str::contains('Laravel Andorra', 'Andorra')
=> true
 
>>> Str::before('joan@laravelandorra.com', '@')
=> "joan"
 
>>> Str::after('joan@laravelandorra.com', '@')
=> "laravelandorra.com"

Helpers de dates#

Laravel inclou Carbon com a biblioteca de dates, i les funcions helper now() i today() la fan molt accessible des de Tinker:

>>> now()
=> Illuminate\Support\Carbon @1739523000 {
     date: 2026-02-14 10:30:00.0 UTC,
   }
 
>>> today()
=> Illuminate\Support\Carbon @1739491200 {
     date: 2026-02-14 00:00:00.0 UTC,
   }
 
>>> now()->addDays(7)->format('d/m/Y')
=> "21/02/2026"
 
>>> now()->diffForHumans(now()->subHours(3))
=> "3 hours after"
 
>>> use Carbon\Carbon;
 
>>> Carbon::parse('2026-03-15')->isWeekend()
=> true
 
>>> Carbon::parse('2026-01-01')->diffInDays(now())
=> 44
 
>>> now()->startOfMonth()->format('Y-m-d')
=> "2026-02-01"
 
>>> now()->isMonday()
=> false

Operacions amb col·leccions#

Les col·leccions de Laravel son un dels seus punts forts, i Tinker es el lloc ideal per experimentar amb les seves operacions:

>>> collect([1, 2, 3, 4, 5])->map(fn ($n) => $n * 2)->filter(fn ($n) => $n > 4)
=> Illuminate\Support\Collection {#1248
     all: [3 => 6, 4 => 10],
   }
 
>>> collect(['pa', 'formatge', 'pernil'])->implode(', ')
=> "pa, formatge, pernil"
 
>>> collect([10, 20, 30, 40])->avg()
=> 25
 
>>> collect(['a' => 1, 'b' => 2, 'c' => 3])->only(['a', 'c'])
=> Illuminate\Support\Collection {#1249
     all: ["a" => 1, "c" => 3],
   }

Helpers de configuracio i entorn#

Tinker es molt practic per verificar la configuracio actual de l'aplicacio:

>>> config('app.name')
=> "Laravel Andorra"
 
>>> config('app.env')
=> "local"
 
>>> config('database.default')
=> "mysql"
 
>>> config('mail.default')
=> "smtp"
 
>>> env('APP_DEBUG')
=> true
 
>>> route('login')
=> "https://laravelandorra.com/login"
 
>>> url('/articles/1')
=> "https://laravelandorra.com/articles/1"

Funcions de xifrat#

Les funcions de hashing i xifrat tambe estan disponibles per provar-les rapidament:

>>> bcrypt('la-meva-contrasenya')
=> "$2y$12$abcdefghijklmnopqrstuuABCDEFGHIJKLMNOPQRSTUVWXYZ0123"
 
>>> $encrypted = encrypt('dades sensibles')
=> "eyJpdiI6Ik1hc2RmYXNkZj..."
 
>>> decrypt($encrypted)
=> "dades sensibles"
 
>>> Illuminate\Support\Facades\Hash::check('la-meva-contrasenya', bcrypt('la-meva-contrasenya'))
=> true

Depuracio#

Tinker brilla especialment com a eina de depuracio. Quan alguna cosa no funciona com esperes a l'aplicacio, Tinker et permet aillar el problema executant cada pas de forma individual i inspeccionant els resultats intermedis.

Inspeccionar objectes i propietats#

Quan Tinker mostra un objecte Eloquent, ja et presenta els seus atributs principals. Pero de vegades necessites veure mes detalls. Pots accedir a propietats especifiques o utilitzar metodes d'introspeccio:

>>> $user = User::find(1)
 
>>> $user->toArray()
=> [
     "id" => 1,
     "name" => "Joan Martí",
     "email" => "joan@laravelandorra.com",
     "email_verified_at" => "2026-01-15T10:30:00.000000Z",
     "created_at" => "2026-01-15T10:30:00.000000Z",
     "updated_at" => "2026-02-10T14:20:00.000000Z",
   ]
 
>>> $user->getAttributes()
=> [
     "id" => 1,
     "name" => "Joan Martí",
     ...
   ]
 
>>> $user->getDirty()
=> []
 
>>> $user->name = 'Joan Modificat'
>>> $user->getDirty()
=> ["name" => "Joan Modificat"]
 
>>> $user->getOriginal('name')
=> "Joan Martí"

El metode getDirty() mostra els camps que han canviat des que es va carregar el model, i getOriginal() retorna el valor original abans de qualsevol modificacio. Aquests metodes son essencials per depurar problemes amb actualitzacions de models.

Comportament de dd() i dump()#

A Tinker, dd() (dump and die) finalitza la sessio de Tinker, cosa que normalment no es el que vols. En canvi, dump() mostra la informacio i permet continuar treballant:

>>> dump(User::find(1))
App\Models\User {#1250
  id: 1,
  name: "Joan Martí",
  email: "joan@laravelandorra.com",
  ...
}
=> null
 
>>> // La sessio continua activa despres de dump()
>>> User::count()
=> 42

En general, a Tinker no necessites ni dd() ni dump(), perque el REPL ja mostra automaticament el resultat de cada expressio. Aquests metodes son mes utils dins del codi de l'aplicacio.

Comprovar valors de configuracio#

Quan l'aplicacio no es comporta com esperes, sovint el problema esta a la configuracio. Tinker et permet verificar rapidament qualsevol valor:

>>> config('app.debug')
=> true
 
>>> config('cache.default')
=> "redis"
 
>>> config('queue.default')
=> "database"
 
>>> config('session.driver')
=> "file"
 
>>> config('app.timezone')
=> "Europe/Andorra"

Testejar rutes#

Pots inspeccionar les rutes registrades i generar-ne les URLs:

>>> route('articles.show', ['article' => 1])
=> "https://laravelandorra.com/articles/1"
 
>>> route('articles.index')
=> "https://laravelandorra.com/articles"
 
>>> url()->current()
=> "http://localhost"
 
>>> app('router')->getRoutes()->count()
=> 47

Verificar variables d'entorn#

Pots verificar que les variables d'entorn tenen els valors esperats, cosa que es especialment util despres d'un desplegament:

>>> env('APP_ENV')
=> "local"
 
>>> env('DB_CONNECTION')
=> "mysql"
 
>>> env('CACHE_DRIVER')
=> "redis"
 
>>> env('QUEUE_CONNECTION')
=> "database"

Tinker te acces complet a tota l'aplicacio, incloent la base de dades i tots els serveis configurats. En un entorn de produccio, qualsevol comanda que executis a Tinker afecta dades reals. Una consulta delete() mal dirigida o un update() sense condicions pot provocar perdua de dades irreversible. Utilitza Tinker en produccio amb extrema precaucio, i nomes quan sigui absolutament necessari. Sempre verifica dues vegades les comandes destructives abans d'executar-les, i considera fer un backup de la base de dades abans de manipular dades en produccio.

Configuracio#

Tinker es configurable a traves del fitxer config/tinker.php. Si aquest fitxer no existeix al teu projecte, pots publicar-lo amb Artisan:

php artisan vendor:publish --provider="Laravel\Tinker\TinkerServiceProvider"

Comandes permeses#

Per defecte, Tinker utilitza un sistema d'alias que permet utilitzar noms de classe curts (com User en lloc de App\Models\User). El camp dont_alias del fitxer de configuracio et permet especificar classes que no vols que es resolguin automaticament:

// config/tinker.php
'dont_alias' => [
    App\Models\User::class,
],

Amb aquesta configuracio, haurias d'escriure \App\Models\User::find(1) o fer un use App\Models\User explicit al principi de la sessio. Aixo es util quan tens classes amb noms conflictius a diferents namespaces.

Alias de classes#

El camp alias et permet definir alias personalitzats per a classes que utilitzes frequentment:

// config/tinker.php
'alias' => [
    'U' => App\Models\User::class,
    'A' => App\Models\Article::class,
],

Comandes disponibles#

Pots configurar quines comandes Artisan estan disponibles dins de Tinker. Per defecte, Tinker desactiva algunes comandes potencialment destructives:

// config/tinker.php
'commands' => [
    // Llista de comandes Artisan permeses dins de Tinker
],

Configuracio de PsySH#

Com que Tinker esta basat en PsySH, pots configurar PsySH directament creant un fitxer de configuracio a ~/.config/psysh/config.php o al directori del projecte. Les opcions inclouen el tema visual, el comportament de l'historial, la paginacio de resultats i mes:

// ~/.config/psysh/config.php
return [
    'defaultIncludes' => [
        // Fitxers que es carreguen automaticament a cada sessio
    ],
    'theme' => [
        'compact' => true,
    ],
    'historySize' => 1000,
    'eraseDuplicates' => true,
];

Trucs i consells#

Tinker te diverses funcionalitats que no son evidents a primera vista pero que milloren molt la productivitat un cop les coneixes.

Referencia a l'ultim resultat#

La variable especial $_ conté sempre el resultat de l'ultima expressio avaluada. Aixo es molt util per encadenar operacions sense haver d'assignar cada resultat a una variable:

>>> User::find(1)
=> App\Models\User {id: 1, name: "Joan Martí", ...}
 
>>> $_->articles()->count()
=> 3
 
>>> User::pluck('name')
=> Illuminate\Support\Collection {all: ["Joan Martí", "Maria López", ...]}
 
>>> $_->map(fn ($name) => strtoupper($name))
=> Illuminate\Support\Collection {all: ["JOAN MARTÍ", "MARIA LÓPEZ", ...]}

Expressions multilinia#

Tinker detecta automaticament quan una expressio no esta completa i et permet continuar a la seguent linia. El prompt canvia de >>> a ... per indicar que esta esperant mes codi:

>>> User::where('active', true)
...     ->where('created_at', '>=', now()->subMonth())
...     ->orderBy('name')
...     ->get()
=> Illuminate\Database\Eloquent\Collection {#1251
     all: [...],
   }

Aixo funciona automaticament amb arrays, closures i qualsevol estructura que requereixi multiples linies.

La comanda doc#

La comanda doc mostra la documentacio d'una funcio o metode de PHP directament dins de Tinker, sense necessitat d'obrir el navegador:

>>> doc array_map
function array_map(callable $callback, array $array, array ...$arrays): array
 
Description:
  Applies the callback to the elements of the given arrays.
 
>>> doc Illuminate\Support\Str::slug

La comanda show#

La comanda show mostra el codi font d'una funcio, metode o classe. Es enormement util per entendre com funciona una classe sense obrir el fitxer manualment:

>>> show Illuminate\Support\Str::slug
 
  public static function slug($title, $separator = '-', $language = 'en', $dictionary = ['@' => 'at'])
  {
      ...
  }

La comanda ls#

La comanda ls llista les variables definides a la sessio actual, cosa que et permet veure que tens disponible:

>>> $user = User::find(1)
>>> $articles = $user->articles
>>> ls
Variables: $user, $articles

Dreceres de teclat#

Tinker hereta les dreceres de PsySH i readline que fan la navegacio molt mes agil:

  • Fletxa amunt / avall: Navegar per l'historial de comandes anteriors
  • Ctrl+L: Netejar la pantalla mantenint la sessio activa
  • Ctrl+A: Moure el cursor al principi de la linia
  • Ctrl+E: Moure el cursor al final de la linia
  • Ctrl+R: Cerca inversa a l'historial (escriu un fragment i Tinker cerca la comanda mes recent que el contingui)
  • Tab: Autocompletat de noms de classes, metodes i variables

L'historial de comandes es persistent entre sessions, cosa que significa que pots recuperar comandes que vas executar dies enrere.

Exemples practics#

A continuacio veurem alguns escenaris reals on Tinker resulta indispensable per a un desenvolupador Laravel.

Depurar una consulta pas a pas#

Imagina que tens un endpoint que hauria de retornar els articles publicats d'un autor amb mes de 10 comentaris, pero retorna resultats incorrectes. A Tinker pots descomposar la consulta per trobar on falla:

>>> use App\Models\Article;
 
>>> // Pas 1: Verificar que existeixen articles publicats
>>> Article::where('published', true)->count()
=> 15
 
>>> // Pas 2: Filtrar per autor
>>> Article::where('published', true)->where('user_id', 1)->count()
=> 3
 
>>> // Pas 3: Afegir la condicio de comentaris
>>> Article::where('published', true)
...     ->where('user_id', 1)
...     ->withCount('comments')
...     ->get()
...     ->pluck('comments_count', 'title')
=> Illuminate\Support\Collection {
     "Introduccio a Laravel" => 12,
     "Eloquent avançat" => 8,
     "Tinker: la guia completa" => 3,
   }
 
>>> // Ara veiem que nomes 1 article te mes de 10 comentaris
>>> Article::where('published', true)
...     ->where('user_id', 1)
...     ->has('comments', '>=', 10)
...     ->get()
...     ->pluck('title')
=> Illuminate\Support\Collection {
     all: ["Introduccio a Laravel"],
   }

Descomponent la consulta pas a pas, pots identificar exactament on el filtre es massa restrictiu o on les dades no son les que esperaves.

Explorar l'API d'un paquet nou#

Quan integres un paquet nou al projecte, Tinker et permet experimentar amb la seva API de manera interactiva en lloc de llegir tota la documentacio primer:

>>> use Illuminate\Support\Str;
 
>>> // Explorar els metodes disponibles de Str
>>> Str::of('laravel andorra')->title()
=> Illuminate\Support\Stringable {value: "Laravel Andorra"}
 
>>> Str::of('laravel-andorra')->studly()
=> Illuminate\Support\Stringable {value: "LaravelAndorra"}
 
>>> Str::of('Hola Mon')->ascii()
=> Illuminate\Support\Stringable {value: "Hola Mon"}
 
>>> Str::of('Article amb un titol molt llarg que volem resumir')
...     ->words(5, '...')
=> Illuminate\Support\Stringable {value: "Article amb un titol molt..."}

Correccions rapides de dades#

De vegades necessites fer una correccio puntual a les dades. Tinker et permet fer-ho de manera controlada, pas a pas:

>>> // Trobar articles sense slug
>>> Article::whereNull('slug')->count()
=> 5
 
>>> // Generar slugs per als articles que no en tenen
>>> Article::whereNull('slug')->each(function ($article) {
...     $article->update(['slug' => Str::slug($article->title)]);
... })
=> Illuminate\Database\Eloquent\Collection {#1252}
 
>>> // Verificar que s'han corregit
>>> Article::whereNull('slug')->count()
=> 0

Prototipar una consulta complexa#

Abans d'escriure una consulta complexa en un controlador, pots construir-la gradualment a Tinker:

>>> // Volem: els 5 autors amb mes articles publicats aquest mes
>>> User::withCount(['articles' => function ($query) {
...     $query->where('published', true)
...         ->where('published_at', '>=', now()->startOfMonth());
... }])
...     ->having('articles_count', '>', 0)
...     ->orderByDesc('articles_count')
...     ->limit(5)
...     ->get()
...     ->pluck('articles_count', 'name')
=> Illuminate\Support\Collection {
     "Joan Martí" => 4,
     "Maria López" => 3,
     "Pere Andorra" => 2,
     "Anna Vidal" => 1,
     "Marc Serra" => 1,
   }

Un cop la consulta retorna el que necessites, pots copiar-la directament al controlador o al repositori amb la confianca que funciona correctament.

Tinker es una de les eines mes infrautilitzades de Laravel. Molts desenvolupadors la coneixen pero l'utilitzen poc, quan en realitat pot estalviar hores de desenvolupament i depuracio. Acostuma't a obrir Tinker sempre que tinguis un dubte sobre com funciona una consulta, un servei o una relacio. El cicle rapid de prova i error que ofereix es molt mes eficient que modificar codi, guardar el fitxer, refrescar el navegador i inspeccionar el resultat.