Utilizarea Laravel Scout pentru a activa căutarea integrală

Publicat: 2023-05-08

Cadrul Laravel a devenit o resursă de bază pentru dezvoltatorii care construiesc servicii web.

Ca instrument open-source, Laravel oferă o multitudine de funcționalități gata de fabricație care permit dezvoltatorilor să creeze aplicații robuste și funcționale.

Printre ofertele sale se numără Laravel Scout, o bibliotecă pentru gestionarea indicilor de căutare pentru aplicația dvs. Flexibilitatea sa le permite dezvoltatorilor să ajusteze configurațiile și să aleagă dintre driverele Algolia, Meilisearch, MySQL sau Postgres pentru a stoca indecșii.

Aici, vom explora acest instrument în profunzime, învățându-vă cum să adăugați suport de căutare full-text la o aplicație Laravel prin intermediul driverului. Veți modela o aplicație demonstrativă Laravel pentru stocarea numelui modelelor de trenuri și apoi veți folosi Laravel Scout pentru a adăuga o căutare în aplicație.

Cerințe preliminare

Pentru a urma, ar trebui să aveți:

  • Compilatorul PHP instalat pe computer. Acest tutorial folosește PHP versiunea 8.1.
  • Motorul Docker sau Docker Desktop instalat pe computer
  • Un cont cloud Algolia, pe care îl puteți crea gratuit
Doriți să vă faceți aplicația mai ușor de utilizat? Încercați să adăugați un suport pentru căutarea textului integral! Iată cum cu Laravel Scout ️ Click to Tweet

Cum se instalează Scout într-un proiect Laravel

Pentru a utiliza Scout, trebuie mai întâi să creați o aplicație Laravel în care intenționați să adăugați funcționalitatea de căutare. Scriptul Laravel-Scout Bash conține comenzile pentru a genera o aplicație Laravel într-un container Docker. Folosirea Docker înseamnă că nu trebuie să instalați software suplimentar, cum ar fi o bază de date MySQL.

Scriptul Laravel-scout folosește limbajul de scripting Bash, așa că trebuie să îl executați într-un mediu Linux. Dacă utilizați Windows, asigurați-vă că configurați Windows Subsystem pentru Linux (WSL).

Dacă utilizați WSL, executați următoarea comandă în terminal pentru a seta distribuția Linux preferată.

 wsl -s ubuntu

Apoi, navigați la locația de pe computer în care doriți să plasați proiectul. Scriptul Laravel-Scout va genera aici un director de proiect. În exemplul de mai jos, scriptul Laravel-Scout ar crea un director în directorul desktop .

 cd /desktop

Rulați comanda de mai jos pentru a executa scriptul Laravel-Scout. Va schelă o aplicație Dockerized cu codul standard necesar.

 curl -s https://laravel.build/laravel-scout-app | bash

După execuție, schimbați directorul folosind cd laravel-scout-app . Apoi, rulați comanda sail-up din folderul proiectului pentru a porni containerele Docker pentru aplicația dvs.

Notă: Pe multe distribuții Linux, poate fi necesar să rulați comanda de mai jos cu comanda sudo pentru a iniția privilegii ridicate.

 ./vendor/bin/sail up

Este posibil să întâmpinați o eroare:

Eroare la care afirmă că portul este alocat
Eroare la care afirmă că portul este alocat.

Pentru a rezolva acest lucru, utilizați variabila APP_PORT pentru a specifica un port în comanda sail up :

 APP_PORT=3001 ./vendor/bin/sail up

Apoi, executați comanda de mai jos pentru a rula aplicația prin Artisan pe serverul PHP.

 php artisan serve
Servirea aplicației Laravel cu Artisan
Servirea aplicației Laravel cu Artisan

Din browserul dvs. web, navigați la aplicația care rulează la http://127.0.0.1:8000. Aplicația va afișa pagina de bun venit Laravel pe ruta implicită.

Pagina de bun venit a aplicației Laravel
Pagina de bun venit a aplicației Laravel

Cum să adăugați Laravel Scout la aplicație

În terminalul dvs., introduceți comanda pentru a permite managerului de pachete Composer PHP să adauge Laravel Scout la proiect.

 composer require laravel/scout

Apoi, publicați fișierul de configurare Scout folosind comanda vendor:publish. Comanda va publica fișierul de configurare scout.php în directorul de configurare al aplicației dvs.

 php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"

Acum, modificați fișierul boilerplate .env pentru a conține o valoare booleană SCOUT_QUEUE .

Valoarea SCOUT_QUEUE va permite lui Scout să pună în coadă operațiunile, oferind timpi de răspuns mai buni. Fără el, șoferii Scout precum Meilisearch nu vor reflecta imediat recorduri noi.

 SCOUT_QUEUE=true

De asemenea, modificați variabila DB_HOST din fișierul .env pentru a indica gazda locală pentru a utiliza baza de date MySQL în containerele Docker.

 DB_HOST=127.0.0.1

Cum să marcați un model și să configurați indexul

Scout nu activează implicit modele de date care pot fi căutate. Trebuie să marcați în mod explicit un model ca fiind căutabil folosind caracteristica Laravel\Scout\Searchable .

Veți începe prin a crea un model de date pentru o aplicație demo Train și marcați-l ca fiind căutat.

Cum se creează un model

Pentru aplicația Train , veți dori să stocați numele substituentului fiecărui tren disponibil.

Executați comanda Artisan de mai jos pentru a genera migrarea și denumiți-o create_trains_table .

 php artisan make:migration create_trains_table
Efectuarea unei migrari numite create_trains_table
Efectuarea unei migrari numite create_trains_table

Migrarea va fi generată într-un fișier al cărui nume combină numele specificat și marca temporală curentă.

Deschideți fișierul de migrare aflat în directorul baza de date/migrații/ .

Pentru a adăuga o coloană de titlu, adăugați următorul cod după coloana id() din linia 17. Codul va adăuga o coloană de titlu.

 $table->string('title');

Pentru a aplica migrarea, executați comanda de mai jos.

 php artisan migrate
Aplicarea migrației artizanale
Aplicarea migrației artizanale

După ce rulați migrarea bazei de date, creați un fișier numit Train.php în directorul app/Models/ .

Cum să adăugați trăsătura de căutare LaravelScout

Marcați modelul Train pentru căutare adăugând trăsătura Laravel\Scout\Searchable la model, așa cum se arată mai jos.

 <?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Laravel\Scout\Searchable; class Train extends Model { use Searchable; public $fillable = ['title'];

De asemenea, trebuie să configurați indecșii de căutare suprascriind metoda searchable . Comportamentul implicit al lui Scout ar persista ca modelul să se potrivească cu numele tabelului model.

Deci, adăugați următorul cod în fișierul Train.php sub codul din blocul anterior.

 /** * Retrieve the index name for the model. * * @return string */ public function searchableAs() { return 'trains_index'; } }

Cum să utilizați Algolia cu Scout

Pentru prima căutare full-text cu Laravel Scout, veți folosi driverul Algolia. Algolia este o platformă software ca serviciu (SaaS) folosită pentru a căuta prin cantități mari de date. Oferă un tablou de bord web pentru dezvoltatori pentru a-și gestiona indexurile de căutare și un API robust pe care îl puteți accesa printr-un kit de dezvoltare software (SDK) în limbajul de programare preferat.

În cadrul aplicației Laravel, veți folosi pachetul client Algolia pentru PHP.

Cum se configurează Algolia

În primul rând, trebuie să instalați pachetul client de căutare PHP Algolia pentru aplicația dvs.

Executați comanda de mai jos.

 composer require algolia/algoliasearch-client-php

Apoi, trebuie să setați ID-ul aplicației și acreditările Secret API Key de la Algolia în fișierul .env .

Folosind browserul web, navigați la tabloul de bord Algolia pentru a obține ID-ul aplicației și acreditările Secret API Key.

Faceți clic pe Setări în partea de jos a barei laterale din stânga pentru a naviga la pagina Setări .

Apoi, faceți clic pe Chei API în secțiunea Echipa și acces a paginii Setări pentru a vedea cheile pentru contul dvs. Algolia.

Navigarea la pagina Chei API pe Algolia Cloud
Pagina Chei API pe Algolia Cloud

În pagina Chei API, notați ID-ul aplicației și valorile Cheii API Admin . Veți folosi aceste acreditări pentru a autentifica conexiunea dintre aplicația Laravel și Algolia.

Vizualizarea ID-ului aplicației și a cheilor API de administrare din pagina Chei API Algolia
ID-ul aplicației și cheile API de administrare

Adăugați codul de mai jos în fișierul dvs. .env folosind editorul de cod și înlocuiți substituenții cu secretele API Algolia corespunzătoare.

 ALGOLIA_APP_ID=APPLICATION_ID ALGOLIA_SECRET=ADMIN_API_KEY

De asemenea, înlocuiți variabila SCOUT_DRIVER cu codul de mai jos pentru a schimba valoarea de la meilisearch la algolia . Schimbarea acestei valori va instrui Scout să folosească driverul Algolia.

 SCOUT_DRIVER=algolia

Cum se creează controlere de aplicație

În directorul app/Http/Controllers/ , creați un fișier TrainSearchController.php pentru a stoca un controler pentru aplicație. Controlorul va lista și va adăuga date la modelul Train .

Adăugați următorul bloc de cod în fișierul TrainSearchController.php pentru a construi controlerul.

 <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Http\Requests; use App\Models\Train; class TrainSearchController extends Controller { /** * Get the index name for the model. * * @return string */ public function index(Request $request) { if($request->has('titlesearch')){ $trains = Train::search($request->titlesearch) ->paginate(6); }else{ $trains = Train::paginate(6); } return view('Train-search',compact('trains')); } /** * Get the index name for the model. * * @return string */ public function create(Request $request) { $this->validate($request,['title'=>'required']); $trains = Train::create($request->all()); return back(); } }

Cum se creează rutele aplicației

În acest pas, veți crea rutele pentru listarea și adăugarea de noi trenuri în baza de date.

Deschideți fișierul rute/web.php și înlocuiți codul existent cu blocul de mai jos.

 <?php use Illuminate\Support\Facades\Route; use App\Http\Controllers\TrainSearchController; Route::get('/', function () { return view('welcome'); }); Route::get('trains-lists', [TrainSearchController::class, 'index']) -> name ('trains-lists'); Route::post('create-item', [TrainSearchController::class, 'create']) -> name ('create-item');

Codul de mai sus definește două rute în aplicație. Solicitarea GET pentru ruta /trains-lists listează toate datele de tren stocate. Solicitarea POST pentru ruta /create-item creează date noi de tren.

Cum se creează vizualizările aplicației

Creați un fișier în directorul resurse/views/ și numiți-l Train-search.blade.php . Fișierul va afișa interfața cu utilizatorul pentru funcționalitatea de căutare.

Adăugați conținutul blocului de cod de mai jos în fișierul Train-search.blade.php pentru a crea o singură pagină pentru funcționalitatea de căutare.

 <!DOCTYPE html> <html> <head> <title>Laravel - Laravel Scout Algolia Search Example</title> <link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body> <div class="container"> <h2 class="text-bold">Laravel Full-Text Search Using Scout </h2><br/> <form method="POST" action="{{ route('create-item') }}" autocomplete="off"> @if(count($errors)) <div class="alert alert-danger"> <strong>Whoops!</strong> There is an error with your input. <br/> <ul> @foreach($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <input type="hidden" name="_token" value="{{ csrf_token() }}"> <div class="row"> <div class="col-md-6"> <div class="form-group {{ $errors->has('title') ? 'has-error' : '' }}"> <input type="text" name="title" class="form-control" placeholder="Enter Title" value="{{ old('title') }}"> <span class="text-danger">{{ $errors->first('title') }}</span> </div> </div> <div class="col-md-6"> <div class="form-group"> <button class="btn btn-primary">Create New Train</button> </div> </div> </div> </form> <div class="panel panel-primary"> <div class="panel-heading">Train Management</div> <div class="panel-body"> <form method="GET" action="{{ route('trains-lists') }}"> <div class="row"> <div class="col-md-6"> <div class="form-group"> <input type="text" name="titlesearch" class="form-control" placeholder="Enter Title For Search" value="{{ old('titlesearch') }}"> </div> </div> <div class="col-md-6"> <div class="form-group"> <button class="btn btn-primary">Search</button> </div> </div> </div> </form> <table class="table"> <thead> <th>Id</th> <th>Train Title</th> <th>Creation Date</th> <th>Updated Date</th> </thead> <tbody> @if($trains->count()) @foreach($trains as $key => $item) <tr> <td>{{ ++$key }}</td> <td>{{ $item->title }}</td> <td>{{ $item->created_at }}</td> <td>{{ $item->updated_at }}</td> </tr> @endforeach @else <tr> <td colspan="4">No train data available</td> </tr> @endif </tbody> </table> {{ $trains->links() }} </div> </div> </div> </body> </html>

Codul HTML de mai sus conține un element de formular cu un câmp de introducere și un buton pentru introducerea titlului unui tren înainte de a-l salva în baza de date. Codul are, de asemenea, un tabel HTML care afișează detaliile id , title , created_at și updated_at ale unei intrări de tren în baza de date.

Cum să utilizați Algolia Search

Pentru a vizualiza pagina, navigați la http://127.0.0.1:8000/trains-lists din browserul dvs. web.

Vizualizarea datelor modelului de tren afișate în pagina de liste de trenuri
Datele modelului de tren

Baza de date este în prezent goală, așa că trebuie să introduceți un titlu al unui tren demonstrativ în câmpul de introducere și să faceți clic pe Creare un tren nou pentru a-l salva.

Se introduce o nouă intrare de tren
Se introduce o nouă intrare de tren

Pentru a utiliza funcția de căutare, introduceți un cuvânt cheie din orice titlu de tren salvat în câmpul de introducere Introduceți titlul pentru căutare și faceți clic pe Căutare .

După cum se arată în imaginea de mai jos, se vor afișa numai intrările de căutare care conțin cuvântul cheie în titlurile lor.

Utilizarea funcției de căutare pentru a găsi o intrare de tren
Utilizarea funcției de căutare pentru a găsi o intrare de tren

Meilisearch cu Laravel Scout

Meilisearch este un motor de căutare open-source care se concentrează pe viteză, performanță și experiență îmbunătățită a dezvoltatorului. Împărtășește mai multe caracteristici cu Algolia, folosind aceiași algoritmi, structuri de date și cercetare - dar cu un limbaj de programare diferit.

Dezvoltatorii pot crea și găzdui singuri o instanță Meilisearch în infrastructura lor locală sau cloud. Meilisearch are, de asemenea, o ofertă de cloud beta similară cu Algolia pentru dezvoltatorii care doresc să folosească produsul fără a-și gestiona infrastructura.

În tutorial, aveți deja o instanță locală a Meilisearch care rulează în containerele dvs. Docker. Acum veți extinde funcționalitatea Laravel Scout pentru a utiliza instanța Meilisearch.

Pentru a adăuga Meilisearch la aplicația Laravel, rulați comanda de mai jos în terminalul proiectului.

 composer require meilisearch/meilisearch-php

Apoi, trebuie să modificați variabilele Meilisearch din fișierul .env pentru a-l configura.

Înlocuiți variabilele SCOUT_DRIVER , MEILISEARCH_HOST și MEILISEARCH_KEY din fișierul .env cu cele de mai jos.

 SCOUT_DRIVER=meilisearch MEILISEARCH_HOST=http://127.0.0.1:7700 MEILISEARCH_KEY=LockKey

Cheia SCOUT_DRIVER specifică driverul pe care Scout ar trebui să-l folosească, în timp ce MEILISEARCH_HOST reprezintă domeniul în care rulează instanța dvs. Meilisearch. Deși nu este necesar în timpul dezvoltării, se recomandă adăugarea MEILISEARCH_KEY în producție.

Notă: Comentați ID-ul și Secretul Algolia atunci când utilizați Meilisearch ca driver preferat.

După finalizarea configurațiilor .env , ar trebui să indexați înregistrările preexistente folosind comanda Artisan de mai jos.

 php artisan scout:import "App\Models\Train"

Laravel Scout cu motor de bază de date

Motorul de baze de date al lui Scout ar putea fi cel mai potrivit pentru aplicațiile care folosesc baze de date mai mici sau gestionează sarcini de lucru mai puțin intensive. În prezent, motorul bazei de date acceptă PostgreSQL și MySQL.

Acest motor folosește clauze „unde asemănătoare” și indexuri full-text împotriva bazei de date existente, permițându-i să găsească cele mai relevante rezultate de căutare. Nu trebuie să indexați înregistrările atunci când utilizați motorul bazei de date.

Pentru a utiliza motorul bazei de date, trebuie să setați variabila SCOUT_DRIVER .env la baza de date.

Deschideți fișierul .env din aplicația Laravel și modificați valoarea variabilei SCOUT_DRIVER .

 SCOUT_DRIVER = database

După ce vă schimbați driverul în baza de date, Scout va trece la utilizarea motorului bazei de date pentru căutarea full-text.

Motor de colectare cu Laravel Scout

Pe lângă motorul de bază de date, Scout oferă și un motor de colectare. Acest motor folosește clauze „unde” și filtrarea colecțiilor pentru a extrage cele mai relevante rezultate ale căutării.

Spre deosebire de motorul de baze de date, motorul de colectare acceptă toate bazele de date relaționale pe care Laravel le acceptă.

Puteți utiliza motorul de colectare setând variabila de mediu SCOUT_DRIVER la collection sau specificând manual driverul de colectare în fișierul de configurare Scout.

 SCOUT_DRIVER = collection

Explorer cu Elasticsearch

Având puterea interogărilor Elasticsearch, Explorer este un driver Elasticsearch modern pentru Laravel Scout. Oferă un driver Scout compatibil și beneficii precum stocarea, căutarea și analizarea unor cantități masive de date în timp real. Elasticsearch cu Laravel oferă rezultate în milisecunde.

Pentru a utiliza driverul Elasticsearch Explorer în aplicația dvs. Laravel, va trebui să configurați fișierul boilerplate docker-compose.yml generat de scriptul Laravel-Scout. Veți adăuga configurațiile suplimentare pentru Elasticsearch și veți reporni containerele.

Deschideți fișierul docker-compose.yml și înlocuiți-i conținutul cu următorul.

 # For more information: https://laravel.com/docs/sail version: '3' services: laravel.test: build: context: ./vendor/laravel/sail/runtimes/8.1 dockerfile: Dockerfile args: WWWGROUP: '${WWWGROUP}' image: sail-8.1/app extra_hosts: - 'host.docker.internal:host-gateway' ports: - '${APP_PORT:-80}:80' - '${VITE_PORT:-5173}:${VITE_PORT:-5173}' environment: WWWUSER: '${WWWUSER}' LARAVEL_SAIL: 1 XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}' XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}' volumes: - '.:/var/www/html' networks: - sail depends_on: - mysql - redis - meilisearch - mailhog - selenium - pgsql - elasticsearch mysql: image: 'mysql/mysql-server:8.0' ports: - '${FORWARD_DB_PORT:-3306}:3306' environment: MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}' MYSQL_ROOT_HOST: "%" MYSQL_DATABASE: '${DB_DATABASE}' MYSQL_USER: '${DB_USERNAME}' MYSQL_PASSWORD: '${DB_PASSWORD}' MYSQL_ALLOW_EMPTY_PASSWORD: 1 volumes: - 'sail-mysql:/var/lib/mysql' - './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh' networks: - sail healthcheck: test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"] retries: 3 timeout: 5s elasticsearch: image: 'elasticsearch:7.13.4' environment: - discovery.type=single-node ports: - '9200:9200' - '9300:9300' volumes: - 'sailelasticsearch:/usr/share/elasticsearch/data' networks: - sail kibana: image: 'kibana:7.13.4' environment: - elasticsearch.hosts=http://elasticsearch:9200 ports: - '5601:5601' networks: - sail depends_on: - elasticsearch redis: image: 'redis:alpine' ports: - '${FORWARD_REDIS_PORT:-6379}:6379' volumes: - 'sail-redis:/data' networks: - sail healthcheck: test: ["CMD", "redis-cli", "ping"] retries: 3 timeout: 5s pgsql: image: 'postgres:13' ports: - '${FORWARD_DB_PORT:-5432}:5432' environment: PGPASSWORD: '${DB_PASSWORD:-secret}' POSTGRES_DB: '${DB_DATABASE}' POSTGRES_USER: '${DB_USERNAME}' POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}' volumes: - 'sailpgsql:/var/lib/postgresql/data' networks: - sail healthcheck: test: ["CMD", "pg_isready", "-q", "-d", "${DB_DATABASE}", "-U", "${DB_USERNAME}"] retries: 3 timeout: 5s meilisearch: image: 'getmeili/meilisearch:latest' ports: - '${FORWARD_MEILISEARCH_PORT:-7700}:7700' volumes: - 'sail-meilisearch:/meili_data' networks: - sail healthcheck: test: ["CMD", "wget", "--no-verbose", "--spider", "http://localhost:7700/health"] retries: 3 timeout: 5s mailhog: image: 'mailhog/mailhog:latest' ports: - '${FORWARD_MAILHOG_PORT:-1025}:1025' - '${FORWARD_MAILHOG_DASHBOARD_PORT:-8025}:8025' networks: - sail selenium: image: 'selenium/standalone-chrome' extra_hosts: - 'host.docker.internal:host-gateway' volumes: - '/dev/shm:/dev/shm' networks: - sail networks: sail: driver: bridge volumes: sail-mysql: driver: local sail-redis: driver: local sail-meilisearch: driver: local sailpgsql: driver: local sailelasticsearch: driver: local

Apoi, rulați comanda de mai jos pentru a extrage noua imagine Elasticsearch pe care ați adăugat-o în fișierul docker-compose.yml .

 docker-compose up

Apoi, executați comanda Composer de mai jos pentru a instala Explorer în proiect.

 composer require jeroen-g/explorer

De asemenea, trebuie să creați un fișier de configurare pentru driverul Explorer.

Executați comanda Artisan de mai jos pentru a genera un fișier explorer.config pentru stocarea configurațiilor.

 php artisan vendor:publish --tag=explorer.config

Fișierul de configurare generat mai sus va fi disponibil în directorul /config .

În fișierul config/explorer.php , puteți face referire la modelul dvs. folosind cheia indexes .

 'indexes' => [ \App\Models\Train::class ],

Schimbați valoarea variabilei SCOUT_DRIVER din fișierul .env la elastic pentru a configura Scout să utilizeze driverul Explorer.

 SCOUT_DRIVER = elastic

În acest moment, veți folosi Explorer în cadrul modelului Train prin implementarea interfeței Explorer și suprascriind metoda mappableAs() .

Deschideți fișierul Train.php din directorul Aplicație > Modele și înlocuiți codul existent cu codul de mai jos.

 <?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use JeroenG\Explorer\Application\Explored; use Laravel\Scout\Searchable; class Train extends Model implements Explored { use HasFactory; use Searchable; protected $fillable = ['title']; public function mappableAs(): array { return [ 'id'=>$this->Id, 'title' => $this->title, ]; } }

Cu codul pe care l-ați adăugat mai sus, puteți utiliza acum Explorer pentru a căuta text în modelul Train .

Laravel + Scout = integrare rapidă, robustă și curată a căutării full-text. Creați o aplicație demonstrativă și încercați-o cu acest ghid ️ Faceți clic pentru a trimite pe Tweet

rezumat

Pentru dezvoltatorii PHP, Laravel și suplimente precum Scout fac ca integrarea unei funcționalități de căutare full-text rapidă și robustă să fie simplă. Cu Motorul de baze de date, Motorul de colectare și capabilitățile Meilisearch și Elasticsearch, puteți interacționa cu baza de date a aplicației dvs. și puteți implementa mecanisme avansate de căutare în doar milisecunde.

Gestionarea și actualizarea perfectă a bazei de date înseamnă că utilizatorii dvs. primesc o experiență optimă, în timp ce codul dvs. rămâne curat și eficient.

Cu soluțiile noastre de găzduire a aplicațiilor și bazelor de date, Kinsta este ghișeul dvs. unic pentru toate nevoile dvs. moderne de dezvoltare Laravel. Primii 20 de dolari sunt la noi.