Laravel 9.*



1. რა არის Laravel ?

Laravel - MVC პრინციპზე დაფუძნებული პლატფორმა, ფრეიმვორკი, ინსტრუმენტთა ნაკრები იმ პროგრამისტებისათვის, რომლებიც PHP-ის მეშვეობით ამზადებენ ვებ-გვერდებს. ფრეიმვორკის დახმარებით გაცილებით სწრაფად და მარტივად ვქმნით აპლიკაციებს და აღარ გვიწევს კოდის წერის დაწყება ნოლიდან. ფაქტიურად ფრეიმვორკი წარმოადგენს მომავალი პროექტის კარკასს, ჩონჩხს, მასში ჩადებულია ისეთი კლასები რომელთა მეშვეობითაც პროგრამისტს აღარ უწევს მთელი რიგი სტანდარტული და რუტინული სამუშაოების ჩატარება, მაგალითად: საიტზე შესვლის წერტილის შექმნა, ადამიანისათვის გასაგები URL-ების შექმნა, შემავალი პარამეტრებისა და მონაცემების ვალიდაციის მექანიზმის შექმნა, მონაცემთა ბაზასთან მუშაობის ორგანიზება და ა.შ

Laravel-ის პირველი ვერსია შეიქმნა 2011 წელს (ავტ. Taylor Otwell).

2. ინსტალაცია
Laravel-თან სამუშაოდ დაგვჭირდება : რა თქმა უნდა ბრაუზერი, რომელიმე ტექსტ-ედიტორი ან IDE (Integrated Development Environment - პროგრამული უზრუნველყოფა, რომელიც გამოიყენება აპლიკაციების შექმნისას და რომელიც ერთიან გრაფიკულ ინტერფეისში (GUI - graphical user interface) აერთიანებს პროგრამისტისათვის საჭირო სხვადასხვა ხელსაწყოებსა და ინსტრუმენტებს. მაგ: NetBeans, PhpStorm ...), PHP ინტერპრეტატორი და მონაცემთა ბაზის სერვერი.

დიდი ალბათობით, Laravel-ის შესწავლისას მომხმარებელს უკვე ექნება შეხება PHP-ს რომელიმე ინტერპრეტატორთან და მონაცემთა ბაზის სერვერთან, ეს შეიძლება იყოს როგორც ცალკე დაინსტალირებული პროგრამები, მაგ: ვებ-სერვერი Apache, PHP ინტერპრეტატორი, მბ სერვერი MYSQL, ასევე გამზადებული ნაკრებები მაგ: Denver, OpenServer, XAMPP, WAMP, LAMP და ა.შ. შესაძლებელია მათი გამოყენებაც.

ინსტალაცია Composer-ით

რა არის Composer-ი ?

Composer-ი არის სხვადასხვა დამოკიდებულებების მენეჯერი, რომლის საშუალებითაც ხდება, ამა თუ იმ ბიბლიოთეკების, დამოკიდებულებებისა და პაკეტების ინტეგრირება PHP პროგრამულ უზრუნველყოფაში. Windows ოპერაციულ სისტემაში Composer-ის ინსტალაცია საკმაოდ მარტივია, უბრალოდ უნდა გადმოვწეროთ საინსტალაციო ფაილი და დავაინსტალიროთ (ავტორები: Nils Adermann და Jordi Boggiano).

ინტალაციის პროცესი მოგვთხოვს გზას PHP-მდე, რომელიც შეიძლება გამოიყურებოდეს ასე:





ინსტალაციის შემდეგ ბრძანებათა ველიდან გავუშვათ შემდეგი ბრძანება : composer თუ შედეგად ვიხილავ ამდაგვარ სურათს:



ესეიგი ყველაფერი რიგზეა.

ახალი პროექტის შექმნა

ახალი პროექტის შესაქმნელად გამოიყენება composer-ის ბრძანება create-project, ბრძანებასთან ერთად ასევე უნდა მივუთითოთ სასურველი პაკეტის დასახელება და იმ დირექტორიის დასახელება სადაც გვსურს, რომ შეიქმნას ახალი პროექტი: composer create-project <PACKAGE_NAME> <MY_PROJECT>

პაკეტების საცავი (Repository)

ამა თუ იმ დამოკიდებულების ან პაკეტის ინსტალაციის პროცესს თუ მარტივი ენით განვმარტავთ, მივიღებთ ასეთ სურათს : მას შემდეგ რაც გაეშვება ინსტალაციის ბრძანება, Composer-ი მიაკითხავს რაღაც წყაროს, რესურსს, სადაც განთავსებულია სასურველი პაკეტის შესაბაისი ფაილები, დამოკიდებულებები და ა.შ და ამ ყველაფერს გადმოწერს ჩვენს ლოკალურ სისტემაში.

ჩნდება კითხვები : მაინც სად არის ინახება ეს პაკეტები ? საიდან მოაქვს Composer-ს ეს ყველაფერი ?

როდესაც Composer-ი ინსტალირდება, ნაგულისხმეობის პრინციპით ხდება ერთადერთი საცავის რეგისტრაცია, ეს საცავია ვებ-გვერდი Packagist.org.

***

მაშ ასე, ბრძანებათა ველის მეშვეობით გადავდივართ სასურველ დირექტორიაში და ვუშვებთ შემდეგ ბრძანებას :
composer create-project laravel/laravel laravel   
            
ბრძანების გაშვების შემდეგ დაიწყება Laravel-ის ინსტალაცია და აგრეთვე შეიქმნება laravel საქაღალდე შესაბამისი ფაილებისა და საქაღალდეების სტრუქტურით :



როგორ გავხსნათ პროექტი ?

რა არის Artisan ?

ინგ: Artisan - ხელოსანი, ოსტატი.

Artisan-ი არის Laravel-ში ჩადგმული ბრძანებათა ინტერფეისის სახელწოდება, რომლის მეშვეობითაც შესაძლებელია სხვადასხვა საჭირო ბრძანებებისა და ინსტრუქციების საკმაოდ მარტივად გაშვება აპლიკაციაზე მუშობის პროცესში. Artisan ბრძანებათა სრული ჩამონათვალის სანახავად უნდა გავუშვათ შემდეგი ბრძანება :

php artisan list

***

ბრძანებათა ველიდან გადავიდეთ ახლად შექმნილ საქაღალდეში - laravel და ავამუშავოთ პროექტი შემდეგი ბრძანების დახმარებით : php artisan serve შედეგი იქნება :



თუ ახლა შევალთ ამ მისამართზე: http://127.0.0.1:8000, ვიხილავთ ჩვენს პროექტს :



3. რა არის MVC ?
MVC (Model–View–Controller ანუ მოდელი-წარმოდგენა-კონტროლერი) - არის კომპიუტერულ ინჟინერიაში გავრცელებული, კოდირების შაბლონი, მეთოდი, იდეა, რომელიც საშუალებას იძლევა განცალკევდეს ვებ-აპლიკაციის ლოგიკა და მისი წარმოდგენა ანუ ის ნაწილი რომელსაც მომხმარებელი ხედავს ბრაუზერში.



ეს განცალკევება აპლიკაციას ხდის უფრო მოქნილს და ადვილად კორექტირებადს, რადგან თუ გვსურს ვიზუალური მხარის ჩასწორება საქმე გვაქვს მხოლოდ მასთან და არა ლოგიკურ ფუნქციონალთან და პირიქით.

წარმოდგენა

MVC-ს ელემენტ - 'წარმოდგენა (view)'-ს ინფორმაცია გამოაქვს ეკრანზე. ეს არის აპლიკაციის დიზაინერული ნაწილი მინიმალური ლოგიკით. წარმოდგენა შეიძლება შედგებოდეს რამდენიმე შაბლონისაგან.



კონტროლერი

MVC-ს ელემენტი - 'კონტროლერი' არის მომხმარებლისა და აპლიკაციის წარმოდგენის დამაკავშირებელი ბლოკი. იგი იღებს ინფორმაციას მომხმარებლისაგან, ამუშავებს, ამოწმებს მას და ეს დამუშავებული ინფორმაცია ეგზავნება MVC-ს მესამე ელემენტს - 'მოდელს', კონტროლერი მისგან ღებულობს შესაბამის პასუხს და წყვეტს თუ წარმოდგენის რომელმა შაბლონმა უნდა დაუბრუნოს ეს პასუხი მომხმარებელს.



მოდელი

MVC-ს მესამე ელემენტში - 'მოდელი', ხდება სისტემის მუშაობის ლოგიკის ძირითადი ნაწილის აღწერა. მოდელი მუშაობს მონაცემებთან, ახდენს მონაცემებით მანიპულირებას. მოდელი იღებს კონტროლერისაგან რაიმე მოთხოვნას, შემდეგ მბ-დან მოაქვს შესაბამისი ინფორმაცია და უბრუნებს კონტროლერს. სხვა სიტყვებით, რომ ვთქვათ მოდელის ფუნქციაა მიიღოს მონაცემი, დაამუშავოს იგი და დააბრუნოს პასუხი. პრაქტიკაში მოდელის რეალიზება ხშირად ხდება ხოლმე კლასის სახით, რომელსაც აქვს მონაცეთა დამუშავებისათვის განსაზღვრული მეთოდები.



მუშაობის კლასიკური სქემა

მომხმარებელმა გააკეთა მოთხოვნა საიტზე, მოთხოვნა გადაეცა საიტზე შესვლის ერთადერთ წერტილს (index.php, frontController), ამ წერტილში მოსულ მოთხოვნას ამუშავებს მარშრუტიზაციის კომპონენტი (Router), ერთგვარი გზამკვლევი მოთხოვნისათვის, როუტერმა უნდა განსაზღვროს თუ რომელმა კონტროლერმა უნდა დაამუშავოს მოთხოვნა



ვთქვათ ეს კონტროლერია NewsController, ეს კონტროლერი მოთხოვნიდან ღებულობს ინფორმაციას თუ რა სახის სიახლეების ნახვა უნდა მომხმარებელს, შემდეგ მიმართავს მოდელს საჭირო ინფორმაციის მისაღებად, პასუხის მიღების შემდეგ კონტროლერი იყენებს საჭირო წარმოდგენას პასუხის ბრაუზერში გამოსატანად, ასე იკვრება მთლიანი წრე.
4. ფრეიმვორკის სტრუქტურა

დირექტორიები

App დირექტორია

App დირექტორია მოიცავს ჩვენი აპლიკაციის ძირითად კოდს, მასშია მოთავსებული აპლიკაციის კლასები. ამ საქაღალდეს უფრო დაწვრილებით განვიხილავთ ოდნავ მოგვიანებით.

Bootstrap დირექტორია

ამ საქაღალდის დასახელებას საერთო არაფერი აქვს ფრეიმვორკ Bootstrap-თან :)) აქ თავმოყრილია ფაილები, რომლებიც ახორციელებენ ფრეიმვორკ Laravel-ის თავდაპირველ ჩატვირთვას და ახდენენ კლასების ავტოჩატვირთვას (ინგლ: Bootstrap - ახალი ვარიანტის შესაქმნელად სისტემის ან პროცესის არსებული ვარიანტის გამოყენება. Bootstrapping - თვითრეგულირება, თვითაწყობა, თვითჩატვირთვა, თვითუზრუნველყოფა).

ამ საქაღალდეში აგრეთვე მოთავსებულია კატალოგი cache, სადაც თავმოყრილი ფაილები გამოიყენება ფრეიმვორკის მუშაობის დროს მიმდინარე პროცესების ოპტიმიზაციისათვის (მაგ: მარშრუტიზაცია, ფაილთა ქეშირება)

Config დირექტორია

ეს საქაღალდე, როგორც მისივე დასახელებიდანაც ჩანს, შეიცავს აპლიკაციის კონფიგურაციულ ფაილებს. სასურველია მომხმარებელი გაეცნოს ამ ფაილებს და შეისწავლოს თუ რომელ მათგანში რა არის განსაზღვრული.

Database დირექტორია

ეს საქაღალდე, როგორც მისივე დასახელებიდანაც ჩანს, შეიცავს მონაცემთა ბაზასთან დაკავშირებულ ფაილებსა და საქაღალდეებს, აქ ხდება მბ-ს პარამეტრების განსაზღვრა (ჰოსტი, მომხმარებელი, პაროლი, მბ-ს სახელი და ა.შ).

Public დირექტორია

ეს დირექტორია შეიცავს index.php ფაილს, რომელიც არის ჩვენ აპლიკაციაში შესასვლელი წერტილი, დირექტორია აგრეთვე შეიცავს ისეთ ხელსაწყო-ატრიბუტებს როგორებიცაა სურათები, ჯავასკრიპტის ფაილები, CSS ფაილები...

Resources დირექტორია

ეს საქაღალდე შეიცავს წარმოდგენის ფაილებს (views), არაკომპილირებად ინსტრუმენტებს როგორებიცაა LESS, SASS ან JavaScript. აქვეა მოთავსებული თარგმანებთან დაკავშირებული ფაილებიც.

Routes დირექტორია

ეს საქაღალდე შეიცავს აპლიკაციის მარშრუტების განმსაზღვრელ ფაილებს, ნაგულისხმეობის პრინციპით Laravel-ში ჩართულია მარშრუტთა რამდენიმე ფაილი :web.php, api.php, console.php და channels.php.

Storage დირექტორია

ეს დირექტორია შეიცავს კომპილირებულ Blade შაბლონებს, ფაილებზე დაფუძნებულ სესიებს, ქეშ-ფაილებს და ფრეიმვორკის ფარგლებში შექმნილ სხვა ფაილებს. საქაღალდე იყოფა app, framework და logs საქაღალდეებად.

Vendor დირექტორია

ეს დირექტორია შეიცავს Composer-ის დამოკიდებულებებს.

App დირექტორია დაწვრილებით

როგორც აღვნიშნეთ, აპლიკაციის ძირითადი ნაწილი განთავსებულია აქ. მას ავტომატურად ტვირთავს Composer-ი PSR-4 (PHP Standard Recommendation) ავტოჩატვირთვის სტანდარტით. ამ საქაღალდეს App დასახელება ენიჭება ნაგულისმეობის პრინციპით, სახელის გადარქმევა კი შესაძლებელია შემდეგი ბრძანებით php artisan app:name <name-of-your-application>

Console დირექტორია

აქ მოთავსებულია სამომხმარებლო Artisan ბრძანებები. ამ ბრძანებების გენერირება ხდება make:command ბრძანებით.

Exceptions დირექტორია

შეიცავს აპლიკაციაში დაფიქსირებულ გამონაკლისთა დამმუშავებლებს, თუ გვსურს რომ განვსაზღვროთ თუ როგორ დარეგისტრირდეს ან გამოისახოს კონკრეტული გამონაკლისი, შესაბამისად უნდა დავარედაქტიროთ, ამ საქაღალდეში არსებული Handler კლასი.

Http დირექტორია

შეიცავს კონტროლერებს, ფორმის მოთხოვნებს. აქვე თავსდება აპლიკაციისაკენ მიმართული მოთხოვნების დამუშავების თითქმის მთლიანი ლოგიკა.

Providers დირექტორია

ეს დირექტორია შეიცავს ჩვენი აპლიკაციის სერვის-პროვაიდერებს.

ზემოთ ჩამოთვლილ თითოეულ საქაღალდესა და დირექტორიას შევეხებით სწავლების პროცესში, კონკრეტული ამოცანების გადაჭრისას.
5. ფრეიმვორკის კონფიგურაციის გამართვა
ფრეიმვორკ Laravel-ს, ინსტალაციის შემდეგ თითქმის არ ჭირდება დამატებით რაიმე კონფიგურაციული პარამეტრების განსაზღვრა, თუმცა არსებობს გამონაკლისებიც, მაგალითად მონაცემთა ბაზასთან დასაკავშირებელი პარამეტრები. ასევე შეიძლება დაგვჭირდეს დროის სარტყელის მითითებაც და ა.შ. როგორც უკვე ვიცით, კორფიგურაციული პარამეტრების განსაზღვრა ხდება config დირექტორიაში არსებული ფაილების მეშვეობით.

პროექტის კეთების ეტაპი შესაძლებელია დავყოთ სამ ნაწილად:

  • პირველ ეტაპზე ვმუშაობთ ლოკალურ სივრცეში, ეს შეიძლება იყოს OpenServer, Virtualbox, XAMPP...
  • მეორე ეტაპზე ხდება პროექტის ტესტირება, სავარაუდო შეცდომების გასწორება...
  • მესამე ეტაპზე კი პროექტი იტვირთება უკვე რეალურ ჰოსტინგზე ანუ ეშვება სამუშაო გარემოში
შევთანხმდეთ, რომ სამივე ეტაპზე, კონფიგურაციული პარამეტრების სხვადასხვაგვარად განსაზღვრაა საჭირო , მაგალითად მბ-სთან დასაკავშირებელი პარამეტრები სულ სხვაა ლოკალურ სივრცეში და სულ სხვა იქნება რეალურ სერვერზე. ამიტომ იმ პარამეტრთა ჯგუფის მიხედვით, რომელთა შეცვლაც საჭიროა მუშაობის პროცესის ეტაპებიდან გამომდინარე, შეიძლება მოვახდინოთ კონფიგურაციული პარამეტრების ერთგვარი არეების, გარემოების ფორმირება. ამ გარემოში შემავალ პარამეტრებს ეწოდებათ გარემოს ცვლადები , რომლებიც, 'გასაღები=მნიშვნელობა' წყვილების სახით ინახება .env ფაილში (ინგ: Environment - გარემოცვა; გარემო). ამ ფაილის სტრუქტურა შემდეგნაირია :

APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:G1LDmxoK8uRi9uWtKO0ae4TQgLmTN7VEJszlIncU1BA=
APP_DEBUG=true
APP_URL=http://localhost

LOG_CHANNEL=stack
LOG_LEVEL=debug

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120

MEMCACHED_HOST=127.0.0.1

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1

MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
            
  • APP_NAME - აპლიკაციის დასახელება.

  • APP_ENV - ანუ სამუშაო გარემო (Application Environment), აპლიკაციის კეთების პროცესის მიმდინარე ფაზა, ეტაპი, მასზეა დამოკიდებული ყველა სხვა პარამეტრის მნიშვნელობა.

  • APP_KEY - ამ პარამეტრში შენახულია შემთხვევითი სტრიქონი, რომელიც გამოიყენება ფრეიმვორკის მუშაობის პროცესში, სხვადასხვა მონაცემების დასაშიფრად. APP_KEY-ს მნიშვნელობა ცნობილია მხოლოდ ჩვენი აპლიკაციის შიგნით და არსად სხვაგან. შესაბამისად მხოლოდ ჩვენი აპლიკაციისთვისაა შესაძლებელი, ორმხრივი ალგორითმებისა და ამ გასაღების მეშვეობით დაშიფრული ინფორმაციის დეშიფრაცია.

    სად გამოიყენება APP_KEY ?

    გამოიყენება ფრეიმვორკის ნებისმიერ ადგილას სადაც საჭიროა მონაცემების შიფრაცია ორმხრივი ალგორითმების დახმარებით (მაგ: Sessions, CSRF tokens, Cookies)

    სად არ გამოიყენება APP_KEY ?

    არ გამოიყენება იმ ადგილას სადაც ხდება მონაცემების ჰეშირება ცალმხრივი ალგორითმების დახმარებით (მაგ: Passwords, password_reset_token)

  • APP_DEBUG - შეცდომების გამოტანის პარამეტრი, თუ მითითებულია მნიშვნელობა true მაშინ სისტემა გამოიტანს დაფიქსირებული შეცდომის შესახებ შეტყობინებას, ხოლო თუ მითითებულია false მაშინ არ გამოიტანს. პროექტის შექმნის ეტაპზე სასურველია ეს პარამეტრი იყოს ჩართული, ხოლო სამუშაო გარემოში კი - გამორთული.

  • DB განყოფილება - მოიცავს მონაცემთა ბაზასთან სამუშაოდ აუცილებელ პარამეტრებს.

  • CACHE_DRIVER - ქეშირების სისტემის პარამეტი.

  • SESSION_DRIVER - სესიებთან სამუშაო პარამეტრი.

  • REDIS განყოფილება - REDIS-თან სამუშაო პარამეტრები. (REDIS - remote dictionary server : «გასაღები — მნიშვნელობა» ფორმატის ინფორმაციის შესანახი საცავი, მონაცემთა ბაზის მართვის სისტემა ღია წყაროთი.)

  • MAIL განყოფილება -ელ_ფოსტასთან დაკავშირებული პარამეტრები.

მუშაობა გარემოს ცვლადებთან

გარემოს ცვლადების მნიშვნელობები მოქცეულია სუპერგლობალურ ცვლადში - $_ENV. მნიშვნელობათა განსაზღვრა შესაძლებელია env() დამხმარე ფუნქციის მეშვეობითაც, რომელსაც პირველ არგუმენტად უნდა გადაეცეს პარამეტრის დასახელება, მეორე არგუმენტად კი შეგვიძლია გადავცეთ ნაგულისმები მნიშვნელობა იმ შემთხვევისათვის თუ ფაილში ვერ მოიძებნება მითითებული გასაღების შესაბამისი პარამეტრი.

შესაძლებელია, რომ .env ფაილში აღვწეროთ ჩვენი საკუთარი პარამეტრებიც. თუ პარამეტრის მნიშვნელობა შეიცავს გამოტოვებულ ადგილებს მაშინ მნიშვნელობა უნდა ჩაისვას ორმაგ ბრჭყალებში:
...

CUSTOM_PARAM="CUSTOM PARAM VALUE"

...
            
მთავარი გვერდის მარშრუტის დამმუშვებელი ფუნქცია გადავაკეთოთ შემდეგნაირად :
Route::get('/', function () {
    
    echo '<pre>';
    print_r($_ENV);
    echo '</pre>';
    
    echo '<pre>';
    print_r($_ENV['APP_DEBUG']);
    echo '</pre>';
    
    echo '<pre>';
    print_r(env('SESSION_LIFETIME'));
    echo '</pre>';
    
    echo '<pre>';
    print_r(env('CUSTOM_PARAM'));
    echo '</pre>';  

    echo '<pre>';
    print_r(env('UNKNOWN_PARAM','UNKNOWN PARAM VALUE'));
    echo '</pre>'; 
    
});
            
თუ ახლა შევალთ შემდეგ მისამართზე : http://127.0.0.1:8000/, ვიხილავთ შემდეგ სურათს :



config საქაღალდე

app.php ფაილი

ეს ფაილი მოიცავს ფრეიმვორკის მუშაობისთვის აუცილებელ გლობალურ პარამეტრებს. თუ მას გავხსნით შევამჩნევთ, რომ ბრუნდება ასოციაციური მასივი, მისი პირველი გასაღები არის "name" 'name' => env('APP_NAME', 'Laravel'), რომლის მნიშვნელობაც ბრუნდება env ფუნქციის მეშვეობით, ეს ფუნქცია ინფორმაციას იღებს .env ფაილიდან, და ამ ინფორმაციას უტოლებს მასივის გასაღებებს, მას აგრეთვე მითითებული აქვს მეორე პარამეტრიც, რომელიც გამოიყენება ნაგულისხმეობის პრინციპით იმ შემთხვევაში თუ .env ფაილში ასეთი კონფიგურაციული პარამეტრი არ არის განსაზღვრული.

ეს ყველაფერი რომ უფრო კარგად გავიგოთ განვიხილოთ მასივის სხვა ელემენტიც:

'debug' => env('APP_DEBUG', false), როგორც ვიცით, "debug" კონფიგურაციული პარამეტრი განსაზღვრავს გამოჩნდეს თუ არა დაშვებული შეცდომების შესახებ შეტყობინებები. თუ .env ფაილში არ არის მითითებული შესაბამისი მნიშვნელობა, მაშინ სისტემა ამ პარამეტრს მიანიჭებს მნიშვნელობას - false.

მასივის ერთ-ერთი გასაღები არის შემდეგი :

'url' => env('APP_URL', 'http://localhost'), ეს იქნება პირველი პარამეტრი, რომელსაც ჩვენ შევცვლით და მივუთითებთ იმ დომენს ან ip მისამართს სადაც გაშვებულია პროექტი, ჩემს შემთხვევაში ეს არის: 'url' => env('APP_URL', 'http://127.0.0.1:8000'), შემდეგი გასაღები არის : 'timezone' => 'UTC', სადაც ხდება დროის სარტყელის მითითება, ჩავანაცვლოთ ნაგულისმები მნიშვნელობა ჩვენთვის სასურველით 'timezone' => 'Asia/Tbilisi', კიდევ ერთი გასაღები არის 'key' => env('APP_KEY'), აქ ეთითება ფრეიმვორკის საიდუმლო გასაღები, შევნიშნოთ, რომ ამ შემთხვევაში "env" ფუნქციას არ გადაეცემა ნაგულისმები მნიშვნელობა არგუმენტად, ეს იმიტომ რომ საიდუმლო გასაღების გენერირება ხდება ფრეიმვორკის ინსტალაციის დროს და მას აგენერირებს Composer-ი.

მასივის providers გასაღებში მოქცეულია ყველა ხელმისაწვდომი სერვის-პროვაიდერი, რომელთა ჩატვირთვაც ხდება ფრეიმვორკის ამუშავებისას. თუ რა არის სერვის-პროვაიდერ, ცოტა მოგვიანებით განვმარტავთ.

მასივის ბოლო გასაღები არის - aliases, მასში შეტანილია ფასადების ანუ სისტემური კლასების ფსევდონიმები. თუ რა არის ფასადი და როგორ ვიმუშაოთ მასთან, ცოტა მოგვიანებით განვმარტავთ.

database.php ფაილი

ეს ფაილი გამოიყენება მონაცემთა ბაზასთან წვდომისათვის. ამ ფაილშიც ბრუნდება ასოციაციური მასივი, რომლის ერთ-ერთი გასაღები არის: 'default' => env('DB_CONNECTION', 'mysql') ანუ მონაცემთა ბაზის სამართავი ნაგულისმები სისტემა, შევამჩნიოთ რომ ამ გასაღების მნიშვნელობაც .env ფაილიდან მოდის env ფუნქციის მეშვეობით, მაგრამ იქ მონაცემთა ბაზის სამართავი სისტემის დასახელება განსაზღვრული ჯერჯერობით არ გვაქვს, ამიტომ ან უნდა განვსაზღროთ იგი .env ფაილში DB_CONNECTION=mysql ანდა არ განვსაზღვროთ და სისტემა გამოიყენებს ნაგულისმებ მნიშვნელობას, რომელიც env ფუნქციას მეორე პარამეტრად აქვს გადაცემული.

წვდომა კონფიგურაციულ პარამეტრებთან

გლობალური დამხმარე ფუნქციის - config-ის მეშვეობით, შესაძლებელია მივწვდეთ კონფიგურაციულ პარამეტრებს ჩვენი აპლიკაციის ნებისმიერი წერტილიდან. ეს ხდება 'კონფიგურაციული_ფაილის_დასახელება.პარამეტრი' სინტაქტსის მეშვეობით. შესაძლებელია ფუნქციას გადაეცეს ნაგულისმები მნიშვნელობაც იმ შემთხვევისათვის თუ შესაბამის ფაილში შესაბამისი კონფიგურაციული პარამეტრი ვერ მოიძებნება :
$value = config('app.timezone');

// განვსაზღვროთ პარამეტრი თუ მისი მნიშვნელობა ვერ მოიძებნა
$value = config('app.timezone', 'Asia/Tbilisi');
            
კონფიგურაციული პარამეტრის მნიშვნელობის განსასაზღვრავად config დამხმარეს უნდა გადავცეთ პარამეტრისა და მისი მნიშვნელობის შემცველი აცოციაციური მასივი : config(['app.timezone' => 'America/Chicago']);

კონფიგურაციული პარამეტრების ქეშირება

იმისათვის რათა აპლიკაცია შედარებით სწრაფად ჩაიტვირთოს სასურველია, რომ მოხდეს კონფიგურაციული პარამეტრების ქეშირება. ეს ხდება შემდეგი ბრძანების მეშვეობით : php artisan config:cache ბრძანების გაშვების შემდეგ შეიქმნება ფაილი bootstrap/cache/config.php, რომელშიც აღწერილი იქნება ყველა კონფიგურაციული პარამეტრის შემცველი ასოციაციური მასივი.
როდესაც ვიმყოფებით სატესტო გარემოში ან პროექტი ჯერ დასრულებული არ არის, მაშინ კონფიგურაციული პარამეტრების ქეშირება არ ღირს, გამომდინარე იქიდან, რომ ეს პარამეტრები ხშირად იცვლება ამ გარემოებში.

თუ config: cache ბრძანებას გავუშვებთ მუშაობის პროცესში ანუ მაშინ, როდესაც აპლიკაცია ჯერ დასრულებული არ იქნება, დარწმუნებულები უნდა ვიყოთ, რომ env() დამხმარე ფუნქციას ვიძახებთ, მხოლოდ და მხოლოდ კონფიგურაციულ ფაილებში და არსად სხვაგან, ვინაიდან ქეშირების შემდეგ env ფაილის ჩატვირთვა საერთოდ აღარ ხდება და შესაბამისად ვერც რაიმე პარამეტრის ამოღებას შევძლებთ მისგან (ქეშირებისას კონფიგურაციულ ფაილებში env() ფუნქციის დახმარებით განსაზღვრული პარამეტრები ავტომატურად შეინახებოდა bootstrap/cache/config.php ფაილში).

კონფიგურაციული პარამეტრების ქეშის გასუფთავება ხდება შემდეგი ბრძანებით : php artisan config:clear ბრძანების გაშვების შემდეგ bootstrap/cache/config.php ფაილი წაიშლება.

შეცდომების აღმოფხვრის რეჟიმი (Debug Mode)

config/app.php ფაილში აღწერილი debug პარამეტრი განსაზღვრავს თუ რა სახით მიიღოს ინფორმაცია მომხმარებელმა რაიმე ხარვეზის ან შეცდომის დაფიქსირების მომენტში. ნაგულისმეობის პრინციპით ამ პარამეტრის მნიშვნელობა ასეა აღწერილი : 'debug' => (bool) env('APP_DEBUG', false),
სატესტო გარემოში ჩვენივე კომფორტისათვის ჯობია, რომ ამ პარამეტრის მნიშვნელობა იყოს true ანუ შეცდომების აღმოფხვრის რეჟიმი იყოს ჩართული. რეალურ გარემოში მისი ჩართვა კი დაუშვებელია, რადგან შეცდომის შესახებ ინფორმაციის გამოტანისას ეკრანზე გამოჩნდება ისეთი კონფიგურაციული პარამეტრების მნიშვნელობები, რომელთა სხვებისათვის ჩვენებაც დაუშვებელია.
6. არქიტექტორული კონცეფციები

მოთხოვნის დამუშავების სქემა

მომხმარებლის მიერ გაკეთებული ნებისმიერი მოთხოვნა მიემართება პროექტის ერთადერთი გლობალური შესავალი წერტილისაკენ - public/index.php ფაილისაკენ, ამის შემდეგ ეს ფაილი ტვირთავს Composer-ის მიერ შექმნილ კლასთა ავტოჩამტვირთველ vendor/autoload.php ფაილს require __DIR__.'/../vendor/autoload.php'; ამის შემდეგ იქმნება აპლიკაციის გლობალური ობიექტი : $app = require_once __DIR__.'/../bootstrap/app.php'; bootstrap/app.php :
... 

$app = new Illuminate\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);

...

return $app;
            
ამის შემდეგ საქმეში ერთვება მოთხოვნათა დამმუშვებელი ძირითადი კლასი Kernel, რომელიც აღწერილია app/Http/Kernel.php ფაილში. ეს კლასი არის იგივე სახელწოდების მქონე Illuminate\Foundation\Http\Kernel კლასის მემკვიდრე (სრული მისამართი : vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php). ამ კლასში აღწერილია $bootstrappers მასივი:
... 

protected $bootstrappers = [
    \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class, // გარემოს ცვლადთა ჩამტვირთველი
    \Illuminate\Foundation\Bootstrap\LoadConfiguration::class, // კონფიგურაციული პარამეტრების ჩამტვირთველი
    \Illuminate\Foundation\Bootstrap\HandleExceptions::class, // გამონაკლისთა დამმუშავებელი
    \Illuminate\Foundation\Bootstrap\RegisterFacades::class, // ფასადების რეგისტრაცია (ვისაუბრებთ ოდნავ მოგვიანებით)
    \Illuminate\Foundation\Bootstrap\RegisterProviders::class, // პროვაიდერთა რეგისტრაცია (ვისაუბრებთ ოდნავ მოგვიანებით)
    \Illuminate\Foundation\Bootstrap\BootProviders::class, // პროვაიდერთა ჩატვირთვა
];

...
            
სწორედ ამ კლასების ჩატვირთვა ხდება მანამ სანამ დამუშვდება მომხმარებლის მიერ გაკეთებული მოთხოვნა.

ამავე კლასის handle() მეთოდში ხდება მოთხოვნის შესაბამისი პასუხის გენერირება ანუ დაბრუნება.

დავუბრუნდეთ ისევ მემკვიდრე Kernel კლასს :)) მასში აღწერილია $middleware მასივი:

... 

protected $middleware = [
    // \App\Http\Middleware\TrustHosts::class,
    \App\Http\Middleware\TrustProxies::class,
    \Fruitcake\Cors\HandleCors::class,
    \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
    \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
    \App\Http\Middleware\TrimStrings::class,
    \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];

...
            

ამ მასივში აღწერილია ის შუამავლები, რომლებიც აუცილებლად უნდა გაიაროს მომხმარებლის მიერ გაკეთებულმა მოთხოვნამ (შუამავლების შესახებ ვისაუბრებთ ოდნავ მოგვიანებით).

ავტოჩატვირთვისა და ყველა საჭირო პროცესის ინიციალიზაციის შემდეგ მოთხოვნა გადაეცემა მარშრუტიზატორს და ფრეიმვორკი ღებულობს გადაწყვეტილებას თუ რომელმა მარშრუტმა უნდა დაამუშავოს ესა თუ ის მოთხოვნა. მარშრუტმა მოთხოვნა შეიძლება გადასცეს კონკრეტულ კონტროლერს ან უბრალოდ ფუნქციას, თუ მოთხოვნა კონტროლერს გადაეცემა, იგი ჩაატარებს შესაბამის სამუშაოებს (ინფორმაციის გადამოწმება, ვალიდაცია და ა.შ) და თავის მხრივ მიმართავს მოდელს, თუ აუცილებელია მოდელი მიმართავს მონაცემთა ბაზას , ბაზა დაუბრუნებს მას პასუხს, მოდელი ამ პასუხს დაუბრუნებს კონტროლერს, კონტროლერი კი მიღებულ პასუხს გადასცემს წარმოდგენის შაბლონს, წარმოდგენის შაბლონი უზრუნველჰყოფს შედეგის ბრაუზერში გამოტანას. ხოლო თუ მარშრუტიზატორი მოთხოვნას არ გადასცემს კონტროლერს, არამედ გადასცემს ფუნქციას, მაშინ ეს ფუნქცია დაამუშავებს მოთხოვნას და შედეგს გადასცემს პირდაპირ წარმოდგენას.

სერვისების კონტეინერი

რა არის სერვისი ?

მარტივად თუ ვიტყვით სერვისის უკან მოიაზრება ფუნქციონალი რომელიც გვიმარტივებს ცხოვრებას :)) როდესაც Laravel-ს დავაინსტალირებთ ჩვენ უკვე გვექნება საკმაოდ ბევრი მზა ასეთი სერვისი: მონაცემთა ბაზასთან სამუშაო სერვისი, ფაილებთან სამუშაო სერვისი და ა.შ, მაგრამ შეიძლება გადავაწყდეთ ისეთი ამოცანებს, რომელთა გადასაჭრელი გზები, ფრეიმვორკის საბაზისო კომპლექტაციაში გათვალისწინებული არ იყოს, ანუ დაგვჭირდეს ჩვენი საკუთარი, სამომხმარებლო ფუნქციონალის ჩამატება სისტემაში. შეგვიძლია ამ ფუნქციონალსაც სერვისები ვუწოდოთ.

რას ნიშნავს დამოკიდებულებათა ინექცია (DI - Dependency injection) ?

ინგ: Injection - ინექცია; დანერგვა; შემოღება; ჩადება;

თუ კონკრეტული კლასის მუშაობისათვის საჭიროა, გამოყენებულ იქნას სხვა კლასის ფუნქციონალი, ეს იმას ნიშნავს, რომ პირველი კლასი დამოკიდებულია მეორე კლასზე. ბუნებრივია უნდა მოვახდინოთ დამხმარე კლასის საწყის კლასში ინტეგრირება (Injection) და მხოლოდ ამის შემდეგ შეგვეძლება დამხმარე კლასის ფუნქციონალის გამოყენება. სწორედ ამ დამხმარე კლასს ეწოდება დამოკიდებულება (Dependency).
...

use Illuminate\Http\Request;

...

class SomeController extends Controller
{
    ...

    public function post(Request $request)
    {
        $request->validate([
            // ...
        ]);

        // ... 
    }

    ...
}
            
ამ მაგალითზე შეიძლება ითქვას, რომ SomeController კლასში მოვახდინეთ Request დამოკიდებულების ინექცია.

რა არის სერვისების კონტეინერი ?

სერვისების კონტეინერი (იგივე დამოკიდებულებათა ინექციების კონტეინერი) არის ერთგვარი სივრცე, გარემო, რომლის დახმარებითაც ხდება კლასებს შორის ურთიერთდამოკიდებულებების მართვა და ამ დამოკიდებულებების სხვადასხვა ადგილას გამოყენება. სერვისების კონტეინერთან წვდომა შესაძლებელია app() ჩანაწერით:
Route::get('/', function(){
    
    echo '<pre>';
    print_r(app());
    echo '</pre>';
    die;    
    
});
            
თუ ახლა აპლიკაციის მთავარ გვერდზე შევალთ, ვიხილავთ ამდაგვარ სურათს :



როგორც ვხედავთ, სერვისების კონტეინერი არის Illuminate\Foundation\Application კლასის ეგზემპლიარი და ინახავს ინფორმაციას ხელმისაწვდომი ანუ დარეგისტრირებული სერვისების შესახებ. Illuminate\Foundation\Application კლასი კი, თავის მხრივ, არის Illuminate\Container\Container.php კლასის ანუ, ძირითადი კონტეინერული კლასის მემკვიდრე.

საკუთარი სერვისის შექმნა

შევქმნათ საქაღალდე app/Services და მასში კი სერვისი - MathService. სერვისში აღვწეროთ მარტივი მეთოდი, რომელიც დაგვიბრუნებს მასივის ელემენტების ჯამს :
namespace App\Services;

class MathService
{
    public function doAddition($numbers)
    {
        return array_sum($numbers);
    }
}
            
ასევე შევქმნათ შესაბამისი მარშრუტი და კონტროლერი :
use Illuminate\Support\Facades\Route;

use App\Http\Controllers\MathController;

Route::get('/math', [MathController::class, 'index']);
            
MathController :
namespace App\Http\Controllers;

use App\Services\Mathservice;

class MathController extends Controller
{
    public function index()
    {
        $serv = new Mathservice();
        
        dd($serv->doAddition([4,6])); // 10
    }
}
            
გადავაკეთოთ კონტროლერი ამდაგვარად :
namespace App\Http\Controllers;

use App\Services\Mathservice;

class MathController extends Controller
{
    public function index(Mathservice $serv)
    {
        dd($serv->doAddition([4,6])); // 10
    }
}
            
შედეგი აქაც იგივე იქნება, ანუ Mathservice სერვისის ამ სახით ინექციაც გასაგებია სისტემისათვის.

ახლა ამოცანა და შესაბამისად სერვისიც, გადავაკეთოთ ასე : სერვისმა დაგვიბრუნოს არა მასივის ელემენტების ჯამი, არამედ ამ ჯამს დამატებული კიდევ ერთი რიცხვი, რომელიც აღწერილი იქნება სერვისის კერძო თვისებაში - $add_param :

namespace App\Services;

class MathService
{
    private $add_param;
    
    public function __construct($add_param) 
    {
        $this->add_param = $add_param;
    }
    
    public function doAddition($numbers)
    {
        return array_sum($numbers) + $this->add_param;        
    }
}
            
ასეთ შემთხვევაში ვიხილავთ შემდეგ შეტყობინებას : Unresolvable dependency resolving [Parameter #0 [ <required> $add_param ]] in class App\Services\MathService ეს იმას ნიშნავს, რომ სისტემამ ვერ იპოვა ის დამოკიდებულება, რომელიც მოვთხოვეთ. სწორედ ამ პრობლემის მოგვარებაში დაგვეხმარება სერვისისების კონტეინერი და სერვისის პროვაიდერი.

რა არის სერვისის პროვაიდერი ?

სერვისების პროვაიდერებს უჭირავთ ცენტრალური ადგილი Laravel-ის არქიტექტურულ სტრუქტურაში. მათი მეშვეობით ხდება აპლიკაციის საწყისი ჩატვირთვა, უფრო კონკრეტულად - პროვაიდერები ტვირთავენ საჭირო ელემენტებსა და სერვისებს, მოვლენათა დამმუშავებლებს (event listeners), შუამავლებს და ა.შ. თუ გავხსნით config/app.php ფაილს, ვნახავთ მასში აღწერილი მასივის providers ველს, სწორედ ამ ველში შეტანილი პროვაიდერების ჩატვირთვა ხდება აპლიკაციის გაშვებისას. ეს ჩანაწერები ამატებენ სხვადასხვა ფუნქციონალს სერვისების კონტეინერში.

ნებისმიერი პროვაიდერი არის Illuminate\Support\ServiceProvider კლასის მემკვიდრე და შეიცავს ორ მეთოდს : register და boot. როდესაც აპლიკაცია იტვირთება, სისტემა აკითხავს ყველა არსებული პროვაიდერის register მეთოდს და ასრულებს თითოეულ მათგანში აღწერილ ინსტრუქციებს. პროვაიდერის შექმნა შესაძლებელია შემდეგი ბრძანების მეშვეობით :

php artisan make:provider MathServiceProvider
            

register მეთოდი

პროვაიდერის register მეთოდში ხდება სერვისების რეგისტრაცია ანუ შენახვა სერვისების კონტეინერში, კონტეინერთან წვდომა შესაძლებელია app თვისების მეშვეობით, ხოლო უშუალოდ ინფორმაციის მიმაგრება სერვისების კონტეინერის bind მეთოდით :
namespace App\Providers;

use App\Services\Mathservice;
use Illuminate\Support\ServiceProvider;

class MathServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind(Mathservice::class, function ($app) {
            // add_param : პარამეტრი, რომელიც უნდა დაემატოს მასივის ელემენტთა ჯამს
            return new Mathservice(add_param : 25);
        }); 
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}
            
ახლა დავარეგისტრიროთ პროვაიდერი config/app.php ფაილში აღწერილ მასივში:
...
        
'providers' => [

    ...

    App\Providers\MathServiceProvider::class,

    ...

],

...
            
ახლა უკვე ყველაფერი რიგზე იქნება. ანუ ჩვენ Mathservice სერვისი დავარეგისტრირეთ სერვისების კონტეინერში სერვისის პროვაიდერის დახმარებით:
namespace App\Http\Controllers;

use App\Services\Mathservice;

class MathController extends Controller
{
    public function index(Mathservice $serv)
    {
        dd($serv->doAddition([4,6])); // 4 + 6 = 10 + 25 = 35
    }
}
            

***

ხშირად საჭიროა, რომ კონკრეტული კლასის ობიექტი შეიქმნას მხოლოდ ერთხელ და სწორედ ეს საწყისი მნიშვნელობა დაბრუნდეს კლასთან ყოველი მიმართვისას.
...
        
public function register()
{
    $this->app->singleton(Someclass::class, function ($app) {
        //
    });
}

...
            

boot მეთოდი

იმ მომენტში, როდესაც მოხდება წარმოდგენის ფაილების გენერირება და ჩატვირთვა, შესაძლებელია დაგვჭირდეს რაიმე ფუნქციონალის შესრულება (მაგალითად წარმოდგენის შაბლონს გადავცეთ რაიმე ინფორმაცია). ასეთი ოპერაციების აღწერა ხდება პროვაიდერის boot მეთოდში :
namespace App\Providers;

use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;

class ComposerServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        View::composer('view', function () {
            //
        });
    }
}
            
წარმოდგენის ფაილებზე უფრო დაწვრილებით ვისაუბრებთ მოგვიანებით.

ფასადები

ფასადი არის სტატიკური ინტერფეისი სერვისების კონტეინერში დარეგისტრირებული კლასებისათვის, რომლის მეშვეობითაც საკმაოდ მარტივად ხდება ამ კლასებთან წვდომა. Laravel-ის ფასადები განთავსებულია vendor/laravel/framework/src/Illuminate/Support/Facades საქაღალდეში, თითოეული მათგანი არის, ამავე საქაღალდეში არსებულ - Facade.php ფაილში აღწერილი აბსტრაქტული კლასის მემკვიდრე და ატარებს Illuminate\Support\Facades სახელსივრცეს (namespace).
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Route;

Route::get('/cache', function () {
    return Cache::get('key');
});
            

საკუთარი ფასადის შექმნა

პირველ რიგში გავამარტივოთ ჩვენი App/Services/MathService.php სერვის, იგი გადავაკეთოთ ამდაგვარად :
namespace App\Services;

class MathService
{
    public static function doAddition($numbers)
    {
        return array_sum($numbers);        
    }
}
            
შევქმნათ ფაილი app/Helpers/Facades/Mathfacade.php. პირველი რაც ფასადის შექმნისას უნდა გავაკეთოთ, არის ის, რომ ხელახლა უნდა აღვწეროთ აბსტრაქტული მშობელი კლასის - Facade-ს getFacadeAccessor მეთოდი :
namespace App\Helpers\Facades;

use Illuminate\Support\Facades\Facade;

class Mathfacade extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'mathfacade';
    }
}
            
ამ მეთოდის დანიშნულება არის ის, რომ დააბრუნოს სერვისების კონტეინერში არსებული, კონკრეტული ფუნქციონალის შესაბამისი სიტყვაგასაღები ანუ მეტსახელი. ჩვენს შემთხვევაში ეს მეტსახელი არის - mathfacade. ახლა გადავინაცვლოთ სერვისპროვაიდერში :
namespace App\Providers;

use App\Services\Mathservice;
use Illuminate\Support\ServiceProvider;

class MathServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind('mathfacade', function ($app) {
            return new Mathservice();
        }); 
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}
            

მაგიური მეთოდები __call() და __callStatic

PHP ში __call() მეთოდი გამოიყენება, როდესაც მივმართავთ კლასის არარსებულ ან დაცულ მეთოდს, __callStatic() მეთოდი კი გამოიყენება მაშინ, როდესაც მივმართავთ კლასის არარსებულ ან დაცულ სტატიკურ მეთოდს. ორივე მათგანს გადაეცემა ორი პარამეტრი: მეთოდის დასახელება და არგუმენტები : public __call ( string $name , array $arguments ) : mixed

public static __callStatic ( string $name , array $arguments ) : mixed
მაგალითად :
class MethodTest
{
    public function __call($name, $arguments)
    {
        echo "მეთოდი '$name' " . implode(', ', $arguments). "\n";
    }

    public static function __callStatic($name, $arguments)
    {
        echo "მეთოდი '$name' " . implode(', ', $arguments). "\n";
    }
}

$obj = new MethodTest;
$obj->runTest('ობიექტის კონტექსტში');

MethodTest::runTest('სტატიკურ კონტექსტში');
            
ამ კოდის შედეგი იქნება : მეთოდი 'runTest' ობიექტის კონტექსტში

მეთოდი 'runTest' სტატიკურ კონტექსტში

***

მშობელ კლას - Facade-ში აღწრილია მაგიური მეთოდი __callStatic :
public static function __callStatic($method, $args)
{
    $instance = static::getFacadeRoot();

    if (! $instance) 
    {
        throw new RuntimeException('A facade root has not been set.');
    }

    return $instance->$method(...$args);
}
            
ამ მეთოდის გამოძახება ხდება მაშინ, როდესაც მივმართავთ ფასადის არარსებულ მეთოდს. იგი ახდენს ფასადის მეთოდის გადამისამართებას სერვისების კონტეინერში არსებული, სასურველი კლასის ობიექტზე და რეალურად ჩვენ უკვე ამ ობიექტს და მის მეთოდს მივმართავთ.

__callStatic მეთოდში თავიდანვე ხდება getFacadeRoot() სტატიკური მეთოდის გამოძახება, დავაკვირდეთ ამ მეთოდს :

public static function getFacadeRoot()
{
    return static::resolveFacadeInstance(static::getFacadeAccessor());
}
            
ეს მეთოდი დავის მხრივ იძახებს resolveFacadeInstance მეთოდს, რომელსაც არგუმენტად გადაეცემა, ჩვენს მიერ დასაწყისშივე აღწერილი მეთოდი getFacadeAccessor. resolveFacadeInstance მეთოდის კოდი ასეთია :
protected static function resolveFacadeInstance($name)
{
    if (is_object($name)) 
    {
        return $name;
    }

    if (isset(static::$resolvedInstance[$name])) 
    {
        return static::$resolvedInstance[$name];
    }

    if (static::$app) 
    {
        return static::$resolvedInstance[$name] = static::$app[$name];
    }
}
            
განსაკუთრებული ყურადღება მივაქციოთ ამ ჩანაწეერს : static::$app[$name], სწორედ $app სტატიკური თვისების უკან მოიაზრება სერვისების კონტეინერი. თავად ჩანაწერი კი აბრუნებს სერვისების კონტეინერში, ჩვენს მიერ განსაზღვრული სიტყვაგასაღების (mathfacade) შესაბამის კლასს, ეს კლასი კი სერვისის პროვაიდერში გვაქვს აღწერილი :
namespace App\Providers;

use App\Services\Mathservice;
use Illuminate\Support\ServiceProvider;

class MathServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->bind('mathfacade', function ($app) {
            return new Mathservice();
        }); 
    }

    ...
}
            
შესაბამისად წორედ Mathservice() კლასის ობიექტთან მოხდება გადამისამართება, როდესაც ფასადის არარსებულ მეთოდს გამოვიძახებთ.

იმისათვის რათა ჩვენმა ფასადმა იმუშავოს, უნდა დავარეგისტრიროთ აღნიშნული ფასადის შესაბამისი ფსევდონიმი, ეს უნდა გავაკეთოთ config/app.php ფაილში :

...

'providers' => [

    ...

    App\Providers\MathServiceProvider::class,

],

    
'aliases' => [

    ...

    'Mathfacade' => App\Helpers\Facades\Mathfacade::class,

],

...
            
ახლა კი შეგვიძლია მივმართოთ ჩვენს ფასადს, ეს გავაკეთოთ MathController-ში:
namespace App\Http\Controllers;

use Mathfacade;

class MathController extends Controller
{
    public function index()
    {
        $res = Mathfacade::doAddition([2,5]);
        
        dd($res); // 7
    }
}
            
7. მარშრუტები
მანამ სანამ ფრეიმვორკ Laravel-ის მარშრუტიზატორების შესწავლაზე გადავალთ, გავარკვიოთ თუ რა არის URI, URL და URN

URI

იშიფრება როგორც Uniform Resource Identifier, ანუ მუდმივი წყაროს იდენტიფიკატორი, წყაროში იგულისხმება ნებისმიერი რესურსი, რომელიც შეიძლება მოითხოვოს მომხმარებელმა: საიტის რომელიმე გვერდი, სურათი, css სტილი და ა.შ. კონკრეტული მაგალითი: https://vnadiradze.ge/info/laravel/index.html URI შედგება ორი ნაწილისაგან : URL და URN.

URL

იშიფრება როგორც Uniform Resource Locator ანუ მუდმივი წყაროს მაჩვენებელი, ლოკატორი. იგი მოიცავს წყაროსთან მიმართვის ტიპს (პროტოკოლს) და წყაროს მდებარეობას ანუ დომენს. კონკრეტული მაგალითი: http://vnadiradze.ge

URN

იშიფრება როგორც Uniform Resource Name ანუ მუდმივი წყაროს სახელი. იგი განსაზღვრავს წყაროს დასახელებას. კონკრეტული მაგალითი: /info/laravel/index.html

მარშრუტის შექმნა

HTTP GET

როგორც ვიცით მარშრუტები ინახება routes/web.php ფაილში. იმისათვის რათა შევქმნათ მარშრუტი პირველ რიგში უნდა მივმართოთ შესაბამის ფასადს - Route, თუ რა არის ფასადი, ამის შესახებ დაწვრილებით ოდნავ მოგვიანებით ვისაუბრებთ, ამ ეტაპზე კი შემოვიფარგლოთ შემდეგი განმარტებით : ფასადი არის კლასი, რომელიც ანხორციელებს წვდომას ფრეიმვორკ Laravel-ის ელემენტებთან. კონკრეტულ ფასადთან მიმართვისას ჩვენ რეალურად მივმართავთ config/app საქაღალდეში აღწერილი მასივის ბოლო ელემენტ aliases-სში მოთავსებული ფასადების ფსევდოკლასებიდან ერთ-ერთს. Route ფასადის შემთხვევაში ეს კლასი არის : 'Route' => Illuminate\Support\Facades\Route::class, ფასადის შემდეგ უნდა მივუთითოთ HTTP მოთხოვნის ტიპი, მოთხოვნის ტიპს კი პირველ პარამეტრად უნდა გადავცეთ შაბლონი, ანუ URI-ს ის ნაწილი, რომლისთვისაც ვქმნით ამ მარშრუტს. ჯერჯერობით ვართ ამ ეტაპზე : Route::get('/page') ანუ მოცემული მარშრუტი ამუშავდება მაშინ თუ მომხმარებელი შევა შემდეგ მისამართზე : example.com/page ყველაზე მარტივ შემთხვევაში მოთხოვნის ტიპს მეორე პარამეტრად შეიძლება გადაეცეს ფუნქცია დამმუშავებელი :
Route::get('/page', function(){

});
            
ამ ფუნქციის ტანში შესაძლებელია ნებისმიერი კოდის ჩაწერა. მაგალითად ეკრანზე გამოვიტანოთ ფრეიმვორკის კონფიგურაციის რომელიმე პარამეტრის მნიშვნელობა. ვთქვათ app კონფიგურაციული ჯგუფის locale პარამეტრის მნიშვნელობა:
Route::get('/page', function(){
    echo config('app.locale');
});
            
იგივეს გაკეთება შეგვეძლო Config ფასადის get მეთოდით:
Route::get('/page', function(){
    echo Config::get('app.locale');
});
            

HTTP POST

POST მეთოდით მოთხოვნის გასაგზავნად public საქაღალდეში დავამატოთ ფაილი form.html რომელშიც შევიტანთ რაიმე მარტივ ფორმას
<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
    <form action="/comments" method="post">
        <input type="text" name="fname" placeholder="სახელი">
        <input type="text" name="lname" placeholder="გვარი">
        <input type="submit" name="send" value="გაგზავნა"> 
    </form>
</body>
</html>            
            
ახლა დავწეროთ შესაბამისი მარშრუტი:
Route::post('/comments' , function(){
    print_r($_POST);
});
            
თუ ახლა შევალთ შემდეგ მისამართზე : http://127.0.0.1:8000/comments ბრაუზერში ვიხილავთ შეტყობინებას : The GET method is not supported for this route. Supported methods: POST. ეს იმიტომ, რომ ჩვემ მარშრუტი დავწერეთ post მეთოდისათვის და მივაკითხეთ get მეთოდით. თუ შევალთ ამ მისამართზე : http://127.0.0.1:8000/form.html მაშინ ვიხილავთ შესაბამის ფორმას, რომელიც ინფორმაციას post მეთოდით გააგზავნის http://127.0.0.1:8000/comments გვერდზე.

ყურადღება !

ფორმის გაგზავნის შემდეგ ბრაუზერში შესაძლებელია ვიხილოთ შემდეგი შეტყობინება : 419 | PAGE EXPIRED ეს მოხდა CSRF (Cross-Site Request Forgery) ვერიფიკაციის გამო, ანუ სისტემამ ჩათვალა, რომ გვერდის მოთხოვნა მოხდა არასწორი სახით. CSRF ვერიფიკაციის შესახებ უახლოეს ხანებში ვისაუბრებთ, ამჟამად კი ეს პრობლემა ასე მოვაგვაროთ : app/Http/Middleware/VerifyCsrfToken.php საქაღალდეში ჩავამატოთ შემდეგი გამონაკლისი :
protected $except = [
    '/comments'
];
            
ახლა http://127.0.0.1:8000/form.html ფორმის გაგზავნის შემდეგ გადავალთ http://127.0.0.1:8000/comments გვერდზე სადაც ვიხილავთ გლობალურ ცვლად $_POST-ში მოქცეულ იმ ინფორმაციას, რომელიც ფორმაში ავკრიფეთ.

მარშრუტის შექმნა ერთდროულად რამდენიმე ტიპის მოთხოვნისათვის

იმისათვის რათა მარშრუტი შეესაბამებოდეს რამდენიმე ტიპის მოთხოვნას ერთდროულად, უნდა გამოვიყენოთ Route ფასადის match მეთოდი, მეთოდს პირველ პარამეტრად გადეცემა მასივი, რომელშიც შეტანილია მოთხოვნათა სასურველი ტიპები :
Route::match(['get','post'] , '/comments' , function(){
    print_r($_POST);
});
             
ამ შემთხვევაში უკვე შეგვეძლება ფორმის გაგზავნის გარეშე http://127.0.0.1:8000/comments გვერდზე შესვლა.

მარშრუტის შექმნა ნებისმიერი ტიპის მოთხოვნისათვის

იმისათვის რათა მარშრუტი შეესაბამებოდეს ნებისმიერი ტიპის მოთხოვნას ერთდროულად, უნდა გამოვიყენოთ Route ფასადის any მეთოდი
Route::any('/comments' , function(){
    print_r($_POST);
});
            

მარშრუტისა და კონტროლერის დაკავშირება

მიუხედავად იმისა, რომ ჯერ არ ვიცნობთ კონტროლერებს, ოდნავ გავუსწოთ მოვლენებს და მოვიყვანოთ მაგალითი, თუ როგორ ხდება ამა თუ იმ მარშრუტთან კონკრეტული კონტროლერის დაკავშირება. პირველ რიგში routes/web.php ფაილში უნდა დავამყაროთ წვდომა შესაბამის კონტროლერთან, შემდეგ მივმართოთ სასურველ კონტროლერს და ამ კონტროლერის სასურველ მეთოდს :
use Illuminate\Support\Facades\Route;

use App\Http\Controllers\UserController;

Route::get('/user', [UserController::class, 'index']);
            

მარშრუტთა გადამისამართება

თუ გვჭირდება ისეთი მარშრუტის შექმნა, რომელიც სხვა URI-ზე უნდა გადამისამართდეს, მაშინ შეგვიძლია გამოვიყენოთ Route ფასადის redirect მეთოდი :
Route::redirect('/here', '/there');
            

წარმოდგენის მარშრუტები

თუ გვჭირდება ისეთი მარშრუტის შექმნა, რომელსაც უბრალოდ წარმოდგენის ფაილის დაბრუნება ევალება, მაშინ შეგვიძლია გამოვიყენოთ Route ფასადის view მეთოდი, რომელსაც პირველ პარამეტრად გადაეცემა URI ფრაგმენტი, მეორე პარამეტრად კი წარმოდგენის ფაილის დასახელება:
Route::view('/welcome', 'welcome');
            
ამის შემდეგ http://127.0.0.1:8000/welcome მისამართზე შესვლისას ჩაიტვირთება resources/views/welcome.blade.php ფაილი.

მარშრუტთა პარამეტრები

სავალდებულო პარამეტრები

აქამდე განხილულ მაგალითებში მარშრუტებს პირველ პარამეტრად გადავცემდით URI-ს კონკრეტულ ნაწილს, სტატიკურ სტრიქონს, მაგრამ შეიძლება დაგვჭირდეს ცვალებადი, დინამიური პარამეტრების გადაცემაც (მაგალითად კონკრეტული მომხმარებლის id-ის). ცვლადი პარამეტრის გადაცემის სინტაქსი ასეთია:
Route::get('/user/{id}', function ($id) {
    return 'User '.$id;
});
            
ანუ პარამეტრები ექცევა ფიგურულ ფრჩხილებში. შესაძლებელია ერთდროულად რამდენიმე პარამეტრის გადაცემაც :
Route::get('/page/{category}/{id}' , function(){
  
});
            
თუ ახლა შევალთ შემდეგ მისამართზე : http://127.0.0.1:8000/page ვიხილავთ შეტყობინებას, რომ გვერდი ვერ მოიძებნა, მაგრამ თუ შევალთ ამ მისამართზე : http://127.0.0.1:8000/page/sport/10 ყველაფერი რიგზე იქნება.

გადაცემულ პარამეტრთან წვდომისათვის ეს პარამეტრი არგუმენტად უნდა გადავცეთ მარშრუტში აღწერილი ფუნქცია დამმუშავებელს :

Route::get('/page/{id}' , function($id){
    echo $id;
});
             
როგორც ზემოთ აღვნიშნეთ, შესაძლებელია მარშრუტს მიეთითოს რამდენიმე ცვლადი პარამეტრი, აქ უნდა გავითვალისწინოთ ერთი ფაქტი: პარამეტრები ფუნქცია დამმუშავებელსაც იმავე თანმიმდევრობით უნდა გადავცეთ რა თანმიმდევრობითაც მარშრუტში აღვწერთ მათ. ფუნქცია ამ პარამეტრებს სწორედ თანმიმდევრობიდან გამომდინარე აღიქვამს და არა ცვლადთა დასახელებებიდან.
Route::get('/page/{category}/{id}',function($c,$i){
    echo "category - "  . $c;
    echo "id - "  . $i;
});
            
თუ ახლა შევალთ შემდეგ მისამართზე : http://127.0.0.1:8000/page/cars/10 ბრაუზერში ვიხილავთ შემდეგ ტექსტს : category - cars
id - 12

არასავალდებულო პარამეტრები

ამ მაგალითებში მარშრუტს ვუთითებდით ისეთ პარამეტრებს, რომელთა განსაზღვრაც აუცილებელი იყო, მაგრამ შეიძლება განისაზღვროს მარშრუტი ისეთი მოთხოვნისათვის რომელიც შეიძლება შეიცავდეს ან არ შეიცავდეს პარამეტრს, ასეთ შემთხვევაში პარამეტრის მითითებისას მას ეწერება კითხვის ნიშანი, ხოლო ფუნქცია დამმუშავებელს კი ეს პარამეტრი გადეცემა ნაგულისმები მნიშვნელობით - null
Route::get('/user_null/{name?}', function ($name = null) {
    return $name; // ცარიელი
});

Route::get('/user_name/{name?}', function ($name = 'ვასო') {
    return $name; // ვასო
});
            
ამ შემთხვევაში უშეცდომოდ შევალთ http://127.0.0.1:8000/user_null გვერდზეც და http://127.0.0.1:8000/user_name გვერდზეც.

მეთოდი where

შეიძლება მოხდეს ისე, რომ დაგვჭირდეს ცვლადი პარამეტრის ტიპის გაფილტვრა, მაგალითად id პარამეტრის მნიშვნელობა უნდა იყოს მხოლოდ და მხოლოდ რიცხვითი ტიპის, ამაში დაგვეხმარება რეგულარული გამოსახულებები და where მეთოდი, მისი გამოყენების სინტაქსი ასეთია:
Route::get('/page/{id}',function($id){
    echo $id;
})->where('id','[0-9]+');
            
ანუ სისტემას ვეუბნებით, რომ id პარამეტრი უნდა იყოს ციფრი და იგი შეიძლება მეორდებოდეს მრავალჯერ (ამას აღნიშნავს რეგ. გამოსახულებაში არსებული "+" ნიშანი), რადგან id შეიძლება იყოს 5-იც და 345343-იც. ასეთ შემთხვევაში შემდეგ მისამართზე შესვლა :
 http://127.0.0.1:8000/page/cars
            
გამოიტანს შეცდომას.

დავუშვათ რამდენიმე პარამეტრთან ერთად ვმუშაობთ და საჭიროა ყველას გაფილტვრა where მეთოდით: პირველი პარამეტრი უნდა შეიცავდეს მხოლოდ ლათინური ანბანის დიდ ან პატარა ასოებს, მეორე პარამეტრი კი მხოლოდ ციფრებს. ასეთ შემთხვევაში მეთოდის გამოყენების სინტაქსი შემდეგნაირია :

Route::get('/page/{cat}/{id}',function($cat,$id){
    echo $id;
})->where(['cat'=>'[A-Za-z]+' , 'id'=>'[0-9]+']);
            

მარშრუტის პარამეტრის ტიპის განსაზღვრა გლობალურად

შეიძლება მოხდეს ისე, რომ id პარამეტრის გაფილტვრა, ანუ ტიპის განსაზღვრა დაგვჭირდეს 100 მარშრუტისათვის, 100-ჯერ ერთი და იგივეს წერა, რა თქმა უნდა მოუხერხებელი და არაკომფორტულია. ასეთ შემთხვევაში დაგვეხმარება სერვის-პროვაიდერი ანუ კლასი app/Providers/RouteServiceProvider.php, კონკრეტულად კი მისი მეთოდი boot, ფრეიმვორკის ინსტალაციის პირველ ეტაპზე ეს მეთოდი გამოიყურება ასე:
public function boot()
{
    //

    parent::boot();
}
            
ჩავამატოთ მასში სასურველი ფილტრი
public function boot()
{
    Route::pattern('id', '[0-9]+');

    parent::boot();
}
            
ამ ჩანაწერის ჩამატების შემდეგ აღარ დაგვჭირდება ყოველი მარშრუტის აღწერისას პარამეტრის თავიდან გაფილტვრა. მარშრუტს წავუშალოთ id პარამეტრის გაფილტვრის ნაწილი
Route::get('/page/{id}',function($cat,$id){
    echo $id;
});
             
ყველაფერი იმუშავებს ისევ კორექტულად.

რამდენიმე პარამეტრის ერთდროულად, გლობალურად გაფილტვრისთვის კი boot მეთოდში უნდა ჩავამატოთ შემდეგი ჩანაწერი

Route::patterns(['id'=>'[0-9]+' , 'cat'=>'[A-Za-z]+']);
            
მეთოდი მიიღებს ასეთ სახეს :
public function boot()
{
    Route::patterns(['id'=>'[0-9]+' , 'cat'=>'[A-Za-z]+']);

    parent::boot();
}
            
მარშრუტიდან კი საერთოდ წავშალოთ გაფილტვრის სინტაქსი :
Route::get('/page/{cat}/{id}',function($cat,$id){
    echo $id;
});
            

მარშრუტთა ჯგუფები

პროექტზე მუშაობისას შესაძლებელია მოხდეს ისე, რომ ბევრ URI-ს გააჩნდეს საერთო ფრაზა, საერთო სეგმენტი, მაგალითად : http://127.0.0.1:8000/application/administrator/index.php
http://127.0.0.1:8000/application/administrator/home.php
http://127.0.0.1:8000/application/administrator/create.php
http://127.0.0.1:8000/application/administrator/edit.php
http://127.0.0.1:8000/application/administrator/delete.php
...
ბუნებრივია თითოეული მათგანის მარშრუტის განსაზღვრისას, მარშრუტის შაბლონში უნდა გავიმეოროთ ეს საერთო ფრაზა, პრეფიქსი application/administrator, ამის თავიდან ასაცილებლად უნდა გამოვიყენოთ მარშრუტთა ჯგუფი, მასთან მუშაობა შესაძლებელია Route ფასადის group მეთოდის დახმარებით :
Route::group(['prefix'=>'application/administrator'],function(){

    Route::get('/index',function(){
        echo '/index';
    });

    Route::get('/home',function(){
        echo '/home';
    });

    Route::get('/create',function(){
        echo '/create';
    });

    Route::get('/edit',function(){
        echo '/edit';
    });

    Route::get('/delete',function(){
        echo '/delete';
    });

});            
            

სახელდებული მარშრუტები, გადამისამართება გვერდებზე, შიდა ბმულები

ხშირადაა საჭირო პროექტის ერთი გვერდიდან მეორეზე გადასასვლელი ბმულების გაკეთება ან ავტომატურად გადასვლა (redirect). შიდა ბმულების შექმნისას საკმაოდ ხელსაყრელია მარშრუტებზე სახელის დარქმევა და შემდეგ ამ სახელების გამოყენება.
Route::get('/user/profile', function () {
    //
})->name('profile');
            
სახელის დარქმევა შესაძლებელია ასეც : Route::get('/user/profile', [UserProfileController::class, 'show'])->name('profile');
მარშრუტთა დასახელებები აუცილებლად უნდა იყოს უნიკალური.
სახელდებული მარშრუტის მიხედვით URL-ის გენერირება და გადამისამართება მოხდბა ასე:
Route::get('/test',function(){

    echo $url = route('profile'); // http://127.0.0.1:8000/user/profile

    return redirect()->route('profile'); // გადამისამართება

});
            
თუ ასხელდებულ მარშრუტს გადაეცემა პარამეტრები, შეგვიძლია ეს პარამეტრები განვსაზღვროთ route დამხმარე ფუნქციის მეორე პარამეტრში :
Route::get('/user/{id}/profile', function ($id) {
    //
})->name('profile');

$url = route('profile', ['id' => 1]);
            
თუ ამ მასივს გადავცემთ დამატებით პარამეტრებსაც, მაშინ გასაღები/მნიშვნელობა წყვილები ავტომატურად ჩაჯდება URL-ში get ტიპის პარამეტრებად :
Route::get('/user/{id}/profile', function ($id) {
    //
})->name('profile');

$url = route('profile', ['id' => 1, 'photos' => 'yes']);

// /user/1/profile?photos=yes
            

მიმდინარე მარშრუტის გადამოწმება

თუ გვსურს დავადგინოთ მიმდინარე მარშრუტი მიემართა თუ არა კონკრეტული სახელდებული მარშრუტისაკენ, შეგვიძლია გამოვიყენოთ route დამხმარის named მეთოდი. მაგალითად გვაქვს მარშრუტთა შუამავალი და მასში გვინდა მარშრუტის სახელის გადამოწმება :
/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return mixed
 */
public function handle($request, Closure $next)
{
    if ($request->route()->named('profile')) 
    {
        //
    }

    return $next($request);
}
            

მარშრუტთა ჯგუფები

მარშრუტთა ჯგუფები საშუალებას გვაძლევენ კონკრეტული ატრიბუტები (მაგალითად შუამავლები) გავუზიაროთ ბევრ სხვადასხვა მარშრუტს ერთდროულად და აღარ ვწეროთ ისინი თითოეული მათგანისათვის ცალ-ცალკე. მაგალითისათვის შევქმნათ ჯგუფი, რომელიც რამდენიმე მარშრუტს გაუზიარებს სხვადასხვა შუამავლებს, ამაში დაგვეხმარება Route ფასადის middleware მეთოდი :
Route::middleware(['first', 'second'])->group(function () {

    Route::get('/', function () {
        // გაივლის first & second შუამავლებს...
    });

    Route::get('/user/profile', function () {
        // გაივლის first & second შუამავლებს...
    });

});
            

სადაზღვევო მარშრუტები :))

როდესაც შევდივართ ისეთ ბმულზე, რომლის შესაბამისი მარშრუტიც არ არის განსაზღვრული, აპლიკაციის გამონაკლისთა დამმუშავებელს ავტომატურად გადავყავართ 404 გვერდზე. შეგვიძლია შევქმნათ მარშრუტი, რომელში აღწერილი ფუნქციაც შესრულდება ყველა უმარშრუტო მისამართზე შესვლისას და აღარ მოხდება 404 გვერდზე გადამისამართება, ამაში დაგვეხმარება Route ფასადის fallback მეთოდი:
Route::fallback(function () {
    echo "გვერდი ვერ მოიძებნა";
});
            

მიმდინარე მარშრუტთან წვდომა

Route ფასადის current, currentRouteName და currentRouteAction მეთოდების დახმარებით შესაძლებელია მივიღოთ სხვადასხვა ინფორმაციები, მიმდინარე მოთხოვნის დამმუშავებელი მარშრუტის შესახებ :
use Illuminate\Support\Facades\Route;

$route = Route::current(); // Illuminate\Routing\Route
$name = Route::currentRouteName(); // მარშრუტის დასახელება
$action = Route::currentRouteAction(); // შესაბამისი კონტროლერის ის მეთოდი, რომელიც ამუშავებს მოთხოვნას
            

მარშრუტთა ქეშირება

სისტემაში არსებული მარშრუტების სრული სიის სანახავად უნდა გავუშვათ შემდეგი ბრძანება : php artisan route:list როდესაც პროექტი დასრულდება და რეალურ გარემოში გაეშვება, სასურველია, რომ მოვახდინოთ მარშრუტთა ქეშირება. ეს საგრძნობლად შეამცირებს აპლიკაციის შატვირთვისას ყველა საჭირო მარშრუტის რეგისტრაციის დროს. ქეშირება ხდება Artisan-ის route:cache ბრძანებით : php artisan route:cache ქეშირების შემდეგ ყოველი მოთხოვნის გაკეთებისას ჩაიტვირთება ქეშირებულ მარშრუტთა ფაილი, რომელიც შეიქმნებოდა - bootstrap/cache საქაღალდეში.
გვახსოვდეს, რომ თუ გაკეთებული გვაქვს მარშრუტთა ქეშირება და ამ დროს შევქმნით სხვა ახალი მარშრუტს, მაშინ უნდა მოვახდინოთ მარშრუტთა ქეშის გასუფთავება და შემდეგ ხელახლა შევქმნათ იგი.
ქეშირების გასუფთავება შესაძლებელია Artisan-ის route:clear ბრძანებით : php artisan route:clear
8. შუამავლები




HTTP middleware ანუ შუამავალი კლასი არის HTTP მოთხოვნის დამამუშავებელი ფილტრი. მაგალითად Laravel-ში განხილულია შუამავალი კლასები, რომლებიც ამოწმებენ გავლილი აქვს თუ არა მომხმარებელს ავტორიზაცია. თუ კონკრეტულ მარშრუტთან დაკავშირებულია შესაბამისი შუამავალი კლასი და მომხმარებელს არ გაუვლია ავტორიზაცია ისე აკეთებს HTTP მოთხოვნას, მაშინ შუამავალი კლასი მას გადაამისამართებს ავტორიზაციის გვერდზე. თუ მარშრუტთან არ არის დაკავშირებული, მაშინ შუამავალი კლასი საქმეში არ ერთვება.

შუამავალი კლასის შექმნა

შუამავალი კლასის შექმნის სინტაქსი ასეთია : php artisan make:middleware MiddlewareName შევქმნათ შუამავალი კლასი სახელად CheckIP php artisan make:middleware CheckIP მისი ნახვა შესაძლებელია app/Http/Middleware საქაღალდეში.
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class CheckIP
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        return $next($request);
    }
}
            
კლასის handle მეთოდს (ინგ: Handle - გარჩევა; განხილვა; რეგულირება; კონტროლის განხორციელება; განკარგვა) გადაეცემა ორი პარამეტრი, პირველი ეს არის $request მოთხოვნა - შუამავალი კლასი მუშაობს მხოლოდ და მხოლოდ მოთხოვნასთან ერთად. შემდეგი პარამეტრი კი არის ფუნქცია $next, რომელიც მართვას გადასცემს შუამავალ კლასთა ჯაჭვში არსებულ შემდეგ შუამავალ კლასს (თუ ზედა სურათს დავაკვირდებით, შევამჩნევთ, რომ შეიძლება არსებობდეს რამდენიმე შუამავალი ერთდროულად, პასუხი არ დაბრუნდება მანამ სანამ ყველა მათგანი არ გააკეთებს თავის საქმეს). ყველა შუამავლის გავლის შემდეგ მოთხოვნა უკვე მიემართება აპლიკაციის ბირთვისაკენ შემდგომი დამუშავების მიზნით.

აღვწეროთ რაიმე მარტივი ფუნქცია შუამავალ კლასში, მაგალითად გადავამოწმოთ ემთხვევა თუ არა მომხმარებლის IP მისამართი კონკრეტულ მნიშვნელობას, თუ ემთხვევა მაშინ გადავამისამართოთ მთავარ გვერდზე. ჩავამატოთ შესაბამისი ლოგიკა შუამავალ კლასში :

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class CheckIP
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        if($request->ip() == 'XXX.XXX.XXX.XXX')
        {
            return redirect()->route('index');
        }
        
        return $next($request);
    }
}
            
ამ შუამავლის მიმაგრება შესაძლებელია როგორც ყველა მარშრუტზე ასევე რომელიმე კონკრეტულ მათგანზე. მივამაგროთ იგი კონკრეტულ მარშრუტს. პირველ რიგში უნდა გავხსნათ HTTP მოთხოვნების დამუშავების ბირთვი ფაილი - app/Http/Kernel.php, რომელშიც აღწერილია კლასი Kernel, ამ კლასში არის დახურული თვისება $routeMiddleware, ამ თვისებაში ასოციაციური მასივის სახით აღწერილია ის შუამავლები, რომელთა გამოყენებაც შეგვიძლია მარშრუტებთან მუშაობისას, მასივის გასაღებები წარმოადგენენ შუამავალი კლასების ფსევდონიმებს რათა მარტივად შეგვეძლოს მათთან მიმართვა. ჩავამატოთ ჩვენი შექმნილი შუამავალი კლასი :
protected $routeMiddleware = [
    'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'checkIP' => \App\Http\Middleware\CheckIP::class
];
            

გლობალური შუამავლები

თუ გვსურს, რომ შუამავალი გავრცელდეს ჩვენს აპლიკაციაში გაკეთებულ ყველა HTTP მოთხოვნაზე, მაშინ იგი უნდა აღვწეროთ app/Http/Kernel.php კლასის $middleware თვისებაში.

შუამავალი კლასის მიმაგრება მარშრუტებზე

ჩვენი შუალედური კლასის ფსევდონიმია checkIP, მივამაგროთ იგი მარშრუტს :
Route::get('/test', function () {
    //
})->middleware('checkIP');     
            
მარშრუტზე რამდენიმე შუალედური კლასის მიმაგრება კი ხდება ასე :
Route::get('/', function () {
    //
})->middleware(['first', 'second']);
            
შუამავალი კლასის მიმაგრება შესაძლებელია მარშრუტის დამმუშავებელ კონტროლერშიც, მეთოდი კონსტრუქტორის მეშვეობით :
public function __construct()
{
    $this->middleware('checkIP');
}            
            
როდესაც შუამავლებს ვამაგრებთ მარშრუტთა ჯგუფს, შესაძლებელია დაგვჭირდეს ისე, რომ ეს შუამავალი არ შეეხოს რომელიმე მათგანს ამ ჯგუფიდან. ამაში დაგვეხმარება withoutMiddleware მეთოდი :
use App\Http\Middleware\CheckIP;

Route::middleware([CheckIP::class])->group(function () {

    Route::get('/', function () {
        //
    });

    Route::get('/profile', function () {
        //
    })->withoutMiddleware([CheckIP::class]);

});          
            
როგორც ვხედავთ routes/web.php ფაილში კლასის სრული დასახელების გამოყენებითაცაა შესაძლებელი შუამავლების მიმაგრება მარშრუტებზე.
withoutMiddleware მეთოდი ვერ აუქმებს გლობალურ შუამავლებს, იგი ეხება მარტო app/Http/Kernel.php კლასის $routeMiddleware თვისებაში აღწერილ შუამავლებს.

შუამავალთა ჯგუფები

ზოგჯერ ხელსაყრელია, რომ რამდენიმე შუამავალი გაერთიანდეს ერთი გასაღების ქვეშ, ანუ მოხდეს მათი დაჯგუფება. გასაღების მეშვეობით შედარებით მარტივად მოხდება შუამავალთა გამოყენება სხვადასხვა ადგილას. ეს ჯგუფები აღწერილია app/Http/Kernel.php კლასის $middlewareGroups თვისებაში.

Laravel-ის ინსტალაციის შემდეგ ავტომატურად გენერირდება მარშრუტთა web და api ჯგუფები, რომლებიც მოიცავენ web და api მარშრუტებთან ყველაზე ხშირად გამოყენებად შუამავლებს.

/**
 * The application's route middleware groups.
 *
 * @var array
 */
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        // \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        'throttle:api',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
];       
            
აღსანიშნავია, რომ ეს ჯგუფები ავტომატურად ემაგრება ჩვენს აპლიკაციას App\Providers\RouteServiceProvider სერვის-პროვაიდერის მიერ :
public function boot()
{
    $this->configureRateLimiting();

    $this->routes(function () {
        Route::prefix('api')
            ->middleware('api')
            ->namespace($this->namespace)
            ->group(base_path('routes/api.php'));

        Route::middleware('web')
            ->namespace($this->namespace)
            ->group(base_path('routes/web.php'));
    });
}
            
9. კონტროლერები
ამ ეტაპზე ჩვენ უკვე ვიცით მარშრუტის შექმნა და მის დამმუშავებელ ფუნქციასთან მუშაობა, მაგრამ შევთანხდეთ, რომ თუ დამმუშავებლის კოდი საკმაოდ დიდია და მარშრუტებიც ბევრი გვექნება, ამ ყველაფრის ერთ ფაილში წერა მოუხერხებელი იქნება და საჭირო გახდება მარშრუტთა დამმუშავებლების ცალკე ფაილებში გატანა. ამაში დაგვეხმარება კონტროლერები.

კონტროლერები ინახება app/Http/Controllers საქაღალდეში. ნაგულისხმეობის პრინციპით ამ საქაღალდეში უკვე შექმნილია ერთი საბაზისო კონტროლერი Controller.php სწორედ მისი მემკვიდრეები უნდა იყვნენ ის კონტროლერები, რომლებსაც მომავალში შევქმნით.

კონტროლერის შექმნა

კონტროლერის დასახელება უნდა ემთხვეოდეს იმ კლასის დასახელებას, რომელსაც ამ კონტროლერში აღვწერთ. შევქმნათ კონტროლერი UserController.php
class UserController extends Controller
{
  
  
}
            
ახლა განსაზღვროთ კონტროლერის namespace ანუ სახელსივრცე :
namespace App\Http\Controllers

class UserController extends Controller
{
  
  
}
            
თუ ვქმნით კლასს, რომელიც არის სხვა კლასის მემკვიდრე, მაშინ მშობელ კლასთანაც უნდა გვქონდეს წვდომა :
namespace App\Http\Controllers

use App\Http\Controllers\Controller;

class UserController extends Controller
{
  
  
}
            
ახლა შევქმნათ მარშრუტი, რომელსაც დაამუშავებს შექმნილი კონტროლერი, routes/web.php :
use App\Http\Controllers\UserController;

Route::get('/user/{id}', [UserController::class, 'show']);
            
შევქმნათ კონტროლერის შესაბამისი მეთოდი show :
namespace App\Http\Controllers;

use App\Http\Controllers\Controller;

class UserController extends Controller
{
    public function show($id)
    {
        echo $id;
    }
}
            
შევიდეთ http://127.0.0.1:8000/user/1 მისამართზე.

კონტროლერის შექმნა artisan ბრძანებით

კონტროლერების ხელით შექმნა ცოტა მოუხერხებელია, ამის გაკეთება გაცილებიდ მარტივია Laravel-ის კონსოლის - artisan-ის მეშვეობით. ბრძანებათა ველიდან გადავდივართ ჩვენი პროექტის საქაღალდეში, კონტროლერის შექმნის ბრძანების სინტაქსი კი ასეთია : php artisan make:controller ControllerName შევქმნათ კონტროლერი TestController.php php artisan make:controller TestController თუ შევალთ კონტროლერების საქაღალდეში, დაგვხვდება ახალი კონტროლერი.

კონტროლერი და შუამავალი

კონტროლერის შესაბამის მარშრუტზე შუამავლის მიმაგრება ხდება ამგვარად : Route::get('profile', [UserController::class, 'show'])->middleware('auth'); ასევე შესაძლებელია შუამავლის განსაზღვრა კონტროლერის მეთოდ კონსტრუქტორშიც :
class UserController extends Controller
{
    /**
     * Instantiate a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
        $this->middleware('log')->only('index');
        $this->middleware('subscribed')->except('store');
    }
}
            

რესურსების კონტროლერები

წარმოვიდგინოთ, რომ აპლიკაციაში გვაქვს Photo და Movie მოდელები, რომელთა მეშვეობითაც შესაძლებელია რესურსების (ფოტო, ფილმი) შექმნა, წაკითხვა, რედაქტირება და წაშლა. ასეთ შემთხვევებში კონტროლერებს აქვთ ხოლმე, ოთხი ძირითადი მეთოდი : create, read, update, delete (CRUD). ნაცვლად იმისა, რომ სათითაო მეთოდისათვის, სათითაო ფუნქცია ვწეროთ ხელით კონტროლერში, შეგვიძლია კონტროლერის შექმნის ბრძანება გავუშვათ --resource ჩანაწერთან ერთად : php artisan make:controller PhotoController --resource ამ ბრძანების შედეგად შეიქმნება app/Http/Controllers/PhotoController.php კონტროლერი, რომელშიც უკვე აღწერილი იქნება ყველა ზემოთ ნახსენები საჭირო მეთოდი.

ახლა აღვწეროთ რესურსის ტიპის მარშრუტი Route ფასადის resource მეთოდის დახმარებით :

Route::resource('photos', PhotoController::class); ეს ერთადერთი ჩანაწერი ახდენს ოთხივე ოპერაციისათვის (CRUD) საჭირო ყველა მარშრუტის დეკლარირებას. საერთო ჯამში კი მიიღება ამდაგვარი სურათი :
მოთხოვნის ტიპი URI კონტროლერის ფუნქცია (მეთოდი) მარშრუტის დასახელება
GET /photos index photos.index
GET /photos/create create photos.create
POST /photos store photos.store
GET /photos/{photo} show photos.show
GET /photos/{photo}/edit edit photos.edit
PUT/PATCH /photos/{photo} update photos.update
DELETE /photos/{photo} destroy photos.destroy

დამოკიდებულების ინექცია (Dependency Injection) და კონტროლერები

რა არის დამოკიდებულების ინექცია

ინგ: Injection - ინექცია; დანერგვა; შემოღება; ჩადება;

თუ კონკრეტული კლასის მუშაობისათვის საჭიროა, გამოყენებულ იქნას სხვა კლასის ფუნქციონალი, ეს იმას ნიშნავს, რომ პირველი კლასი დამოკიდებულია მეორე კლასზე. ბუნებრივია უნდა მოვახდინოთ დამხმარე კლასის საწყის კლასში ინტეგრირება (Injection) და მხოლოდ ამის შემდეგ შეგვეძლება დამხმარე კლასის ფუნქციონალის გამოყენება. სწორედ ამ დამხმარე კლასს ეწოდება დამოკიდებულება (Dependency).
...

use Illuminate\Http\Request;

...

class SomeController extends Controller
{
    ...

    public function post(Request $request)
    {
        $request->validate([
            // ...
        ]);

        // ... 
    }

    ...
}
            

***

სერვისების კონტეინერში დეკლარირებული ნებისმიერი დამოკიდებულების ინექცია უმარტივესადაა შესაძლებელი. არსებობს ინექციის რამდენიმე ვარიანტი.

ინექცია მეთოდ კონსტრუქტორში

namespace App\Http\Controllers;

use App\Repositories\UserRepository;

class UserController extends Controller
{
    
    protected $users;

    public function __construct(UserRepository $users)
    {
        $this->users = $users;
    }
}
            

ინექცია სტანდარტულ მეთოდში

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    public function store(Request $request)
    {
        $name = $request->name;

        //
    }
}
            
თუ მოხდა ისე, რომ კონტროლერს გადმოეცემა მარშრუტის პარამეტრიც, მაშინ ეს პარამეტრი უნდა აღვწეროთ ინექციის შემდეგ. მაგალითად თუ გვაქვს ასეთი მარშრუტი :
        
use App\Http\Controllers\UserController;

Route::put('/user/{id}', [UserController::class, 'update']);
            
კონტროლერის მეთოდს ეს პარამეტრი ინექციასთან ერთად გადაეცემა ამდაგვარად :
        
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    public function update(Request $request, $id)
    {
        //
    }
}
            

მარშრუტთა დაჯგუფებები კონტროლერის მიხედვით

დავუშვათ გვაქვს პოსტებთან სამუშო კონტროლერი - PostsController, როგორც ვიცით, ლარაველის მე-8-ე ვერსიაში, შესაბამისი მარშრუტების დაგენერირება მოხდებოდა ასე :
use Illuminate\Support\Facades\Route;

use App\Http\Controllers\PostsController;

Route::get('/posts', [PostsController::class, 'index']); // პოსტების ჩამონათვალი
Route::get('/posts/{post}', [PostsController::class, 'show']); // კონკრეტული პოსტი
Route::post('/posts', [PostsController::class, 'store']); // ახალი პოსტის დამატება
            
ლარაველის მე-9-ე ვერსიაში შესაძლებელია მარშრუტთა დაჯგუფება კონტროლერის მიხედვით, ამისათვის გამოიყენება Route ფასადის controller მეთოდი group მეთოდთან ერთად :
use Illuminate\Support\Facades\Route;

use App\Http\Controllers\PostsController;

Route::controller(PostsController::class)->group(function(){
    Route::get('/posts', 'index'); // პოსტების ჩამონათვალი
    Route::get('/posts/{post}', 'show'); // კონკრეტული პოსტი
    Route::post('/posts', 'store'); // ახალი პოსტის დამატება
});
            
როგორც ვხედავთ, მარშრუტებისათვის, სათითაოდ ცალ-ცალკე კონტროლერის განსაზღვრა აღარ გვჭირდება და უბრალოდ კონტროლერის მეთოდების დასახელებებს ვუთითებთ.
10. მოთხოვნის მიღება და დამუშავება, კლასი Request
აპლიკაციის გახსნის შემდეგ პირველი რაც ხდება ისაა, რომ სისტემა ღებულობს ამა თუ იმ შიგთავსის გამოტანის მოთხოვნას მომხმარებლისაგან. ამ თავში ვისაუბრებთ Illuminate\Http\Request კლასის შესახებ, რომლის მეშვეობითაც ხდება ნებისმიერი მოთხოვნის დამუშავება.

იმისათვის რათა მივიღოთ მიმდინარე HTTP მოთხოვნის ობიექტი, Illuminate\Http\Request კლასი, დამოკიდებულებათა ინექციის საშუალებით უნდა ჩავსვათ საჭირო კონტროლერში ან მარშრუტის ფუნქცია-დამმუშავებელში:

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    public function store(Request $request)
    {
        $name = $request->input('name');

        //
    }
}
            
მარშრუტის შემთხვევაში :
use Illuminate\Http\Request;

Route::get('/', function (Request $request) {
    //
});
            

Request კლასის მეთოდები

path() მეთოდი

ეს მეთოდი აბრუნებს URI-ს იმ ნაწილს, რომელიც შეიცავს მომხმარებლის მიერ გაკეთებული მოთხოვნის გზას, მაგალითად თუ URI არის http://127.0.0.1:8000/foo/bar, მეთოდი დააბრუნებს foo/bar - ს : $uri = $request->path(); // foo/bar

is() მეთოდი

ეს მეთოდი აბრუნებს მნიშვნელობას - true, თუ მომხმარებლის მიერ გაკეთებული მოთხოვნის შესაბამისი გზა (ანუ URI-ს ფრაგმენტი) ემთხვევა იმ შაბლონს, რომელსაც პარამეტრად გადავცემთ მეთოდს.
if ($request->is('foo/*')) 
{
    //
}
            

routeIs() მეთოდი

ეს მეთოდი აბრუნებს მნიშვნელობას - true, თუ მომხმარებლის მიერ გაკეთებული მოთხოვნა ემთხვევა, რომელიმე სახელდებულ მარშრუტს :
if ($request->routeIs('index')) 
{
    //
}
            

url(), fullUrl() და fullUrlWithQuery() მეთოდები

პირველი მათგარი აბრუნებს მიმდინარე მისამართს GET პარამეტრების გარეშე, ხოლო მეორე მათგანი - GET პარამეტრებთან ერთად :
// http://127.0.0.1:8000/foo/bar?want_drink=true

$request->url() // http://127.0.0.1:8000/foo/bar

$request->fullUrl() // http://127.0.0.1:8000/foo/bar?want_drink=true
            
თუ გვინდა, რომ მიმდინარე მისამართს მივაწეროთ დამატებითი GET პარამერები, მაშინ უნდა გამოვიყენოთ fullUrlWithQuery მეთოდი :
// http://127.0.0.1:8000/foo/bar?want_drink=true

$request->url() // http://127.0.0.1:8000/foo/bar

$request->fullUrl() // http://127.0.0.1:8000/foo/bar?want_drink=true

$request->fullUrlWithQuery(['drink' => 'vodka'])) // http://127.0.0.1:8000/foo/bar?want_drink=true&drink=vodka
            

method() და isMethod() მეთოდები

ეს მეთოდი აბრუნებს მომხმარებლის მიერ გაკეთებული მოთხოვნის ტიპს სტრიქონული სახით (get, post, ...). isMethod() მეთოდი აბრუნებს მნიშვნელობას - true, თუ გაკეებული მოთხოვნის ტიპი ემთხვევა არგუმენტად გადაცემული სტრიქონის მნიშვნელობას :
$method = $request->method();

if ($request->isMethod('get')) 
{
    // 
}
            

ip() მეთოდი

ეს მეთოდი აბრუნებს იმ მომხმარებლის IP მისამართს, რომელმაც მოთხოვნა გააკეთა ჩვენს აპლიკაციაში : $ipAddress = $request->ip();

all() მეთოდი

ეს მეთოდი აბრუნებს ასოციაციურ მასივს, რომლის ინდექსებიცაა html ფორმის ველთა დასახელებები, ხოლო ამ ინდექსების მნიშვნელობები კი ველებში შეყვანილი ინფორმაციებია, მაგალითად თუ გავგზავნით (submit) ასეთი ველების მქონე ფორმას : <input type="text" name="name">
<input type="password" name="password">
public function login(Request $request)
{
    print_r($request->all());
}
            
შედეგად ვიხილავთ დაახლოებით შემდეგი სახის მასივს :
Array
(
    [name] => vaso
    [password] => pass123
)
            

input() მეთოდი

ეს მეთოდი გამოიყენება მოთხოვნიდან კონკრეტული ველის მნიშვნელობის ამოსაღებად, პირველ პარამეტრად მეთოდს უნდა გადავცეთ ველის დასახელება, მეორე პარამეტრად კი შეგვიძლია გადავცეთ ალტერნატიული მნიშვნელობა ისეთი ველისათვის, რომელიც მოთხოვნაში არ იქნება:
// http://127.0.0.1:8000/foo/bar?want_drink=true

$want = $request->input('want_drink')); // true

$drink = $request->input('drink', 'vodka')); // vodka
            
უნდა აღინიშნოს, რომ input() მეთოდი მუშაობს ნებისმიერი ტიპის HTTP მოთხოვნებთან.

query() მეთოდი

ეს მეთოდი მუშაობს მხოლოდ GET ტიპის მოთხოვნებთან, შეგვიძლია მასაც გადაცხეთ ალტერნატიული მნიშვნელობა არარსებული ველისათვის :
$name = $request->query('name', 'Helen');
            
თუ მეთოდს საერთოდ არ გადავცემთ პარამეტრებს, მაშინ იგი დაგვიბრუნებს GET ტიპის ყველა პარამეტრს.

boolean() მეთოდი

როდესაც ვამუშავებთ ისეთ HTML ელემენტებს, როგორიცაა მაგალითად 'checkbox', შესაძლებელია, რომ აპლიკაციამ მათი მონიშნულობის (მოპწიჩკულობის :) ) აღმნიშვნელად მიიღოს სტრიქონული ტიპის ტექსტები, მაგალითად : 'true' ან 'on'. სწორედ ასეთ ელემენტებთან სამუშაოდ გამოიყენება boolean მეთოდი. იგი აბრუნებს ჭეშმარიტ მნიშვნელობას (true), 'checkbox' ტიპის ველის 'name' ატრიბუტის შემდეგი მნიშვნელობებისათვის : 1, '1', true, 'true', 'on', და 'yes', ყველა სხვა შემთხვევაში ბრუნდება მნიშვნელობა false. $archived = $request->boolean('archived');

ველის ამოღება დინამიური მეთოდების დახმარებით

შესაძლებელია, რომ მოთხოვნის ველები განვიხილოთ როგორც Illuminate\Http\Request კლასის ობიექტის თვისებები და ისე მივწვდეთ მათ. მაგალითად თუ აპლიკაციაში გვაქვს ფორმა, რომლის ერთ-ერთი ველის დასახელებაცაა 'name', ამ ველის მნიშვნელობა შეიძლება გავიოთ ასე : $name = $request->name; დინამიური მეთოდის გამოყენებისას ფრეიმვორკი პირველ რიგში გადაამოწმებს მოთხოვნაში ჩადებულ ველებს, თუ აქ ვერ მოიძებნა შესაბამისი ველი, მაშინ გადაამოწმებს მარშრუტის პარამეტრებს.

only() მეთოდი

ეს მეთოდი მუშაობს all მეთოდის ანალოგიურად, იმ განსხვავებით, რომ თუ ეს უკანასკნელი აბრუნებს გაგზავნილი ინფორმაციის შემცველი მასივის ყველა ინდექსსა და მათ მნიშვნელობებს, only მეთოდი აბრუნებს მხოლოდ იმ ინდექსებს, რომლებსაც პარამეტრებად გადავცემთ :
$input = $request->only(['username', 'password']);

$input = $request->only('username', 'password');
            
მეთოდს პარამეტრად უნდა გადაეცეს შესაბამისი ველის დასახელება.

except() მეთოდი

ეს მეთოდი არის all და only მეთოდების ერთფგვარი შებრუნებული მეთოდი :)) იგი აბრუნებს გაგზავნილი ინფორმაციის შემცველ მასივს იმ ინდექსების გამოკლებით, რომლებსაც პარამეტრებად გადავცემთ :
$input = $request->except(['credit_card']);

$input = $request->except('credit_card');
            
მეთოდს პარამეტრად უნდა გადაეცეს შესაბამისი ველის დასახელება (name ატრიბუტის მნიშვნელობა)

has() მეთოდი

მეთოდი აბრუნებს მნიშვნელობას - true თუ მოთხოვნაში ჩადებული ინფორმაციის შემცველი მასივი შეიცავს იმ ინდექსს, რომელსაც პარამეტრად გადავცემთ მეთოდს, წინააღმდეგ შემთხვევაში მეთოდი აბრუნებს მნიშვნელობას false.
if ($request->has('name')) 
{
    //
}
            

filled() მეთოდი

მეთოდი აბრუნებს მნიშვნელობას - true თუ მოთხოვნაში ჩადებული ინფორმაციის შემცველი მასივი შეიცავს იმ ინდექსს, რომელსაც პარამეტრად გადავცემთ მეთოდს და ამასთანავე ველის მნიშვნელობა არ იქნება ცარიელი, წინააღმდეგ შემთხვევაში მეთოდი აბრუნებს მნიშვნელობას false.
if ($request->filled('name')) 
{
    //
}
            

flash() მეთოდი

შესაძლებელია საჭირო გახდეს მომხმარებლის მიერ აკრეფილი ინფორმაციის გადამოწმება, ვალიდაცია. თუ ეს ინფორმაცია არ აკმაყოფილებს ვალიდაციის პირობებს და თუ ფორმაც მარტივია და შედგება რამდენიმე ველისაგან, მომხმარებელს უბრალოდ გადავამისამართებთ ისევ ფორმის გვერდზე, მაგრამ თუ ფორმა რთულია და შეიცავს ძალიან ბევრ ველებს, მაშინ მომხმარებელს ამ ველების თავიდან შევსება მოუწევს, რაც არც თუ ისე მოსახერხებელია. ამ პრობლემის გადასაწყვეტად გამოიყენება request ობიექტის flash() მეთოდი, რომელიც მოთხოვნის ტანში ჩადებულ ინფორმაციას ინახავს სესიაში. $request->flash(); შენახული ინფორმაცია შეიძლება გამოიყურებოდეს ასე :
Array
(
    [_token] => xtLofMZlLR1b4oEZeT9YPr8SZiOzqfLrGof9huOj
    [_previous] => Array
        (
            [url] => http://127.0.0.1:8000/contact
        )

    [_flash] => Array
        (
            [old] => Array
                (
                )

            [new] => Array
                (
                    [0] => _old_input
                )

        )

    [_old_input] => Array
        (
            [name] => vaso
            [password] => pass123
        )

)
            
_token არის საიტის უსაფრთხოების გასაღები და მის შესახებ მოგვიანებით ვისაუბრებთ. რაც შეეხება _old_input უჯრას - იგი შეიცავს ბოლო მოთხოვნაში შესული ინფორმაციის შემცველ მასივს. ამ ინფორმაციასთან წვდომისათვის გამოიყენება სპეციალური ფუნქცია old(), ფორმის წარმოდგენის ფაილი გადავაკეთოთ ასე :
<input type="name" name="name" value="{{ old('name') }}">

<input type="password" name="password" value="{{ old('password') }}">
            
ამის შემდეგ თუ ფორმას გავაგზავნით ვნახავთ, რომ აკრეფილი ინფორმაცია არ დაიკარგება და ველები ავტომატურად შეივსება.

flashOnly() მეთოდი

ეს მეთოდი სესიაში ინახავს მხოლოდ იმ ველების მნიშვნელობებს, რომლებსაც გადავცემთ პარამეტრებად : $request->flashOnly(['username', 'email']);

flashExcept() მეთოდი

ეს მეთოდი სესიაში ინახავს ყველა ველის მნიშვნელობას გარდა იმ ველებისა, რომლებსაც გადავცემთ პარამეტრებად : $request->flashExcept('password');
11. პასუხი სერვერიდან, კლასი Response
წინა თავში განვიხილეთ თუ როგორ ხდება მოთხოვნის მიღება და დამუშავება. მოთხოვნის გაშვების შემდეგ, ბუნებრივია სერვერიდან ბრუნდება პასუხი. ამ თავში განვიხილავთ თუ როგორ აკეთებს Laravel-ი ამას და რა საშუალებები არსებობს პასუხის რეალიზებისათვის.

კონკრეტულ გვერდზე რაიმე ინფორმაციის გამოტანის, ანუ ერთგვარი პასუხის დაბრუნების უმარტივესი გზა არის კონტროლერში ან მარშრუტის დამმუშავებელში ტექსტის დაბრუნება :

public function index()
{
    return 'Hello World';
}
            
Route::get('/', function () {
    return 'Hello World';
});
            
ასევე შესაძლებელია მასივის დაბრუნებაც, ფრეიმვორკი ავტომატურად გადააფორმატებს მას JSON ფორმატში :
Route::get('/', function () {
    return [1, 2, 3];
});
            

პასუხის ობიექტი

მოთხოვნათა პასუხების აბსტრაქცია ანუ განზოგადებული სახე არის Response კლასი, რომელიც აღწერილია vendor/laravel/framework/src/Illuminate/http/Response.php ფაილში. ამ კლასის მეთოდ-კონსტრუქტორს თუ დავაკვირდებით, გავიგებთ რა პარამეტრები შეგვიძლია გადავცეთ პასუხებთან სამუშაო დამხმარე ფუნქცია response-ს :
public function __construct($content = '', $status = 200, array $headers = [])
{
    $this->headers = new ResponseHeaderBag($headers);

    $this->setContent($content);
    $this->setStatusCode($status);
    $this->setProtocolVersion('1.0');
}
            
ანუ შეგვიძლია განვსაზღვროთ პასუხის აღწერილობა, HTTP სტატუსი და სათაურები :
Route::get('/home', function () {
    return response('Hello World', 200)
            ->header('Content-Type', 'text/plain');
});
            

Cookie-ს მიმაგრება პასუხზე

პასუხზე Cookie-ს მიმაგრება შესაძლებელია cookie მეთოდით, მეთოდს უნდა გადავეთ სამი პარამეტრი : დასახელება, მნიშვნელობა და Cookie-ს ქმედითუნარიანობის ხანგრძლივობა წუთებში : return response('Hello World')->cookie('name', 'value', $minutes);

Cookie-ს წაშლა პასუხიდან

პასუხიდან Cookie-ს წასაშლელად გამოიყენება withoutCookie მეთოდი, რომელსაც პარამეტრად უნდა გადავცეთ Cookie-ს დასახელება : return response('Hello World')->withoutCookie('name');

Cookie-ბი და შიფრაცია

ნაგულისხმეობის პრინციპით Laravel-ი ახდენს Cookie-ბის შიფრაციას, შესაბამისად შენახული ინფორმაცია მომხმარებლისათვის არ არის ხელმისაწვდომი. თუ გვსურს, რომ არ მოხდეს რომელიღაც კონკრეტული Cookie-ს შიფრაცია, მაშინ უნდა გამოვიყენოთ App\Http\Middleware\EncryptCookies შუამავლის $except მეთოდი :
/**
 * იმ cookie-ბის დასახელებები, რომელთა შიფრაციაც არ მოხდება
 *
 * @var array
 */
protected $except = [
    'cookie_name',
];
            

გადამისამართებები

რომელიმე გვერდზე გადასამისამართებლად გამოიყენება Illuminate\Http\RedirectResponse კლასის ობიექტები,არსებობს ამ ობიექტებთან წვდომის რამდენიმე ვარიანტი, ერთ-ერთია დამხმარე ფუნქცუა redirect, რომელსაც პარამეტრად უნდა გადავცეთ ბმული სადაც გვსურს გადამისამართება :
Route::get('/dashboard', function () {
    return redirect('home/dashboard');
});
            
ზოგჯერ საჭიროა, რომ მომხმარებელი გადავამისამართოთ წინა გვერდზე (მაგალითად გაგზავნა ფორმა არავალიდური ინფორმაციებით), ანუ დავაბრუნოთ უკან, ამისათვის გამოიყენება დამხმარე ფუნქცია back. ფუნქცია იყენებს სესიებს, ამიტომ დარწმუნებულები უნდა ვიყოთ, რომ მარშრუტი, რომლის დამმუშავებელშიც back ფუნქციას ვიძახებთ, მოქცეულია web შუამავალში (როგორც ვიცით სწორედ ეს შუამავალი ახდენს, სესიების მიმაგრებას მარშრუტებთან) :
Route::post('/user/profile', function () {
    
    // მოთხოვნის ვალიდაცია...

    return back()->withInput();

});
            

გადამისამართება სახელდებულ მარშრუტებზე

სახელდებულ მარშრუტზე გადასამისამართებლად, გამოიყენება redirect ფუნქციის route მეთოდი, რომელსაც პარამეტრად უნდა გადავცეთ მარშრუტის დასახელება : return redirect()->route('login'); თუ მარშრუტს აქვს პარამეტრები, მათი გადაცემა შეგვიძლია მეთოდის მეორე არგუმენტად :
// მარშრუტი შემდეგი URI-სათვის : /profile/{id}

return redirect()->route('profile', ['id' => 1]);
            

გადამისამართება გარე ბმულებზე

ხანდახან საჭიროა, რომ გადამისამართება მოვახდინოთ ისეთ ბმულზე, რომელიც მდებარეობს ჩვენი აპლიკაციის გარეთ. ასეთ შემთხვევაში უნდა გამოვიყენოთ redirect ფუნქციის away მეთოდი, რომელსაც პარამეტრად გადაეცემა სასურველი ბმული : return redirect()->away('https://www.google.com');

გადამისამართება სესიის ინფორმაციასთან ერთად

გადამისამართებისას შეიძლება დაგვჭირდეს სესიაში რაიმე ინფორმაციის შენახვა და შემდეგ ამ ინფორმაციის იმ გვერდზე გამოყენება, სადაც გადამისამართებას ვაკეთებთ. ამ შემთხვევაში გამოიყენება redirect ფუნქციის with მეთოდი, რომელსაც პარამეტრად გადაეცემა სესიის გასაღები და ამ გასაღების შესაბამისი მნიშვნელობა :
Route::post('/user/profile', function () {
    // ...

    return redirect('dashboard')->with('status', 'ინფორმაცია წარმატებით განახლდა !');
});
            
გადამისამართების შემდეგ, წარმოდგენის ფაილში ამ ინფორმაციის გამოყენების სინტაქსი იქნება ასეთი :
@if (session('status'))
    <div class="alert alert-success">
        {{ session('status') }}
    </div>
@endif
            

JSON პასუხები

response ფუნქციის json მეთოდი, პასუხის სათაურ (header) Content-Type-ის მნიშვნელობად ავტომატურად სვამს application/json-ს.
return response()->json([
    'name' => 'Abigail',
    'state' => 'CA',
]);
            

ფაილის გადმოწერა

თუ გვსურს, რომ დაბრუნებული პასუხის შედეგად მომხმარებლის ბრაუზერმა მოახდინოს კონკრეტული ფაილის გადმოწერა, უნდა გამოვიყენოთ response ფუნქციის download მეთოდი, რომელსაც პარამეტრად უნდა გადავცეთ სასურველი ფაილის მისამართი : return response()->download($pathToFile);
12. წარმოდგენის შაბლონები, ინფორმაციის მიმაგრება მათზე
რა თქმა უნდა საკმაოდ არაკომფორტულია HTML კოდების პირდაპირ მარშრუტებში და კონტროლერებში დაბრუნება. წარმოდგენა არის MVC შაბლონის ერთ-ერთი ელემენტი, რომელიც უზრუნველჰყოფს ინფორმაციის ბრაუზერში გამოტანას და მისი საშუალებით ასევე ხდება HTML შიგთავსების, ძირითადი ლოგიკისაგან გამოყოფა, განცალკევება. წარმოდგენის ფაილები ინახება resources/views საქაღალდეში. მოვიყვანოთ წარმოდგენის უმარტივესი მაგალითი :
<!-- resources/views/greeting.blade.php -->

<html>
    <body>
        <h1>{{ $name }} გამარჯობა ! </h1>
    </body>
</html>
            
წარმოდგენის დაბრუნება შესაძლებელია view დამხმარე ფუნქციის მეშვეობით :
Route::get('/', function () {
    return view('greeting', ['name' => 'შამილი']);
});
            
წარმოდგენის დაბრუნება შესძლებელია View ფასადის მეშვეობითაც :
use Illuminate\Support\Facades\View;

return View::make('greeting', ['name' => 'შამილი']);
            
დავუშვათ resources/views საქაღალდეში გავაკეთეთ ახალი საქაღალდე templates და წარმოდგენის ფაილები გადავიტანეთ მასში, მაშინ წარმოდგენის მოთხოვნის სინტაქსი იქნება შემდეგნაირი : return view('templates.greeting', ['name' => 'შამილი']);
წარმოდგენის ფაილის დასახელება არ უნდა შეიცავდეს . სიმბოლოს (წერტილს)
ამ თავში ვისაუბრებთ წარმოდგენებზე, რომლებიც იმუშავებენ შაბლონიზატორ blade-ს გარეშე.

resources/views საქაღალდეში შევქმნათ ახალი საქაღალდე templates და მასში გავაკეთოთ წარმოდგენის ახალი ფაილი template.php. შესაბამისად გადავაკეთოთ view ფუნქციაც :

return view('templates.template') ამჟამად გვაქვს სტატიკური გვერდი სადაც ლოგიკის არავითარი ელემენტი არ არის და არც ცვლადებია გამოყენებული. გადავცეთ მას რაიმე ცვლადი : <h1><?php echo $title; ?></h1> ეს მოგვცემს შეცდომას რადგან $title ცვლადი განსაზღვრული არ არის. ცვლადი უნდა აღვწეროთ კონტროლერში, ან მარშრუტის დამმუშავებელში : return view('templates.template',['title'=>'Hello World !']); დავუშვათ გვინდა რამდენიმე ცვლადის, ანუ რამდენიმე ინფორმაციის ერთდროულად გამოყენება, ასეთ შემთხვევაში ხელსაყრელია დავიხმაროთ მასივი : $data = array('title'=>'Hello World !' , 'title1'=>'Hello World 1');
return view('templates.template',$data);

with მეთოდი

ინფორმაციის მიმაგრება შესაძლებელია with მეთოდითაც : return view('templates.template')->with('title','Hello World 2 !'); with მეთოდის გამოყენებისას რამდენიმე ცვლადის მიმაგრება ხდება ასე :
public function index()
{
    $view = view('templates.template');
    $view->with('title','Hello World !'); 
    $view->with('title1','Hello World 1'); 
    $view->with('title2','Hello World 2');  
    
    return $view;
}
             
არსებობს with მეთოდის გამოყენების კიდევ ერთი ვარიანტი : return view('templates.template')->withTitle('Hello World'); ანუ with მეთოდის დასახელება პრეფიქსად ერთვის ცვლადის დიდი ასოთი დაწყებულ სახელს, შემდეგ კი ფრხილებში ეთითება ცვლადის მნიშვნელობა.

compact მეთოდი

წარმოდგენის ფაილზე ინფორმაციის მიმაგრების კიდევ ერთი, არანაკლებ ეფექტური მეთოდია compact. ეს არის PHP-ს სტანდარტული ფუნქცია, რომელიც ცვლადთა დასახელებებისა და მათი მნიშვნელობებისაგან აკეთებს ასოციაციურ მასივს :
$firstname = "ვასო";
$lastname = "ნადირაძე";
$age = "30";

$result = compact("firstname", "lastname", "age");

print_r($result); // Array ( [firstname] => ვასო [lastname] => ნადირაძე [age] => 30 )
             
რაც შეეხება laravel-ში ამ მეთოდის გამოყენების სინტაქსს, იგი შემდეგნაირია :
public function index()
{
    $firstname = "ვასო";
    $lastname = "ნადირაძე";
    $age = "30";

    return view('templates.template', compact('firstname', 'lastname', 'age'));
}
            
ამ ინფორმაციების, წარმოდგენის ფაილში გამოყენების ხერხებს განვიხილავთ შემდეგ თავში.

***

წარმოდგენის ფაილების გასაფორმებლად უნდა გამოვიყენოთ Laravel ფრეიმვორკის ფუნქციები. მაგალითად ნავიგაციური მენიუს HTML კოდი ხშირად არის შემდეგნაირი :

<ul>
    <li><a href="#">Home</a></li>
    <li><a href="#">Articles</a></li>
    <li><a href="#">Article</a></li>
    <li><a href="#">About</a></li>
</ul>
            
თითოეული ბმული დაკავშირებულია კონკრეტულ გვერდთან. გვერდის უკან კი მოიაზრება კონკრეტული მარშრუტი, ამიტომ ბმულების ფორმირებისას ისინი უნდა დავაკავშიროთ ამ მარშრუტებთან. ამის გაკეთება კი, როგორც ვიცით, შესაძლებელია route ფუნქციის მეშვეობით :
<ul class="nav navbar-nav">
    <li><a href="<?php echo route('home'); ?>">Home</a></li>
    <li><a href="<?php echo route('articles'); ?>">Articles</a></li>
    <li><a href="<?php echo route('article',array('id'=>10)); ?>">Article</a></li>
    <li><a href="<?php echo route('about'); ?>">About</a></li>
</ul>
            

view()->exists()

როგორ გადავამოწმოთ კონტროლერში, არსებობს თუ არა წარმოდგენის ესა თუ ის ფაილი ? როგორც ვიცით view() ფუნქცია ქმნის გლობალური view კლასის ობიექტს, ამ ობიექტს გააჩნია მეთოდი exists(), რომელიც ამოწმებს არსებობს თუ არა წარმოდგენის კონკრეტული ფაილი. მეთოდს პარამეტრად გადეცემა წარმოდგენის ფაილის დასახელება და აბრუნებს true მნიშვნელობას თუ ეს ფაილი არსებობს. კონტროლერში შეგვიძლია ჩავწეროთ ასეთი რამ :
public function index()
{
    if (view()->exists('templates.template'))
    {
        return view('templates.template')->withTitle('Hello World');
    }
}            
            

ინფორმაციის გაზიარება წარმოდგენის ყველა ფაილისათვის

ინფორმაციის გაზიარება წარმოდგენის ყველა ფაილისათვის შესაძლებელია View ფასადის share მეთოდით. როგორც წესი, ეს გაზიარება აღიწერება ხოლმე სერვისპროვაიდერის boot მეთოდში :
namespace App\Providers;

use Illuminate\Support\Facades\View;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        //
    }
    
    public function boot()
    {
        View::share('key', 'value');
    }
}         
            

წარმოდგენის ფაილების ქეშირება

ნაგულისხმეობის პრინციპით ფრეიმვორკი ახდენს წარმოდგენათა ფაილების კომპილაციას. როდესაც სრულდება მოთხოვნა, რომლის შედეგადაც უნდა მოხდეს წარმოდგენის ჩატვირთვა, Laravel-ი ადგენს არსებობს თუ არა საჭირო წარმოდგენის კომპილირებული ვერსია, თუ ეს ვერსია არსებობს ამის შემდეგ სისტემა დაადგენს რომელი ვერსია უფრო გვიან შეიცვალა - კომპილირებული თუ არაკომპილირებული. თუ კომპილირებული ვერსია საერთოდ არ არსებობს ან არსებობს, მაგრამ არაკომპილირებულში მოხდა ცვლილებები მაშინ გაკეთდება წარმოდგენის ფაილის ხელახალი კომპილაცია.

შესაძლებელია, რომ ამ პროცესმა უარყოფითი გავლენა იქონიოს აპლიკაციის სისწრაფეზე, ასე რომ view:cache Arttisan ბრძანებით ეგვიძლია დავქეშოთ წარმოდგენის ფაილები :

php artisan view:cache ქეშირებული შაბლონები შეინახება storage/framework/views საქაღალდეში. ქეშის გასუფთავება კი მოხდება ასე : php artisan view:clear
13. შაბლონიზატორი Blade
ამ თავში ვისაუბრებთ შაბლონიზატორ blade-ზე, რომელიც ჩაშენებულია Laravel-ის ფუნქციონალში. შაბლონიზატორი არის სპეციალური მექანიზმი, რომელიც გამოიყენება შაბლონის კონკრეტულ ადგილებზე ინფორმაციის მისამაგრებლად და გვერდის საბოლოო იერსახის ჩამოსაყალიბებლად. თავის მხრივ წარმოდგენა არის PHP ფაილი, რომელშიც აღწერილია HTML კოდი და აგრეთვე სპეციალური ნიშნულები რომელთა ნაცვლადაც უნდა ჩაჯდეს პროექტის ლოგიკური ნაწილიდან მოსული ინფორმაციები. blade შაბლონიზატორში არ უნდა ეწეროს PHP კოდი. იმდენად რამდენადაც გვერდის გაფორმებისათვის აუცილებელი ყველანაირი ლოგიკა ჩანაცვლებულია სპეციალური ნიშნულებითა და შაბლონიზატორის კონსტრუქციებით, რომელთა გადათარგმნა და ლოგიკის კოდით ჩანაცვლება ხდება კომპილაციის დროს.

კომპილირებული შაბლონები ინახება storage/framework/views საქაღალდეში.

იმისათვის რათა წარმოდგენის ფაილი blade შაბლონიზატორმა დაამუშავოს, ფაილის გაფართოება უნდა იყოს blade.php. გადავარქვათ ჩვენს მიერ შექმნილ ფაილს სახელი:

template.blade.php ამ ფაილს ახლა უკვე ამუშავებს შაბლონიზატორი Blade.

ინფორმაციის გამოტანა

იმისაათვის რათა შაბლონში გამოვიტანოთ მასზე მიმაგრებული ინფორმაცია, უნდა გამოვიყენოთ ორმაგი ფიგურული ბრჭყალები :
Route::get('/', function () {
    return view('templates.template', ['name' => 'შამილი']);
});
            
წარმოდგენის ფაილი : {{ $name }} გამარჯობა ! არ არის აუცილებელი მაინცდამაინც ცვლადის სახით მიმაგრებული ინფორმაცია გამოვიტანოთ ამ გზით, შესაძლებელია PHP-ს ნებისმიერი ფუნქციის შედეგის გამოტანაც : მიმდინარე UNIX დროითი ნიშნული არის {{ time() }}

JSON ფორმატის ინფორმაცია

შეიძლება მოხდეს ისე, რომ დაგვჭირდეს PHP მასივის JSON ფორმტში გადაყვანა და შედეგის JavaScript ცვლადში მოქცევა :
<script>
    var app = <?php echo json_encode($array); ?>;
</script>
            
იგივეს გაკეთება უფრო მარტივადაა შესაძლებელი შაბლონიზატორის @json დირექტივის გამოყენებით :
<script>
    var app = @json($array);
</script>
            

HTML გარემოს გამოტანა

შევქნათ კონტროლერი და აღვწეროთ ამდაგვარი მეთოდი :
public function index()
{
    $script = "<script>alert('Hello')</script>";
    return view('templates.template')->with('script', $script);
}
            
წარმოდგენის ფაილში შევიტანოთ ამდაგვარი ჩანაწერი : {{ $script }} ასევე შევქმნათ შესაბამისი მარშრუტი, რომელსაც ეს მეთოდი დაამუშავებს და შევიდეთ შესაბამის ბმულზე (ეს ყველაფერი უკვე ვიცით და ამიტომ კოდის ნიმუშს აღარ დავწერ). შედეგად ვიხილავთ : <script>alert('Hello')</script> ნაგულისხმეობის პრინციპით შაბლონიზატორის {{ }} ჩანაწერი ავტომატურად იყენებს PHP-ს htmlspecialchars ფუნქციას, XSS შეტევებისაგან თავის დასაცავად. ყველა HTML სიმბოლოს ჩანაცვლება ხდება შესაბამისი ნიშნულებით და HTML კოდი გარდაიქმნება სტრიქონად.

თუ წარმოდგენის ფაილში ამდაგვარ ჩანაწერს შევიტანთ :

{!! $script !!} ვნახავთ, რომ Javascript-ის alert ფუნქცია მართლაც იმუშავებს.
{!! !!} ჩანაწერის გამოყენებისას უნდა ვიყოთ უკიდურესად ფრთხილად, განსაკუთრებით იმ შემთხვევაში თუ მომხმარებლის მიერ შეყვანილი ინფორმაცია გამოგვაქვს ამ ხერხით.

დირექტივები

პირობითი ოპერატორები

if ოპერატორთან მუშაობა ხდება @if, @elseif, @else და @endif დირექტივების მეშვეობით :
@if (count($records) === 1)
    ერთი ჩანაწერი
@elseif (count($records) > 1)
    რამდენიმე ჩანაწერი
@else
    არცერთი ჩანაწერი
@endif
            
მეტი კომფორტულობისათვის არსებობს @unless, @isset და @empty დირექტივებიც :
@unless (Auth::check())
    თქვენ არ ხართ სისტემაში შესული
@endunless
            
@isset($records)
    // $records განსაზღვრულია და არ არს null...
@endisset
            
@empty($records)
    // $records ცარიელია
@endempty
            

აუტენტიფიკაციის დირექტივები

@auth და @guest დირექტივების მეშვეობით უმარტივესად ხდება იმის დადგენა აუტენტიფიცირებულია მომხმარებელი თუ არა :
@auth
    // აუტენტიფიცირებულია
@endauth

@guest
    // არააუტენტიფიცირებულია
@endguest
            

switch ინსტრუქცია

switch ინსტრუქციებთან მუშაობა ხდება @switch, @case, @break, @default და @endswitch დირექტივების მეშვეობით :
@switch($i)
    @case(1)
        First case...
        @break

    @case(2)
        Second case...
        @break

    @default
        Default case...
@endswitch
            

ციკლები

@for ($i = 0; $i < 10; $i++)
    მიმდინარე მნიშვნელობა არის {{ $i }}
@endfor

@foreach ($users as $user)
    <p>მომხმარებლის ID : {{ $user->id }}</p>
@endforeach

@forelse ($users as $user)
    <li>{{ $user->name }}</li>
@empty
    <p>მომხმარებლები ვერ მოიძებნა</p>
@endforelse

@while (true)
    <p>ჩაციკლვა :))</p>
@endwhile
            
ციკლებთან მუშაობისას შეიძლება დაგვჭირდეს კონკრეტული იტერაციების გამოტოვება. ასეთ შემთხვევაში დაგვეხმარება @continue and @break დირექტივები :
@foreach ($users as $user)
    @if ($user->type == 1)
        @continue
    @endif

    <li>{{ $user->name }}</li>

    @if ($user->number == 5)
        @break
    @endif
@endforeach
            
იგივეს გაკეთება შესაძლებელია ასეც :
@foreach ($users as $user)
    @continue($user->type == 1)

    <li>{{ $user->name }}</li>

    @break($user->number == 5)
@endforeach
            

ციკლის ცვლადი $loop

ციკლებთან მუშაობისას საშუალება გვაქვს მივწვდეთ $loop ცვლადს, რომელიც გვიმარტივებს ამ პროცესს.
@foreach ($users as $user)
    @if ($loop->first)
        პირველი იტერაცია
    @endif

    @if ($loop->last)
        ბოლო იტერაცია
    @endif

    <p>მომხმარებლის ID : {{ $user->id }}</p>
@endforeach
            
თუ ვიმყოფებით ჩადგმულ ციკლში, $loop ცვლადის parent თვისების მეშვეობით შეგვიძვლია მივწვდეთ მშობელ ციკლს :
@foreach ($users as $user)
    @foreach ($user->posts as $post)
        @if ($loop->parent->first)
            მშობელი ციკლის პირველი იტერაცია
        @endif
    @endforeach
@endforeach
            
$loop ცვლადის თვისებები :
თვიდება აღწერა
$loop->index მიმდინარე იტერაციის ინდექსი (იწყება 0-დან).
$loop->iteration მიმდინარე იტერაცია (იწყება 1-დან)
$loop->remaining დარჩენილი იტერაციების რაოდენობა
$loop->count ელემენტების რაოდენობა მასივის გავლისას ციკლში
$loop->first ვიყოფებით თუ არა ციკლის პირველ იტერაციაზე
$loop->last ვიყოფებით თუ არა ციკლის ბოლო იტერაციაზე
$loop->even არის თუ არა ლუწი მიმდინარე იტერაცია
$loop->odd არის თუ არა კენტი მიმდინარე იტერაცია
$loop->parent მშობელ ციკლთან წვდომა ჩადგმული ციკლიდან

კომენტარები

შაბლონიზატორი ბლეიდი კომენტარების გაკეთების საშუალებასაც გვაძლევს, თუმცა HTML კომენტარებისაგან განსხვავებით ბლეიდის კომენტარები არ შედის გენერირებულ HTML კოდში: {{-- ეს კომენტარი არ შევა დაგენერირებულ HTML-ში --}}

წარმოდგენის ფაილის ჩასმა წარმოდგენის ფაილში

შაბლონიზატორის @include დირექტივის მეშვეობით საშუალება გვაქვს წარმოდგენის ფაილში ჩავსვათ სხვა წარმოდგენის ფაილები. მშობელ ფაილზე მიმაგრებული ნებისმიერი ცვლადი ხელმისაწვდომია შვილობილ ფაილშიც :
<div>
    @include('shared.errors')

    <form>
        
    </form>
</div>
            
გარდა იმისა, რომ მშობელ ფაილზე მიმაგრებული ინფორმაცია, მემკვიდრეობით ავტომატურად გადაეცემა შვილობილ ფაილსაც, შეგვიძლია დამატებითი ინფორმაციაც მივამაგროთ ამ უკანასკნელს : @include('view.name', ['status' => 'complete']) როდესაც @include დირექტივის მეშვეობით ფაილის გამოძახებას ვაკეთებთ, Laravel-დააბრუნებს შეცდომას თუ მითითებული ფაილი ვერ მოიძებნება. ამის თავიდან ასაცილებლად შეგვიძლია გამოვიყენოთ @includeIf დირექტივა : @includeIf('view.name', ['status' => 'complete']) თუ გვსურს წარმოდგენის ფაილი გამოვიძახოთ იმისდამიხედვით თუ რა მნიშვბნელობა აქვს მინიჭებული კონკრეტულ ლოგიკურ ოპერატორს. მაშინ უნდა გამოვიყენოთ @includeWhen and @includeUnless დირექტივები :
@includeWhen($boolean, 'view.name', ['status' => 'complete'])

@includeUnless($boolean, 'view.name', ['status' => 'complete'])
            

სტანდარტული PHP ბლეიდში

ზოგჯერ საჭიროა, რომ წარმოდგენის ფაილში სტანდატული PHP კოდი შევიტანოთ, ამისათვის გამოიყენება @php დირექტივა :
@php
    $counter = 1;
@endphp
            

მშობელი შაბლონები, წარმოდგენის ფაილების სტუქტურის გამართვა

ხშირად ხდება ისე, რომ საიტის სხვადასხვა გვერდებზე გვხვდება ერთი და იგივე ფრაგმენტები, მაგალითად საიტის ქუდი (header), საიტის ძირი (footer), ნავიგაციური მენიუ და ა.შ. ბუნებრიბვია გაუმართლებელია ამ ფრაგმენტების ყველა გვერდისათვის სათითაოდ გაკეთება და ჯობია თუ მათ ცალკე ფაილებში გავიტანთ, შემდეგ კი სხვადასხვა ადგილებში გამოვიყენებთ საჭიროებისამებრ.

განვიხილოთ მშობელი შაბლონის მარტივი მაგალითი :

<!-- resources/views/layouts/app.blade.php -->

<html>
    <head>
        <title>App Name - @yield('title')</title>
    </head>
    <body>
        @section('sidebar')
            მშობელი ბლეიდის გვერდითი არე
        @show

        <div class="container">
            @yield('content')
        </div>
    </body>
</html>
            
მივაქციოთ ყურადღება @section და @yield დირექტივებს, პირველი მათგანის მეშვეობით ხდება შიგთავსისის კონკრეტული ფრაგმენტის ანუ სექციების შექმნა, მეორე მათგანი კი უზრუნველჰყოფს ამ სექციების საჭირო ადგილებში გამოტანას.

ახლა შევქმნათ ამ მშობელი შაბლონის მემკვიდრე შაბლონი. ამისათვის გამოიყენება @extends დირექტივა:

<!-- resources/views/child.blade.php -->

@extends('layouts.app')

@section('title', 'გვერდის სათაური')

@section('sidebar')
    @parent

    <p>ეს არე დაემატება მშობელი შაბლონის გვერდით არეს</p>
@endsection

@section('content')
    <p>შვილობილი შაბლონის შიგთავსი</p>
@endsection
            

ფორმები

CSRF

CSRF იშიფრება, როგორც Cross-site request forgeries - საიტთა შორის ყალბი მოთხოვნების გაცვლა-გამოცვლის პროცესი, რომლის დროსაც ხდება არაავტორიზირებული მოთხოვნების შესრულება აუტენტიფიცირებული მომხმარებლის სახელით.

განვიხილოთ მოქმედებათა ასეთი ჯაჭვი:

  • წარმოვიდგინოთ, რომ რომელიმე ონლაინ-ბანკში (პირობითად www.mybank.com) შესულები ვართ პირად კაბინეტში.
  • ასევე დავუშვათ, რომ თანხის ტრანსფერის განხორციელება შესაძლებელია http://www.mybank.com/transfer?to=<SomeAccountnumber>;amount=<SomeAmount> ბმულზე მიკითხვით (ჩვენი ანგარიშის ნომერი ან რაიმე სხვა იდენტიფიკატორი აღარაა საჭირო რადგან, აუტენტიფიკაცია გავლილი გვაქვს და სისტემა უკვე ისედაც 'გვცნობს').
  • დავუშვათ ახალ ფანჯარაში გავხსენით www.cute-cat-pictures.org ჰაკერული საიტი, მაგრამ არ ვიცით რომ აქ შესვლა სახიფათოა :))
  • თუ ამ საიტის მფლობელმა იცის რომელ ბმულს უნდა მიაკითხოს ტრანზაქციის განსახორციელებლად (ამის გაგება საკმაოდ მარტივია, ბოლოს და ბოლოს თვითონაც იქნება დარეგისტრირებული www.mybank.com საიტზე :))) და ასევე იცის, რომ დროის კონკრეტულ მომენტში თქვენ სისტემაში ხართ შესული, მას შეუძლია თავის საიტზე განათავსოს ასეთი ბმული : http://www.mybank.com/transfer?to=123456;amount=10000 (სადაც 123456 არის მისი ანგარიშის ნომერი, 10000 კი არის თანხა, რომლის გადარიცხვასაც ცდილობს თქვენი ანგარიშიდან.
  • www.cute-cat-pictures.org შესვლისას ჩვენი ბრაუზერი ავტომატურად გააკეთებს ამ მოთხოვნას.
  • საბანკო სისტემა ვერ დაადგენს თუ საიდან წამოვიდა მოთხოვნა, რადგან როგორც ზემოთ ვთქვით სისტემაში შესულები ვართ ანუ ბრაუზერში შენახულია საჭირო Cookie-ბი, სისტემა ჩათვლის, რომ მოთხოვნა ლეგალურია და ჩამოგვეჭრება 10000 ლარი ))

ახლა განვიხილოთ ასეთი შემთხვევა:

  • ტრანსფერის მოთხოვნას დავამატოთ კიდევ ერთი პარამეტრი : http://www.mybank.com/transfer?to=123456;amount=10000;token=31415926535897932384626433832795028841971.
  • მესამე პარამეტი token არის რთულად გამოსაცნობი შემთხვევით სტრიქონი, რომლის გენერირებასაც mybank.com საიტი მოახდენს მისი გვერდების თითოეული ჩატვირთვისას. ეს სტრიქონი განსხვავებული იქნება ნებისმიერი გვერდის ყოველ ახალ ჩატვირთვაზე.
  • თავდამსხმელს არ მიუწვდება ხელი ამ თოქენთან და შესაბამისად არც ის შეუძლია რომ იგი მოთხოვნას გამოაყოლოს, არასწორი თოქენის შემცველი ან საერთოდდ უთოქენოდ გამოგზავნილი მოთხოვნები კი უარყოფილი იქნება www.mybank.com-ის მიერ.

CSRF ველი

ყოველთვის როცა ჩვენს ნებისმიერ აპლიკაციაში აღვწერთ HTML ფორმას, აუცილებლად უნდა განვსაზღვროთ ერთი დამალული ველი (type="hidden") CSRF თოქენისათვის, ფორმით გაგზავნილი მოთხოვნა კი უნდა დაამუშავოს CSRF თავდასხმისაგან დამცავმა შესაბამისმა შუამავალმა შუამავალმა. ამ ველის გენერირება შესაძლებელია @csrf დირექტივის მეშვეობით :
<form method="POST" action="/profile">
    @csrf

    ...
</form>
            

შიგთავსის სახელდებული ფრაგმენტები, დასტები

შაბლონიზატორი ბლეიდი საშუალებას გვაძლევს წარმოდგენის ფაილში განვათავსოთ, სადღაც სხვა წარმოდგენის ფაილში აღწერილი შიგთავსის (მარქაფის) სახელდებული ფრაგმენტები. მაგალითად თუ გვაქვს რამდენიმე შვილობილი შაბლონი, რომლებსაც თავიანთი კონკრეტული Javascript ფაილები ესაჭიროებათ, შეგვიძლია მოვიქცეთ ასე, მშობელი შაბლონი :
<!-- resources/views/layouts/app.blade.php -->

<html>
    <head>
        <title>App Name - @yield('title')</title>
    </head>
    <body>
        @section('sidebar')
            მშობელი ბლეიდის გვერდითი არე
        @show

        <div class="container">
            @yield('content')
        </div>

        @stack('scripts')

    </body>
</html>
            
შვილობილი შაბლონი :
<!-- resources/views/child.blade.php -->

@extends('layouts.app')

@section('title', 'გვერდის სათაური')

@section('sidebar')
    @parent

    <p>ეს არე დაემატება მშობელი შაბლონის გვერდით არეს</p>
@endsection

@section('content')
    <p>შვილობილი შაბლონის შიგთავსი</p>
@endsection


@push('scripts')
    <script src="/example.js"></script>
@endpush

            
ასევე შესაძლებელია დასტების თანმიმდევრობის განსაზღვრა :
@push('scripts')
    ეს იქნება მეორე დასტა...
@endpush

// Later...

@prepend('scripts')
    ეს იქნება პირველი დასტა...
@endprepend
            
14. მუშაობა URL-ებთან
Laravel-ში შექმნილია რამდენიმე დამხმარე ფუნქცია, რომლებიც გვიმარტივებენ URL-ებთან მუშაობას. ამ ფუნქციებთან მუშაობა განსაკუთრებით კომფორტულია, როდესაც გვჭირდება სხვადასხვა ბმულების გენერირება ჩვენს აპლიკაციაში ან კონკრეტული მოთხოვნის ისეთი პასუხს ვაგენერირებთ, რომლის მიხედვითაც აპლიკაციის ერთი ნაწილიდან მეორეში გვიწევს გადამისამართება.

ბმულების გენერირება

ბმულების გენერირებისათვის გამოიყენება url დამხმარე :
$post = App\Models\Post::find(1);

echo url("/posts/{$post->id}");

// http://127.0.0.1:8000/posts/1
            

წვდომა მიმდინარე ბმულთან

// მიმდინარე URL GET პარამეტრების (query string) გარეშე 
echo url()->current();

// მიმდინარე URL GET პარამეტრებთან (query string) ერთად 
echo url()->full();

// წინა მოთხოვნის სრული URL (GET პარამეტრებთან (query string) ერთად )
echo url()->previous();
            
ნებისმიერ ამ მეთოდთან წვდომა შესაძლებელია URL ფასადის მეშვეობითაც :
use Illuminate\Support\Facades\URL;

echo URL::current();               
            

URL-ები სახელდებული მარშრუტებისათვის

სახელდებული მარშრუტებისათვის ბმულების გენერირებაში დაგვეხმარება route ფუნქცია. ასეთი ბმულების შექმნისას, თუ უშუალოდ მარშრუტში აღწერილი ბმული შეიცვლება ჩვენ არ მოგვიწევს არანაირი ცვლილება route ფუნქციის გამოძახებისას, სისტემა ავტომატურად დააგენერირებს მარშრუტის ახალი ინსტრუქციის შესაბამის ბმულს. მაგალითად, დავუშვათ გვაქვს ასეთი მარშრუტი :
Route::get('/post/{post}', function () {
    //
})->name('post.show');               
            
route ფუნქციით ამ მარშრუტის შესატყვისი ბმული დაგენერირდება ასე :
echo route('post.show', ['post' => 1]);

// http://127.0.0.1:8000/post/1               
            
რა თქმა უნდა შესაძლებელია, რომ route ფუნქციას გადავცეთ რამდენიმე პარამეტრი ერთდროულადაც :
Route::get('/post/{post}/comment/{comment}', function () {
    //
})->name('comment.show');

echo route('comment.show', ['post' => 1, 'comment' => 3]);

// http://127.0.0.1:8000/post/1/comment/3               
            
ნებისმიერი დამატებითი პარამეტრი, რომელიც აღწერილი არ იქნება მარშრუტის განსაზღვრისას, ბმულს დაემატება GET პარამეტრის სახით :
echo route('post.show', ['post' => 1, 'search' => 'rocket']);

// http://127.0.0.1:8000/post/1?search=rocket           
            

URL-ები კონტროლერების მეთოდებისათვის

action მეთოდის მეშვეობით შეგსაძლებელია, რომ დავაგენერიროთ ბმული კონკრეტული მარშრუტის კონკრეტული მეთოდისათვის :
use App\Http\Controllers\HomeController;

$url = action([HomeController::class, 'index']);  
            
თუ კონტროლერის მეთოდს გადაეცემა მარშრუტის პარამეტრები, შეგვიძლია ისინი აღვწეროთ ასოციაციურ მასივში და ეს მასივი action ფუნქციას გადავცეთ მეორე პარამეტრად : $url = action([UserController::class, 'profile'], ['id' => 1]);
15. სესიები
სესიათა მექანიზმის პარამეტრები აღწრილია config/session.php ფაილში სადაც ბრუნდება მასივი. განვიხილოთ ძირითადი პარამეტრები : 'driver' => env('SESSION_DRIVER', 'file'), ეს არის სესიათა დამუშავების მექანიზმი ნაგულისხმეობის პრინციპით. როგორც ვხედავთ ამ მექანიზმის მნიშვნელობად მითითებულია file, ეს ნიშნავს, რომ სესიები ინახება კონკრეტულ ფაილებში, კომენტარებში აღწერილია სხვა შესაძლო მნიშვნელობებიც ("cookie", "database", "apc", "memcached", "redis", "array", memcached არის ერთგვარი პროგრამული უზრუნველყოფა, რომლის მეშვეობითაც ხდება ინფორმაციის ჰეშირებული სახით შენახვა ოპერატიულ მეხსიერებაში). 'lifetime' => env('SESSION_LIFETIME', 120), ეს არის წუთების რაოდენობა, რომლის ამოწურვის შემდეგაც სესიები გაუქმდდება თუ მომხმარებელი უმოქმედოდ იქნება აპლიკაციაში მთელი ამ ხნის განმავლობაში. 'expire_on_close' => false, გაუქმდეს თუ არა სესიები ბრაუზერის დახურვისას. 'encrypt' => false, დაიშიფროს თუ არა სესიაში შენახული ინფორმაცია. 'files' => storage_path('framework/sessions'), სესიის ინფორმაციები ინახება ამ მისამართზე განთავსებულ ფაილებში. 'table' => 'sessions', აქ უნდა განისაზღვროს მონაცემთა ბაზის ცხრილის დასახელება იმ შემთხვევაში, თუ driver პარამეტრის მნიშვნელობად ავირჩევთ database-ს. ანუ სესიის ინფორმაციები შეინახება მბ-ში და კერძოდ აქ მითითებულ ცხრილში.

დრაივერი database

როგორც აღვნიშნეთ, driver პარამეტრი განსაზღვრავს, თუ რა სახით იქნეს შენახული სესიის ინფორმაციები. თუ ამ პარამეტრის მნიშვნელობა იქნება database, მაშინ ეს ინფორმაცია შეინახება მბ-ში. კონსოლის დახმარებით შევქმნათ შესაბამისი ცხრილი, ამისათვის უნდა გავუშვათ შემდეგი ბრძანება : php artisan session:table ეს ბრძანება შექმნის მიგრაციას ახალ ფაილს : database/migrations/2021_05_28_100647_create_sessions_table ცხრილის სტრუქტურა იქნება ამდაგვარი :
Schema::create('sessions', function (Blueprint $table) {
    $table->string('id')->primary();
    $table->foreignId('user_id')->nullable()->index();
    $table->string('ip_address', 45)->nullable();
    $table->text('user_agent')->nullable();
    $table->text('payload');
    $table->integer('last_activity')->index();
});       
            
გავუშვათ მიგრაციის შესრულკების ბრძანება : php artisan migrate ახლა გადავაკეთოთ driver პარამეტრის აღწერაც : 'driver' => env('SESSION_DRIVER', 'database'), ეს ყველაფერი კიდევ არ ნიშნავს, რომ სესიები მბ-ში შეინახება, დავაკვირდეთ ჩანაწერს: როგორც ვხედავთ env ფუნქციას გადაცემული აქვს ორი პარამეტრი. SESSION_DRIVER პარამეტრი აღნიშნავს, რომ სესიები უნდა შეინახოს .env ფაილში SESSION_DRIVER პარამეტრის მნიშვნელობად მითითებული მექანიზმის მიხედვით, ამ ფაილში ამ მომენტისათვის კი სავარაუდოდ ეს მდგომარეობაა :
...
SESSION_DRIVER=file
...
            
ეს იმას ნიშნავს, რომ სესიები ფაილებში ინახება, მიუხედავად იმისა, რომ driver პარამეტრს მეორე არგუმენტად გადაცემული აქვს database, ამიტომ ჩავასწოროთ .env ფაილიც :
...
SESSION_DRIVER=database
...
             

მუშაობა სესიებთან

სესიებთან მუშაობა $request ობიექტით

get()

მოთხოვნის ობიექტს - $request-ს აქვს დამხმარე მეთოდი session, რომელიც გვაძლევს სესიებთან წვდომის საშუალებას. კონკრეტული სესიის მნიშვნელობის მისაღებად session დამხმარე უნდა გამოვიყენოთ get მეთოდთან ერთად, სესიებში ინფორმაციები ინახება წყვილების სახით "გასაღები:მნიშვნელობა", get მეთოდს პირველ პარამეტრად უნდა გადავცეთ სესიის სასურველი გასაღების დასახელება, მეორე პარამეტრად კი შეგვიძლია გადავცეთ ნაგულსხმები მნიშვნელობა იმ შემთხვევისათვის თუ სესიაში ეს გასაღები ვერ მოიძებნება :
public function show(Request $request)
{
    $result = $request->session()->get('key','არ არსებობს');
    dump($result);
}
          
სესიაში უჯრა სახელად key არ არსებობს, ამიტომ ბრაუზერში დაგვიბრუნდება "არ არსებობს".

all()

თუ გვინდა, რომ დავაბრუნოთ სესიაში შენახული ყველა ინფორმაცია უნდა გამოვიყენოთ session დამხმარეს all მეთოდი, რომელიც სესიას აბრუნებს მასივის სახით :
public function show(Request $request)
{
    $result = $request->session()->all();
    dump($result);
}
            

put()

სესიაში ინფორმაციის შეტანა ხდება put მეთოდის მეშვეობით, მას პარამეტრებად უნდა გადაეცეს სესიის უჯრის დასახელება და შესაბამისი მნიშვნელობა :
public function show(Request $request)
{
    $request->session()->put('key','value');
    $result = $request->session()->all();
    dump($result);
}
             
ამ კოდის შედეგი იქნება დაახლოებით ამდაგვარი რამ :

has()

იმის გასაგებად არსებობს თუ არა კონკრეტული დასახელების სესია, გამოიყენება has მეთოდი, რომელსაც პარამეტრად უნდა გადაეცეს საძიებელი სესიის დასახელება :
public function show(Request $request)
{
    if ($request->session()->has('key'))
    {
        dump("1");
    }
    else
    {
        dump("0");
    }
}
            

flash()

ხანდახან საჭოროა, რომ სესიაში ინფორმაცია შევინახოთ მხოლოდ შემდეგი მოთხოვნის დამუშავებამდე, შემდეგ კი წავშალოთ ეს ინფორმაცია სესიიდან. ამისათვის უნდა გამოვიყენოთ flash მეთოდი, რომლის გამოყენებაც საკმაოდ ეფექტურ შედეგს იძლევა დროებითი თვალსაჩინოებისათვის გამოყენებული შეტყობინებების გამოტანისას : $request->session()->flash('status', 'შეტყობინება წარმატებით გაიგზავნა !'); ამ ინფორმაციის ნახვა კი ასე შეგვიძლია წარმოდგენის ფაილში :
@if(Session::has('status'))
    <p>{{ Session::get('status') }}<p>
@endif
            

სესიის მნიშვნელობის გაზრდა და შემცირება

თუ სესიაში შენახული გვაქვს მთელი ტიპის მნიშვნელობა და გვსურს მისი გაზრდა ან შემცირება, უნდა გამოვიყენიოთ increment და decrement მეთოდები :
$request->session()->increment('count');

$request->session()->increment('count', $incrementBy = 2);

$request->session()->decrement('count');

$request->session()->decrement('count', $decrementBy = 2);              
            

Session ფასადი

ზემოთ აღწერილი მეთოდები შეგვიძლია გამოვიყენოთ Session ფასადთანაც. მაგალითად დავბეჭდოთ სესია წარმოდგენის ფაილში : {{ dump(Session::all()) }} ამ ფასადის გამოყენება, რა თქმა უნდა შესაძლებელია კონტროლერშიც.

სესიის კონკრეტული უჯრის წასაშლელად გამოიყენება forget მეთოდი, რომელსაც პარამეტრად უნდა გადავცეთ შესაბამისისი უჯრის დასახელება :

Session::forget('key2'); სესიის მთლიანად წასაშლელად გამოიყენება flush მეთოდი, რომელსაც პარამეტრის გადაცემა არ სჭირდება. Session::flush();

session დამხმარე

სესიებთან წვდომა შესაძლებელია session დამხმარე ფუნქციითაც. მაგალითად დავაბრუნოთ სესიაში შენახული key გასაღების მნიშვნელობა : dump(session('key')); თუ გვსურს, რომ session ფუნქციის მეშვეობით სესიაში შევიტანოთ ახალი მნიშვნელობები : session(['key' => 'value']);
16. მონაცემთა ვალიდაცია
მომხმარებლის მიერ სერვერზე გაგზავნილ ინფორმაციას აუცილებლად სჭირდება გადამოწმება ანუ ვალიდაცია. ამ თავში ვისაუბრებთ სწორედ ამ თემაზე.

პირველ რიგში routes/web.php ფაილში შევქმნათ მარშრუტები :

use App\Http\Controllers\PostController;

Route::get('/post/create', [PostController::class, 'create']);
Route::post('/post', [PostController::class, 'store']);
            
GET მარშრუტი გამოიტანს სიახლის დასამატებელ ფორმას, POST მარშრუტი კი ამ ფორმაში აკრეფილ ინფორმაციას შეინახავს მონაცემთა ბაზაში.

ახლა შევქმნათ კონტროლერი, ამ ეტაპზე მისი store მეთოდი დავტოვოთ ცარიელი:

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class PostController extends Controller
{
    /**
     * სიახლის დასამატებელი ფორმის გამოტანა
     *
     * @return \Illuminate\View\View
     */
    public function create()
    {
        return view('post.create');
    }

    /**
     * სიახლის შენახვა მბ-ში
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        // ინფორმაციის ვალიდაცია და შენახვა
    }
}
            
ეს კონტროლერი, ისევე როგორც, ყველა სხვა კონტროლერი, არის Controller კლასის მემკვიდრე. თუ გავხსნით Controller კლასს, ვნახავთ, რომ მასში აღწერილია შემდეგი კოდი :
namespace App\Http\Controllers;

use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;

class Controller extends BaseController
{
    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}
            
ეს კონტროლერი კი, თავის მხრივ, არის BaseController მშობელი კლასის მემკვიდრე და იყენებს სამი ტრეიტის, ანუ დამატებითი კლასის ფუნქციონალს. ჩვენ გვაინტერესებს ტრეიტი ValidatesRequests, სწორედ ამ კლასის დახმარებითაა შესაძლებელი, ამა თუ იმ კონტროლერში ინფორმაციის ვალიდაცია, ტრეიტი აღწერილია შემდეგ ფაილში vendor/laravel/framework/src/Illuminate/Foundation/Validation/ValidatesRequests.php.

ინფორმაციის ვალიდაციისათვის უნდა მივმართოთ Illuminate\Http\Request კლასის ობიექტის validate მეთოდს :

public function store(Request $request)
{
    $validated = $request->validate([
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ]);

    // ინფორმაცია ვალიდურია...
} 
            
როგორც ვხედავთ ვალიდაციის წესები პარამეტრად გადავეცით validate მეთოდს (ვალიდაციის წესების სრული სია შეგიძლიათ იხილოთ აქ). თუ ყველა წესი შესრულდება, კონტროლერი ჩვეულებრივად გააგრძელებს მუშაობას, წინააღმდეგ შემთხვევაში კი შესაბამისი პასუხი დაუყოვნებლივ დაუბრუნდება მომხმარებელს და ვალიდაციის შემდეგ აღწერილი ინსტრუქციები აღარ შესრულდება.

არსებობს ვალიდაციის წესების გადაცემის სხვაგვარი სინტაქსიც :

$validatedData = $request->validate([
    'title' => ['required', 'unique:posts', 'max:255'],
    'body' => ['required'],
]);
            

ვალიდაციის შეწყვეტა პირველივე დარღვევისას

დავუშვათ ვალიდაციაში აღწერილი გვაქვს რამდენიმე წესი, მაგრამ გვინდა, რომ ვალიდაცია შეწყდეს წესების პირველივე დარღვევისას, ამისათვის წესების აღწერაში უნდა ჩავსვათ bail წესი :
$request->validate([
    'title' => 'bail|required|unique:posts|max:255',
    'body' => 'required',
]);
            
ამ შემთხვევაში თუ title ატრიბუტის unique წესი დაირღვევა, მაშინ max წესის გადამოწმება აღარ მოხდება.

ვალიდაციის შეცდომების გამოტანა

როდესაც ვალიდაციის წესები დაირღვევა, Laravel-ი მომხმარებელს ავტომატურად გადაამისამართებს წინა გვერდზე, დარღვევების შესახებ ინფორმაცია კი, ასევე ავტომატურად შეინახება სესიაში.

Illuminate\View\Middleware\ShareErrorsFromSession შუამავლის დამსახურებით, $errors ცვლადი ხელმისაწვდომია აპლიკაციის ნებისმიერ წარმოდგენის ფაილში და სწორედ მასში ინახება შეტყობინებები დარღვევების შესახებ ($errors ცვლადი არის Illuminate\Support\MessageBag ფაილში აღწერილი კლასის ობიექტი).

ვალიდაცია აღწერილი გვაქვს store მეთოდში და თუ ვამბობთ, რომ წესების დარღვევისას სისტემა უკან ამისამართებს მომხმარებელს, შესაბამისად გადავალთ create მეთოდში, რომელშიც სიახლის დასამატებელი ფორმის წარმოდგენის ფაილს ვაგენერირებთ, ან ფაილში შეცდომების ნახვა შემდეგნაირად შეგვიძლია :
<!-- /resources/views/post/create.blade.php -->

<h1>სიახლის დამატებაt</h1>

@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

<!-- სიახლის დასამატებელი ფორმა -->
            

ვალიდაციის შეტყობინებების განსაზღვრა

სისტემაში არსებულ, ვალიდაციის ნებისმიერ წესს, შეესაბამება კონკრეტული შეტყობინება, ეს შეტყობინებები აღწერილია lang/en/validation.php ფაილში და შესაძლებლობა გვაქვს, ნებისმიერი მათგანი გადავაკეთოთ ჩვენი საჭიროებისამებრ.

@error დირექტივა

იმის დასადგენად ფიქსირდება თუ არა შეცდომა კონკრეტული ატრიბუტისათვის (მაგალითად სიახლის სათაურისათვის - title), შეგვიძლია გამოვიყენოთ @error დირექტივა :
<!-- /resources/views/post/create.blade.php -->

<label for="title">სიახლის სათაური</label>

<input id="title" type="text" name="title" class="@error('title') is-invalid @enderror">

@error('title')
    <div class="alert alert-danger">{{ $message }}</div>
@enderror
            

ფორმის ხელახალი შევსება

როდესაც მომხმარებელი ვალიდაციის წესების დარღვევით შეავსებს ფორმას და გაგზავნის მას, თუ ფორმა მარტივია და შედგება რამდენიმე ველისაგან, მომხმარებელს უბრალოდ გადავამისამართებთ ისევ ფორმის გვერდზე, მაგრამ თუ ფორმა რთულია და შეიცავს ძალიან ბევრ ველებს, მაშინ მომხმარებელს ამ ველების თავიდან შევსება მოუწევს, რაც არც თუ ისე მოსახერხებელია. ამ პრობლემის გადასაწყვეტად გამოიყენება request ობიექტის flash მეთოდი, რომელიც მოთხოვნის ტანში ჩადებულ ინფორმაციას ინახავს სესიაში : $title = $request->old('title'); ასევე შეგვიძლია გამოვიყენოთ გლობალური დამხმარე old : <input type="text" name="title" value="{{ old('title') }}">

სამომხმარებლო ვალიდატორი

იმისათვის რათა შევქმნათ საკუთარი ვალიდატორი, უნდა მივმართოთ Validator ფასადს და გამოვიყენოთ მისი მეთოდი - make, რომელიც ქმნის ვალიდატორის ობიექტს, ამ მეთოდს პარამეტრებად უნდა გადავცეთ შესამოწმებელი ინფორმაციის შემცველი მასივი და ვალიდაციის წესების შემცველი მასივი. პირველ პარამეტრს ანუ შესამოწმებელ ინფორმაციას, მოგვცემს მოთხოვნის ობიექტის - request-ის all() მეთოდი.
namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class PostController extends Controller
{
    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'title' => 'required|unique:posts|max:255',
            'body' => 'required',
        ]);

        if ($validator->fails()) 
        {
            return redirect('post/create')->withErrors($validator)->withInput();
        }

        // სიახლის შენახვა...
    }
}
            
withErrors მეთოდი სესიაში შეინახავს შეტყობინებს შეცდომების შესახებ და ასევე, საშუალებას მოგვცემს წარმოდგენის ფაილში გამოვიყენოთ $errors ცვლადი.

make მეთოდში შესაძლებელია ვალიდაციის შეცდომის შეტყობინებების განსაზღვრაც :

$validator = Validator::make($input, $rules, $messages = [
    'required' => ':attribute არის აუცილებელი ველი',
]);
            
შეტყობინებაში :attribute ჩანაწერი ავტომატურად ჩანაცლდება ველის დასახელებით.

***

გავაერთიანოთ ეს ყველაფერი. მაშ ასე, მარშრუტები უკვე გვაქვს :
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;

Route::get('/post/create', [PostController::class, 'create']);
Route::post('/post', [PostController::class, 'store']);
            
            
შევქმნათ წარმოდგენის ფაილი resources/views/post/create.blade.php :
@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

<form action="{{ route('store_post') }}" method="post">
    @csrf
    <input type="text" name="title" class="@error('title') is-invalid @enderror" value="{{ old('title') }}">
    <textarea name="body" class="@error('title') is-invalid @enderror">{{ old('body') }}</textarea>
    <input type="submit" value="გაგზავნა">
</form>
            
PostController :
namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class PostController extends Controller
{
    public function create()
    {
        return view('post.create');
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'title' => 'required|alpha|min:5',
            'body' => 'required',
        ]);
    }
}
            
ფორმის სანახავად შევიდეთ მისამართზე http://127.0.0.1:8000/post/create. ფორმა გავაგზავოთ შემდეგი ვარიანტებით :
  • ორივე ველი დავტოვოთ ცარიელი და ისე დავაჭიროთ გაგზავნის ღილაკს
  • სათაურის ველში შევიყვანოთ მნიშვნელობა - '45', ტექსტი დავტოვოთ ცარიელი და ისე დავაჭიროთ გაგზავნის ღილაკს
ამ უკანასკნელ შემთხვევაში ვნახავთ, რომ title ველისათვის დაირღვევა ორი წესი : ის უნდა შეიცავდეს მხოლოდ ანბანის ასოებს და შეყვანილი მნიშვნელობის მიმიმალური სიგრძე უნდა იყოს 5.

იმისათვის რათა, კონკრეტული ველის ყველა შეცდომის შეტყობინება გამოვიტანოთ უნდა გამოვიყენოთ $errors ობიექტის get მეთოდი, რომელსაც პარამეტრად უნდა გადავცეთ ველის დასახელება :

...

@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->get('title') as $message)
                <li>{{ $message }}</li>
            @endforeach
        </ul>
    </div>
@endif

...
            
იმის დასაგენად, დაფიქსირდა თუ არა კონკრეტულ ველზე ვალიდაციის შეცდომა, გამოიყენება $errors ობიექტის has მეთოდი, რომელსაც პარამეტრად უნდა გადავცეთ ასევე ველის დასახელება :
@if($errors->has('email')) 
    ...
@endif
            
17. მიგრაციები, მბ ვერსიათა კონტროლი, ცხრილების მოწყობა მბ-ში
ამ თავში განვიხილავთ მონაცემთა ბაზასთან (მბ) სამუშაო ინსტრუმენტებს.

მბ მიგრაცია

მიგრაცია არის ვერსიათა კონტროლის გამარტივებული სახე მონაცემთა ბაზებთან სამუშაოდ, მისი მეშვეობით ფრეიმვორკის კონსოლიდან შესაძლებელია მბს ცხრილების შექმნა, რედაქტირება და ა.შ. მიგრაციების გამოყენებას განსაკუთრებით დიდი მნიშვნელობა აქვს მაშინ, როდესაც ვმუშაობთ სხვა პროგრამისტებთან ერთად, ანუ გუნდური მუშაობისას. უფრო კონკრეტულად : თუ ჩვენ, ჩვენს ლოკალურ სივრცეში შევიტანთ ცვლილებებს მონაცემთა ბაზაში (დავამატებთ ახალ ცხრილს, წავშლით არსებულს, რომელიმე კონკრეტულ ცხრილში ჩავამატებთ ახალ ველს და ა.შ), ბუნებრივია ეს ცვლილებები შეცდომებს გამოიწვევს გლობალურ, ანუ რეალურ გარემოში ჩვენი კოდის ატვირთვისას ან სხვებისათვის გაზიარებისას, რადგანაც ამ გარემოებში არ იქნება ასახული ჩვენს მიერ გაკეთებული ცვლილებები. მიგრაცია კი არის ერთგვარი 'დოკუმენტაცია', რომელშიც აღწერილია ეს ცვლილებები და მისი დახმარებით, გუნდის სხვა წევრებს მარტივად შეუძლიათ თავიანთ გარემოშიც ასახონ თითოეული სიახლე.

მბ კონფიგურაცია

როგორც ვიცით მბს კონფიგურაციული პარამეტრები ინახება config/database.php ფაილში. ეს ფაილი აბრუნებს მასივს რომელშიც აღწერილია სხვადასხვა პარამეტრები. 'default' => env('DB_CONNECTION', 'mysql'), ეს ჩანაწერი განსაზღვრავს თუ მონაცემთა ბაზის მართვის რომელ სისტემასთან ვმუშაობთ. ამავე ფაილში აღწერილია მბ-სთან დასაკავშირებელი პარამეტრები სხვადასხვა სისტემებისათვის. mysql-ისათვის ეს პარამეტრებია :
...

'mysql' => [
    'driver' => 'mysql',
    'url' => env('DATABASE_URL'),
    'host' => env('DB_HOST', '127.0.0.1'),
    'port' => env('DB_PORT', '3306'),
    'database' => env('DB_DATABASE', 'forge'),
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'unix_socket' => env('DB_SOCKET', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'prefix_indexes' => true,
    'strict' => true,
    'engine' => null,
    'options' => extension_loaded('pdo_mysql') ? array_filter([
        PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
    ]) : [],
],

...

            
როგორც ვხედავთ ზოგიერთი პარამეტრის მნიშვნელობა ბრუნდება env ფუნქციით, ეს ფუნქცია კავშირს ამყარებს .env ფაილთან და სწორედ იქიდან მოაქვს ინფორმაცია. მივაქციოთ ყურადღება, რომ env ფუნქციას მეორე არგუმენტებად გადაცემული აქვს მნიშვნელობები, რომლებსაც სისტემა ავტომატურად გამოიყენებს თუ .env ფაილში არ განვსაზღვრავთ შესაბამის პარამეტრებს. შევიტანოთ ცვლილებები .env ფაილში:
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:Y2FMuhHrSmNjAh5NRuHY6NPlVjhl/YDVmHhe115iwXU=
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_URL=http://localhost

DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
            
ახლა შევქმნათ მიგრაცია, ამისათვის, როგორც ვთქვით, დაგვჭირდება ფრეიმვორკის კონსოლი, გავხსნათ ბრძანებათა კონსოლი და გავუშვათ ბრძანება : php artisan make:migration create_articles_table ეს ბრძანება შექმნის მიგრაციის ახალ ფაილს - 2021_06_02_074019_create_articles_table, რომელშიც აღწერილი იქნება შესაბამისი კლასი. ფაილის დასახელებაში გარდა ჩვენს მიერ მითითებული სათაურისა დამატებულია მიმდინარე თარიღი და მიმდინარე დროის ნიშნული. მიგრაციების ფაილების ნახვა შესაძლებელია შემდეგ მისამართზე database/migrations. ახლად შექმნილ ფაილში აღწერილი იქნება შემდეგი კლასი :
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateArticlesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('articles');
    }
}
            
როგორვ ვხედავთ, ეს კლასი არის გლობალური კლასის - Migration-ის მემკვიდრე. აღწერილია ორი მეთოდი up() და down(). პირველ მათგანში მითითებული ინსტრუქციები შესრულდება მაშინ, როდესაც გამოვიძახებთ CreateArticlesTable მიგრაციას, ხოლო მეორე მათგანის ინსტრუქციები შესრულდება მაშინ, როცა შევწყვეტთ კონკრეტული მიგრაციების გამოყენებას (მაგალითად გავაუქმებთ ბოლოს გაშვებულ მიგრაციებს).

'php artisan make:migration create_articles_table' ჩანაწერიდან სისტემამ ავტომატურად დაადგინა, რომ ცხრილის შექმნის მიგრაციას ვქმნით და Schema ფასადსაც შესაბამისი 'create' მეთოდით მიმართა.

up() მეთოდი მიმართავს Schema კლასს, ეს არის ცხრილების სპეციალური კონსტრუქტორი, მისი დახმარებით ხდება მბს ცხრილებთან მუშაობა. ამ კლასის create მეთოდი ქმნის ახალ ცხრილს, მეთოდს პირველ პარამეტრად უნდა გადაეცეს ცხრილის სახელი, მეორე პარამეტრი კი არის ქოლბექ ფუნქცია, რომელიც უნდა შესრულდეს ცხრილის შექმნის შემდეგ. ამ ფუნქციას, თავის მხრივ, მითითებული აქვს არგუმენტი, რომლის მეშვეობითაც შეგვიძლია მივმართოთ უშუალოდ ცხრილის ობიექტს.

დავამატოთ რამდენიმე ველი ცხრილს :
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateArticlesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->id(); // id ველი იქნება : INT, AUTO_INCREMENT, PRIMARY KEY
            $table->string('name', 100); // name ველი იქნება : Varchar 100
            $table->text('text'); // text ველი იქნება : Text
            $table->string('img', 255); // img ველი იქნება : Varchar 255
            $table->timestamps(); // შეიქმნება timestamp ტიპის ორი ველი created_at და updated_at
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('articles');
    }
}
            
ველთა ტიპების სრული სია შეგიძლიათ იხილოთ აქ.

მიგრაციის გაშვება

მიგრაციის შესრულებისათვის უნდა გავუშვათ შემდეგი ბრძანება : php artisan migrate ამ ბრძანების შემდეგ შესრულდება ყველა მიგრაცია, რომელიც database/migrations საქაღალდეშია.

მიგრაციის გაუქმება

იმისათვის რათა გავაუქმოთ ის შედეგები რაც ბოლოს გაშვებულმა მიგრაციამ მოგვცა უნდა გავუშვათ შემდეგი ბრძანება : php artisan migrate:rollback თუ ახლა phpmyadmin-ს შევამოწმებთ იქ დაგვხვდება მხოლოდ ერთი ცხრილი migrations.

ცხრილის რედაქტირება

დავარედაქტიროთ უკვე შექმნილი ცხრილი, მაგალითად დავამატოთ რამდენიმე სვეტი. ამისათვის უნდა შევქმნათ ახალი მიგრაცია : php artisan make:migration change_articles_table --table=articles შეიქმნება ახალი მიგრაცია :
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class ChangeArticlesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('articles', function (Blueprint $table) {
            //
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('articles', function (Blueprint $table) {
            //
        });
    }
}            
            
დავამატოთ ველი :
public function up()
{
    Schema::table('articles', function (Blueprint $table) {
        $table->string('alias', 100); // Varchar 100
    });
}
            
ამასთანავე არ უნდა დაგვავიწყდეს, რომ down() მეთოდში მისათითებელია ინსტრუქცია, რომელიც წაშლის ამ ველს მიმდინარე მიგრაციის გაუქმების შემთხვევაში. ველების წასაშლელად გამოიყენება $table ობიექტის dropColumn() მეთოდი, რომელსაც პარამეტრად უნდა გადაეცეს შესაბამისი ველის დსასახელება :
public function down()
{
    Schema::table('articles', function (Blueprint $table) {
        $table->dropColumn('alias');
    });
}
            

'php artisan make:migration change_articles_table' ჩანაწერიდან სისტემამ ავტომატურად დაადგინა, რომ ცხრილის რედაქტირების მიგრაციას ვქმნით და Schema ფასადსაც შესაბამისი 'table' მეთოდით მიმართა.

ისღა დაგვრჩენია გავუშვათ მიგრაცია შესრულებაზე : php artisan migrate

ცხრილის წაშლა და სახელის შეცვლა

ცხრილის სახელის შესაცვლელად გამოიყენება Schema ფასადის rename მეთოდი :
use Illuminate\Support\Facades\Schema;

Schema::rename($from, $to);
            
ცხრილის წასაშლელად უნდა გამოვიყენოთ Schema ფასადის drop ან dropIfExists მეთოდი :
Schema::drop('users');

Schema::dropIfExists('users');
            

ანონიმური მიგრაციის კლასები

ლარაველის მე-9-ე ვერსიაში აღარ ხდება მიგრაციის კლასთა დასახელების განსაზღვრა, ამის ნაცვლად გამოიყენება ანონიმური კლასები. შევადაროთ მე-8-ე ვერსიის მიგრაციის ფაილი მე-9-ე ვერსიისას :
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            //
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}
            
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            //
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
};
            
ახლა განვმარტოთ თუ რის გამო მოხდა ეს ცვლილება. განვიხილოთ ასეთი სიტუაცია :

  1. დავუშვათ ჩვენი აპლიკაციის 1.0 ვერსიაში გვქონდა 'create_news_table' მიგრაციით შექმნილი 'news' ცხრილი.
  2. აპლიკაციის 1.1 ვერსიაში შევქმენით მიგრაცია, რომელმაც წაშალა 'news' ცხრილი.
  3. აპლიკაციის 1.2 ვერსიაში ისევ გვინდა 'news' ცხრილის შექმნა, ამჯერად უკვე სხვა ველებითა და შინაარსით, ამისათვის ისევ გავაკეთეთ 'create_news_table' მიგრაცია.
ბუნებრივია მე-3-ე ბიჯზე შექმნილ მიგრაციაში აღწერილი კლასის დასახელება დაემთხვევა 1-ელ ბიჯზე შექმნილ მიგრაციაში აღწერილი კლასის დასახელებას. რაც შეცდომას გამოიწვევს მიგრაციების გაშვებისას ლარაველის მე-8-ე ვერსიაში, მე-9-ე ვერსიაში კი ეს აღარ მოხდება ანონიმური კლასების დახმარებთ.
18. ინფორმაციის შეტანა მბ-ში (Seeders)
ამ თავში განვიხილავთ ფრეიმვორკის მექანიზმს, რომელიც გამოიყენება მბ-ს საწყისი მონაცემებით შევსებისათვის. ეს ნექანიზმი აღწერილია შემდეგ ფაილში : database/seeders/DatabaseSeeder.php (ing: Seed წყარო, საწყისი). გარდა ამ ფაილში აღწერილი DatabaseSeeder კლასისა, შესაძლებელია რომ ჩვენც შევქმნათ ჩვენი საკუთარი კლასები, ფრეიმვორკის კონსოლის გამოყენებით. მაგალითისათვის შევქმნათ კლასი ArticlesSeeder, ამისათვის უნდა ავკრიფოთ ბრძანება : php artisan make:seeder ArticlesSeeder შეიქმნება ფაილი database/seeders/ArticlesSeeder.php :
namespace Database\Seeders;

use Illuminate\Database\Seeder;

class ArticlesSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        //
    }
}
            
როგორც ვხედავთ კლასი ArticlesSeeder არის Seeder კლასის მემკვიდრე და მას გააჩნია მეთოდი run(), ამ მეთოდში აღწერილი ინსტრუქციები შესრულდება მაშინ, როცა ავამუშავებთ ჩვენს მიერ შექმნილ მექანიზმს. ამ მეთოდში აღვწეროთ მბ-ს ცხრილში ინფორმაციის შესატანი ინსტრუქციები, მართალია ჯერ არ ვიცით თუ როგორ უნდა ვიმუშავოთ მბ-სთან, მაგრამ ოდნავ გავუსწროთ მოვლენებს და მოვიყვანოთ მარტივი მაგალითი :
namespace Database\Seeders;

use DB;
use Illuminate\Database\Seeder;

class ArticlesSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        DB::table('articles')->insert([
            [
                'name' => 'Blog Post 2',
                'text' => 'Blog Post 2 testing post 2 and its text',
                'img' =>  'pic2.jpg'
            ],
            [
                'name' => 'Blog Post 3',
                'text' => 'Blog Post 3 testing post 3 and its text',
                'img' =>  'pic3.jpg'
            ]
        ]);
    }
}
            
ამის შემდეგ database/seeders/DatabaseSeeder.php ფაილში აღწერილი DatabaseSeeder კლასის run მეთოდში უნდა ჩავამატოთ ჩვენს მიერ შექმნილი, მბ-ში ინფორმაციის შემტანი ფაილის (ArticlesSeeder.php) შესაბამისი ჩანაწერი, ეს საჭიროა იმისათვის, რომ ინფორმაციის შეტანის ბრძანების გაშვებისას სისტემამ ეს ფაილიც გამოიძახოს.
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call(ArticlesSeeder::class);
    }
}
           
ამის შემდეგ საჭიროა, რომ ხელახლა მოვახდინოთ composer-ის ავტოჩამტვირთველის გენერირება, რათა ახალდამატებული კლასიც შევიდეს ჩატვირთული კლასების სიაში, ეს ხდება შემდეგი ბრძანებით : composer dump-autoload ახლა უკვე შეგვიძლია გავუშვათ მბ-ში ინფორმაციის შეტანის ბრძანება : php artisan db:seed არსებობს მეორე ვარიანტიც : თუ DatabaseSeeder კლასში არ ჩავამატებთ ზემოთ აღწერილ ჩანაწერს, მაშინ ინფორმაციის შეტანის ბრძანება უნდა გავუშვათ შემდეგი სახით : php artisan db:seed --class=ArticlesSeeder
19. მუშაობა მბ-სთან, ფასადი DB

ფასადი DB

ფასადი DB გამოიყენება მბ-სთან სამუშაოდ, იგი აღჭურვილია იმ მეთოდებით, რომლებიც შეიძლება დაგვჭირდეს ნებისმიერი ტიპის მოთხოვნის გასაშვებად მონაცემთა ბაზაში: select, update, insert, delete, statement.

DB::select

DB ფასადის select მეთოდი გამოიყენება მბს ცხრილიდან ინფორმაციის ამოსაღებად. მეთოდს პირველ პარამეტრად უნდა გადაეცეს მოთხოვნის შაბლონი, ტანი.
namespace App\Http\Controllers;

use DB;
use App\Http\Controllers\Controller;

class PostController extends Controller
{
    public function index()
    {
        $articles = DB::select("SELECT * FROM articles");
        dump($articles);
    }    
}
            
ბრძანებას დავამატოთ WHERE ფილტრი, მაგრამ მანამდე აღვნიშნოთ ერთი რამ : laravel-ი მბ-სთან მუშაობისას იყენებს PDO ინტერფეისს, რაც იმას ნიშნავს, რომ ბრძანებების გაშვება ხდება წინასწარგანსაზღვრის პრინციპით (პრეპარირებული განაცხადები). ასეთ შემთხვევაში შეგვიძლია select მეთოდს მეორე პარამეტრად, მასივის სახით გადავცეთ ის მნიშვნელობები, რომლებიც ჩაანაცვლებენ პრეპარირებული განაცხადის ნიშნულებს, მარკერებს :
$articles = DB::select("SELECT * FROM articles WHERE id=?", [2]);
dump($articles);    
            
select მეთოდი აბრუნებს შედეგთა ნაკრებს მასივის სახით, მასივისა, რომლის თითოეული ელემენტიც არის PHP stdClass-ის ობიექტის სახით წარმოდგენილი კონკრეტული ჩანაწერი მონაცემთა ბაზიდან :


ამოღებული ინფორმაციის გამოყენება შესაძლებელია მაგალითად ასე :
foreach ($articles as $article) 
{
    echo $article->name;
}
            

DB::insert

DB ფასადის insert მეთოდი გამოიყენება მბს ცხრილში ინფორმაციის შესატანად :
$insert = DB::insert("INSERT INTO articles (name, text, img) VALUES(?,?,?)", ['Article 4','Article 4 Text','img4.jpg']);
dd($inser);
            

DB::update

DB ფასადის update მეთოდი გამოიყენება მბს ცხრილში ინფორმაციის განახლებისათვის :
$update = DB::update("UPDATE articles SET name=? WHERE id > ?", ['Renamed Article', 1]);
dd($update);
            
ეს მეთოდი აბრუნებს ზემოქმედებული ჩანაწერების რაოდენობას.

DB::delete

DB ფასადის delete მეთოდი გამოიყენება მბს ცხრილში ჩანაწერების წასაშლელად :
$delete = DB::delete("DELETE FROM articles WHERE id=?", [1]);
dd($delete);        
            
მეთოდი აბრუნებს წაშლილი ჩანაწერების რაოდენობას.

DB::statement

DB ფასადის statement მეთოდი გამოიყენება ისეთი ტიპის ბრძანებების შესასრულებლად, რომლებიც არ მიეკუთვნებიან არც ამორჩევითი ტიპის ბრძანებათა ოჯახს (select) და არც ცვლილებათა ტიპის ბრძანებათა ოჯახს (insert, delete, update). მაგალითად მბ-ცხრილის წასაშლელად ჩვენ დაგვჭირდება სწორედ statement მეთოდი.
$statement = DB::statement("DROP TABLE test");
dd($statement);  // true/false     
            

DB::unprepared

თუ გვსურს, რომ ბრძანება გავუშვათ არაწინასწარგანსაზღრული ფორმატით მაშინ უნდა გამოვიყენოთ DB ფასადის unprepared მეთოდი :
$unprepared = DB::unprepared('UPDATE articles SET text = "New text" WHERE id = 2');
dd($unprepared); // true/false       
            
გამომდინარე იქიდან, რომ unprepared მეთოდი არ იყენებს წინასწარგანსაზღრულ ფორმატსა და მიმაგრებულ პარამეტრებს, არსებობს SQL ინექციის დიდი საფრთხე. მომხმარებლის მიერ გამოგზავნილი ინფორმაცია ამ მეთოდით არასდროს უნდა შევინახოთ ბაზაში.
20. მბ მოთხოვნათა კონსტრუქტორი

ინგ : Builder - მწარმოებელი, მწარმოებელი-ქარხანა, მშენებელი

მოთხოვნათა კონსტრუქტორის უკან მოიაზრება სპეციალური კლასი Builder (ფსევდონიმი queryBuilder ანუ მოთხოვნათა მშენებელი :)) ), რომელსაც გააჩნია კონკრეტული მეთოდები, რომელთაგანაც თითოეული უზრუნველჰყოფს ბრძანების სრული ტანის კონკრეტული ნაწილის ფორმირებას, ჩვენ აღარ გვიწევს მოთხოვნის ხელით დაწერა. აღნიშნული კლასი აღწერილია vendor/laravel/framework/src/Illuminate/Database/Builder.php ფაილში.

იმისათვის რათა გამოვიყენოთ ეს კლასი, პირველ რიგში უნდა შევქმნათ მბ-ს ცარიელი მოთხოვნის ობიექტი კონკრეტული ცხრილისათვის, ამისათვის უნდა მივმართოთ DB ფასადის table მეთოდს, რომელსაც პარამეტრად უნდა გადავცეთ ცხრილის დასახელება.

get მეთოდი

ეს მეთოდი იღებს ყველანაირ ინფორმაციას კონკრეტული ცხრილიდან და აბრუნებს ობიექტთა მასივს :
$articles = DB::table('articles')->get();
dd($articles);          
            
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება "SELECT * FROM articles"

first მეთოდი

ეს მეთოდი იღებს პირველ ჩანაწერს კონკრეტული ცხრილიდან და აბრუნებს stdClass კლასის ობიექტის სახით:
$article = DB::table('articles')->first();
            
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება : "SELECT * FROM articles LIMIT 1"

value მეთოდი

ეს მეთოდი იღებს ინფორმაციას ერთი რომელიმე კონკრეტული ველიდან, პარამეტრად უნდა გადაეცეს ველის დასახელება. მეთოდი აბრუნებს სტრიქონული ტიპის შედეგს, აგრეთვე უნდა აღინიშნოს, რომ ეს მეთოდიც, ისევე როგორც წინა, ინფორმაციას იღებს მხოლოდ პირველი ჩანაწერიდან.
$name = DB::table('articles')->value('name');
            
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება : "SELECT 'name' FROM articles LIMIT 1"

pluck მეთოდი

ეს მეთოდი იღებს ინფორმაციას ერთი რომელიმე კონკრეტული ველიდან, პარამეტრად უნდა გადაეცეს ველის დასახელება. მეთოდი აბრუნებს ველის მნიშვნელობათა მასივს, აღსანიშნავია რომ, pluck მეთოდი, value მეთოდისაგან განსხვავებით, ინფორმაციას იღებს ყველა ჩანაწერიდან. (ინგ: Pluck - კრეფა, აღება, აკრეფა, შეგროვება).
$names = DB::table('articles')->pluck('name');
            
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება : "SELECT 'name' FROM articles"

count მეთოდი

ეს მეთოდი თვლის ჩანაწერების რაოდენობას ცხრილში და აბრუნებს რიცხვითი ტიპის მნიშვნელობას :
$count = DB::table('articles')->count();
            
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება : "SELECT COUNT(*) FROM articles"

max მეთოდი

ეს მეთოდი აბრუნებს მაქსიმალურ მნიშვნელობას განსაზღვრული ველისათვის, პარამეტრად უნდა გადაეცეს ველის დასახელება :
$max = DB::table('articles')->max('id');
            
ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება : "SELECT MAX('id') FROM articles" ასევე არსებობს min, avg და sum მეთოდებიც, რომლებიც ანალოგიურად მუშაობს.

select მეთოდი

ამ მეთოდის გამოყენება ხელსაყრელია მაშინ, როდესაც გვსურს კონკრეტული ველების ამოღება ჩანაწერებიდან და არა ყველა ველისა. ველთა დასახელებები მეთოდს უნდა გადაეცეს პარამეტრებად, შესაძლებელია მასივის სახით გადაცემა ან თითოეული ველის დასახელების გადაცემა ცალკე პარამეტრად :
$articles = DB::table('articles')->select('id','name');
            
თუ ამ ბრძანებას გავუშვებთ, შედეგად დაგვიბრუნდება Builder კლასის ობიექტი და არა ის შედეგი რაც გვსურს, იმიტომ რომ select მეთოდს ჯერ არ შეუსრულებია თავისი საქმე, ამისათვის მას უნდა მივაშველოთ get მეთოდი :
$articles = DB::table('articles')->select('id','name');
            
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება : "SELECT id, name FROM articles"

where მეთოდი

ხშირად საჭიროა ინფორმაციის ამოღება გარკვეული ფილტრების მიხედვით (მაგ: ამოირჩეს ჩანაწერები სადაც id მეტია 2-ზე), ასეთი სახის ბრძანებების შესასრულებლად select მეთოდთან ერთად უნდა გამოვიყენოთ where მეთოდი. როგორც ვიცით where ოპერატორის სინტაქსი სტანდარტულ PHP-ში შემდეგნაირია : SELECT * FROM articles WHERE id > 10 Laravel-ში კი შემდეგნაირი :
$articles = DB::table('articles')->select('name')->where('id','>',2)->get();
            
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება "SELECT 'name' FROM articles WHERE id > 2" როგორც ვხედავთ where მეთოდს გადაეცა სამი პარამეტრი: იმ ველის დასახელება რომლის მიხედვითაც ვფილტრავთ, პირობითი ოპერატორი და შესადარებელი მნიშვნერლობა. თუ პირობით ოპერატორტს საერთოდ არ მივუთითებთ ფრეიმვორკი იგულისხმებს, რომ ეს ოპერატორი არის ტოლობის ოპერატორი.

რამდენიმე პირობითი ფილტრის ერთდროულად გამოყენების სინტაქსი ასეთია :

$articles = DB::table('articles')->select('id','name')
                       ->where('id','>',2)
                       ->where('name','like','%A%')
                       ->get();
            
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება : "SELECT 'name' FROM articles WHERE id > 2 AND name LIKE '%A%'"

როგორც ვხედავთ, პირობითი ოპერატორები ერთმანეთთან დაკავშირდა ლოგიკური "და" -ს მეშვეობით. ჩნდება კითხვა : როგორ მოვიქცეთ თუ გვჭირდება მაგალითად ლოგიკური "ან" ? ამისათვის where ოპერატორს უნდა დავუმატოთ მეოთხე არგუმენტი :

$articles = DB::table('articles')->select('id','name')
                 ->where('id','>',2)
                 ->where('name','like','%A%','or')
                 ->get();
            
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება : "SELECT 'name' FROM articles WHERE id > 2 OR name LIKE '%A%'" რამდენიმე პირობითი ოპერატორის გამოყენება შესაძლებელია where მეთოდზე მხოლოდ ერთი მიმართვითაც, ასეთ შემთხვევაში მას არგუმენტად უნდა გადაეცეს მასივი, რომელიც თავის თავში მოიცავს ფილტრის პირობების შემცველ ქვე-მასივებს :
$articles = DB::table('articles')->select('id','name')
                 ->where([
                            ['id','>',2],
                            ['name','like','a%','or']
                         ])
                 ->get();   
            

whereBetween მეთოდი

$articles = DB::table('articles')->whereBetween('id',[2,5])->get();   
            
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება : "SELECT 'name' FROM articles WHERE id BETWEEN 2 AND 5" ამ მეთოდის შებრუნებული მეთოდია whereNotBetween.

ამ ორი მეთოდიას ანალოგიურია მეთოდები whereIn და whereNotIn ამიტომ მათ მაგალითებს აღარ მოვიყვანთ.

groupBy მეთოდი

ეს მეთოდი გამოიყენება ცხრილის ჩანაწერთა დაჯგუფებისათვის, პარამეტრად უნდა გადაეცეს იმ ველის დასახელება რომლის მიხედვითაც ვაჯგუფებთ :
$articles = DB::table('articles')->get()->groupBy('name');
            
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება : "SELECT * FROM articles GROUP BY name"

take მეთოდი

ეს მეთოდი დაგვეხმარება მაშინ თუ გვსურს ამოღებული ჩანაწერების რაოდენობის ლიმიტირება :
$articles = DB::table('articles')->take(2)->get();
            
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება : "SELECT * FROM articles LIMIT 2"

insert მეთოდი

ეს მეთოდი გამოიყენება მბს ცხრილში ინფორმაციის შესატანად, მას პარამეტრად უნდა გადაეცეს ის ინფორმაცია, რომლის შეტანაც გვსურს ცხრილში :
$insert = DB::table('articles')->insert([
    ['name' => 'test name', 'text' => 'test text', 'img' => 'test.jpg'],
    ['name' => 'test name 1', 'text' => 'test text 1', 'img' => 'test.jpg']
]);

dd($insert);
            
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ორი ბრძანება : "INSERT INTO articles (name, text) VALUES ('test name', 'test text', 'test.jpg')"
"INSERT INTO articles (name, text) VALUES ('test name 1', 'test text 1', 'test.jpg')"
მეთოდი აბრუნებს TRUE მნიშვნელობას წარმატების შემთხვევაში, წინააღმდეგ შემთხვევაში ბრუნდება მნიშვნელობა FALSE.

ანალოგიურად მუშაობს insertGetId მეთოდიც, უბრალოდ ის აბრუნებს ბოლოს დამატებული ჩანაწერის id-ს.

update მეთოდი

ეს მეთოდი გამოიყენება მბს ცხრილში ინფორმაციის განახლებისათვის. ლოგიკურია, რომ მეთოდის გამოყენება ხდება where მეთოდთან ერთად, რადგან თუ ვუშვებთ ბრძანებას რომელიც სისტემას ეუბნება, რომ ჩაატაროს განახლების ოპერაცია მაშინ ისიც უნდა მივუთითოთ თუ რა უნდა განაახლოს :
$update = DB::table('articles')->where('id',2)->update(['name' => 'hello world']);
             
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება : "UPDATE articles SET name='hello world' WHERE id=2" მეთოდი აბრუნებს ზემოქმედებული ჩანაწერების რაოდენობას.

delete მეთოდი

ეს მეთოდი გამოიყენება მბს ცხრილში ინფორმაციის წასაშლელად. ამ მეთოდის გამოყენებაც where მეთოდთან ერთად ხდება, რადგან თუ ვუშვებთ წაშლის ბრძანებას მაშინ ისიც უნდა მივუთითოთ თუ რა და სად უნდა წაიშალოს :
$delete = DB::table('articles')->where('id',2)->delete();
            
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება : "DELETE FROM articles WHERE id=2"

find მეთოდი

თუ გვსურს ერთი ჩანაწერის ამორება id ველის მეშვეობით, უნდა გამოვიყენოთ find მეთოდი :
$article = DB::table('articles')->find(3);
            
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება : "SELECT * FROM articles WHERE id = 3" მეთოდი აბრუნებს ზემოქმედებული ჩანაწერების რაოდენობას.

join მეთოდი

$users = DB::table('users')
            ->join('contacts', 'users.id', '=', 'contacts.user_id')
            ->join('orders', 'users.id', '=', 'orders.user_id')
            ->select('users.*', 'contacts.phone', 'orders.price')
            ->get();
            

leftJoin მეთოდი

$users = DB::table('users')->leftJoin('posts', 'users.id', '=', 'posts.user_id')->get();    
            

დაუმუშავებელი განაცხადები

ზოგჯერ შეიძლება დაგვჭირდეს, რომ ბრძანებებში ჩავრთოთ, მოთხოვნათა კონსტრუქტორის ჩვეული სტილისაგან განსხვავებული, არასდანტარტული გამოსახულებები. დავარქვათ მათ დაუმუშავებელი გამოსახულებები. ამისათვის გამოიყენება DB ფასადის raw მეთოდი (ინგ: Raw Data - საწყისი, დაუმუშავებელი მონაცემები).
 $users = DB::table('users')
             ->select(DB::raw('count(*) as user_count, status'))
             ->where('status', '<>', 1)
             ->groupBy('status')
             ->get();
            
ეს ჩანაწერი დააგენერირებდა ასეთ ბრძანებას :
 select count(*) as user_count, status from `users` where `status` <> 1 group by `status`
            
ეს ყველაფერი მოგვცემდა ასეთ შედეგს :



დაუმუშავებელი გამოსახულებები მოთხოვნაში შედის სტრიქონის სახით და ამიტომ მათი გამოყენებისას უკიდურესად ფრთხილად უნდა ვიყოთ რათა თავი დავიცვათ SQL ინექციებისაგან.

JSON ველები

რომელიმე სატესტო ცხრილში გავაკეთოთ JSON ტიპის ველი 'properties' და ასევე ცხრილში შევიტანოთ რამდენიმე ჩანაწერი properties ველების შემდეგი მნიშვნელობებით :
{
    "age":32,
    "sex":"male",
    "salary":4500,
    "languages":[
        "ka","en"
    ]
}

{
    "age":30,
    "sex":"male",
    "salary":5500,
    "languages":[
        "ka"
    ]
}

{
    "age":28,
    "sex":"female",
    "salary":2500,
    "languages":[
        "ka","ru","en"
    ]
}

{
    "age":21,
    "sex":"male",
    "salary":1500,
    "languages":[
        "ka"
    ]
}
            
properties ველის მიხედვით მოვძებნოთ მომხმარებლები, რომელთა ხელფასიც 5500 ლარია :
$users = DB::table('users')->where('properties->salary', 5500)->get();
            
იგივეს გაკეთება ასეც შეგვიძლია :
$users = DB::table('users')->whereJsonContains('properties->salary', 5500)->get();
            
თუ ვიყენებთ MySQL ან PostgreSQL მონაცემთა ბაზებს, შეგვიძლია, რომ whereJsonContains მეთოდს სასურველი პარამეტრები გადავცეთ მასივის სახით :
$users = DB::table('users')->whereJsonContains('properties->languages', ['en', 'ka'])->get();
            
ახლა გავიგიოთ რომელმა მომხმარებლებმა იციან ორი ენა, ამაში დაგვეხმარება whereJsonLength მეთოდი :
$users = DB::table('users')->whereJsonLength('properties->languages', 2)->get();
            
ახლა გავიგიოთ რომელმა მომხმარებლებმა იციან ორ ენაზე მეტი :
$users = DB::table('users')->whereJsonLength('properties->languages', '>', 2)->get();
            

WHERE ფილტრის დამატებითი ფუნქციონალი

whereBetween / orWhereBetween

$users = DB::table('users')->whereBetween('id', [1, 100])->get();
            

whereNotBetween / orWhereNotBetween

$users = DB::table('users')->whereNotBetween('id', [1, 100])->get();
            

whereIn / whereNotIn / orWhereIn / orWhereNotIn

$users = DB::table('users')->whereIn('id', [1, 2, 3])->get();

$users = DB::table('users')->whereNotIn('id', [1, 2, 3])->get();
            

whereNull / whereNotNull / orWhereNull / orWhereNotNull

$users = DB::table('users')->whereNull('updated_at')->get();

$users = DB::table('users')->whereNotNull('updated_at')->get();
            

whereDate / whereMonth / whereDay / whereYear / whereTime

$users = DB::table('users')->whereDate('created_at', '2016-12-31')->get();

$users = DB::table('users')->whereMonth('created_at', '12')->get();

$users = DB::table('users')->whereDay('created_at', '31')->get();

$users = DB::table('users')->whereYear('created_at', '2016')->get();

$users = DB::table('users')->whereTime('created_at', '=', '11:20:45')->get();
            

whereColumn / orWhereColumn

whereColumn მეთოდის მეშვეობით შეგვიძლია დავადგინოთ ტოლია თუ არა ორი სხვადასხვა ველის მნიშვნელობები :
$users = DB::table('users')->whereColumn('first_name', 'last_name')->get();
            
შეგვიძლია მეთოდს დავამატოთ მესამე პარამეტრიც :
$users = DB::table('users')->whereColumn('updated_at', '>', 'created_at')->get();
            
ასევე შეგვიძლია, რომ შედარების პირობები გადავცეთ მასივის სახით :
$users = DB::table('users')
                ->whereColumn([
                    ['first_name', '=', 'last_name'],
                    ['updated_at', '>', 'created_at'],
                ])->get();
            
21. მონაცემთა მოდელი
როგორც ვიცით, ფრეიმვორკი laravel-ი დაფუძნებულია შაბლონ mvc-ზე (Model, View, Controller ანუ მოდელი, წარმოდგენა, კონტროლერი). ამ თავში ვისაუბრებთ მოდელებზე. იმის შესახებ თუ რა არის მოდელი და რა ევალება მას, ვისაუბრეთ მე-3-ე თავში, ახლა კი მოვიყვანოთ შემდეგი განმარტება: მოდელი არის მბ-ს ცხრილში შეტანილი კონკრეტული ჩანაწერების აბსტრაქცია, რომელიც მბს ცხრილის ელემენტებს წარმოგვიდგენს ობიექტების სახით, მარტივი სიტყვებით მოდელი არის განსაზღვრული კლასის ობიექტი, რომლის მეთოდებითაც ხდება ცხრილის მონაცემებთან მუშაობა.

მოდელის შსაქმნელად კონსოლში უნდა ავკრიფოთ შემდეგი ბრძანება :

php artisan make:model Article მოდელის სახელის განსაზღვრისას შეზღუდვები არ არსებობს, მაგრამ როგორც წესი მოდელს სახელს არქმევენ ხოლმე მბს იმ ცხრილის დასახელების მიხედვით, რომელთან სამუშაოდაც უნდა გამოვიყენოთ ეს მოდელი, მაგალითად თუ ცხრილს ჰქვია articles მაშინ სასურველია შესაბამის მოდელს დავარქვათ Article. ცხრილს სახელი ჰქვია მრავლობით ფორმაში რადგან იგი შეიცავს რამდენიმე article-ს ანუ ჩანაწერის შესახებ ინფორმაციას, მოდელი კი როგორც ვთქვით მუშაობს ცხრილის კონკრეტულ ჩანაწერებთან, ამიტომ მოდელს დავარქვით ცხრილის სახელი მხოლობით ფორმაში.

მოდელები ინახება app/Models საქაღალდეში, ბრძანების შედეგად შექმნილი მოდელიც შეინახება აქ.

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    //
}
            
ჩვენს მიერ შექმნილი ნებისმიერი მოდელი იქნება Model მშობელი კლასის მემკვიდრე, რომელიც აღწერილია შემდეგ ფაილში : vendor/laravel/framework/src/Illuminate/Database/Model.php

თვისება $table

$table თვისება არის მოდელის ობიექტის დახურული თვისება, რომელშეიც უნდა განისაზღვროს მბს იმ ცხრილის სახელი, რომელთანაც ვმუშაობთ მოცემულ მოდელში :
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    protected $table = 'articles';
}
            
უნდა აღინიშნოს, რომ ამ შემთხვევაში $table თვისების განსაზღვრა საჭირო არ არის, რადგანაც ცხრილისა და მოდელის სახელებს შორის გვაქვს ის დამოკიდებულება რაც ზემოთ ვთქვით : მოდელს სახელად აქვს ცხრილის დასახელების მხოლობითი ფორმა. ასეთ შემთხვევაში კი სისტემა ავტომატურად მიხვდება, თუ რომელ ცხრილთან უნდა იმუშავოს.

თვისება $primaryKey

$primaryKey თვისება არის მოდელის ობიექტის დახურული თვისება, რომელშეიც უნდა განისაზღვროს მბს ცხრილის პირველადი გასაღები ველის სახელი, რომელიც გამოიყენება ჩანაწერთა იდენტიფიკაციისათვის, თუ ამ თვისებაში არაფერს განვსაზღვრავთ მაშინ ფრეიმვორკი გაარკვევს შეიცავს თუ არა ცხრილი ველს სახელად id და ჩათვლის, რომ ისაა პირველადი გასაღები და აგრეთვე ავტოგადამთვლელი (auto_increment), ხოლო თუ გვინდა, რომ პირველადი გასაღები იყოს დავუშვათ ველი article_id მაშინ ეს უნდა განვსაზღვვროთ შემდეგნაირად :
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    protected $primaryKey = 'article_id';
}
            

თვისება $incrementing

ეს ღია თვისება გამოიყენება იმის განსასაზღვრავად არის თუ არა რომელიმე ველი ავტოგადამთვლელი :
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    public $incremeting = FALSE;
}
            

თვისება $timestamps

ეს ღია თვისება გამოიყენება იმის განსასაზღვრავად შეივსოს თუ არა ცხრილის created_at და updated_at ველები ავტომატურად ცხრილთან მუშაობისას. როგორც ვიცით, მიგრაციით ცხრილის შექმნისას ფრეიმვორკი ამ ველებს ავტომატურად ამატებს ცხრილში.
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    public $timestamps = FALSE; // ამ შემთხვევაში ეს ველები შეივსება მნიშვნელობა Null-ით
}
            

თვისება $fillable

ეს დახურული თვისება გამოიყენება მბს ცხრილის იმ ველთა განსასაზღვრავად, რომლებშიც შესაძლებელია, რომ მომხმარებელმა შეიტანოს ინფორმაცია :
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    protected $fillable = ['name','text','img'];
}
            

თვისება $guarded

ეს დახურული თვისება გამოიყენება მბს ცხრილის იმ ველთა განსასაზღვრავად, რომლებშიც მომხმარებელს არ შეუძლია ინფორმაციის შეტანა :
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    protected $guarded = ['name','text','img'];
}
            

მოდელისა და კონტროლერის დაკავშირება

იმისათვის რათა კონტროლერში მივმართოთ მოდელს, უნდა დავამყაროთ წვდომა ამ მოდელთან, ამის შემდეგ კი შეგვიძლია გამოვიყენოთ მისი მეთოდები :
namespace App\Http\Controllers;

use App\Models\Article;
use App\Http\Controllers\Controller;

class PostController extends Controller
{
    public function index()
    {
        foreach (Article::all() as $article) 
        {
            echo $article->name;
        }    
    }    
}
            
all() მეთოდმა რეალურად გაუშვა შემდეგი ბრძანება : SELECT * FROM articles შედეგად კი დააბრუნა მოდელთა კოლექცია, რას ნიშნავს ეს ? როგორვ ვთქვით, მოდელი არის ობიექტის სახით აღწერილი, ცხრილის კონკრეტული ჩანაწერი, კონკრეტული ჩანაწერის აბსტრაქცია, აქედან გამომდინარე, თუ ცხრილში რამდენიმე ჩანაწერია, დაბრუნდება რამდენიმე ჩანაწერის ობიექტური წარმოდგენა ანუ ამ წარმოდგენათა (მოდელთა) ნაკრები.

ჩნდება კითხვა, როგორ გამოვიყენოთ მიღებული ინფორმაცია ანუ ცხრილის ველთა მნიშვნელობები ? ეს ხდება მოდელის იმავე სახელწოდებების მქონე თვისებების მიხედვით რაც აქვს ცხრილთა ველებს :

... 

foreach (Article::all() as $article) 
{
    echo $article->name;
}   

... 
            






ამ მიდგომას ეწოდება ORM - Object Relational Mapping და არის ერთგვარი ხიდი რელაციურ ბაზებსა და ოოპ ობიექტებს შორის.

რასაკვირველია მოდელში შესაძლებელია მთხოვნათა კონსტრუქტორის გამოყენებაც :

$a$articles = Article::where('id', '>', 2)->orderBy('name')->take(3)->get();
            

კონკრეტული მოდელის ამოღება

კონკრეტული მოდელის ამოსაღებად გამოიყენება find, first და firstWhere მეთოდები, რომლებიც კოლექციის ნაცვლად აბრუნებენ ერთ ობიექტს.
// მოდელის ამოღება პირველადი გასაღების მიხედვით (primary key)
$article = Article::find(1);

// პირველივე ისეთი მოდელის ამოღება, რომელიც აკმაყოფილებს მითითებულ პირობებს
$article = Article::where('status', 1)->first();
 
// პირველივე ისეთი მოდელის ამოღება, რომელიც აკმაყოფილებს მითითებულ პირობებს
$article = Article::firstWhere('active', 1);
            
შეიძლება მოხდეს ისე, რომ დაგვჭირდეს კონკრეტული ჩანაწერის ამოღება და მისი დაბრუნება თუ იგი მოიძებნება, წინააღმდეგ შემთხვევაში კონკრეტული ფუნქციონალის შესრულება :
$model = Article::where('id', 65673)->firstOr(function () {

    echo 'ვერ მოიძებნა';

});     
            

findOrFail() მეთოდი

ზოგჯერ საჭიროა, რომ იმ შემთხვევაში, თუ მოდელი ვერ მოიძებნება, დავაფიქსიროთ კონკრეტული გამონაკლისი. findOrFail და firstOrFail მეთოდები შეეცდებიან სასურველი მოდელის პოვნას და თუ ეს არ მოხერხდა მაშინ შეგვიძლია :
  • ჩვენს კონტროლერში დავაფიქსიროთ Illuminate\Database\Eloquent\ModelNotFoundException.php ფაილში აღწერილი ინსტრუქციების მიხედვით დაგენერირებული გამონაკლისი :
    namespace App\Http\Controllers;
    
    use App\Models\Article;
    use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException;
    
    class PostController extends Controller
    {
        public function index() 
        {
            try 
            {
                $article = Article::findOrFail(31);
                
                // მოდელი მოიძებნა...
            } 
            catch (ModelNotFoundException $e) 
            {
                if ($e instanceof ModelNotFoundException) 
                {
                    dd($e->getMessage()); // No query results for model [App\Models\Article] 31
                }
            }
        }
    }    
                        
  • გადავმისამართდეთ 404 გვერდზე (სწორედ ამას აკეთებს სისტემა ავტომატურად თუ პირველ ვარიანტს არ განვიხილავთ).

ინფორმაციის შეტანა მბს ცხრილში

firstOrCreate() მეთოდი

ამ მეთოდის გამოყენება ძალიან ხელსაყრელია მაშინ თუ გვინდა, რომ ცხრილში დავამატოთ უნიკალური ინფორმაცია განსაზღვრული ველისათვის. ამ მეთოდსაც პარამეტრად უნდა გადაეცეს მასივში აღწერილი ველთა დასახელებები და შესაბამისი მნიაშვნელობები :
$article = Article::firstOrCreate([
    'name' => 'Article Name',
    'text' => 'Article Text',
]);
            
მუშაობის პროცესის გასამარტივებლად ხშირად იყენებენ ხოლმე მიდგომას, რომლის მიხედვითაც კონკრეტული მოდელების შესაქმნელად საჭირო ინფორმაცია ერთ სივრცეშია ხოლმე მოქცეული (მაგალითად მასივში როგორც ზემოთ მოვიქეცით) და მოდელისათვის კონკრეტული ველების ცალ-ცალკე მიკუთცნება აღარ არის საჭირო. ამ მიდგომას ეწოდება მასიური განსაზღვრებადობა (Mass Assignment), რომელიც, რიგ შემთხვევებში, არც ისე უსაფრთხო შეიძლება იყოს.

ნახსენები მასივის როლში ხშირად შეიძლება მოგვევლინოს HTTP მოთხოვნის ტანი ($request->all()). წარმოვიდგინოთ ასეთი შემთხვევა: დავუშვათ მომხმარებლების ცხრილში გვაქვს 'admin' ველი, რომლის შესაძლო მნიშვნელობებიცაა 0 (არ არის ადმინსტრატორი) ან 1 (ადმინსტრატორია). ბუნებრივია მომხმარებლებს არ უნდა მივცეთ ამ ველის შეცვლის უფლება. არადა თუ იგი ფორმაში ახალ ველს ჩაამატებს სახელით - admin და მნიშვნელობით 1, რა თქმა უნდა ეს ველი HTTP მოთხოვნის ტანშიც შევა და შესაბამისად მომხმარებელი არალეგალური გზით გაიხდის თავს ადმინად )) :

// მომხარებლის დამატების კოდი
$user = new User(request()->all());
ამ ყველაფრის თავიდან ასაცილებლად Laravel-ში შემოღებულია შევსებადი და დაცული ველების ცნებები.

დავუბრუნდეთ ჩვენს კოდს :

$article = Article::firstOrCreate([
    'name' => 'Article Name',
    'text' => 'Article Text',
]);
            
თუ ახლა ამ კოდსს გავუშვებთ ვიხილავთ შეცდომას, უფრო სწორად ფრეიმვორკის მიერ დაგენერირებულ გამონაკლისს (MassAssignmentException), ეს იმიტომ, რომ Article მოდელში, $fillable მეთოდის მეშვეობით არ არის აღწერილი ცხრილის იმ ველთა დასახელებები, რომლებშიც ნებადართულია ინფორმაციის შეტანა მასიური განსაზღვრებადობის გზით :
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    protected $fillable = ['name', 'text'];
}
            
ინფორმაციის შეტანამდე firstOrCreate მეთოდი გადაამოწმებს უკვე ხომ არ არსებობს ცხრილში ისეთი ჩანაწერი რომლისთვისაც name ველის მნიშვნელობა არის 'Article Name', თუ ესეთი ჩანაწერი არსებობს მაშინ მეთოდი დააბრუნებს ამ ჩანაწერის მოდელს. ხოლო თუ არ არსებობს ასეთი ჩანაწერი, მაშინ მეთოდი შექმნის მას და დააბრუნებს ახალშექმნილ მოდელს.

save() მეთოდი

იმისათვის რათა ცხრილში ინფორმაცია შევიტანოთ save მეთოდით, პირველ რიგში უნდა შევქმნათ ცარიელი მოდელის ობიექტი, შემდეგ კი უბრალოდ მივმართოთ და განვუსაზღვროთ მნიშვნელობები შექმნილი ობიექტის იმ თვისებებს, რომელთა დასახელებებიც ემთხვევა ცხრილის ველთა დასახელებებს :
$article = new Article;

$article->name = 'ტესტი';
$article->text = 'ტესტი';
$article->img  = 'ტესტი';

$article->save();
            
save მეთოდით ჩანაწერების დამატებისას ავტომატურად ხდება ცხრილის created_at და updated_at ველების შევსება.

create() მეთოდი

ეს მეთოდი გამოიყენება ცხრილში ინფორმაციის შესატანად :
$article = Article::create([
    'name' => 'სათაური',
    'text' => 'ტექსტი',
    'img' => 'test.jpg',
]);    
            
create() მეთოდით ჩანაწერების შექმნისას მოდელში აუცილებლად უნდა გვქონდეს აღწერილი მასიურ განსაზღვრებადობასთან დაკავშირებული fillable და guarded თვისებები :
protected $fillable = ['name', 'text','img'];  
            
ან :
protected $fillable = [];  
            

ინფორმაციის განახლება მბს ცხრილში

ინფორმაციის განახლებისათვის, ჯერ უნდა ამოირჩეს კონკრეტული ჩანაწერი, შემდეგ კი უბრალოდ თავიდან უნდა განვსაზღროთ სასურველი ველების მნიშვნელობები, ბოლოს კი გამოვიძახოთ ისევ მეთოდი save() :
$article = Article::find(3);
$article->name = "ახალი სათაური";
$article->save();
            
updated_at ველის მნიშვნელობა ავტომატურად განახლდება.

მასიური განახლებები

შესაძლებელია, რომ ერთ ჯერზე განვაახლოთ არა მარტო კონკრეტული ჩანაწერი, არამედ რამდენიმე ჩანაწერიც ერთდროულად :
Article::where('id','>',1)->update([
    'name' => 'ახალი სათიურები',
    'text' => 'ახალი ტექსტები'
]);
            

Delete() მეთოდი

ეს მეთოდი შლის ჩანაწერებს მბს ცხრილიდან, მაგრამ იმისათვის რათა ცხრილის რომელიმე ჩანაწერი წაიშალოს, ჯერ უნდა ამოირჩეს ეს ჩანაწერი :
$article = Article::find(4);
$article->delete();
            

destroy() მეთოდი

ამ მეთოდის მეშვეობით შესაძლებელია ჩანაწერების წაშლა ამოურჩევლად, მას პარამეტრად უნდა გადაეცეს წასაშლელი ჩანაწერის იდენტიფიკატორი (id)
  Article::destroy(9);
            
თუ რამდენიმე ჩანაწერის წაშლა გვსურს ერთდროულად, მაშინ მეთოდს პარამეტრად უნდა გადაეცეს მასივი სადაც შეტანილი იქნება ამ ჩანაწერთა იდენტიფიკატორები.

softDelete

ეს მეთოდი გამოიყენება ჩანაწერთა წასაშლელად, იმ განსხვავებით, რომ იგი რეალურად არ შლის ჩანაწერებს, მისი მუშაობის პრინციპი წააგავს ოპერაციულ სისტემაში ფაილების წაშლის პრინციპს, რის შედეგადაც ეს ფაილები ხვდება სანაგვე ყუთში. ამ მეთოდის გამოსაყენებლად ცხრილს უნდა დავამატოთ ახალი ველი deleted_at, რომელშიც შეინახება ჩანაწერის წაშლის მომენტის შესაბამისი დროის ნიშნული. ამისათვის გავაკეთოთ ახალი მიგრაცია :
php artisan make:migration change_article_table_soft --table=articles
            
იმისათვის რათა მიგრაციაში განვსაზღვროთ აღნიშნული ველი, მიგრაციის up მეთოდში უნდა გამოვიყენოთ softDeletes მეთოდი. სწორედ ეს მეთოდი დაამატებს ცხრილში deleted_at ველს. შესაბამისად მიგრაციის down მეთოდში მოვახდინოთ მისი უგულებელყოფა :
...

public function up()
{
    Schema::table('articles', function (Blueprint $table) {
        $table->softDeletes();
    });
}

/**
 * Reverse the migrations.
 *
 * @return void
 */
public function down()
{
    Schema::table('articles', function (Blueprint $table) {
        $table->dropColumn('deleted_at');
    });
}

...
            
ახლა გავუშვათ ამ მიგრაციის შესრულების ბრძანება : php artisan migrate თუ ახლა შევამოწმებთ articles ცხრილს, ვნახავთ, რომ მას დამატებული ექნება deleted_at ველი.

ახლა გამოვიყენოთ softDelete() მეთოდი. ამისათვის მოდელში უნდა დავამატოთ სპეციალური კლასი softDeletes, ეს კლასი მდებარეობს შემდეგ მისამართზე : vendor/laravel/framework/src/Illuminate/Database/Eloquent/SoftDeletes.php.

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Article extends Model
{
    use SoftDeletes;
    protected $fillable = ['name', 'text'];
}
            
კონტროლერში კი ხდება შემდეგი :
$article = Article::find(10);
$article->delete();
            
თუ ახლა შევამოწმებთ ცხრილს ვნახავთ რომ id=10 ჩანაწერი განახლებული იქნება და deleted_at ველში მითითებული იქნება წაშლის თარიღი. როგორც ვხედავთ ეს ჩანაწერი წაშლილი არ არის მაგრამ იგი აღარ შევა შედეგთა ნაკრებში, თუ ამოვარჩევთ მაგალითად ცხრილის ყველა ჩანაწერს.

იმის დასადგენად წაიშლა თუ არა ჩანაწერი, გამოიყენება trashed მეთოდი :

$article = Article::find(8);
$article->delete();

if ($article->trashed()) 
{
    die('წაიშლა');
}
            
წაშლილი ჩანაწერის აღსადგენად გამოიყენება withTrashed და restore მეთოდები :
Article::withTrashed()->find(10)->restore();
            
onlyTrashed მეთოდის დახმარებით ხდება softDelete მეთოდით წაშლილი ჩანაწერების ამოღება :
$articles = Article::onlyTrashed()->get();
            
22. მბ-ს ცხრილების ურთიერთდამოკიდებულებები (hasmany, belongsto, ...)
ამ თავში ვისაუბრებთ მბს ცხრილების ურთიერთკავშირებზე. როგორც ვიცით, ცხრილების შექმნისას შესაძლებელია მათი ერთმანეთთან დაკავშირება კონკრეტული ველების გამოყენებით (foreign key).

მაგალითად გვაქვს სტატიების ცხრილი articles და იმ მომხმარებლების ცხრილი - users, რომლებიც ამატებენ ამ სტატიებს. ასეთ შემთხვევაში, როგორც წესი, მომხმარებლის საიდენტიფიკაციო ნომერი (id) იწერება ხოლმე articles ცხრილის user_id ველში. ანუ articles ცხრილის user_id ველი არის users ცხრილთან კავშირის საგარეო გასაღები. პრაქტიკაში ასეთი კავშირები საკმაოდ ხშირია და ამიტომ laravel-ში ჩადგმულია ფუნქციონალი, რომელიც ამარტივებს ამ კავშირებთან მუშაობას.





laravel-ში არსებობს ცხრილთა შორის კავშირის რამდენიმე ვარიანტი, მათ შორის ძირითადებია :

  • ერთი ერთთან
  • ერთი ბევრთან
  • ბევრი ბევრთან

კავშირი 'ერთი ერთთან', hasOne() მეთოდი

Laravel-ის ინსტალაციის შემდეგ database/migrations საქაღალდეში ავტომატურად შეიქმნებოდა მიგრაციის რამდენიმე ფაილი, მათ შორის users ცხრილის შესაქმნელი xxxx_xx_xx_xxxxxx_create_users_table. შესაბამისად, როდესაც პირველად გავუშვით 'php artisan migrate' ბრძანება, ეს ცხრილიც შეიქმნებოდა.

ახლა შევქმნათ ტელეფონის ნომრების ცხრილი :
php artisan make:migration create_phones_table
            
აღვწეროთ ველები :
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreatePhonesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('phones', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained()->onDelete('cascade');
            $table->string('phone', 100);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('phones');
    }
}
            
გავუშვათ მიგრაციის ბრძანება :
php artisan migrate
            
ვიხილავთ ამდაგვარ შეტყობინებას :



ეს იმიტომ, რომ სისტემამ მიგრაციის ძველ ფაილებსაც მიაკითხა და შესაბამისი შეტყობინებაც დააბრუნა - კონკრეტული ცხრილები უკვე არსებობსო. ამ პრობლემის მოგვარების რამდენიმე ვარიანტი არსებობს, ყველაზე მარტივია შევქმნათ database/migrations/old საქაღალდე, მასში გადავიტანოთ ყველა ძველი მიგრაცია და ისე გავუშვათ 'php artisan migrate'.

ახლა კი ყურადღება მივაქციოთ მიგრაციის შემდეგ ჩანაწერს :

$table->foreignId('user_id')->constrained()->onDelete('cascade'); foreignId მეთოდი პარამეტრად გადაცემულ მნიშვნელობას - 'user_id'-ს, მოხსნის '_id' ბოლოსართს, მიღებულ სიტყვას დაამატებს მრავლობითი ფორმის აღმნიშვნელ 's' ასოს და ამგვარად მიიღებს სიტყვა 'users' - ს, რაც ნიშნავს, რომ phones ცხრილის user_id ველი უკავშირდება users ცხრილის id ველს.

constrained()->onDelete('cascade') ჩანაწერი კი აღნიშნავს, რომ users ცხრილიდან კონკრეტული მომხმარებლის წაშლის შემთხვევაში, მისი შესაბამისი ტელეფონის ნომერიც წაიშლება phones ცხრილში.

ახლა შევქმნათ ტელეფონების მოდელი :

php artisan make:model Phone
            
იმისათვის რათა User მოდელი დავაკავშიროთ Phone მოდელთან, User მოდელში უნდა ჩავსვათ phone მეთოდი, რომელიც, თავის მხრივ, გამოიძახებს hasOne მეთოდს და დააბრუნებს შესაბამის შედეგს. hasOne მეთოდი აღწერილია Illuminate\Database\Eloquent\Model მშობელ მოდელში.
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * მომხმარებელთან დაკავშირებული ტელეფონის ნომრის ამოღება
     */
    public function phone()
    {
        return $this->hasOne(Phone::class);
    }
}
            
ახლა გამოვიყენოთ დამყარებული კავშირი :
$user = User::find(1); // select * from users where id=1 limit 1
dump($user->phone); // select * from phones where user_id = 1 and user_id is not null limit 1
            
მას შემდეგ რაც User მოდელში, hasOne() მეთოდის მეშვეობით განვსაზღვრეთ კავშირი 'ერთი-ერთთან', მოდელთან მიმართებაში შეგვიძლია გამოვიყენოთ დინამიური ანუ ცვალებადსახელიანი მეთოდი, რომლის სახელიც ემთხვევა User მოდელის იმ მეთოდის სახელს, რომელშიც მოხდა კავშირის განსაზღვრა.

სისტემა საგარეო გასაღებს (foreign key) ადგენს მშობელი კლასის სახელიდან გამომდინარე, მაგალიოთად ამ შემთხვევაში იგი ავტომატურად გულისხმობს, რომ Phone მოდელს აქვს ველი user_id. თუ გვსურს, რომ ეს მიდგომა გადავფაროთ, hasOne მეთოდს, მეორე პარამეტრად უნდა გადავცეთ ჩვენთვის სასურველი ველის დასახელება :

return $this->hasOne(Phone::class, 'foreign_key'); ამ მომენტისათვის, User მოდელი დაკავშირებულია მოდელ Phone-სთან, მაგრამ უკუკავშირი არ არის დამყარებული. ამის გასაკეთებლად Phone მოდელში ჩავამატოთ user მეთოდი, რომელშიც გამოვიყენებთ belongsTo() მეთოდს (ინგ: belongs - კუთვნილება, ეკუთვნის) :
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Phone extends Model
{
    /**
     * მომხმარებელი რომელსაც ეკუთვნის ტელეფონის კონკრეტული ნომერი
     */
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}
            

ამ შემთხვევაში სისტემა საგარეო გასაღებს (foreign key) ადგენს ურთიერთკავშირის აღმწერელი მეთოდის დასახელებითა და '_id' სუფიქსის კომბინაციით. ამ შემთხვევაში მეთოდის დასახელებაა - 'user', სუფიქსთან ერთად კი მიიღება 'user_id', შესაბამისად სისტემა ჩათვლის, რომ Phone მოდელს აქვს ველი 'user_id'. თუ გვსურს, რომ ეს მიდგომა გადავფაროთ, belongsTo მეთოდს, მეორე პარამეტრად უნდა გადავცეთ ჩვენთვის სასურველი ველის დასახელება :

public function user()
{
    return $this->belongsTo(User::class, 'foreign_key');
}
            
ტელეფონის კონკრეტული ნომრის მფლობელის დადგენა შესაძლებელია ასე :
$phone = Phone::find(1); // select * from phones where id = 1 limit 1
dump($phone->user); // select * from users where id = 1 limit 1
            

კავშირი 'ერთი მრავალთან', hasMany() მეთოდი

ამ მომენტისათვის ჩვენ უკვე გვაქვს მომხმარებლებისა და სიახლეების ცხრილები - users და articles. დავაკავშიროთ ისინი შემდეგნაირად: სიახლეების ცხრილს დავამატოთ ერთი ველი - 'user_id', რომელშიც ჩაიწერება სიახლეების ავტორების იდენტიფიკატორები.
php artisan make:migration change_articles_table
            
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class ChangeArticlesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('articles', function (Blueprint $table) {
            $table->foreignId('user_id')->constrained()->onDelete('cascade');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        $table->dropColumn('user_id');
    }
}
            
ბუნებრივია, რომ ერთმა მომხმარებელმა შესაძლებელია დაამატოს რამდენიმე სიახლე, შესაბამისად users ცხრილი სიახლეების ცხრილ -articles-თან დაკავშირდება კავშირის ტიპით - ერთი მრავალთან.



user მოდელში ჩავამატოთ ახალი მეთოდი articles
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * მომხმარებელთან დაკავშირებული ტელეფონის ნომრის ამოღება
     */
    public function phone()
    {
        return $this->hasOne(Phone::class);
    }

    /**
     * მომხმარებელის მიერ დამატებული სიახლეების ამოღება
     */
    public function articles()
    {
        return $this->hasMany(Article::class);
    }
}
            
როგორც ვხედავთ, გამომდინარე იქედან, რომ ერთი მომხმარებელი შეიძლება იყოს რამდენიმე სიახლის ავტორი, მეთოდის დასახელება მრავლობით ფორმაშია გასაზღვრული. კონკრეტული მომხმარებლის სიახლეებთან წვდომა შესაძლებელია ასე :
$articles = User::find(1)->articles; 

foreach ($articles as $article) 
{
    //
} 
            
'User::find(1)->articles' ჩანაწერის შედეგად გაეშვებოდა ორი ბრძანება :
select * from users where id = 1 limit 1

select * from articles where user_id = 1 and user_id is not null and deleted_at is null 
            
მეორე ბრძანებას წითლად მონიშნული ჩანაწერი მიემატა იმის გამო, რომ ჩვენ ადრე Article მოდელში გამოვიყენეთ ე.წ 'მსუბუქი წაშლის სისტემა (softDeletes).

ეს ჩანაწერი :

dump(User::find(1)->articles()); 
            
მოგვცემს HasMany ობიექტს :



hasMany მეთოდით აღწერილ ურთიერთკავშირებთან ერთად შესაძლებელია მოთხოვნათა კონსტრუქტორის გამოყენებაც :
$article = User::find(1)->articles->where('id',3)->first(); 
            
როგორც ვნახეთ, users და articles ცხრილებს შორის დამყარდა კავშირი ერთი ბევრთან. ახლა განვსაზღროთ უკუკავშირიც, ამისათვის სიახლეების მოდელში ჩავამატოთ შემდეგი ჩანაწერი :
public function user()
{
    return $this->belongsTo(User::class);
}
            
თუ ვამბობთ, რომ უნდა განვსაზღროთ 'ერთი ბევრთან' კავშირის უკუკავშირი, ბუნებრივია ამ კავშირის ფორმულირება იქნება 'ბევრი ერთთან', სწორედ ამიტომაა მეთოდის დასახელება განსაზღვრული მხოლობით ფორმაში.

დავაბრუნოთ იმ სიახლის ავტორის სახელი, რომლის id-იც არის 3

$article = Article::find(3);

return $article->user->name;
            

sql ბრძანებათა ოპტიმიზაცია, ე.წ 'ძუნწი ჩატვირთვა'

როგორც ვიცით შემდეგი კოდის გაშვებეისას :
$articles = Article::all();
dump($articles);
            
შესრულდება შემდეგი ბრძანება და ბრუნდება მოდელების შემდეგი კოლექცია :


დავუშვათ გვსურს დავბეჭდოთ ავტორის სახელი თითოეული სიახლისათვის :
$articles = Article::all();
        
foreach($articles as $article)
{
    echo $article->user->name . '<br>';
}
            
ასეთ შემთხვევაში მივიღებთ შემდეგ სურათს :



როგორც ვხედავთ ციკლის ყოველ იტერაციაზე შესრულდა ერთი და იგივე sql ბრძანება, ეს დიდი პრობლემა არაა, როდესაც ბაზაში სულ რამდენიმე ჩანაწერი გვაქვს, მაგრამ თუ იქ 10 000 ჩანაწერია, ამ ბრძანების გაშვება საკმაოდ დიდი დატვირთვა იქნება მბ-ს სერვერისათვის, რაც, დიდი ალბათობით, პრობლემებს შექმნის.

ასეთ შემთხვევაში გამოიყენება ე.წ 'ძუნწი ჩატვირთვა' :)) ამ შემთხვევაში დამატებითი ინფორმაციის ჩატვირთვა ხდება კოლექციასთან ერთად. ოპტიმიზირებული ჩატვირთვისას უნდა გამოვიყენოთ მეთოდი with, რომელიც უზრუნველჰყოფს ინფორმაციის ჩატვირთვას ძირითად ცხრილთან დაკავშირებული სხვა ცხრილებიდანაც. მეთოდს პარამეტრად უნდა გადაეცეს იმ მოდელის დასახელება, რომელთან დაკავშირებაც გვსურს :

$articles = Article::with('user')->get();

foreach($articles as $article)
{
    echo $article->user->name . '<br />';
}
            
ასეთ შემთხვევაში მივიღებთ შემდეგ სურათს :



ანუ სულ გაეშვა ორი ბრძანება : პირველმა მოახდინა კოლექციის გენერირება, მეორემ კი ჩატვირთა ამ კოლექციასთან დაკავშირებული საჭირო ინფორმაციები. ბრძანებათა ამდაგვარ ოპტიმიზაციას ეწოდება 'ძუნწი ჩატვირთვა' :))

მეთოდი has()

დავუშვათ გვინდა ამოვარჩიოთ ისეთი მომხმარებლები, რომლებსაც დამატებული აქვთ ერთი სიახლე მაინც, ასეთ შემთხვევაში გამოიყენება has მეთოდი :
$users = User::has('articles')->get();

foreach($users as $user)
{
    echo $user->name . '<br />';
}        
            




ანუ : User კლასის has მეთოდს პარამეტრად გადაეცა იმ მოდელის დასახელება, რომლის შესაბამის ცხრილშიც გვსურს User კოლექციის შესაბამისი ჩანაწერების არსებობა/არარსებობის დადგენა.

has მეთოდთან ერთად შესაძლებელია სხვადასხვა პირობითი ოპერატორების გამოყენებაც, დავუშვათ გვინდა ამოვარჩიოთ ის მომხმარებლები, რომლებსაც ორზე მეტი სიახლე აქვთ დამატებული:

$users = User::has('articles','>=', 2)->get();

foreach($users as $user)
{
    echo $user->name . '<br />';
}        
            




კავშირი 'ბევრი ბევრთან', belongsToMany() მეთოდი

ცხრილებს შორის კავშირის ეს ვარიანტი განვიხილოთ მომხმარებლებისა და მათი როლების მაგალითზე. მომხმარებელს შეიძლება გააჩნდეს რამდენიმე როლი (ადმინისტრატორი, სტუმარი ...), მეორეს მხრივ კი ერთი როლიც შეიძლება დაკავშირებული იყოს რამდენიმე მომხმარებელთან. ამდაგვარი კავშირის ასაღწერად დაგვჭირდება სამი ცხრილი : მომხმარებლების ცხრილი (users), როლების ცხრილი (roles) და მომხმარებლებისა და როლების საიდენტიფიკაციო ნომრების ცხრილი (role_user). მომხმარებლების ცხრილი უკვე გვაქვს, შევქმნათ დანარჩენი ორის შესაბამისი მიგრაციები : php artisan make:migration create_roles_table
...

public function up()
{
    Schema::create('roles', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->timestamps();
    });
}

...
            
php artisan make:migration create_role_user_table
...

public function up()
{
    Schema::create('role_user', function (Blueprint $table) {
        $table->id();
        $table->integer('user_id')->unsigned()->default(1);
        $table->foreign('user_id')->references('id')->on('users');
        $table->integer('role_id')->unsigned()->default(1);
        $table->foreign('role_id')->references('id')->on('roles');
        $table->timestamps();
    });
}

...
            
მივაქციოთ ყურადღება, რომ ბოლოს შექმნილი ცხრილის დასახელება 'role_user' შემთხვევითი არ არის - მისი პირველი ნაწილი 'role' არის 'roles' ცხრილთან სამუშაო მოდელის დასახელება, მეორე ნაწილი 'user' კი არის 'users' ცხრილთან სამუშაო მოდელის დასახელება.

გავუშვათ ამ მიგრაციების შესრულების ბრძანება და შევქმნათ ცხრილები.







ახლა შევქმნათ "roles" ცხრილის შესაბამისი მოდელი php artisan make:model Role მომხმარებლების მოდელში კი განვსაზღვროთ შემდეგი კავშირი ცხრილებს შორის : ერთი მომხმარებელი უკავშირდება რამდენიმე როლს :
...

public function roles()
{
    return $this->belongsToMany(Role::class);
}

...
            
ახლა თუ სასურველ კონტროლერში შევიტანთ შემდეგ კოდს :
$user = User::find(1);
$roles = $user->roles;

foreach ($roles as $role) 
{
    echo $role->name . '<br>';
}     
            
ბრაუზერში ვიხილავთ ჩვენს მიერ დამატებული ორივე როლის დასახელებას (admin, moderator).

ახლა მაგალითისათვის ამოვარჩიოთ მომხმარებლის ის როლი რომლის საიდენტიფიკაციო ნომერიცაა 2 :

$user = User::find(1);
$role = $user->roles()->where('roles.id',2)->first();

dump($role);
            
მივაქციოთ ყურადრება, რომ 'where' ფილტრში დაგვჭირდა იმის დაკონკრეტება, თუ რომელი ცხრილის საიდენტიფიკაციო ნომრის მიხედვით ვცდილობთ ინფორმაციის ამოღებას, ეს იმიტომ მოხდა, რომ 'id' ველი სამივე ცხრილშია (users, roles, role_user) და თუ ასე არ მოვიქცეოდით დაფიქსირდებოდა კონფლიქტი, შეცდომა.

ზუსტად ანალოგიურად მოხდება უკუკავშირის დამყარება : "ერთი როლი უკავშირდება რამდენიმე მომხმარებელს".

save(), saveMany() და create() მეთოდები

$user = User::find(1);

$article = new Article([
            'name' => 'მესამე სიახლე',
            'text' => 'მესამე სიახლის ტექსტი'
        ]);

$user->articles()->save($article);
            
როგორც ვხედავთ save მეთოდს არგუმენტად გადაეცა იმ ინფორმაციის შემცველი მოდელი, რომლის შეტანაც გვსურს ბაზაში.

რამდენიმე ჩანაწერის ერთდროულად დამატებისათვის გამოიყენება მეთოდი saveMany :

$user = User::find(1);

$user->articles()->saveMany([
    new Article(['name'=>'მეხუთე სიახლე', 'text'=>'მეხუთე სიახლის ტექსტი']),
    new Article(['name'=>'მეექვსე სიახლე', 'text'=>'მეექვსე სიახლის ტექსტი'])
]);
            

არსებობს ინფორმაციია შეტანის კიდევ ერთი მეთოდი create, რომელსაც პარამეტრად გადაეცემა უშუალოდ შესატანი ინფორმაცია და არა ამ ინფორმაციის შემცველი მოდელი :

$user = User::find(1);

$user->articles()->create([
    'name' => 'მეოთხე სიახლე',
    'text' => 'მეოთხე სიახლის ტექსტი'
]);      
            

update() მეთოდი

მეთოდს პარამეტრად უნდა გადაეცეს მბ-ს ცხრილის იმ ველთა დასახელებების შემცველი მასივი, რომელთა შეცვლაც გვსურს :
$user = User::find(1);

$user->articles()->where('id', 3)->update([
    'name' => 'მესამე სიახლის ახალი სათაური'
]);
            
ამ ჩანაწერში უნდა გავითვალისწინოთ ერთი რამ : როგორც ვხედავთ ჯერ ვიღებთ მომხმარებლის შესახებ ინფორმაციას (id=1) და შემდეგ ვუშვებთ ინფორმაციის განახლების შესახებ ბრძანებას. თუ სიახლე რომლის შეცვლაც გვსურს (id=3), არ ეკუთვნის ამორჩეულ მომხმარებელს, მაშინ სისტემა არ განაახლებს ამ ჩანაწერს, და ეს ასეც უნდა იყოს.
23. მომხმარებელთა აუტენტიფიკაცია
აპლიკაციების შექმნისას ხშირად აუცილებელია, რომ აპლიკაციის კონკრეტული ნაწილი დაიმალოს საერთო თვალთახედვიდან (მაგალითად ადმინისტრატორის პანელი) და მასზე ხელი მიუწვდებოდეს მხოლოდ რეგისტრირებულ მომხმარებლებს, ამისათვის გამოიყენება მომხმარებელთა აუტენთიფიკაციის სისტემა, რომელიც ჩაშენებულია ფრეიმვორკ ლარაველის სტანდარტულ ფუნქციონალში.

რა არის აუტენტიფიკაცია ?

აუტენტიფიკაცია ეს არის მომხმარებელთა გადამოწმების პროცესი, რომლის დროსაც დარდება მომხმარებლის მიერ აკრეფილი ინფორმაცია (მაგ: სახელი და პაროლი), სისტემაში არსებულ მონაცემებთან. თუ მოხდა ამ ინფორმაციათა დამთხვევა შეიძლება ითქვას, რომ მოხდა მომხმარებელის აუტენტიფიცირება, მაგრამ ეს კიდევ არ ნიშნავს იმას, რომ მას აქვს სისტემაში რაიმეს გაკეთების უფლება. აუტენთიფიკაციის ლოგიკური გაგრძელებაა ავტორიზაცია.

რა არის ავტორიზაცია ?

ავტორიზაცია არის აუტენტიფიცირებული მომხმარებლის უფლებათა გადამოწმების პროცესი.

აუტენთიფიკაციის პარამეტრები განსაზღვრულია config/auth.php ფაილში. მომხმარებლის აუტენთიფიკაციის პროცესი შედგება ორი ძირითადი ელემენტისაგან: პირველი ეს არის ე.წ მცველი - guard, მეორე კი - პროვაიდერი provider.

მცველი განსაზღვრავს თუ რა სახით იქნას შენახული ინფორმაცია იმ მომხმარებლის შესახებ, რომელიც აკეთებს მოთხოვნას, ანუ როგორ შევინახოთ ინფორმაცია იმის შესახებ, რომ მოთხოვნა გააკეთა მაგალითად აუტენთიფიცირებულმა მომხმარებელმა, ეს ინფორმაცია შესაძლებელია შენახულ იქნას სესიაში ან სპეციალურ სტრიქონში სახელად token.

პროვაიდერი განსაზღვრავს თუ როგორ და რა სახით შეიძლება მიიღოს მომხმარებელმა ინფორმაცია მბ-დან ან სხვა წყაროდან.

აუტენტიფიკაციის სისტემასთან მუშაობისთვის საჭიროა წარმოდგენის ფაილები, მარშრუტები და კონტროლერები. არსებობს ამ ყველაფრის შექმნის რამდენიმე ვარიანტი. განვიხილოთ ერთ-ერთი მათგანი - Laravel Breeze

რა არის Laravel Breeze ?

Laravel Breeze არის პაკეტი, რომელიც საშუალებას გვაძლევს შევქმნათ ყველა აუცილებელი კომპონენტი, აპლიკაციაში აუტენტიფიკაცის სისტემის ჩასაშენებლად. წარმოდგენის ფაილები იქმნება Laravel შაბლონიზატორისა და Tailwind CSS-ის დახმარებით. Tailwind CSS არის CSS ფრეიმვორკი, რომელიც მოიცავს სხვადასხვა კლასებისა და სელექთორების საკმაოდ ფართო ნაკრებს, მასში ასევე აღწერილია ამ კლასების შესაბამისი სტილები და ჩვენ ისღა დაგვრჩენია უბრალოდ მოვარგოთ ეს კლასები ჩვენს აპლიკაციას.

Laravel Breeze-ს ინსტალაცია ხდება შემდეგი ბრძანების მეშვეობით :

composer require laravel/breeze --dev
            
ამის შემდეგ უნდა გავუშვათ Artisan-ის ბრძანება :
php artisan breeze:install
            
ამ ყველაფრის შედეგად ვიხილავთ ამდაგვარ შეტყობინებებს :
Breeze scaffolding installed successfully.
Please execute the "npm install && npm run dev" command to build your assets.
            
იმისათვის რათა ხელი მიგვიწვდებოდეს CSS სტილებთან საჭიროა შემდეგი ბრძანებების გაშვება :
npm install 

npm run dev
            
ამ მომენტისათვის აუტენტიფიკაციის შაბლონების სტილები ჩვენთვის ნაკლებად მნიშვნელოვანია, მაგრამ თუ მაინც გსურთ, რომ გქონდეთ ავტორიზაციის ლამაზი ფორმა, მაშინ დააინსტალირეთ node.js (იხილეთ Typescript-ის ცნობარის მე-2-ე თავი) და გაუშვით ზემოთ მოყვანილი ორი ბრძანება :))

Breeze-ს ინსტალაციის შემდეგ, შეიქმნებოდა routes/auth.php ფაილი, რომელშიც აღწერილი იქნება აუტენტიფიკაციის სისტემის მარშრუტები და რომლის გამოძახებაც ავტომატურად მოხდებოდა routes/web.phpფაილში :

require __DIR__.'/auth.php';

კონტროლერები განთავსდებოდა App/Http/Controllers/Auth საქაღალდეში.

წარმოდგენის ფაილები განთავსდებოდა resources/views/auth საქაღალდეში.

ისღა დაგვრჩენია ვესტუმროთ http://127.0.0.1:8000/login და http://127.0.0.1:8000/register მისამართებს.

Laravel-ის ინსტალაციის შემდეგ ავტომატურად შეიქმნებოდა მომხმარებლებთან სამუშო App/Models/User მოდელი და ასევე მიგრაციის ორი ფაილი შემდეგი ცხრილებისათვის : users და password_resets. სწორედ users ცხრილში შეინახება რეგისტრაციისას მომხმარებლის მიერ აკრეფილი ინფორმაციები. password_resets ცხრილს კი შევეხებით ოდნავ მოგვიანებით.

routes/web.php ფაილს თუ გადავამოწმებთ, შევნიშნავთ, რომ Breeze-ს ინსტალაციის შემდეგ, მასში ასევე ჩაემატებოდა შემდეგი ჩნაწერი :
Route::get('/dashboard', function () {
    return view('dashboard');
})->middleware(['auth'])->name('dashboard');
            
ეს არის რეგისტრირებული მომხმარებლის პირადი კაბინეტის მარშრუტი, რომელსაც მიმაგრებული აქვს auth შუამავალი. ბუნებრივია მომხმარებლს კაბინეტში შესვლა შეუძლია მხოლოდ მაშინ, როდესაც მას აუტენტიფიკაცია გავლილი აქვს და სწორედ ამას ემსახურება ეს შუამავალიც. ამაში ადვილად დავრწმუნდებით თუ /dashboard გვერდზე შევალთ აუტენტიფიკაციის გარეშე. ასეთ შემთხვევაში სისტემა გადაგვამისამართებს /login გვერდზე.

დავაკვირდეთ app/Http/Kernel.php ფაილის შემდეგ ფრაგმენტს :

...

protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    
    ...
];

...
            

Auth ფასადი

user() მეთოდი

აუტენტიფიცირებული მომხმარებლის შესახებ ინფორმაციის მისაღებად უნდა მივმართოთ Auth ფასადს :
use Illuminate\Support\Facades\Auth;

// აუტენტიფიცირებული მომხმარებელი
$user = Auth::user(); // App\Models\User Object

// აუტენტიფიცირებული მომხმარებლის ID
$id = Auth::id(); // 6
            
user მეთოდი აბრუნებს აუტენტიფიცირებული მომხმარებლის ობიექტს, id მეთოდი კი აუტენტიფიცირებული მომხმარებლის იდენტიფიკატორს.

აუტენტიფიცირებულ მომხმარებელთან წვდომა შესაძლებელია Illuminate\Http\Request კლასის მეშვეობითაც :

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TestController extends Controller
{
    public function index(Request $request)
    {
        dd($request->user());
    }
}
            

check() მეთოდი

იმის დასადგენათ არის თუ არა აუტენტიფიცირებული მომხმარებელი, რომელიც აკეთებს HTTP მოთხოვნას, გამოიყენება Auth ფასადის check მეთოდი :
use Illuminate\Support\Facades\Auth;

if(Auth::check())
{
    echo 'აუტენტიფიცირებულია';
}
else
{
    return redirect()->route('login');
}
            
მიუხედავად იმისა, რომ ამ მეთოდით შესაძლებელია მომხმარებლის აუტენტიფიცირება/არააუტენტიფიცირების გადამოწმება, უკეთესი ვარიანტია თუ საჭირო მარშრუტებს შუამავლების მეშვეობით დავიცავთ ხოლმე და თუ მომხმარებელი ამ შუამავალს გაივლის, შესაბამისად აღარც იმის გადამოწმება დაგვჭირდება არის თუ არა იგი აუტენტიფიცირებული.

დაცული მარშრუტები

რიგ შემთხვევებში საჭიროა, რომ კონკრეტულ მარშრუტებთან წვდომა შეეძლოთ მხოლოდ აუტენტიფიცირებულ მომხმარებლებს. როგორც ზემოთ აღვნიშნეთ, ამისათვის გამოიყენება auth შუამავალი :
Route::get('/profile', function () {

    // მხოლოდ აუტენტიფიცირებული მომხმარებლები

})->middleware('auth');
            

არააუტენტიფიცირებული მომხმარებლების გადამისამართება

როდესაც auth შუამავალი დაადგენს, რომ მომხმარებელი არააუტენტიფიცირებულია, იგი მას გადაამისამართებს მარშრუტზე სახელად - auth. შეგვიძლია შევცვალოთ ეს მიდგომა, თუ ჩავერევით app/Http/Middleware/Authenticate.php შუამავლის redirectTo მეთოდში :
protected function redirectTo($request)
{
    return route('somewhere');
}
            

აუტენტიფიკაციის სამომხმარებლო სისტემა

როგორც ადრე აღვნიშნეთ, არსებობს აუტენტიფიკაციის სისტემის შექმნის რამდენიმე ვარიანტი და განვიხილეთ ერთ-ერთი მათგანი - Laravel Breeze. რა თქმა უნდა შესაძლებელია, რომ შევქმნათ ჩვენი საკუთარი სისტემაც. ამაში დაგვეხმარება, ისევ და ისევ, Auth ფასადი :
namespace App\Http\Controllers;

use App\Http\Controllers\Controller;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class LoginController extends Controller
{
    public function authenticate(Request $request)
    {
        $credentials = $request->validate([
            'email' => ['required', 'email'],
            'password' => ['required'],
        ]);

        if (Auth::attempt($credentials)) 
        {
            $request->session()->regenerate();

            return redirect()->intended('dashboard');
        }

        return back()->withErrors(['email' => 'არასწორი ელ_ფოსტა']);
    }
}
            
რა თქმა უნდა, საჭიროა მარშრუტის განსაზღვრაც და ვინაიდან აქამდე Laravel Breeze პაკეტს ვიყენებდით შევიტანოთ შესაბამისი ცვლილებები routes/auth.php ფაილშიც :
use App\Http\Controllers\LoginController;

Route::post('/login', [LoginController::class, 'authenticate'])->middleware('guest');
            
attempt მეთოდს პარამეტრად გადაეცემა მასივი, რომელშიც თავმოყრილია აუტენტიფიკაციისათვის საჭირო ინფორმაციები, ამ შემთხვევაში - ელ_ფოსტა და პაროლი (ინგ: Attempt - გასინჯვა, შემოწმება, გამოცდა, მცდელობა). ამის შემდეგ მონაცემთა ბაზაში მოიძებნება მომხმარებლის მიერ აკრეფილი ელ_ფოსტის შესაბამისი ჩანაწერი (email ველის მიხედვით). თუ ასეთი ჩანაწერი მოიძებნება მაშინ უკვე დარდება ამ ჩანაწერის password ველისა და მომხმარებლის მიერ აკრეფილი პაროლის მნიშვნელობები. როგორც ვიცით password ველში ჰეშირებული პაროლია შენახული, თუმცა ეს იმას არ ნიშნავს, რომ აუტენტიფიკაციისას ჩვენც უნდა დავჰეშოთ აკრეფილი პაროლი - სისტემა ამას ავტომატურარდ გააკეთებს. თუ პაროლიც დაემთხვა მაშინ მოხდება აუტენტიფიცირებული მომხმარებლის შესახებ ინფორმაციის სესიაში შენახვა. მეთოდი აბრუნებს ლოგიკურ მნიშვნელობას - true, თუ აუტენტიფიკაცია წარმატებულია, წინააღმდეგ შემთხვევაში ბრუნდება მნიშვნელობა - false.

intended მეთოდი მომხმარებელს გადაამისამართებს იმ მარშრუტზე, რომელთან წვდომასაც იგი ცდილობდა აუტენტიფიკაციამდე (ინგ: Intended - განზრახული, ჩაფიქრებული).

თუ გვსურს, რომ attempt მეთოდს დავუმატოთ სხვა გადასამოწმებელი პარამეტრებიც, უნდა მოვიქცეთ ასე :
if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) 
{
    // წარმატებული აუტენტიფიკაცია
}
            

მომხმარებლების დამახსოვრება

ალბათ ხშირად შეგვხვედრია აუტენტიფიკაციის ფორმები, რომლებსაც თან ახლავს 'დამიმახსოვრე' ღილაკი (remember me). იმისათვის რათა აპლიკაციაში გამოვიყენოთ ეს ფუნქციონალი attempt მეთოდს უნდა გადავცეთ ლოგიკური ტიპის დამატებითი პარამეტრი. true მნიშვნელობის შემთხვევაში სისტემა მომხმარებლის შესახებ ინფორმაციას სესიაში შეინახავს მანამ, სანამ თავად მომხმარებელი არ დააჭერს სისტემიდან გამოსვლის ღილაკს (logout). users ცხრილს თუ დავაკვირდებით, ვნახავთ, რომ იგი შეიცავს remember_token ველს. სწორედ ამ ველში შეინახება დამახსოვრებული მომხმარებლის შესაბამისი უნიკალური სტრიქონი.
use Illuminate\Support\Facades\Auth;

$remember = $request->has('remember');

if (Auth::attempt(['email' => $email, 'password' => $password], $remember)) 
{
    // მომხმარებელი დამახსოვრებულია ...
}
            
როდესაც მომხმარებელი აუტენტიფიკაციისას აწვება 'დამიმახსოვრე' ღილაკს, იკვრება მოქმედებათა შემდეგი ჯაჭვი : გენერირდება უნიკალური ჰეშირებული სტრიქონი, რომელიც ინახება როგორც ბრაუზერში (Cookie-ს სახით), ასევე სერვერზე ('users' ცხრილის 'remember_token' ველში), ამის შემდეგ თუ მომხმარებელი დახურავს და ისევ გახსნის ბრაუზერს, სისტემა გადაამოწმებს არსებობს თუ არა დამახსოვრებული ჰეშ-სტრიქონი Cookie-ში, თუ კი - მაშინ შეამოწმებს შეესაბამება თუ არა ეს სტრიქონი ბაზაში არსებულ რომელიმე ჩანაწერს და თუ ეს ასეა მაშინ მომხმარებელი ავტომატურად ხდება აუტენტიფიცირებული. Cookie-ში შენახული ინფორმაცია იარსებებს მანამ, სანამ მომხმარებელი არ გამოვა სისტემიდან (logout), უბრალოდ ბრაუზერის დახურვით ეს ინფორმაცია არ იშლება.

კონკრეტული მომხმარებლის ობიექტის აუტენტიფიკაცია

დავუშვათ გვაქვს app/Models/User კლასის კონკრეტული ობიექტი და გვსურს, რომ ამ ობიექტის შესაბამისი მომხმარებელი გახდეს აუტენტიფიცირებული სისტემაში. ამისათვის უნდა მივმართოთ Auth ფასადის login მეთოდს :
use App\Models\User;
use Illuminate\Support\Facades\Auth;

$user = User::find(1);

Auth::login($user);

Auth::login($user, $remember = true);
            
იმისათვის რათა login მეთოდმა იმუშავოს, საჭიროა, რომ მომხმარებლის ობიექტი დაკავშირებული იყოს Illuminate\Contracts\Auth\Authenticatable კონტრაქტთან, სწორედ ამას ემსახურება, Laravel-ში ნაგულისხმევად შექმნილი app/Models/User მოდელის შემდეგი ჩანაწერი :
namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    ...
}

            

აუტენტიფიკაცია იდენტიფიკატორის მეშვეობით

თუ გვსურს, რომ მომხმარებელს, იდენტიფიკატორის მეშვეობით გავატაროთ აუტენტიფიკაცია, უნდა მივმართოთ Auth ფასადის loginUsingId მეთოდს :
Auth::loginUsingId(1, $remember = true);
            

სისტემიდან გამოსვლა

იმისათვის რათა სესიიდან წაიშალოს ინფორმაცია აუტენტიფიცირებული მომხმარებლის შესახებ და შესაბამისად მომხმარებელიც გამოვიდეს სისტემიდან, უნდა მივმართოთ Auth ფასადის logout მეთოდს. რეკომენდებულია, რომ სისტემიოდან გამოსვლის შემდეგ მოვახდინოთ სესიის გასუფთავება და CSRF თოქენის ხელახალი გენერირება :
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

public function logout(Request $request)
{
    Auth::logout();

    $request->session()->invalidate();

    $request->session()->regenerateToken();

    return redirect('/');
}
            
24. მომხმარებელთა ავტორიზაცია
როგორც უკვე აღვნიშნეთ, მომხმარებელთა ავტორიზაცია არის პროცესი, რომლის დროსაც ხდება მომხმარებლის ხელმისაწვდომობის, უფლების ქონა/არქონის გადამოწმება ამა თუ იმ მოქმედებაზე. Laravel-ში შესაძლებელია შეიქმნას კონკრეტული ინსტრუმენტები, რომლებიც განსაზღვრავენ ამ ხელმისაწვდომობას. ამ ინსტრუმენტებს პირობითად დავარქვათ 'კონტროლიორები'.

როგორც წესი, კონტროლიორების განსაზღვრა ხდება ხოლმე Gate ფასადთან მიმართვით App\Providers\AuthServiceProvider პროვაიდერის boot მეთოდში. მაგალითისათვის შევქმნათ კონტროლიორი, რომელიც გადაწყვეტს აქვს თუ არა კონკრეტულ მომხმარებელს კონკრეტული სიახლის დარედაქტირების უფლება :

use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Gate;

public function boot()
{
    $this->registerPolicies();

    Gate::define('update-post', function (User $user, Post $post) {
        return $user->id === $post->user_id;
    });
}
            
კონტროლიორის გამოყენება ხდება Gate ფასადის allows და denies მეთოდების მეშვეობით. შევნიშნოთ, რომ კონტროლიორს პარამეტრად არ გადავცემთ აუტენტიფიცირებულ მომხმარებლს, რადგან ამას Laravel-ი ავტომატურად გააკეთებს :
namespace App\Http\Controllers;

use App\Http\Controllers\Controller;

use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;

class PostController extends Controller
{
    public function update(Request $request, Post $post)
    {
        if (! Gate::allows('update-post', $post)) 
        {
            abort(403);
        }

        // სიახლის განახლება ...
    }
}
            
თუ გვსურს, რომ კონკრეტულ ქმედებაზე გადავამოწმოთ, არა აუტენტიფიცირებული, არამედ სხვა მომხმარებლის უფლებები, მაშინ უნდა გამოვიყენიოთ Gate ფასადის forUser მეთოდი :
if (Gate::forUser($user)->allows('update-post', $post)) 
{
    // მომხმარებელს შეუძლია განაახლოს სიახლე ...
}

if (Gate::forUser($user)->denies('update-post', $post)) 
{
    // მომხმარებელს არ შეუძლია განაახლოს სიახლე ...
}
            
ასევე შესაძლებელია, რომ გადავამოწმოთ მომხმარებლის უფლებები ერთდროულად რამდენიმე ქმედებაზე. ამისათვის გამოიყენება Gate ფასადის any და none მეთოდები :
if (Gate::any(['update-post', 'delete-post'], $post)) 
{
    // მომხმარებელს შეუძლია სიახლის წაშლა ან რედაქტირება ... 
}

if (Gate::none(['update-post', 'delete-post'], $post)) 
{
    // მომხმარებელს არ შეუძლია სიახლის არც წაშლა და არც რედაქტირება ... 
}
            
25. ლოკალიზაცია (localization, lang)
ფრეიმვორკ laravel-ში გვხვდება, ტექსტების სხვადასხვა ენაზე გადათრგმნისათვის საჭირო, საკმაოდ მოსახერხებელი ფუნქციები. მათი დახმარებით მარტივად ხდება ჩვენი აპლიკაციის გამართვა რამდენიმე ენაზე ერთდროულად. ენობრივი სტრიქონები (სათარგმნი სტრიქონები) ინახება lang საქაღალდეში. აქვე უნდა შევქმნათ ქვე-საქაღალდეები თითოეული იმ ენისათვის, რომელზეც გვსურს ჩვენი პროექტის გადათარგმნა:
/lang
    /en
        messages.php
    /ka
        messages.php
            
ფრეიმვორკის დაინსტალირების შემდეგ ამ საქაღალდეში, ნაგულისხმეობის პრინციპით, იქმნება ლოკალიზაციის ერთადერთი საქაღალდე ინგლისური ენისათვის lang/en.

როგორც წესი, თითოეული ლოკალიზაცია ინახება საქაღალდეში, რომლის დასახელებაც ემთხვევა შესაბამისი ენის კოდს (მაგ: ინგლისური - en, ქართული - ka და ა.შ). ლოკალიზაციის ქვე-საქაღალდეებში ინახება ე.წ ფაილი ლექსიკონები, მათში აღწერილია კონკრეტული სტრიქონების თარგმანები კონკრეტულ ენაზე. ამ სტრიქონებს ეწოდებათ ენობრივი კონსტანტები. ფაილ ლექსიკონებში ბრუნდება უბრალო ასოციაციური მასივები, რომლის გასაღებებიც გადასათარგმნი სტრიქონებია, ხოლო ამ გასაღებთა მნიშვნელობები - ამ სტრიქონების თარგმანები შესაბამის ენაზე.

თითოეული ფაილი ლექსიკონი განკუთვნილია, პროექტის კონკრეტული ელემენტისათვის, მაგალითად ვალიდაციის ელემენტს აქვს თავისი ფაილი (validation.php), გვერდების გადანომრვის ელემენტს - თავისი (pagination.php), აუთენტიფიკაციის გვერდს - თავისი (auth.php) და ა.შ.

ლოკალიზაციისა და ფაილ-ლექსიკონის შექმნა

lang საქაღალდეში შევქმნათ ახალი ლოკალიზაცია ქართული ენისათვის : lang/ka. ამ ლოკალიზაციაში უნდა ჩავაკოპიროთ ის სტანდარტული ფაილ-ლექსიკონები, რომლებსაც ფრეიმვორკი ავტომატურად ქმნის ინსტალაციისას lang/en ლოკალიზაციაში, ეს ფაილებია : validation.php, pagination.php, auth.php და passwords.php. ამის გაკეთება აუცილებელია, იმდენად რამდენადაც, აოლიკაციის მუშაობისას, დიდი ალბათობით დაგვჭირდება იმ ელემენტებთან მუშაობა, რომლებთანაც ეს ლექსიკონებია დაკავშირებული.

ამის შემდეგ უბრალოდ უნდა გავხსნათ ახლადშექმნილ ლოკალიზაციაში არსებული ლექსიკონ-ფაილები და მათში აღწერილ მასივებში, გასაღებების მნიშვნელობები მივუთითოთ ქართულად.

ეს რაც შეეხებოდა უკვე არსებულ ლექსიკონ-ფაილებს. ახლა შევქმნათ საკუთარი ლექსიკონ-ფაილი და ვნახოთ თუ როგორ ხდება მისი გამოყენება, lang/ka საქაღალდეში შევქმნათ ფაილი - messages.php :
return [
    'welcome' => 'კეთილი იყოს თქვენი მობრძანება',
    'hello' => 'მოგესალმებით'
];
            
ლოკალიზაციის შექმნის შემდეგ საჭიროა config/app.php ფაილში აღწერილი ასოციაციური მასივის locale გასაღების მნიშვნელობის ჩასწორება : 'locale' => 'ka' ამავე მასივის fallback_locale გასაღებში მითითებულია ალტერნატიული ლოკალიზაციის დასახელება : 'fallback_locale' => 'en' ანუ თუ locale გასაღებში მითითებული ლოკალიზაცია რაიმე მიზეზის გამო მიუწვდომელი იქნება სისტემისათვის, მაშინ ფრეიმვორკი შეეცდება გამოიყენოს ალტერნატიული ლოკალიზაცია.

Lang ფასადი

Lang ფასადი შექმნილია ლოკალიზაციებთან და ფაილ-ლექსიკონებთან სამუშაოდ. ფასადს აქვს მეთოდი get, რომლის მეშვეობითაც ხდება საჭირო ენობრივი კონსტანტის თარგმანის მიღება :
use Lang;

$title = Lang::get('messages.welcome');
            
როგორც ვხედავთ, მეთოდს პარამეტრად გადაეცა ჯერ სასურველი ფაილ-ლექსიკონის (messages) დასახელება, შემდეგ კი იმ ენობრივი კონსტანტის დასახელება (welcome), რომლის გადათარგმნაც გვსურს და რომელიც ამავე ფაილშია აღწერილი.

Lang::get ჩანაწერი შეიძლება ჩაიწეროს უფრო მოკლედაც. შემდეგი ორი ჩანაწერი ერთმანეთის ტოლფასია :

$title = Lang::get('messages.welcome');
$title = trans('messages.welcome');
შეიძლება, მოხდეს ისე, რომ ენობრივი კონსტანტის თარგმანი იყოს დინამიური, მაგალითად სხვადსხვა შემთხვევაში შეიძლება დაგვჭირდეს სხვადასხვა ტექსტები : კეთილი იყოს თქვენი მობრძანება გიორგი
კეთილი იყოს თქვენი მობრძანება მარიამ
კეთილი იყოს თქვენი მობრძანება ცოტნე
ასეთ შემთხვევაში ენობრივი კონსტანტის თარგმნისას ორწერტილით უნდა გამოიყოს თარგმანის სტატიკური და დინამიური ნაწილები (ორწერტილის შემდეგ არ უნდა იყოს გამოტოვებული ადგილი), ჩვენს შემთხვევაში სტატიკურია ტექსტი - "კეთილი იყოს თქვენი მობრძანება", ხოლო სახელები დინამიურია :
return [
    'welcome' => 'კეთილი იყოს თქვენი მობრძანება :name',
    'hello' => 'მოგესალმებით'
];
            
ამის შემდეგ Lang ფასადის get მეთოდს, მასივის სახით, არგუმენტად უნდა გადავცეთ სასურველი სახელი :
use Lang;

$title = Lang::get('messages.welcome', array('name' => 'ვასო'));
             
იმის გასარკვევად აღწერილია თუ არა ესა თუ ის ენობრივი კონსტანტა ამა თუ იმ ფაილ-ლექსიკონში, გამოიყენება Lang ფასადის has მეთოდი, რომელსაც არგუმენტებად უნდა გადაეცეს საურველი ფაილ-ლექსიკონისა და ენობრივი კონსტანტის დასახელებები :
use Lang;

if(Lang::has('messages.welcome'))
{
    $title = Lang::get('messages.welcome', array('name' => 'ვასო'));
}
            

მიმდინარე ლოკალიზაციის განსაზღვრა

მიმდინარე ლოკალიზაციის დასადგენად გამოიყენება App ფასადის currentLocale და isLocale მეთოდები :
use Illuminate\Support\Facades\App;

$locale = App::currentLocale();

if (App::isLocale('ka')) 
{
    //
}