გადმოწერა


ძირითადი კონცეფციები



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

Laravel არის MVC პრინციპზე დაფუძნებული ფრეიმვორკი, მისი პირველი ვერსია შეიქმნა 2011 წელს (ავტ. Taylor Otwell).

ოფიციალური ვებ-გვერდია www.laravel.com

სწავლების პროცესი გაიყოფა სამ გლობალურ ნაწილად :

  1. თეორიული ნაწილი
  2. პრაქტიკული ნაწილი - მარტივი პროექტის შექმნა
  3. პრაქტიკული ნაწილი - შედარებით რთული პროექტის შექმნა

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

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

აღსანიშნავია რომ PHP ინტერპრეტატორი უნდა აკმაყოფილებდეს შემდეგ მოთხოვნებს:
  • PHP >= 7.0.0
  • OpenSSL PHP Extension
  • PDO PHP Extension
  • Mbstring PHP Extension
  • Tokenizer PHP Extension
  • XML PHP Extension

ინსტალაცია Homestead-თან ერთად

Homestead არის ფრეიმვორკის მუშაობისათვის აუცილებელი პროგრამული უზრუნველყოფების ნაკრები, სრულფასოვანი გარემო Laravel-თან სამუშაოდ. შინაარსობრივად Homestead არის ვირტუალური მანქანა, ანუ "ცალკე" კომპიუტერი ჩვენს კომპიუტერში :)) Homestead-ის გასამართავად დაგვჭირდება შემდეგი პროგრამული უზრუნველყოფები:
  1. VirtualBox - სივრცე, ბუფერი ვირტუალური მანქანის ფორმირებისათვის. შექმნილია კორპორაცია Oracle-ს მიერ.
  2. Vagrant - ანუ Ruby ენაზე დაწერილი სკრიპტების ნაკრები, რომელიც ახდენს ვირტუალურ მანქანასთან მუშაობის ავტომატიზაციას. ეს არის ვირტუალურ მანქანასთან VirtualBox-თან სამუშაო ბრძანებათა ველების ინტერფეისი (cmd).
  3. Git - ანუ ვერსიათა კონტროლის სისტემა, იგი საჭიროა იმდენად რამდენადაც Homestead გარემოს სრულფასოვანი მუშაობისათვის აუცილებელია Github სერვისების კლონირება, კლონირებისათვის კი რა თქმა უნდა ხელსაყრელია ბრძანებათა ველების შესაბამისი ინტერფეისის გამოყენება.

VirtualBox

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

Vagrant

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

Git

Git-ის გადმოწერა შესაძლებელია ოფიციალური გვერდიდან. ინსტალაცია მიმდინარეობს სტანდარტულად, ყოველგვარი სირთულეებისა და განსაკუთრებულობების გარეშე. უბრალოდ ინსტალაციის პროცესში შესაძლებელია დაგვჭირდეს MS NET ფრეიმვორკის განახლება.

ამ საფეხურების გავლის შემდეგ პროგრამული უზრუნველყოფების დაინსტალირება დასრულებულია. ამის შემდეგ ჩვენს კომპიუტერში უნდა დავამატოთ ვირტუალური მანქანის ნიმუში, მაგალითი, ე.წ "box" - ი. ამისათვის ვინდოუსის ბრძანებათა სტანდარტული ველიდან (cmd) უნდა გავუშვათშემდეგი ბრძანება

vagrant box add laravel/homestead ამის შემდეგ დაიწყება აღნიშნული ბოქსის გადმოწერა, ამ პროცესს დაჭირდება საკმაო დრო რადგან ბოქსისათვის აუცილებელია ერთი გბ სივრცე მყარ დისკზე. გადმოწერის დასაწყისში სისტემა შეგვეკითხება თუ რომელ ვირტუალურ მანქანასთან ვმუშაობთ



ჩვენს შემთხვევაში ეს არის Virtualbox, ანუ ვკრეფთ 2-იანს და ვაწვებით ენთერს. პროცესის წარმატებით დასრულების შემთხვევაში უნდა ვიხილოთ დაახლოებით შემდეგნაირი შეტყობინება box: Successfully added box 'laravel/homestead' (v3.1.0) for 'virtualbox'! გადმოწერილი ბოქსის ნახვა შესაძლებელია შემდეგ მისამართზე C\Users\User\.vagrant.d\boxes აღნიშნული ბოქსი მოიცავს შემდეგ პროგრამულ უზრუნველყოფებს
  • Ubuntu 16.04 (ოპერაციული სისტემა)
  • Git (ვერსიათა კონტროლი)
  • PHP 7.1 (PHP ინტერპრეტატორი)
  • Nginx (UNIX ოპერაციულ სისტემებთან მომუშავე ვებ-სერვერი)
  • MySQL
  • MariaDB
  • Sqlite3
  • PostgreSQL
  • Composer
  • Node (With Yarn, Bower, Grunt, and Gulp)
  • Redis
  • Memcached
  • Beanstalkd
  • Mailhog
  • ngrok
ინსტალაციის შემდეგ ეტაპზე უნდა მოვახდინოთ Github Homestead რეპოზიტორის კლონირება, ეს არის Homestead გარემოსთან სამუშაო ბრძანებათა ველების ინტერფეისი. ამ შემთხვევაში windows-ის cmd აღარ გამოგვადგება, ამისათვის დაგვჭირდება Git-ის cmd. პირველ რიგში "cd" Git cmd ბრძანების მეშვეობით უნდა გადავინაცვლოთ იმ საქაღალდეში სადაც ჩვენი პროექტი განთავსდება, მაგალითად: cd C:\site რეპოზიტორის კლონირება კი ხდება შემდეგი ბრძანებით: git clone https://github.com/laravel/homestead.git Homestead ამის შემდეგ თუ C:\site საქაღალდეში შევალთ დაგვხვდება საქაღალდე Homestead.

ამის შემდეგ ისევ "cd" ბრძანების მეშვეობით უნდა გადავიდეთ Homestead საქაღალდეში და გავუშვათ შემდეგი ბრძანება (Windows ოს-ის შემთხვევაში):

init.bat ეს ბრძანება Homestead საქაღალდეში შექმნის კონფიგურაციულ ფაილს - Homestead.yaml, რომელსაც გამოვიყენებთ Homestead გარემოს კონფიგურაციული პარამეტრების განსასაზღვრავად (აქ მივუთითებთ პროექტის დომეინებს, მივუთითებთ ჩვენი კომპიუტერის რეალურ საქაღალდეებს, რომლებიც სინქროლულად უნდა შეესაბამებოდნენ ვირტუალური მანქანის ანალოგიურ საქაღალდეებს და ა.შ).

ორიოდ სიტყვით .yaml გაფართოების შესახებ

YAML ფორმატით შექმნილ ფაილში ინფორმაცია შეტანილია ადამიანისათვის გასაგები ფორმატით, იგი გამოიყენება მონაცემთა წაკითხვისა და ჩაწერისათვის პროგრამირების სხვადასხვა ენების სპეციფიკაციიდან გამომდინარე. ასეთი ფაილების გამოყენება შესაძლებელია პროგრამირების შემდეგ ენებთან: C/C++, Ruby, Python, Java, Perl, C#, და PHP.

დავუბრუნდეთ ინსტალაციას :))

Homestead.yaml ფაილს ოდნავ მოგვიანებით დავუბრუნდებით. მანამდე კი უნდა დავაგენერიროთ ვირტუალურ მანქანასთან SSH პროტოკოლით წვდომის გასაღები.

ორიოდ სიტყვით SSH პროტოკოლის შესახებ

SSH (ინგლ. Secure Shell — «უსაფრთხო გარსი») — კრიპტოგრაფიული ინტერნეტ-პროტოკოლი რომელიც გამოიყენება ინტერნეტ-სერვისებთან უსაფრთხოდ სამუშაოდ.

დავუბრუნდეთ ინსტალაციას :))

SSH პროტოკოლით წვდომის გასაღების გენერირება ხდება შემდეგი ბრძანების მეშვეობით (ვიმყოფებით ისევ Homestead საქაღალდეში) ssh-keygen -t rsa -C "your@email.com"

ყურადრება !!!

Git cmd-მ არ გააკეთა გასაღების გენერირება , და ამოაგდო ასეთი შეცდომა: ssh-keygen' is not recognized as an internal or external command ... გენერირება გააკეთა Git bash-მა.

ბრძანების შედეგად შეიქმნება ორი ფაილი id_rsa და id_rsa.pub, მათი ნახვა შეგვიძლია შემდეგ მისამართზე

C:\Users\user\.ssh

დავუბრუნდეთ Homestead.yaml ფაილს

მისი შიგთავსი დაახლოებით ამდაგვარი იქნება:
---
ip: "192.168.10.10"
memory: 2048
cpus: 1
provider: virtualbox

authorize: ~/.ssh/id_rsa.pub

keys:
    - ~/.ssh/id_rsa

folders:
    - map: C:\site
      to: /home/vagrant/code

sites:
    - map: homestead.localhost
      to: /home/vagrant/code/public

databases:
    - homestead

# blackfire:
#     - id: foo
#       token: bar
#       client-id: foo
#       client-token: bar

# ports:
#     - send: 50000
#       to: 5000
#     - send: 7777
#       to: 777
#       protocol: udp

          
  • ip - ვირტუალური მანქანის ip მისამართი.
  • memory - ვირტუალური მანქანის მუშაობისას ხელმისაწვდომი მეხსიერების მოცულობა.
  • authorize - ვირტუალური მანქანასთან SSH პროტოკოლით წვდომის საჯარო გასაღებამდე გზა, აქ მითითებულია გზა იმ ფაილამდე, რომელიც შეიქმნა C:\Users\user\.ssh საქაღალდეში ბოლო ბრძანების გაშვებისას.
  • keys - ვირტუალური მანქანასთან SSH პროტოკოლით წვდომის დაფგარულ გასაღებამდე გზა, აქ მითითებულია გზა იმ ფაილამდე, რომელიც შეიქმნა C:\Users\user\.ssh საქაღალდეში ბოლო ბრძანების გაშვებისას.
  • folders - როგორც ადრე ვთქვით Homestead.yaml საქაღალდეში უნდა განვსაზღვროთ რეალურ კომპიუტერში არსებული პროექტის საქაღალდისა და ვირტუალურ მანქანაში არსებულ საქაღალდეს შორის კავშირი მათი სინქრონიზაციის მიზნით. ჩვენი რეალური საქაღალდე კი არის C:\site საქაღალდე, მისი შესაბამისი ვირტუალური საქაღალდე კი იქნება /home/vagrant/code საქაღალდე. C:\site ფაილში შეტანილი ნებისმიერი ცვლილება იქნება ეს ახალი საქაღალდისა თუ ფაილის შექმნა და ა.შ უნდა გავიმეოროთ მის ვირტუალურ პარტნიორშიც.
  • sites - აქ უნდა მივუთითოთ იმ პროექტების დომეინები რომლებთანაც ვაპირებთ მუშაობას, map განყოფილებაში ვუთითებთ დომეინს, ხოლო to განყოფილებაში ვუთითებთ ვირტუალური სისტემის გზას რომელზეც უნდა გადამისამართდეს მომხმარებელი აღნიშნულ დომეინზე შესვლისას.
ამ ყველაფრის შემდეგ ისღა დაგვრჩენია ცვლილებები შევიტანოთ Windows-ის ფაილში - hosts, რტომელიც მდებარეობს შემდეგ მისამართზე: C:\Windows\System32\drivers\etc ამ ფაილში უნდა ჩავამატოთ შემდეგი დამოკიდებულება : როგორც Homestead.yaml ფაილში ვხედავთ, ჩვენი მომავალი პროექტის დომეინი არის homestead.localhost, ხოლო ვირტუალური მანქანის ip მისამართი კი არის - 192.168.10.10, ე.ი ჩვენ გვინდა რომ ამ დომეინზე შესვლისას მომხმარებელი გადამისამართდეს ამ ip მისამართზე, ამიტომ hosts საქაღალდის ბოლოში ვამატებთ ასეთ ჩანაწერს 192.168.10.10 homestead.localhost ინსტალაციის კონფიგურაციული ეტაპი დასრულებულია, ახლა ისღა დაგვრჩენია გავუშვათ ვირტუალური მანქანა. ამისათვის Git bash-ით გადავდივართ C\site\Homestead საქაღალდეში და ვუშვებთ ბრძანებას: vagrant up ვირტუალური მანქანის პირველად ჩართვისას მოხდება სრულფასოვანი ვირტუალ-მანქანის ფორმირება და შემდეგ გაშვება, რომელიც შეინახება ცალკე საქაღალდეში (ამაზე ოდნავ მოგვიანებით ვისაუბებთ), ამიტომ ამ პროცესს დასჭირდება დრო. შემდეგ ჩართვებზე კი მოხდება ვირტუალ-მანქანის პირდაპირ გაშვება. ამის ცოდნა საჭიროა რადგანაც თუ დაფიქსირდება რაიმე შეცდომა, შეიძლება დაგვჭირდეს ბოლოს ფორმირებული მანქანის წაშლა და თავიდან ფორმირება, წაშლა ხდება შემდეგი ბრძანებით vagrant destroy --force თუ ახლა შევალთ შემდეგ მისამართზე homestead.localhost ბრაუზერში ვიხილავთ შემდეგ ტექსტს



ეს იმიტომ, რომ homestead.localhost დომეინზე შესვლით ჩვენ ფაქტიურად მივმართავთ ვირტუალური მანქანის /home/vagrant/code/public საქაღალდეს, მაგრამ ეს კატალოგი ჯერ არ არსებობს ისევე როგორც არ არსებობს /home/vagrant/code საქაღალდე. ამიტომ site საქაღალდეში ვქმნით code საქაღალდეს და მასში კი ვქმნით public საქაღალდეს. ამის შემდეგ თუ იგივე დომეინზე შევალთ უკვე ვნახავთ 403 შეცდომას რაც იმას ნიშნავს, რომ არ გვაქვს უფლება ვნახოთ კატალოგის შიგთავსი. ამის მოსაგვარებლად public საქაღალდეში შევქმნათ მაგალითად index.php ფაილი რაიმე მატივი კოდით
<?php
echo "This is a tast";
          
ამის შემდეგ კი იგივე დომეინზე შესვლისას უკვე ვიხილავთ index.php ფაილის შიგთავსს.

დაკავშირება phpmyadmin-თან

phpmyadmin-ის გადმოწერა შესაძლებელია ოფიციალური გვერდიდან. site საქაღალდეში შევქმნათ ახალი საქაღალდე - phpmyadmin და გადმოწერილი არქივი გავხსნათ მასში. როგორც ადრე აღვნიშნეთ იგივე ცვლილება უნდა მოვახდინოთ ვირტუალურ საქაღალდეშიც. როგორც ვიცით phpmyadmin არის ცალკე საიტი და ამიტომ Homestead.yaml ფაილის sites განყოფილებაში უნდა დავამატოთ ახალი დომეინი და ეს განყოფილება მიიღებს ასეთ სახეს
sites:
  - map: homestead.localhost
    to: /home/vagrant/code/public

  - map: phpmyadmin.localhost
    to: /home/vagrant/code/phpmyadmin
          
ამის შემდეგ კი უნდა განვაახლოთ ვირტუალური მანქანის კონფიგურაცია შემდეგი ბრძანებით vagrant provision ახლა hosts ფაილში ჩავამატოთ ახალი ჩანაწერი ახალი დომეინისათვის 192.168.10.10 phpmyadmin.localhost ახლა უკვე შეგვიძლია შევიდეთ phpmyadmin.localhost დომეინზე. თავად phpmyadmin-ში შესასვლელი პარამეტრები კი შემდეგია მომხმარებელი : homestead
პაროლი : secret

Laravel ინსტალაცია

ამის შემდეგ საჭიროა დავაინსტალიროთ თავად Laravel-ი. ამისათვის საჭიროა PHP ინტერპრეტატორი და Composer პაკეტ-მენეჯერი, რომლებიც, როგორც ადრე ვთქვით დაინსტალირებულია ვირტუალურ მანქანაში ამიტომ უნდა დავამყაროთ მასთან ssh პროტოკოლით წვდომა შემდეგი ბრძანებით (ვიმყოფებით ისევ Homestead-ში) vagrant ssh ამის შემდეგ გადავერთვებით ვირტუალური მანქანის ოპერაციულ სისტემა - Ubuntu-ში. აქ უკვე PHP ინტერპრეტატორთანაც გვაქვს წვდომა და Composer-თანაც ამის გადამოწმება შეგვიძლია შემდეგი ბრძანებებით php -v და composer -v ახლა უკვე შეიძლება მოვითხოვოთ Laravel-ის საინსტალაციო ფაილის გადმოწერა (და არა ინსტალაცია) ვირტუალურ მანქანაში შემდეგი ბრძანებით composer global require "laravel/installer" ამ ბრძანების შემდეგ ბრძანებათა ველში გამოჩნდება შემდეგი გზა home/vagrant/.config/composer ამის შემდეგ უნდა გავუშვათ Laravel-ის საინსტალაციო ბრძანება laravel new project_name ფრეიმვორკი დაინსტალირდება project_name საქაღალდეში, ეს დასახელება პირობითია და მის მაგივრად უნდა მივუთითოთ ჩვენი პროექტის სახელი, ასე რომ C:\site საქაღალდეში ვშლით ხელით შექმნილ პროექტის ფაილს და მას ვქმნით უკვე ბოლოს ნახსენები ბრძანების მეშვეობით. მაგრამ ბრძანება გამოიტანს ასეთ შეტყობინებას laravel: command not found ამის გამოსასწორებლად სოეციალური ცვლად - PATH-ში უნდა შევინახოთ ზემოთ ნახსენები გზა შემდეგი ბრძანებით export PATH="~/.config/composer/vendor/bin:$PATH" როგორც ვხედავთ ჩვენი სერვერის მთავარი კატალოგი "home/vagrant" ჩანაცვლებულია "~" სიმბოლოთი.

ამის შემდეგ უნდა გადავიდეთ ვირტუალურ კატალოგში - Code.

ახლა კი შესაძლებელია გავუშვათ ისევ ეს ბრძანება laravel new laravel ამის შემდეგ ფიზიკურ C:\site და ვირტუალურ /home/vagrant/code საქაღალდეებში შეიქმნება laravel საქაღალდე, რომელშიც დაინსტალირდება ფრეიმვორკი.

ბოლოს და ბოლოს ვეწვიოთ მისამართს :))

homestead.localhost

Laravel-ის ინსტალაცია Composer-ით XAMPP სისტემაში

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

რა არის Composer ?

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

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



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



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

ამის შემდეგ ბრძანებათა ველის მეშვეობით გადავდივართ C:\xampp\htdocs დირექტორიაში და ვუშვებთ Composer-ის ბრძანებას create-project-ს.

composer create-project --prefer-dist laravel/laravel laravel ბოლოს მითითებული სიტყვა laravel პირობითია და განსაზღვრავს ჩვენი პროექტის სახელს. ბრძანების გაშვების შემდეგ დაიწყება Laravel-ის ინსტალაცია და აგრეთვე შეიქმნება laravel დირექტორია პროექტის შესაბამისი ფაილებისა და საქაღალდეების სტრუქტურაით



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

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



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



აპლიკაციის გასაღები

შემდეგი ნაბიჯი რაც უნდა გავაკეთოთ Laravel-ის ინსტალაციის შემდეგ, არის აპლიკაციის გასაღების განსაზღვრა, რომელიც არის შემთხვევითი ტექსტი. php artisan key:generate თუ Laravel-ი Composer-ით დავაინსტალირეთ, გასაღები უკვე განსაზღვრული იქნება. გასაღების მითითება ხდება .env ფაილში. თუ აპლიკაციის გასაღები განსაზღვრული არ არის, მომხმარებელთა სესიები და სხვა დაშიფრული მონაცემები დაუცველი იქნება !
3. ფრეიმვორკის სტრუქტურა

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

App დირექტორია

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

Bootstrap დირექტორია

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

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

Config დირექტორია

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

Database დირექტორია

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

Public დირექტორია

ეს დირექტორია შეიცავს index.php ფაილს, რომელიც არის ჩვენ აპლიკაციაში შესასვლელი წერტილი, დირექტორია აგრეთვე შეიცავს ისეთ ხელსაწყო-ატრიბუტებს როგორებიცაა სურათები JavaScript და 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 დასახელება ენიჭება ნაგულისმეობის პრინციპით, სახელის გადარქმევა კი შესაძლებელია შემდეგი ბრძანებით hp artisan app:name <name-of-your-application>

Console დირექტორია

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

Exceptions დირექტორია

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

Http დირექტორია

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

Providers დირექტორია

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

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



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

წარმოდგენა

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



კონტროლერი

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



მოდელი

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



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

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



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

Laravel-ის მუშაობის სქემა





მომხმარებლის მიერ გაკეთებული ნებისმიერი მოთხოვნა მიემართება პროექტის ერთადერთი გლობალური შესავალი წერტილისაკენ - public/index.php ფაილისაკენ, ამის შემდეგ ეს ფაილი ტვირთავს Composer-ის მიერ შექმნილ კლასთა ავტოჩამტვირთველ vendor/autoload.php ფაილს require __DIR__.'/../vendor/autoload.php'; ავტოჩატვირთვისა და ყველა საჭირო პროცესის ინიციალიზაციის შემდეგ მოთხოვნა გადაეცემა მარშრუტიზატორს და ფრეიმვორკი ღებულობს გადაწყვეტილებას თუ რომელმა მარშრუტმა უნდა დაამუშაოს ესა თუ ის მოთხოვნა. მარშრუტმა მოთხოვნა შეიძლება გადასხეს კონკრეტულ კონტროლერს ან უბრალოდ ფუნქციას, თუ მოთხოვნა კონტროლერს გადეცემა, იგი ჩაატარებს შესაბამის სამუშაოებს (ინფორმაციის გადამოწმება ვალიდაცია და ა.შ) და თავის მხრივ მიმართავს მოდელს, თუ აუცილებელია მოდელი მიმართავს მონაცემთა ბაზას , ბაზა დაუბრუნებს მას პასუხს, მოდელი ამ პასუხს დაუბრუნებს კონტროლერს, კონტროლერი კი მიღებულ პასუხს გადასცემს წარმოდგენის შაბლონს, წარმოდგენის შაბლონი უზრუნველჰყოფს შედეგის ბრაუზერში გამოტანას. ხოლო თუ როუტერი მოთხოვნას არ გადასცემს კონტროლერს, არამედ გადასცემს ფუნქციას, მაშინ ეს ფუნქცია დაამუშავებს მოთხოვნას და შედეგს გადასცემს პირდაპირ წარმოდგენას.

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





გავხსნათ routes/web.php ფაილი. მასში მითითებულია მარშრუტები. დავინახავთ მთავარი გვერდის მარშრუტს:
Route::get('/', function () {
    return view('welcome');
});
            
'/' შაბლონი მიუთითებს პროექტის მთავარ გვერდზე. მარშრუტში მითითებულია მოთხოვნის დამმუშავებელი ფუნქცია, რომელიც თავის მხრივ იძახებს view('welcome') ფუნქციას, welcome არის იმწარმოდგენის შაბლონის სახელი, რომელიც უნდა გამოჩნდეს მთავარ გვერდზე. როგორც ვიცით, წარმოდგენის შაბლონები ინახება resources/views საქაღალდეში, თუ მას გავხსნით დავინახავთ ფაილს - resources/views/welcome.blade.php, სწორედ ეს ფაილი იტვირთება პროექტის მთავარ გვერდზე შესვლისას და მისი კოდი შემდეგნაირია:
<!DOCTYPE html>
<html>
   
   <head>
      <title>Laravel</title>
      <link href = "https://fonts.googleapis.com/css?family=Lato:100" rel = "stylesheet" 
         type = "text/css">
      
      <style>
         html, body {
            height: 100%;
         }
         body {
            margin: 0;
            padding: 0;
            width: 100%;
            display: table;
            font-weight: 100;
            font-family: 'Lato';
         }
         .container {
            text-align: center;
            display: table-cell;
            vertical-align: middle;
         }
         .content {
            text-align: center;
            display: inline-block;
         }
         .title {
            font-size: 96px;
         }
      </style>
   </head>
   
   <body>
      <div class = "container">
         
         <div class = "content">
            <div class = "title">Laravel 5</div>
         </div>
      
      </div>
   </body>

</html>
          

შევქმნათ ჩვენი პირველი გვერდი ფრეიმვორკში

მაგალითად შევქმნათ გვერდი "page", თუ ამ მომენტისათვის შევალთ შემდეგ მისამართზე http://127.0.0.1:8000/page სისტემა გვეტყვის, რომ გვერდი ვერ მოიძებნა (ჩემს შემთხვევაში პროექტი განთავსებულია ამ მისამართზე - http://127.0.0.1:8000, თქვენ უნდა გამოიყენოთ თქვენი მისამართი იმისდამიხედვით თუ როგორ და რა გზით გამართეთ სისტემა).

პირველ რიგში ჩავამატოთ ახალი მარშრუტი routes/web.php ფაილში:

Route::get('/page', function () {
    return view('page');
});
          
ამის შემდეგ შევქმნათ წარმოდგენის ახალი ფაილი resources/views/page.blade.php და შევიტანოთ მასში რაიმე ტექსტი, თუ ახლა ვეწვევით იგივე მისამართს http://127.0.0.1:8000/page ბრაუზერში ვიხილავთ page.blade.php ფაილში აკრეფილ ტექსტს. ანუ ფრეიმვორკმა URL მისამართიდან ამოიღო სეგმენტი რომელიც მოდის მთავარი გვერდის შემდეგ http://127.0.0.1:8000/page შემდეგ შევიდა routes/web.php ფაილში და გადაამოწმა შექმნილია თუ არა მარშრუტი ამ დასახელებისათვის, ჩვენ ეს მარშრუტი შექმნილი გვაქვს და ამიტომაც გამოიტანა შესაბამისი მარშრუტის შესაბამისი ფუნქციით გამოძახებული შესაბამისი წარმოდგენა : resources/views/page.blade.php, თუ რატომ ემატება page სიტყვას .blade.php ბოლოსართი, ამის შესახებ ვისაუბრებთ მოგვიანებით.
5. ფრეიმვორკის კონფიგურაციის გამართვა
ფრეიმვორკ Laravel-ს, ინსტალაციის შემდეგ თითქმის არ ჭირდება დამატებით რაიმე კონფიგურაციული პარამეტრების განსაზღვრა, თუმცა არის ისეთი პარამეტრებიც, რომლებიც უნდა განვსაზღვროთ, მაგალითად მონაცემთა ბაზასთან დაკავშირების პარამეტრები, შეიძლება დაგვჭირდეს დროის სარტყელის მითითებაც და ა.შ. როგორც უკვე ვიცით, კორფიგურაციული პარამეტრების განსაზღვრა ხდება config დირექტორიაში არსებული ფაილების მეშვეობით.

პროექტის კეთების ეტაპი შესაძლებელია დავყოთ სამ ნაწილად: პირველ ეტაპზე ვმუშაობთ ლოკალურ სივრცეში, ეს შეიძლება იყოს OpenServer, Virtualbox, XAMPP და ა.შ, მეორე ეტაპზე ხდება პროექტის ტესტირება, სავარაუდო შეცდომების გასწორება და ა.შ, მესამე ეტაპზე კი პროექტი იტვირთება უკვე რეალურ ჰოსტინგზე ანუ ეშვება სამუშაო გარემოში. შევთანხმდეთ, რომ სამივე ეტაპზე, კონფიფურაციული პარამეტრების სხვადასხვაგვარად განსაზღვრაა საჭირო , მაგალითად მბ-სთან დასაკავშირებელი პარამეტრები სულ სხვაა ლოკალურ სივრცეში და სულ სხვა იქნება რეალურ სერვერზე. ამიტომ იმ პარამეტრთა ჯგუფის მიხედვით, რომელთა შეცვლაც საჭიროა მუშაობის პროცესის ეტაპებიდან გამომდინარე, შეიძლება მოვახდინოთ კონფიგურაციული პარამეტრების ერთგვარი არეების, გარემოების ფორმირება. ამ გარემოში შემავალ პარამეტრებს ეწოდებათ გარემოს ცვლადები , რომლებიც ინახება .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=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

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=

          
  • APP_NAME - აპლიკაციის დასახელება.
  • APP_ENV - ანუ სამუშაო გარემო (Application Environment), აპლიკაციის კეთების პროცესის მიმდინარე ფაზა, ეტაპი, მასზეა დამოკიდებული ყველა სხვა პარამეტრის მნიშვნელობა.
  • APP_KEY - ამ პარამეტრში შენახულია შემთხვევითი ტექსტი, რომელიც გამოიყენება ფრეიმვორკის მუშაობის პროცესში, სხვადასხვა მონაცემების დასაშიფრად.
  • APP_DEBUG - შეცდომების გამოტანის პარამეტრი, თუ მითითებულია მნიშვნელობა true მაშინ სისტემა გამოიტანს დაფიქსირებული შეცდომის შესახებ შეტყობინებას, ხოლო თუ მითითებულია false მაშინ არ გამოიტანს. პროექტის შექმნის ეტაპზე სასურველია ეს პარამეტრი იყოს ჩართული, ხოლო სამუშაო გარემოში კი - გამორთული.
  • DB განყოფილება - მოიცავს მონაცემთა ბაზასთან სამუშაოდ აუცილებელ პარამეტრებს.
  • CACHE_DRIVER - კეშირების სისტემის პარამეტი.
  • SESSION_DRIVER - სესიებთან სამუშაო პარამეტრი.
  • REDIS განყოფილება - REDIS-თან სამუშაო პარამეტრები. (REDIS - remote dictionary server : «გასაღები — მნიშვნელობა» ფორმატის ინფორმაციის შესანახი საცავი, მონაცემთა ბაზის მართვის სისტემა ღია წყაროთი.)
  • MAIL განყოფილება -ელ_ფოსტასთან დაკავშირებული პარამეტრები.
ამ ფაილში შესაძლებელია განვსაზღვროთ ჩვენი საკუთარი პარამეტრებიც, ადვილი მისახვედრია, რომ ფაილში აღწერილი კონფიგურაციული პარამეტრები მრგებულია ჩვენს სერვერზე, სამუშაო გარემოზე და სისტემაზე, მაგრამ თუ ვმუშაობთ ჯგუფთან ერთად სავარაუდოდ ჯგუდის სხვა წევრებსაც ექნებათ უკვე თავიანთ სისტემაზე მორგებული .env ფაილი, არადა აუცილებელია, რომ ყველა პროგრამისტს გააჩნდეს წვდომა ყველა სხვა პროგრამისტის .env ფაილთან, ამისათვის გამოიყენება .env.example ფაილი, მასში უნდა შევინახოთ ჩვენი სისტემიდან გამომდინარე დაფიქსირებული კონფიგურაციული პარამეტრები ჩვენს მიერ დამატებულ პარამეტრებთან ერთად, ჯგუფის სხვა წევრებიც თავის მხრივ გააკეთებენ იგივეს. (.env ფაილში ვერ ნახავენ რაც გავაკეთე ?? :| )

config საქაღალდე

app.php ფაილი

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

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

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

ფრეიმვორკ Laravel-ის კონსოლი

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



თუ რომელიმე ბრძანების სინტაქსთან დაკავშირებით გაგვიძნდება კითხვა, უნდა ავკრიფოთ შემდეგი ბრძანება php artisan help command_name
6. მარშრუტის შექმნის მეთოდები HTTP მოთხოვნების მიხედვით
მანამ სანამ ფრეიმვორკ Laravel-ის მარშრუტიზატორების შესწავლაზე გადავალთ, გავარკვიოთ თუ რა არის URI, URL და URN

URI

იშიფრება როგორც Uniform Resource Identifier, ანუ მუდმივი წყაროს იდენტიფიკატორი, წყაროში იგულისხმება ნებისმიერი ელემენტი, რომელსაც შეიძლება მიმართოს მომხმარებელმა: საიტის რომელიმე გვერდი, სურათი css სტილი და ა.შ. კონკრეტული მაგალითი: http://domen.ge/articles/internet/article.html URI შედგება ორი ნაწილისაგან : URL და URN.

URL

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

URN

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

ორიოდ სიტყვით HTTP მოთხოვნების შესახებ

ზოგადად რომ ვთქვათ HTTP (HyperText Transfer Protocol) პროტოკოლი აღწერს მომხმარებლის კომპიუტერსა და სერვერს შორის ურთიერთქმედებას, ეს ურთიერთქმედება მოიცავს მომხმარებლის მიერ გაგზავნილ მოთხოვნას (request) და სერვერიდან მიღებულ პასუხს (response). მოთხოვნის ზოგადი სინტაქსი ასეთია METHOD URI HTTP_VERSION კონკრეტული მაგალითი კი ასეთი POST /test/demo_form.php HTTP/1.1
Host: w3schools.com
name1=value1&name2=value2




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

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(){

});
          
ამ ფუნქციის ტანში შესაძლებელია ნებისმიერი კოდის ჩაწერა. მაგალითად ეკრანზე გამოვითანოთ ფრეიმვორკის კონფიგურაციის რომელიმე პარამეტრის მნიშვნელობა, კონფიგურაციასთან წვდომისათვის უნდა გამოვიყენოთ config ფუნქცია, არგუმენტად კი უნდა გადავცეთ შესაბამისი კონფიგურაციული ჯგუფის დასახელება და შემდეგ წერტილით გამოყოფილი სასურველი პარამეტრის დასახელება. (კონფიგურაცუიული ჯგუფები მოთავსებულია config საქაღალდეში). ვთქვათ გვინდა 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="Nname"><br />
    <input type="text" name="lname" placeholder="Last Nname"><br />
    <input type="submit" name="send" value="send"> 
  </form>
</body>
</html>            
          
ახლა დავწეროთ შესაბამისი მარშრუტი:
Route::post('/comments' , function(){
  print_r($_POST);
});
          
თუ ახლა შევალთ შემდეგ მისამართზე your_domain.com/comments ბრაუზერში ვიხილავთ შეტყობინებას, რომ გვერდი ვერ მოიძებნა რადგან ჩვენ მარშრუტი დავწერეთ post მეთოდისათვის და არა get მეთოდისათვის, მაგრამ თუ შევალთ შემდეგ მისამართზე your_domain.com/form.html მაშინ ვიხილავთ შესაბამის ფორმას რომელიც ინფორმაციას გზავნის your_domain.com/comments გვერდზე.

ყურადღება !

ფორმის გაგზავნის შემდეგ ბრაუზერში შესაძლებელია ვიხილოთ შემდეგი შეტყობინება The page has expired due to inactivity. ეს მოხდა CSRF (Cross-Site Request Forgery) ვერიფიკაციის გამო, ანუ სისტემამ ჩათვალა, რომ გვერდის მოთხოვნა მოხდა არსწორი სახით და პრინციპში ეს ასეც არის. ამის მოსაგვარებლად app/Http/Middleware/VerifyCsrfToken.php საქაღალდეში უნდა ჩავამატოთ შემდეგი გამონაკლისი
protected $except = [
  '/comments'
];
          
ამის შემდეგ კი your_domain.com/form.html ფორმის გაგზავნის შემდეგ გადავალთ your_domain.com/comments გვერდზე სადაც ვიხილავთ გლობალურ ცვლად $_POST-ში მოქცეულ იმ ინფორმაციას, რომელიც ფორმაში ავკრიფეთ.

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

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

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

იმისათვის რათა მარშრუტი შეესაბამებოდეს ნებისმიერი ტიპის მოთხოვნას ერთდროულად, უნდა გამოვიყენოთ Route ფასადის any მეთოდი
Route::any('/comments' , function(){
  print_r($_POST);
});
          
7. მარშრუტთა პარამეტრები
აქამდე განხილულ მაგალითსებში მარშრუტებს პირველ პარამეტრად გადავცემდით URI-ს კონკრეტულ ნაწილს, მუდმივ, სტატიკურ სტრიქონს, მაგრამ ხშირად შეიძლება მოხდეს, რომ დაგვჭირდეს ცვალებადი, დინამიური პარამეტრების გადაცემაც, მაგალითად ბაზაში მოთავსებული სტატიებიდან ერთ-ერთის სტატიის id. ცვლადი პარამეტრის გადაცემის სინტაქსი ასეთია:
Route::get('/page/{id}' , function(){
  
});
          
ანუ ფარამეტრები ექცევა ფიგურულ ფრჩხილებში. შესაძლებელია ერთდროულად რამოდენიმე პარამეტრის გადაცემაც
Route::get('/page/{category}/{id}' , function(){
  
});
          
თუ ახლა შევალთ შემდეგ მისამართზე your_domain.com/page ვიხილავთ შეტყობინებას, რომ გვერდი ვერ მოიძებნა, მაგრამ თუ შევალთ ამ მისამართზე your_domain.com/page/10 ყველაფერი რიგზე იქნება.

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

Route::get('/page/{id}' , function($id){
  echo $id;
});
          
როგორც ზემოთ აღვნიშნეთ, შესაძლებელია მარშრუტს მიეთითოს რამოდენიმე ცვლადი პრამეტრი, აქ უნდა გავითვალისწინოთ ერთი ფაქტი: პარამეტრები ფუნქცია დამმუშავებელსაც იმავე თანმიმდევრობით უნდა გადავცეთ რა თანმიმდევრობითაც მარშრუტში აღვწერთ მათ. ფუნქცია ამ პარამეტრებს სწორედ თანმიმდევრობიდან გამომდინარე აღიქვვამს და არა ცვლადთა დასახელებებიდან.
Route::get('/page/{category}/{id}',function($category,$id){
  echo "category - "  . $category. '<br>';
  echo "id - "  . $id;
});
          
თუ ახლა შევალთ შემდეგ მისამართზე your_domain.com/page/cars/10 ბრაუზერში ვიხილავთ შემდეგ ტექსტს category - cars
id - 12
ახლა მარშრუტი გადავაკეთოთ ასე
Route::get('/page/{category}/{id}',function($id,$category){
  echo "category - "  . $category. '<br>';
  echo "id - "  . $id;
});
          
ბრაუზერში ვიხილავთ შემდეგ ტექსტს category - 12
id - cars
ამ მაგალითებში მარშრუტს ვუთიტებდით ისეთ პარამეტრებს, რომელთა განსაზღვრაც აუცილებელი იყო, მაგრამ შეიძლება განისაზღვროს მარშრუტი, ისეთი მოთხოვნისათვის რომელიც შეიძლება შეიცავდეს ან არ შეიცავდეს პარამეტრს, ასეთ შემთხვევაში პარამეტრის მითითებისას მას ეწერება კითხვის ნიშანი, ხოლო ფუნქცია დამმუშავებელს კი ეს პარამეტრი გადეცემა ნაგულისმევი მნიშვნელობით - null
Route::get('/page/{id?}',function($id=null){
  
});
          
ამ შემთხვევაში უშეცდომოდ შევალთ your_domain.com/page გვერდზეც და your_domain.com/page/10 გვერდზეც.

მეთოდი where

შეიძლება მოხდეს ისე, რომ დაგვჭირდეს ცვლადი პარამეტრის ტიპის გაფილტვრა, მაგალითად id პარამეტრის მნიშვნელობა უნდა იყოს მხოლოდ და მხოლოდ რიცხვითი ტიპის, ამაში დაგვეხმარება რეგულარული გამოსახულებები და where მეთოდი, მისი გამოყენების სინტაქსი ასეთია:
Route::get('/page/{id}',function($id){
  echo $id;
})->where('id','[0-9]+');
          
ანუ სისტემას ვეუბნებით, რომ id პარამეტრი უნდა იყოს ციფრი და იგი შეიძლება მეორდებოდეს მრავალჯერ (ამას აღნიშნავს რეგ. გამოსახულებაში არსებული "+" ნიშანი), რადგან id შეიძლება იყოს 5-იც და 345343-იც. ასეთ შემთხვევაში შემდეგ მისამართზე შესვლა
 your_domain.com/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-ს გააჩნდეს საერთო ფრაზა, საერთო სეგმენტი, მაგალითად domain.com/application/administrator/index.php
domain.com/application/administrator/home.php
domain.com/application/administrator/create.php
domain.com/application/administrator/edit.php
domain.com/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). შიდა ბმულების შექმნისას საკმაოდ ხელსაყრელია მარშრუტებზე სახელის დარქმევა და შემდეგ ამ სახელების გამოყენება. მაგალითისათვის მთავარი გვერდის მარშრუტს დავარქვათ სახელი "home"
Route::get('/', ['as'=>'home' , function () {
    return view('welcome');
}]);
          
სახელის დარქმევა შესაძლებელია ასეც
Route::get('/',  function () {
    return view('welcome');
})->name('home');
          
ახლა კი შევქმნათ გვერდი რომლიდანაც გადმოვმისამართდებით მთავარ გვერდზე, ან შევქმნათ ბმული ამ გვერდზე რომლის მეშვეობითაც გადავალთ მთავარ გვერდზე. სახელდებული მარშრუტის უბრალოდ გამოტანა მოხდება ასე
Route::get('/test',function(){
  echo route('home');  // http://127.0.0.1:8000
});
          
გადამისამართება კი ასე:
Route::get('/test',function(){
  return redirect()->route('home');
});
          
დავუშვათ გვაქვს ცვლადპარამეტრიანი მარშრუტი
Route::get('/article/{id}',['as'=>'article',function($id){
  echo $id;
}]);
          
"test" გვერდიდან ამ გვერდზე გადასამისამართებელი სინტაქსი იქნება ასეთი
Route::get('/test',function(){
  return redirect()->route('article',array('id'=>25));
});
          
8. კონტროლერები
ამ ეტაპზე ჩვენ უკვე ვიცით მარშრუტის შექმნა და მის დამმუშავებელ ფუნქციასთან მუშაობა, მაგრამ შევთანხდეთ, რომ თუ დამმუშავებლის კოდი საკმაოდ დიდი იქნება და მარშრუტებიც ბევრი გვექნება, ამ ყველაფრის ერთ ფაილში წერა მოუხერხებელი იქნება და საჭირო გახდება მარშრუტთა დამმუშავებლების ცალკე ფაილებში გატანა. ამაში დაგვეხმარება კონტროლერები. კონტროლერები ინახება app/Http/Controllers საქაღალდეში. ამ საქაღალდეში, ნაგულისმეობის პრინციპით შექმნილია ერთი კონტროლერი Controller.php ეს არის ჩვენი აპლიკაციის საბაზისო კონტროლერი, ე.წ მშობელი კონტროლერი, რომლის მემკვიდრეებიც უნდა იყვნენ ის კონტროლერები, რომლებსაც მომავალში შევქმნით.

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

კონტროლერის დასახელება უნდა ემთხვეოდეს იმ კლასის დასახელებას, რომელსაც ამ კონტროლერში აღვწერთ. შევქმნათ კონტროლერი FirstController.php
<?php

class FirstController extends Controller
{
  
  
}
          
ახლა განსაზღვროთ კონტროლერის namespace ანუ სახელთა სივრცე
<?php

namespace App\Http\Controllers

class FirstController extends Controller
{
  
  
}
          
თუ ვქმნით კლასს, რომელიც არის სხვა კლასის მემკვიდრე, მაშინ ამ მშობელ კლასთანაც უნდა გვქონდეს წვდომა
<?php

namespace App\Http\Controllers
use App\Http\Controllers\Controller;

class FirstController extends Controller
{
  
  
}
          
ახლა შევქმნათ მარშრუტი, რომელსაც დაამუშავებს შექმნილი კონტროლერი Route::get('/about','FirstController@about'); ანუ მარშრუტს მეორე პარამეტრად მივუთითეთ კონტროლერის დასახელება შემდეგ გამომყოფი სიმბოლო @ და შემდეგ კონტროლერის იმ მეთოდის დასახელება, რომელმაც უნდა დაამუშავოს ეს მარშრუტი, შევქმნათ კონტროლერის შესაბამისი მეთოდი და მას გამოვატანინოთ მაგალითად თავად მეთოდის დასახელება
<?php

namespace App\Http\Controllers;
use App\Http\Controllers\Controller;

class FirstController extends Controller
{
  
  public function about()
  {
    echo __METHOD__;
  }
}
          
your_domain/about მისამართზე შესვლისას ბრაუზერში გამოჩნდება შემდეგი ტექსტი App\Http\Controllers\FirstController::about მივაქციოთ ყურადღება, რომ მარშრუტის განსაზღვრისას კონტროლერის დასახელება მივუთითეთ namespace-ს ანუ ადგილთა სივრცის გარეშე, საქმე იმაშია, რომ სერვის-პროვაიდერ RouteServiceProvider.php-ში აღწერილია დახურული(protected) მეთოდი : $namespace = 'App\Http\Controllers'; და ფრეიმვორკი ავტომატურად ამატებს ამ სივრცეს იმ კლასის სახელს, რომელსაც მარშრუტის განსაზღვრისას ვუთითებთ.

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

რაც შეეხება ცვალებად პარამეტრიან მარშრუტებს, მაგალითად გვაქვს მარშრუტი Route::get('/about/{id}','FirstController@about'); იმისათვის რათა მარშრუტის დამმუშავებელი კონტროლერის მეთოდში გვქონდეს წვდომა ცვალებად პარამეტრთან, ეს პარამეტრი მეთოდს უნდა გადავცეთ არგუმენტის სახით
public function about($id)
{
  echo $id;
}
          

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

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




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

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

შევქმნათ შუამავალი კლასი ფრეიმვორკის კონსოლის - artisan-ის მეშვეობით php artisan make:middleware MiddlewareName შევქმნათ შუამავალი კლასი სახელად Mymiddleware php artisan make:middleware Mymiddleware მისი ნახვა შესაძლებელია app/Http/Middleware საქაღალდეში.
<?php

namespace App\Http\Middleware;

use Closure;

class Mymiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        return $next($request);
    }
}

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

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

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

Route::get('/article/{page}','ArticleController@test'); ჩავამატოთ შესაბამისი ლოგიკა შუამავალ კლასში
<?php

namespace App\Http\Middleware;

use Closure;

class Mymiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if($request->route('page') != 'pages')
        {
            return redirect()->route('home');
        }
        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,
    'mymiddle' => \App\Http\Middleware\Mymiddleware::class
];
          
ჩვენი შუალედური კლასის ფსევდონიმია mymiddle, მივამაგროთ იგი მარშრუტს Route::get('/article/{page}','ArticleController@test')->middleware('mymiddle'); მარშრუტზე რამოდენიმე შუალედური კლასის მიმაგრება კი ხდება ასე Route::get('/article/{page}','ArticleController@test')->middleware('mymiddle','secondmiddk'); შუამავალი კლასის მიმაგრება შესაძლებელია მარშრუტის დამმუშავებელ კონტროლერშიც, მეთოდი კონსტრუქტორის მეშვეობით
public function __construct()
{
  $this->middleware('mymiddle');
}            
          
10. წარმოდგენის შაბლონები
წარმოდგენა არის MVC შაბლონის ერთ-ერთი ელემენტი, რომელიც უზრუნველჰყოფს ინფორმაციის ბრაუზერში გამოტანას. წარმოდგენის ფაილები ინახება resources/views საქაღალდეში. წარმოდგენის შაბლონში არ შეიძლება მოთავსდეს კოდის ისეთი ნაწილი, რომელიც უზრუნველჰყოფს მაგალითად ინფორმაციის ამოღებას მბ-დან, ამ ინფორმაციის დამუშავებას და ა.შ.

მთავარი გვერდის წარმოდგენა გავმართოთ ასე:

მარშრუტი

Route::get('/','IndexController@index');
          

კონტროლერი

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class IndexController extends Controller
{
    public function index()
    {
      return view('welcome');
    }
}
          
დავუშვათ resources/views საქაღალდეში გავაკეთეთ ახალი საქაღალდე templates და წარმოდგენის ფაილები გადავიტანეთ მასში, მაშინ წარმოდგენის მოთხოვნის სინტაქსი იქნება შემდეგნაირი return view('templates.welcome'); ამ თავში ვისაუბრებთ წარმოდგენებზე, რომლებიც იმუშავებენ შაბლონიზატორ blade-ს გარეშე. blade შაბლონიზატორზე ვისაუბრებთ შემდეგ თავში.

resources/views საქაღალდეში შევქმნათ ახალი საქაღალდე templates და მასში გავაკეთოთ წარმოდგენის ახალი ფაილი template.php, რომელშიც შევიტანთ Bootstrap ფრეიმვორკის რაიმე მარტივ კოდს. შესაბამისად გადავაკეთოთ 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');

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 მეთოდის დასახელება პრეფიქსად ერთვის ცვლადის დიდი ასოთი დაწყებულ სახელს, შემდეგ კი ფრხილებში ეთითება ცვლადის მნიშვნელობა.

წარმოდგენის ფაილების გასაფორმებლად უნდა გამოვიყენოთ 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'))
  {
    $view = view('templates.template')->withTitle('Hello World');
    return $view;
  }
}            
          

view()->file()

როგორც ვიცით წარმოდგენის ფაილებს აქამდე ვიძახებდით უშუალოდ view ფუნქციიდან და არ ვუთითებდით ფაილების გაფართოებას. view ფუნქციის მიერ შექმნილი ობიექტის კიდევ ერთი მეთოდი არის file(), მისი მეშვეობით შესაძლებელია წარმოდგენის ფაილების ჩატვირთვა უშუალოდ ფაილთა დასახელებების მეშვეობით. მეთოდს უნდა გადაეცეს სრული გზა საჭირო ფაილამდე, ჩნდება კითხვა : როგორ გავიგოთ მარტივად სრული გზა ფაილამდე ? გავხსნათ ფაილი config.view.php ამ ფაილში ინახება ფრეიმვორკ Laravel-ის წარმოდგენათა პარამეტრები. ფაილში ბრუნდება ასოციაციური მასივი სადაც მითითებულია სულ ორი პარამეტრი, ჩვენ გვაინტერესებს მასივის შემდეგი ელემენტი
'paths' => [
    resource_path('views'),
]
          
რომელიც განსაზღვრავს საქაღალდეს სადაც ინახება წარმოდგენის ფაილები.

კონფიგურაციულ პარამეტრებთან წვდომისათვის გამოიყენება მეთოდი config(), მას პარამეტრად უნდა გადავცეთ კონფიგურაციის იმ განყოფილების დასახელება, რომელიც გვჭირდება. ანუ ამ შემთხვევაში უნდა გადავცეთ view.php განყოფილება გაფართოების გარეშე , შემდეგ კი მივუთითოთ კონფიგურაციის საჭირო პარამეტრის დასახელება, ჩვენს შემთხვევაში paths

$path = config('view.paths'); როგორც config.view.php ფაილში ვხედავთ paths ელემენტი თავის მხრივ თავის თავში მოიცავს ერთელემენტიან მასივს, ჩვენ გვჭირდება ამ მასივიწს პირველი ელემენტი, ამიტომ file() ფუნქცია უნდა ჩავწეროთ ასე $path = config('view.paths');
return view()->file($path[0].'/templates/template.php')->withTitle('Hello World');
(ეს ყველაფერი ალბათ იმიტომ გაკეთდა, რომ config() ფუნქციის გამოყენება გვესწავლა, თორემ ამდენ წვალებას ნაღდად ჯობია ხელით მიუთითო ბოლო-ბოლო ეს გზა)

view()->render()

ხანდახან საჭიროა ჭარმოდგენის ფაილში არსებული კონტენტის ცვლადში შენახვა. ამისათვის გამოიყენება view ფუნქციის მიერ შექმნილი ობიექტის კიდევ ერთი მეთოდი render(), რომელიც შაბლონის კონრენტს აბრუნებს სტრიქონის სახით. (ingl: Render - წარმოდგენა, გარდაქცევა, გარდაქმნა, გამოსახვა, წარმოსახვა, გამოხატვა). $view = view('templates.template')->withTitle('Hello World')->render();
echo $view;
11. შაბლონიზატორი Blade (ნაწილი 1)
ამ თავში ვისაუბრებთ შაბლონიზატორ blade-ზე, რომელიც ჩაშენებულია Laravel-ის ფუნქციონალიტეტში. შაბლონიზატორი ეს არის სპეციალური მექანიზმი, რომელიც გამოიყენება შაბლონის კონკრეტულ ადგილებზე ინფორმაციის მისამაგრებლად და გვერდის საბოლოო იერსახის ჩამოსაყალიბებლად. თავის მხრივ წარმოდგენა არის PHP ფაილი, რომელშიც აღწერილია HTML კოდი და აგრეთვე სპეციალური ნიშნულები რომელთა ნაცვლადაც უნდა ჩაჯდეს პროექტის ლოგიკური ნაწილიდან მოსული ინფორმაციები. blade შაბლონიზატორში არ უნდა ეწეროს PHP კოდი. იმდენად რამდენადაც გვერდის გაფორმებისათვის აუცილებელი ყველანაირი ლოგიკა ჩანაცვლებულია სპეციალური ნიშნულებითა და შაბლონიზატორის კონსტრუქციებით, რომელთა გადათარგმნა და ლოგიკის კოდით ჩანაცვლება ხდება კომპილაციის დროს.



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

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

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

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

მაშ ასე, ჩვენი ძირითადი შაბლონი განთავსებულია შემდეგ მისამართზე resources/views/teplates. ამ შაბლონიდან ამოვიღოთ ის ნაწილები რომლებიც საერთოა ყველა გვერდისათვის და მოვათავსოთ ცალკე ფაილებში. შაბლონიზატორის სპეციალური დირექტივების მეშვეობით კი ამ ფაილებს ჩავსვამთ პროექტის ნებისმიერ ადგილას. მაგალითისათვის განვაცალკევოთ საიტის ზედა მენიუ.

შაბლონიზატორ blade-ს ინსტრუქციის მისათითებლად გამოიყენება @ სიმბოლო. ანუ თუ მითითებულია ეს სიმბოლო, ეს იმას ნიშნავს, რომ შემდეგ მოდის შაბლონიზატორის დირექტივა. სექციების განსასაზღვრავად კი გამოიყენება დირექტივა section. დირექტივის სინტაქსი ასეთია

@section{'navbar'}
...
@endsection
@section('navbar')
<nav class="navbar navbar-inverse navbar-fixed-top">
  <div class="container">
      <div class="navbar-header">
          <a class="navbar-brand" href="#">WebSiteName</a>
      </div>
      <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>
  </div>
</nav>
@endsection
          
თუ ახლა გვერდს დავარეფრეშებთ მენიუ არ გამოჩნდება, ეს იმიტომ რომ ჩვენ იგი მოვათავსეთ სექციაში სახელად navbar მაგრამ არ მიგვითითებია ამ სექციის გამოსატანი დირექტივა, რომელიც არის შემდეგი: yield
@section('navbar')
<nav class="navbar navbar-inverse navbar-fixed-top">
  <div class="container">
      <div class="navbar-header">
          <a class="navbar-brand" href="#">WebSiteName</a>
      </div>
      <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>
  </div>
</nav>
@endsection
@yield('navbar')
          
yield დირექტივის მეშვეობით navbar სექციის ჩასმა შესაძლებელია გვერდის ნებისმიერ ადგილას.

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

@endsection
@yield('navbar')
ჩანაწერის მაგივრად შეიძლება გამოვიყენოთ დირექტივა - show, რომელიც ერთდროულად არის @section('navbar') სექციის დამხურავიც და გამომტანიც.

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

resources/views/teplates საქაღალდეში გავაკეთოთ ახალი საქაღალდე layouts, ამ საქაღალდეში გადავიტანოთ ამ მომენტისათვის არსებული ერთადერთი შაბლონი template.blade.php და გადავარქვათ მას სახელი layout.blade.php რათა ადვილი მნისახვედრი იყოს რომ ეს არის მაკეტი. resources/views/teplates ში შევქმნათ ახალი ფაილი index.blade.php, ეს იქნება ჩვენი პროექტის მთავარი გვერდის შაბლონი, რომელიც გამოიყენებს layout.blade.php მაკეტში ანუ მშობელ მაკეტში აღწერილ ფუნქციონალს.

იმისათვის რათა index.blade.php შვილობილ შაბლონში, გამოვიტანოთ ძირითადი შაბლონის (layout.blade.php) კონტენტი index.blade.php გვერდზე უნდა მივმართოთ შემდეგ დირექტივას

@extends('default.layouts.layout') ამ ჩანაწერით განვსაზღვრეთ შვილობილი შაბლონის მემკვიდრეობითობა. თუ ახლა გავხსნით პროექტს, ბრაუზერში ვიხილავთ layout.blade.php შაბლონში აღწერილ შიგთავსს. შესაძლებელია გაჩნდეს კითხვა : რა აზრი აქვს ცალკე შაბლონიზატორში კონტენტის სექციებად დაყოფასა და აღწერას, თუ შემდეგ რომელიმე კონკრეტულ გვერდზე ისევ ამ შაბლონიდან მოგვაქვს ყველანაირი ინსტრუქცია ? არ ჯობია პირდაპირ საჭირო გვერდზე აღვწეროთ ყველაფერი ?, საქმე იმაშია, რომ შიგთავსის მშობელ შაბლონში აღწერა გვაძლევს შვილობილ, ანუ მემკვიდრე შაბლონებში, ამ შიგთავსის თავიდან აღწერის საშუალებას, მაგალითად layout.blade.php ფაილში აღწერილი გვაქვს სექცია navbar
@section('navbar')
<nav class="navbar navbar-inverse navbar-fixed-top">
  <div class="container">
      <div class="navbar-header">
          <a class="navbar-brand" href="#">WebSiteName</a>
      </div>
      <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>
  </div>
</nav>
@endsection
@yield('navbar')
        
დავუშვათ დაგვჭირდა რომ მთავარ გვერდზე ეს სექცია გამოვიტანოთ სხვა სახით. შვილობილ შაბლონში შევიტანოთ შემდეგი ცვლილება
@extends('default.layouts.layout')
  @section('navbar')
  hello
@endsection          
          
თუ ახლა გვერდს დავარეფრეშებთ, ვნახავთ რომ მთავარი მენიუს მაგივრად საიტის თავზე გამოჩნდება წარწერა 'hello', რადგან შვილობილ შაბლონში შესაბამისი სექცია თავიდან აღვწერეთ.

თუ გვსურს, რომ კონკრეტული სექციის თავიდან განსაზღვრისას მშობელ შაბლონში აღწერილი შიგთავსიც მოხვდეს და კიდევ დამატებითი, მიმდინარე გვერდისათვის საჭირო ინფორმაციაც, მაშინ უნდა მივმართოთ @parent დირექტივას

@extends('default.layouts.layout')
  @section('navbar')
  @parent
  hello
@endsection          
          

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

ძირითად შაბლონში აღვწეროთ სექცია content დირექტივა yield დირექტივის მეშვეობით (ინგ: Yield - წარმოება, მზადება, კეთებ, მოცემა ჩაბარება).
@yield('content')     
          
ეს ჩანაწერი ნიშნავს, რომ ამ ადგილას უნდა მოხდეს content სექციის ჩადგმა, აქედან გამომდინარე ეს სექცია სადღაც უნდა განისაზღვროს, ეს უნდა მოხდეს საჭირო შვილობილ შაბლონში საჭირო ადგილას
@section('content')
  <div class="containerr">
    შიგთავსი მოთავსდება აქ
  </div>
@endsection 
          
როდესაც მიმდინარე კონტენტის კოდი საკმაოდ დიდია, უმჯობესია ეს კოდები გავიტანოთ ცალკე ფაილებში და შემდეგ ეს ფაილები საჭირო ადგილას გამოვიძახოთ include დირექტივის მეშვეობით (ინგ: Include - ჩასმა, მოთავსება, ჩართვა). default საქაღალდეში შევქმნათ ფაილი content და მასში აღვწეროთ სასურველი კონტენტი
<div class="containerr">
  შიგთავსი მოთავსდება აქ
</div>
          
ამის შემდეგ კი გამოვიძახოთ ეს ფაილი საჭირო ადგილას
@section('content')
  @include('default.content')
@endsection 
          
12. შაბლონიზატორი Blade (ნაწილი 2), პირობითი ოპერატორები და ციკლები
ამ თავში გავეცნობით შაბლონში ლოგიკის რეალიზებისათვის საჭირო კონსტრუქციებსა და დირექტივებს.

კონტროლერში აღწერილი ინფორმაციის გამოყენება შაბლონში

ამ მომენტისათვის ჩვენი საიტის მთავარი გვერდის კონტროლერს აქვს შემდეგი სახე
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class IndexController extends Controller
{
    public function index()
    {
      return view('welcome');
    }
}
          
კონტროლერის index მეთოდს დავამატოთ რაიმე სახის ინფორმაცია
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class IndexController extends Controller
{
    public function index()
    {
      $array = array(
        'title' => 'Laravel Project', 
        'data' => [
          'one' => 'list 1',
          'two' => 'list 2',
          'three' => 'list 3',
          'four' => 'list 4',
        ],
        'dataI' => ['list 1','list 2','list 3','list 4',],
        'bvar' => true,
        'script' => "<script>alert('Hello')</script>"
      );

      return view('welcome',$array);
    }
}
          
$array ცვლადის title ინდექსის მნიშვნელობა გამოვიყენოთ, ძირითად შაბლონში. როგორც ვიცით, კონკრეტული ცვლადის ეკანზე გამოტანის ერთ-ერთი ვარიანტი PHP-ში არის შემდეგი ჩანაწერი <?php echo $title; ?> შაბლონიზატორთან მუშაობისას კი ცვლადის გამოტანა ხდება შემდეგი სინტაქსით {{ $title }} ცვლადის დასახელების შემდეგ წერტილმძიმის მითითება არ არის საჭირო. ასეთი სინტაქსით შესაძლებელია არამარტო ცვლადთა მნიშვნელობების გამოტანა არამედ ნებისმიერი PHP ფუნქციის დაბეჭდვაც {{ date('y-m-d') }} როგორც ზემოთ მოყვანილ მაგალითში ვხედავთ მასივის ერთ-ერთი ელემენტი არის შემდეგნაირი <script>alert('Hello')</script>, რა მოხდება თუ ამ ელემენს გამოვიტანთ {{ }} ინსტრუქციით ? {{ $script }} // შედეგი იქნება <script>alert('Hello')</script> ანუ ჯავასკრიპტის კოდი არ შესრულდება, ეს იმიტომ რომ შაბლონიზატორის ეს ინსტრუქცია, ნაგულისხმეობის პრინციპით, გადაცემულ მნიშვნელობებს ამუშავებს PHP-ს htmlentities() ფუნქციის მეშვეობით, ანუ ყველა html სიმბოლოს ჩანაცვლება ხდება შესაბამისი ნიშნულებით და html კოდი გარდაიქმნება სტრიქონად.

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

{!! $script !!} // შედეგად მართლაც გამოვა შეტყობინების ფანჯარა

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

{{ jsVar }} ეს ჩანაწერი მიგვიყვანს შეცდომამდე რადგან შაბლონიზატორი ეძებს რაიმე PHP ფუნქციას ან ცვლადს რომელსაც ექნება სახელი jsVar, მაგრამ სინამდვილეში jsVar არის ჯავასკრიპტის ცვლადი, ასეთ შემთხვევაში უნდა გამოვიყენოთ შემდეგი ინსტრუქცია @{{ jsVar }}

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

ტერნარული ოპერატორი

დავუშვათ გვაქვს ასეთი ამოცანა : გამოვიტანოთ ცვლადი $bvar თუ ის არსებობს, წინააღმდეგ შემთხვევაში გამოვიტანოთ ცვლადი $title. როგორც ვიცით ამ ამოცანის გადაჭრა შესაძლებელია სტანდარტული PHP-ს ტერნარული ფუნქციის გამოყენებით {{ isset($bvar) ? $bvar : $title }} შაბლონიზატორი კი გვაძლევს საშუალებას ეს გამოსახულება ჩავანაცვლოთ უფრო მარტივი სინტაქსით {{ $bvar or $title }}

if ინსტრუქცია

@if(count($data) > 3)
  მასივი შეიცავს 3 ელემენტზე მეტს
@endif
          

else ინსტრუქცია

@if(count($data) > 3)
  მასივი შეიცავს 3 ელემენტზე მეტს
@else
  მასივი არ შეიცავს 3 ელემენტზე მეტს
@endif
          

elseif ინსტრუქცია

@if(count($data) > 3)
  მასივი შეიცავს 3 ელემენტზე მეტს
@elseif(count($data) > 10)
  მასივი შეიცავს 10 ელემენტზე მეტს
@else
  მასივი არ შეიცავს 3 ელემენტზე მეტს
@endif
          

ციკლები

for ციკლი

<ul>
@for($i = 0; $i < count($dataI); $i++)
  <li>{{ $dataI[$i] }}</li>
@endfor
</ul>
          

foreach ციკლი

<ul>
@foreach($data as $key=>$value)
  <li>{{ $key . '=>' . $value }}</li>
@endforeach
</ul>
          

forelse ციკლი

Laravel-ში გვხვდება ახალი ციკლი forelse რომელიც foreach-ის ანალოგიურია უბრალოდ აქვს დამატებითი დირექტივა empty. თუ forelse ციკლზე გადაცემული მასივი შეიცავს ერთ ელემენტს მაინც, მაშინ ციკლი მუშაობს, როგორც foreach, ხოლო თუ ეს მასივი ცარიელია მაშინ შესრულდება empty დირექტივის შემდეგ აღწერილი ინსტრუქცია
<ul>
@forelse($data as $key=>$value)
    <li>{{ $key . '=>' . $value }}</li>
  @empty
    <p>მასივი ცარიელია</p>
@endforelse
</ul>
          

while ინსტრუქცია

@while(true)
  // ....
@endwhile
          

each დირექტივა

ამ დირექტივას პირველ პარამეტრად უნდა გადაეცეს წარმოდგენის ფაილის დასახელება, მეორე პარამეტრად - მასივი რომელიც შეიცავს წარმოდგენის ამ ფაილზე მისამაგრებელ ინფორმაციას, ხოლო მესამე პარამეტრად - ცვლადის სახელი რომელიც გამოიყენება ინფორმაციის გადასაცემად. @each('default.list', $dataI, 'varName') each დირექტივა მუშაობს შემდეგნაირად: ტრიალდება ციკლი რომლის ყველა იტერაციაზეც $dataI მასივის მიმდინარე მნიშვნელობა ხვდება ცვლად $varName-ში, ეს ცვლადი კი თავის მხრივ გადაეცემა წარმოდგენის default.list ფაილს. ამ ფაილში $varName ცვლადის გამოძახება კი მოხდება შაბლონიზატორის სტანდარტული სინტაქსით {{ $varName }}
13. მოთხოვნის მიღება და დამუშავება, კლასი Request
აპლიკაციის გახსნის შემდეგ პირველი რაც ხდება ისაა, რომ აპლიკაცია ღებულობს ამა თუ იმ კონტენტის გამოტანის მოთხოვნას მომხმარებლისაგან. ამ თავში ვისაუბრებთ Request კლასის შესახებ, რომელიც წარმოადგენს მომხმარებლის მიერ გაგზავნილი მოთხოვნის აბსტრაქციას.

იმისათვის რათა მომხმარებელმა შეძლოს სხვადასხვა ტიპის HTTP მოთხოვნების (GET, POST) გაგზავნა, შევქმნათ კონტაქტის გვერდი ჩვეულებრივი HTML ფორმით. პირველ რიგში შევქმნათ შესაბამისი მარშრუტი

Route::match(['get','post'],'/contact',['uses'=>'Admin\ContactController@show','as'=>'contact']); ამის შემდეგ შევქმნათ კონტროლერი App\Http\Controllers\Admin\ContactController.php
<?php
namespace App\Http\Controllers\Admin;

use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;

class ContactController extends Controller
{
    public function show()
    {
      return view('default.contact', ['title'=>'Contacts']);
    }
}
          
და ბოლოს - შევქმნათ წარმოდგენის ფაილი contact.blade.php
<div class="col-md-9">
    <form method="post" action="{{ route('contact') }}">
      {{ csrf_field() }} <!-- იმის შესახებ თუ რას ნიშნავს ეს ჩანაწერი ვისაუბრეთ მე-6-ე თავში -->
      <div class="form-group">
          <label for="name">სახელი:</label>
          <input type="name" class="form-control" id="name" name="name">
      </div>
      <div class="form-group">
          <label for="pwd">Password:</label>
          <input type="password" class="form-control" id="pwd" name="password">
      </div>
      <button type="submit" class="btn btn-default">Submit</button>
  </form>
</div>
          
როგორც ვიცით, აპლიკაციაში შესავალი ძირითადი წერტილი არის public/index.php ფაილი. გავხსნათ იგი და დავაკვირდეთ შემდეგ ფრაგმენტს
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

$response->send();

$kernel->terminate($request, $response);
          
$kernel არის HTTP მოთხოვნების დამუშავებელი კლასის ობიექტი. ამის შემდეგ ვიძახებთ ამ ობიექტის მეთოდს - handle(), სწორედ ეს მეთოდი ახდენს მომხმარებლის მოთხოვნათა დამუშავებას. მეთოდს არგუმენტად გადაეცემა მოთხოვნის ობიექტი $request, რომელიც თავის მხრივ არის Request კლასის ეგზემპლიარი ობიექტი. Request კლასი განთავსებულია შემდეგ მისამართზე vendor/laravel/framework/src/Illuminate/http/Request.php

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

<?php
namespace App\Http\Controllers\Admin;

use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;

class ContactController extends Controller
{
    public function show(Request $request)
    {
      return view('default.contact', ['title'=>'Contacts']);
    }
}
          
წითლად მონიშნული ჩანაწერი გულისხმობს, რომ კონტროლერის მეთოდს გადავეცით პარამეტრად Request კლასის $request ობიექტი.

თუ მარშრუტს გადეცემა დამატებითი პარამეტრი, დავუშვათ არასავალდებულო პარამეტრი id

Route::match(['get','post'],'/contact/{id?}',['uses'=>'Admin\ContactController@show','as'=>'contact']); რასაკვირველია ეს პარამეტრი უნდა გადაეცეს კონტროლერის მეთოდსაც
public function show(Request $request, $id)
{
  return view('default.contact', ['title'=>'Contacts']);
}

          

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

all() მეთოდი

ეს მეთოდი აბრუნებს ასოციაციურ მასივს, რომლის ინდექსებიცაა html ფორმის ველთა დასახელებები, ხოლო ამ ინდექსების მნიშვნელობებია ველებში შეყვანილი ინფორმაციები
public function show(Request $request)
{
   print_r($request->all());
   return view('default.contact', ['title'=>'Contacts']);
}
          
ფორმის გაგზავნის შემდეგ თუ გავხსნით მიმდინარე გვერდის წყაროს შედეგად ვიხილავთ დაახლოებით შემდეგი სახის მასივს
Array
(
    [name] => vaso
    [password] => pass123
)
          

input() მეთოდი

ეს მეთოდი საშუალებას გვაძლევს გაგზავნილი ინფორმაციის შემცველი მასივიდან ამოვიღოთ კონკრეტული ველის მნიშვნელობა.
public function show(Request $request)
{
   echo $request->input('name');
   return view('default.contact', ['title'=>'Contacts']);
}
          
მეთოდს პარამეტრად უნდა გადაეცეს შესაბამისი ველის დასახელება (name ატრიბუტის მნიშვნელობა)

has() მეთოდი

მეთოდი აბრუნებს მნიშვნელობას - true თუ ფორმის გაგზავნის შემდეგ, გაგზავნილი ინფორმაციის შემცველი მასივი შეიცავს იმ ინდექსს, რომელსაც პარამეტრად გადავცემთ has() მეთოდს და ამასთანავე ამ ინდექსის მნიშვნელობა არ არის ცარიელი. წინააღმდეგ შემთხვევაში მეთოდი აბრუნებს მნიშვნელობას false.
public function show(Request $request, $id=False)
{
    if ($request->has('name'))
    {
      echo $request->input('name');
    }
    return view('default.contact', ['title'=>'Contacts']);
}
          
მეთოდს პარამეტრად უნდა გადაეცეს შესაბამისი ველის დასახელება (name ატრიბუტის მნიშვნელობა).

only() მეთოდი

ეს მეთოდი მუშაობს all მეთოდის ანალოგიურად, იმ განსხვავებით, რომ თუ ეს უკანასკნელი აბრუნებს გაგზავნილი ინფორმაციის შემცველი მასივის ყველა ინდექსსა და მათ მნიშვნელობებს, only მეთოდი აბრუნებს მხოლოდ იმ ინდექსებს, რომლებსაც პარამეტრებად გადავცემთ.
public function show(Request $request, $id=False)
{
    print_r($request->only('name'));
    return view('default.contact', ['title'=>'Contacts']);
}
          
მეთოდს პარამეტრად უნდა გადაეცეს შესაბამისი ველის დასახელება (name ატრიბუტის მნიშვნელობა)

except() მეთოდი

ეს მეთოდი არის all და only მეთოდების ერთფგვარი შებრუნებული მეთოდი :)) იგი აბრუნებს გაგზავნილი ინფორმაციის შემცველ მასივს იმ ინდექსების გამოკლებით, რომლებსაც პარამეტრებად გადავცემთ
public function show(Request $request, $id=False)
{
    print_r($request->except('name'));
    return view('default.contact', ['title'=>'Contacts']);
}
          
მეთოდს პარამეტრად უნდა გადაეცეს შესაბამისი ველის დასახელება (name ატრიბუტის მნიშვნელობა)

path() მეთოდი

ეს მეთოდი აბრუნებს URI-ს იმ ნაწილს, რომელიც შეიცავს მომხმარებლის მიერ გაკეთებული მოთხოვნის გზას, მაგალითად თუ URI არის http://127.0.0.1:8000/contact/121232, მეთოდი დააბრუნებს contact/121232 - ს.
public function show(Request $request, $id=False)
{
    echo $request->path(); 
    return view('default.contact', ['title'=>'Contacts']);
}
          

is() მეთოდი

ეს მეთოდი აბრუნებს მნიშვნელობას - true, თუ მომხმარებლის მიერ გაკეთებული მოთხოვნის შესაბამისი გზა (ანუ URI-ს ფრაგმენტი) ემთხვევა იმ შაბლონს, რომელსაც პარამეტრად გადავცემთ მეთოდს.
public function show(Request $request, $id=False)
{
    if ($request->is('contact/*'))
    {
      $request->path();
    }
    return view('default.contact', ['title'=>'Contacts']);
}
          
'contact/* შაბლონი გულისხმობს, რომ გზა უნდა შეიცავდეს contact/ ჩაბაწერს და მის შემდეგ ნებისმიერ რამეს.

url() მეთოდი

ეს მეთოდი აბრუნებს URI-ს GET პარამეტრების გარეშე, მაგალითად თუ URI არის http://127.0.0.1:8000/contact?345345, მეთოდი დააბრუნებს http://127.0.0.1:8000/contact - ს.

fullurl() მეთოდი

ეს მეთოდი აბრუნებს ბრაუზერის სამისამართო ველში არსებულ მთლიან მისამართს.

method() მეთოდი

ეს მეთოდი აბრუნებს მომხმარებლის მიერ გაკეთებული მოთხოვნის ტიპს სტრიქონული სახით (GET, POST).

isMethod() მეთოდი

ეს მეთოდი აბრუნებს მნიშვნელობას - true, თუ გაკეტებული მოთხოვნის ტიპი ემთხვევა არგუმენტად გადაცემული სტრიქონის მნიშვნეკლობას
public function show(Request $request, $id=False)
{
    if ($request->isMethod('get'))
    {
      echo $request->method();
    }
    return view('default.contact', ['title'=>'Contacts']);
}
          

flash() მეთოდი

იმის გარკვევის შემდეგ თუ რა ტიპისაა მომხმარებლის მიერ გაკეთებული მოთხოვნა, შესაძლებელია საჭირო გახდეს შეყვანილი ინფორმაციის გადამოწმება, ვალიდაცია. თუ ეს ინფორმაცია არ აკმაყოფილებს ვალიდაციის პირობებს და თუ ფორმაც მარტივია და შედგება რამოდფენიმე ველისაგან, მომხმარებელს უბრალოდ გადავამისამართებთ ისევ ფორმის გვერდზე, მაგრამ თუ ფორმა რთულია და შეიცავს ძალიან ბევრ ველებს, მაშინ ამ ველების თავიდან შევსება მოუწევს მას, რაც არც თუ ისე მოსახერხებელია. ამ პრობლემის გადასაწყვეტად გამოიყენება request ობიექტის flash() მეთოდი, რომელიც მოთხოვნის ტანში ჩადებულ ინფორმაციას ინახავს სესიაში.
public function show(Request $request, $id=False)
{
    if ($request->isMethod('post'))
    {
      // ვალიდაცია

      $request->flash();
    }
    return view('default.contact', ['title'=>'Contacts']);
}
          
იმისათვის რათა დავრწმუნდეთ, რომ ინფორმაცია ნამდვილად შეინახა სესიაში, ფორმის წარმოდგენის ფაილში სატესტოდ დავამატოთ შემდეგი ჩანაწერი
<pre>
  {{ print_r(Session::all()) }}
</pre>
          
ეკრანზე ვიხილავთ დაახლოებით ამდაგვარ ჩანაწერს
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
        (
            [_token] => xtLofMZlLR1b4oEZeT9YPr8SZiOzqfLrGof9huOj
            [name] => vaso
            [password] => pass123
        )

)
          
_token არის საიტის უსაფრთხოების გასაღები და მის შესახებ მოგვიანებით ვისაუბრებთ. რაც შეეხება _old_input უჯრას - იგი შეიცავს ბოლო მოთხოვნაში შესული ინფორმაციის შემცველ მასივს. ამ ინფორმაციასთან წვდომისათვის გამოიყენება სპეციალური ფუნქცია old(), ფორმის წარმოდგენის ფაილი გადავაკეთოთ ასე
<div class="col-md-9">
    <form method="post" action="{{ route('contact') }}">
      {{ csrf_field() }} <!-- იმის შესახებ თუ რას ნიშნავს ეს ჩანაწერი ვისაუბრეთ მე-6-ე თავში -->
      <div class="form-group">
          <label for="name">სახელი:</label>
          <input type="name" class="form-control" id="name" name="name" value="{{ old('name') }}">
      </div>
      <div class="form-group">
          <label for="pwd">Password:</label>
          <input type="password" class="form-control" id="pwd" name="password" value="{{ old('password') }}">
      </div>
      <button type="submit" class="btn btn-default">Submit</button>
  </form>
</div>
          
ამის შემდეგ თუ ფორმას გავაგზავნით ვნახავთ, რომ აკრეფილი ინფორმაცია არ დაიკარგება და ველები ავტომატურად შეივსება.

flush() მეთოდი

ეს მეთოდი შლის სესიაში შენახულ ინფორმაციას.

flashOnly() მეთოდი

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

flashExcept() მეთოდი

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

root() მეთოდი

ეს მეთოდი აბრუნებს საიტის დომეინს.

query() მეთოდი

ეს მეთოდი აბრუნებს get პარამეტრებიდან რომელიმე კონკრეტული პარამეტრის მნიშვნელობას. მაგალითად მიმდინარე URI არის შემდეგი : http://127.0.0.1:8000/contact?option=hello&send=ok
public function show(Request $request, $id=False)
{
    echo $request->query('send'); // შედეგი იქნება ok
    return view('default.contact', ['title'=>'Contacts']);
}
          
14. პასუხი სერვერიდან, კლასი Response
წინა თავში განვიხილეთ თუ როგორ ხდება მოთხოვნის მირება და დამუშავება. მოთხოვნის გაშვების შემდეგ ბუნებრივია სერვერიდან ბრუნდება პასუხი. ამ თავში განვიხილავთ თუ როგორ აკეთებს Laravel-ი ამას და რა სასუალებები არსებონს პასუხის რეალიზებისათვის.

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

class AboutController extends Controller
{
    public function index()
    {
       return "Hello";
       return view('default.about')->withTitle('Hello World');
    }
}
          
ანუ კონტროლერში უბრალოდ დავაბრუნეთ კონკრეტული შიგთავსი, ტექსტი და ამ შემთხვევაში სწორედ ეს ტექსტია about გვერდზე შესვლის შედეგად გაკეთებული მოთხოვნის პასუხი.

გავსხსნათ ფაილი public/index.php და დავაკვირდეთ შემდეგ ფრაგმენტს

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

$response->send();

$kernel->terminate($request, $response);
          

http მოთხოვნათა დამმუშავებელი $kernel იძახებს handle მეთოდს, რომელიც ახდენს გაკეთებული მოთხოვნის დამუშავებას. ეს მეთოდი კი აბრუნებს Response კლასის ობიექტს, რომელიც არის მოთხოვნათა პასუების აბსტრაქცია, განზოგადებული სახე. (Response კლასი განთავსებულია შემდეგ მისამართზე vendor/laravel/framework/src/Illuminate/http/Response.php). Response კლასი არის ამავა სახელწოდების მშობელი კლასის მემკვიდრე და იმისათვის რათა არ მოხდეს სახელთა კონფლიქტი მშობელს აქვს ფსევდონიმი BaseResponse.
            // ...

            use Symfony\Component\HttpFoundation\Response as BaseResponse;

            // ...
          
ეს მშობელი კლასი განთავსებულია შემდეგ მისამართზე Symfony/Component/HttpFoundation/Response.

გაგრძელება იქნება ... (როდისმე)

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

მბ მიგრაცია

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

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

როგორც ვიცით მბს კონფიგურაციული პარამეტრები ინახება config/database.php ფაილში. ეს ფაილი აბრუნებს მასივს რომელშიც აღწერილია სხვადასხვა პარამეტრები. 'default' => env('DB_CONNECTION', 'mysql'), ეს ჩანაწერი განსაზღვრავს თუ მონაცემთა ბაზის მართვის რომელ სისტემასთან ვმუშაობთ. ამავე ფაილში აღწერილია მბ-სთან დასაკავშირებელი პარამეტრები სხვადასხვა სისტემებისათვის. mysql-ისათვის ეს პარამეტრებია
'mysql' => [
    'driver' => 'mysql',
    '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' => '',
    'strict' => true,
    'engine' => null,
],
          
როგორც ვხედავთ ზოგიერთი პარამეტრის მნიშვნელობა ბრუნდება 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=tlaravel
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=
          
ახლა შევქმნათ მიგრაცია, ამისათვის, როგორც ვთქვით, დაგვჭირდება ფრეიმვორკის კონსოლი, გავხსნათ ბრძანებათა კონსოლი(cmd) და გავუშვათ ბრძანება php artisan make:migration create_articles_table ეს ბრძანება შექმნის მიგრაციის ახალ ფაილს - 2018_02_15_134021_create_articles_table.php, რომელშიც აღწერილი იქნება შესაბამისი კლასი. ფაილის დასახელებაში გარდა ჩვენს მიერ მითითებული სათაურისა დამატებულია მიმდინარე თარიღი და მიმდინარე დროის ნიშნული. მიგრაციების ფაილების ნახვა შესაძლებელია შემდეგ მისამართზე 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->increments('id'); // id ველი იქნება : INT, AUTO_INCREMENT, PRIMARY KEY
        });
    }

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

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->increments('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
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('articles');
    }
}
          

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

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

ყურადრება !!!

შესაძლებელია ამ ბრძანების შედეგად ვიხილოთ შემდეგი შეცდომა: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes ამ პრობლემის გადასაჭრელ გზებს იპოვით აქ

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

იმისათვის რათა გავაუქმოთ ის შედეგები რაც ბოლოს გაშვებულმა მიგრაციამ მოგვცა უნდა გავუშვათ შემდეგი ბრძანება 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 migrate
          
16. ინფორმაციის შეტანა მბ-ში
ამ თავში განვიხილავთ ფრეიმვორკის მექანიზმს, რომელიც გამოიყენება მბ-ს საწყისი მონაცემებით შევსებისათვის. ეს ნექანიზმი აღწერილია შემდეგ ფაილში : database/seeds/DatabaseSeeder.php (ing: Seed წყარო, საწყისი). გარდა ამ ფაილში აღწერილი DatabaseSeeder კლასისა, შესაძლებელია რომ ჩვენც შევქმნათ ჩვენი საკუთარი კლასები, ფრეიმვორკის კონსოლის გამოყენებით. მაგალითისათვის შევქმნათ კლასი ArticlesSeeder, ამისათვის უნდა ავკრიფოთ ბრძანება php artisan make:seeder ArticlesSeeder შეიქმნება ფაილი database/seeds/ArticlesSeeder.php
use Illuminate\Database\Seeder;

class ArticlesSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        //
    }
}
          
როგორც ვხედავთ კლასი ArticlesSeeder არის Seeder კლასის მემკვიდრე და მას გააჩნია მეთოდი run(), ამ მეთოდში აღწერილი ინსტრუქციები შესრულდება მაშინ, როცა გავუშვებთ ჩვენს მიერ შექმნილ მექანიზმს. ამ მეთოდში აღვწეროთ მბ-ს ცხრილში ინფორმაციის შესატანი ინსტრუქციები, მართალია ჯერ არ ვიცით თუ როგორ უნდა ვიმუშავოთ მბ-სთან (ამაზე ვისაუბრებთ შემდეგ თავში) მაგრამ ოდნავ გავუსწროთ მოვლენებს და მოვიყვანოთ მარივი მაგალითი.
public function run()
{
  // ვარიანტი 1
  DB::insert('INSERT INTO articles (name, text, img) VALUES(?,?,?)',
              [
                  'Blog Post 1',
                  'Blog Post testing post and its text',
                  'pic1.jpg'
              ]);

  // ვარიანტი 2, რამდენიმე ჩანაწერის დამატება ერთდროულად.
  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'
                ]
              ]

  );
 }
          
17. მუშაობა მბ-სთან, ფასადი DB

რა არის ფასადი ?

ფრეიმვორკ laravel-ში ფასადი არის ერთგვარი სტატიკური ინტერფეისი იმ კლასებისათვის, რომლებიც ხელმისაწვდომია ფრეიმვორკის ფარგლებში. Laravel-ში ჩაშენებულია სხვადასხვა ფასადები, რომლებიც გამოიყენება ფრეიმვორკის ფუნქციებთან წვდომისათვის. ფასადებში აღწერილია მოკლე სინტაქსი და საბაზისო მეთოდები, რომლებიც ავტომატურად გადაეცემა შესაბამის კლასებს და აღაა საჭირო მთელი რიგი ოპერაციებიც ჩატარება ყოველი ახალი კლასის გამოყენებისას, რაც ზოგადად სისტემა ძალიან მოქნილს ხდის. ფასადები განთავსებულია შემდეგ საქაღალდეში laravel/framework/src/Illuminate/Support/Facades

ფასადი DB

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

DB::select

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

use Illuminate\Http\Request;

use DB;

class AboutController extends Controller
{
    public function index()
    {
       $articles = DB::select("SELECT * FROM articles");
       dump($articles);
    }
}
          
დავამატოთ ფილტრი WHERE წინადადებას, მაგრამ მანამდე აღვნიშნოთ ერთი რამ : laravel-ი მბ-სთან მუშაობისას იყენებს PDO ინტერფეისს, რაც იმას ნიშნავს, რომ ბრძანებების მბ-ს გაშვება ხდება ბრძანებათა წინასწარგანსაზღვრის პრინციპით (პრეპარირებული განაცხადები). ასეთ შემთხვევაში select მეთოდს მეორე პარამეტრად, მასივის სახით უნდა გადავცეთ ის მნიშვნელობები, რომლებიც ჩაანაცვლებენ პრეპარირებული განაცხადის ნიშნულებს, მარკერებს
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB;

class AboutController extends Controller
{
    public function index()
    {
       $articles = DB::select("SELECT * FROM articles WHERE id=?", [2]);
       dump($articles);
    }
}
          
select მეთოდი ასრულებს მითითებულ ბრძანებას და ავტომატურად აბრუნებს შედეგთა ნაკრებს.

DB::insert

DB ფასადის insert მეთოდი გამოიყენება მბს ცხრილში ინფორმაციის შესატანად.
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB;

class AboutController extends Controller
{
    public function index()
    {
      DB::insert("INSERT INTO articles (name, text, img, alias) VALUES(?,?,?,?)", ['Article 4','Article 4 Text','img4.jpg','Alias 4']);
    }
}
          

DB::update

DB ფასადის update მეთოდი გამოიყენება მბს ცხრილში ინფორმაციის განახლებისათვის.
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB;

class AboutController extends Controller
{
    public function index()
    {
      $update = DB::update("UPDATE articles SET name=? WHERE id=?", ['First Article', 1]);
      echo $update; // 1
    }
}
          
ეს მეთოდი აბრუნებს ზემოქმედებული ჩანაწერების რაოდენობას.

DB::delete

DB ფასადის delete მეთოდი გამოიყენება მბს ცხრილში ჩანაწერების წასაშლელად.
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB;

class AboutController extends Controller
{
    public function index()
    {
      $delete = DB::delete("DELETE FROM articles WHERE id=?", [1]);
      echo $delete; // 1
    }
}
          
ეს მეთოდი აბრუნებს ზემოქმედებული ჩანაწერების რაოდენობას.

DB::statement

DB ფასადის statement მეთოდი გამოიყენება ისეთი ტიპის ბრძანებების შესასრულებლად, რომლებიც არც ამორჩევითი ტიპის ბრძანებათა ოჯახს (select) მიეკუთვნებიან და არც ცვლილებათა ტიპის ბრძანებათა ოჯახს (insert, delete, update). მაგალითად მბ-ცხრილის წასაშლელად ჩვენ დაგვჭირდება სწორედ statement მეთოდი.
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB;

class AboutController extends Controller
{
    public function index()
    {
      DB::statement("DROP TABLE articles");
    }
}
          
18. მბ მოთხოვნათა კონსტრუქტორი
ამ თავში განვიხილავთ მბ მოთხოვნათა კონსტრუქტორს, მოთხოვნათა კონსტრუქტორი არის სპეციალური კლასი Builder (ფსევდონიმიqueryBuilder ), რომელსაც გააჩნია კონკრეტული მეთოდები, რომელთაგან თითოეული უზრუნველჰყოფს მომავალი მოთხოვნის ტანის კონკრეტული ნაწილის ფორმირებას, ჩვენ აღარ გვიწევს მოთხოვნის ხელით დაწერა. აღნიშნული კლასი აღწერილია laravel/framework/src/Illuminate/Database/Builder.php ფაილში.

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

get მეთოდი

ეს მეთოდი იღებს ყველანაირ ინფორმაციას კონკრეტული ცხრილიდან და აბრუნებს ობიექტთა მასივს.
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB;

class ArticlesController extends Controller
{
    public function getArticles()
    {
      $articles = DB::table('articles')->get();
    }
}
          
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება "SELECT * FROM articles"

first მეთოდი

ეს მეთოდი იღებს პირველ ჩანაწერს კონკრეტული ცხრილიდან.
class ArticlesController extends Controller
{
    public function getArticles()
    {
      $articles = DB::table('articles')->first();
    }
}
          
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება "SELECT * FROM articles LIMIT 1"

value მეთოდი

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

pluck მეთოდი

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

count მეთოდი

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

max მეთოდი

ეს მეთოდი აბრუნებს მაქსიმალურ მნიშვნელობას განსაზღვრული ველისათვის, პარამეტრად უნდა გადაეცეს ველის დასახელება.
class ArticlesController extends Controller
{
    public function getArticles()
    {
      $articles = DB::table('articles')->max('id');
    }
}
          
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება "SELECT MAX('id') FROM articles"

select მეთოდი

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

where მეთოდი

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

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

class ArticlesController extends Controller
{
    public function getArticles()
    {
      $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 ოპერატორს უნდა დავუმატოთ მეოთხე არგუმენტი

class ArticlesController extends Controller
{
    public function getArticles()
    {
      $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 მეთოდზე მხოლოდ ერთი მიმართვითაც, ასეთ შემთხვევაში მას არგუმენტად უნდა გადაეცეს, მასივი რომელიც თავის თავში მოიცავს ფილტრის პირობების შემცველ ქვე-მასივებს
class ArticlesController extends Controller
{
    public function getArticles()
    {
      $articles = DB::table('articles')->select('id','name')
                       ->where([
                                  ['id','>',2],
                                  ['name','like','a%','or']
                               ])
                       ->get();
    }
}
          

whereBetween მეთოდი

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

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

groupBy მეთოდი

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

ყურადრება !!!

შესაძლებელია ამ ბრძანების შედეგად ვიხილოთ შემდეგი შეცდომა: Syntax error or access violation: 1055 'tlaravel.articles.id' isn't in GROUP BY (SQL: select * from `articles` group by `name`) ამ პრობლემის გადასაჭრელ გზებს იპოვით აქ

take მეთოდი

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

insert მეთოდი

როგორც ალბათ უკვე მივხვდით, ეს მეთოდი გამოიყენება მბს ცხრილში ინფორმაციის შესატანად, მას პარამეტრად უნდა გადაეცეს ის ინფორმაცია, რომლის შეტანაც გვსურს ცხრილში.
class ArticlesController extends Controller
{
    public function getArticles()
    {
      $articles = DB::table('articles')->insert(
                               [
                                       ['name' => 'test name', 'text' => 'test text'],
                                       ['name' => 'test name 1', 'text' => 'test text 1']
                               ]
                               );
    }
}
          
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ორი ბრძანება "INSERT INTO articles (name, text) VALUES ('test name', 'test text')"
"INSERT INTO articles (name, text) VALUES ('test name 1', 'test text 1')"
მეთოდი აბრუნებს TRUE მნიშვნელობას წარმატების შემთხვევაში, წინააღმდეგ შემთხვევაში ბრუნდება მნიშვნელობა FALSE.

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

update მეთოდი

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

delete მეთოდი

როგორც ალბათ უკვე მივხვდით, ეს მეთოდი გამოიყენება მბს ცხრილში ინფორმაციის წასაშლელად, ლოგიკურია, რომ ამ მეთოდის გამოყენება ხდება where მეთოდთან ერთად რადგან თუ ვუშვებთ წაშლის ბრძანებას მაშინ ისიც უნდა მივუთითოთ თუ რა და სად უნდა წაშალოს.
class ArticlesController extends Controller
{
    public function getArticles()
    {
      $articles = DB::table('articles')->where('id',7)->delete();
    }
}
          
ამ ჩანაწერმა რეალურად შექმნა შემდეგი ბრძანება "DELETE FROM articles WHERE id=7" მეთოდი აბრუნებს ზემოქმედებული ჩანაწერების რაოდენობას.

join მეთოდი

class ArticlesController extends Controller
{
    public function getArticles()
    {
      $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 მეთოდი

class ArticlesController extends Controller
{
    public function getArticles()
    {
      $users = DB::table('users')
            ->leftJoin('posts', 'users.id', '=', 'posts.user_id')
            ->get();
    }
}
          
19. მონაცემთა მოდელი
როგორც ვიცით ფრეიმვორკი laravel-ი დაფუძვნებულია შაბლონ mvc-ზე (Model, View, Controller ანუ მოდელი, წარმოდგენა, კონტროლერი). ამ თავში ვისაუბრებთ მოდელებზე. იმის შესახებ თუ რა არის მოდელი და რა ევალება მას, ვისაუბრეთ მე-4-ე თავში, ახლა კი მოვიყვანოთ შემდეგი განმარტება: მოდელი ეს არის მბ-ს ცხრილში შეტანილი კონკრეტული ჩანაწერების აბსტრაქცია, რომელიც მბს ცხრილის ელემენტებს წარმოვიდგენს ობიექტების სახით, მარტივი სიტყვებით მოდელი არის განსაზღვრული კლასის ობიექტი, რომლის მეთოდებითაც ხდება ცხრილის მონაცემებთან მუშაობა.

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

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

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

namespace App;

use Illuminate\Database\Eloquent\Model;

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

თვისება $table

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

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    protected $table = 'articles';
}
          

თვისება $table

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

use Illuminate\Database\Eloquent\Model;

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

თვისება $incrementing

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

use Illuminate\Database\Eloquent\Model;

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

თვისება $timestamps

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

use Illuminate\Database\Eloquent\Model;

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

თვისება $fillable

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

use Illuminate\Database\Eloquent\Model;

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

თვისება $guarded

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

use Illuminate\Database\Eloquent\Model;

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

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

ჩვენ უკვე გვაქვს კონტროლერი
            namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB;

class ArticlesController extends Controller
{
    public function getArticles()
    {
      
    }
}
          
იმისათვის რათა კონტროლერში მივმართოთ მოდელს, უნდა დავამყაროთ წვდომა ამ მოდელთან, ამის შემდეგ კი შეგვიძლია მივმართოთ მოდელს და გამოვიყენოთ მისი მეთოდები
            namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB;
use App\Article

class ArticlesController extends Controller
{
    public function getArticles()
    {
      $articles =  Article::all();  
      dump($articles); 
    }
}
          

ინფორმაციის ამოღება მბს ცხრილიდან

all() მეთოდი

ამ მეთოდმა რეალურად გაუშვა შემდეგი ბრძანება SELECT * FROM articles შედეგად კი დააბრუნა მოდელთა კოლექცია, რას ნიშნავს ეს ? ეს იმას ნიშნავს, რომ როგორვ ვთქვით მოდელი ეს არის ცხრილის კონკრეტული ჩანაწერის ობიექტური წარმოდგენა, კონკრეტული ჩანაწერის აბსტრაქცია, აქედან გამომდინარე თუ ცხრილში რამოდენიმე ჩანაწერია, დაბრუნდება რამოდენიმე ჩანაწერის ობიექტური წარმოდგენა ანუ ამ წარმოდგენათა (მოდელთა) ნაკრები. ამ ყველაფერს ექნება შემდეგი ვიზუალური სახე



ანუ იმ მომენტისათვის, როდესაც მე ბოლოს ბოყვანილი კოდი გავუშვი, ცხრილში იყო 7 ჩანაწერი და სურათზეც ვხედავთ კოლექციას, რომელიც შედგება შვიდი ელემენტისაგან, ერთ-ერთი მასთგანი გახსნილია და თუ დავაკვირდებით ვნახავთ, რომ მასში აღწერილია ცხრილის ველთა სახელები და მათი შესაბამისი მნიშვნელობები. ჩნდება კითხვა, როგორ გამოვიყენოთ მიღებული ინფორმაცია ანუ ცხრილის ველთა მნიშვნელობები ? ეს ხდება მოდელის იმავე სახელწოდებების მქონე თვისებების მიხედვით რაც აქვს ცხრილთა ველებს. მაგალითისათვის ამოვიღოთ ცხრილის text ველის მნიშვნელობები
            namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB;
use App\Article;

class ArticlesController extends Controller
{
    public function getArticles()
    {
      $articles = Article::all();
      foreach ($articles as $article)
      {
        echo $article->text . "<br />";
      }
    }
}
          
რასაკვირველია მოდელში შესაძლებელია ბრძანებათა კონსტრუქტორის გამოყენებაც
            namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB;
use App\Article;

class ArticlesController extends Controller
{
    public function getArticles()
    {
      $articles = Article::where('id','>',3)->get();
      foreach ($articles as $article)
      {
        echo $article->text . "<br />";
      }
    }
}
          

find() მეთოდი

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

use Illuminate\Http\Request;

use DB;
use App\Article;

class ArticlesController extends Controller
{
    public function getArticles()
    {
      $article = Article::find(3);
      dump($article);
    }
}
          
ეს კოდი ამოარჩევს იმ ჩანაწერს და შექმნის მის მოდელს, რომლისთვისაც id=3. შესაძლებელია რამოდენიმე პარამეტრის ერთდროულად გადაცემაც და ამ შემთხვევაში მეთოდი უკვე დააბრუნებს მოდელთა, ანუ შედეგთა კოლექციას
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB;
use App\Article;

class ArticlesController extends Controller
{
    public function getArticles()
    {
      $articles = Article::find([1,2,3]);
    }
}
          

findOrFail() მეთოდი

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

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

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

use Illuminate\Http\Request;

use DB;
use App\Article;

class ArticlesController extends Controller
{
    public function getArticles()
    {
      $article = new Article;
    }
}
          
ამის შემდეგ კი უბრალოდ მივმართოთ და განვუსაზღვროთ მნიშვნელობები შექმნილი ობიექტის იმ თვისებებს, რომელთა დასახელებებიც ემთხვევა ცხრილის ველთა დასახელებებს.

save() მეთოდი

უკვე გამზადებულია მოდელის ობიექტი და მითითებულია ინფორმაციები. save() მეთოდის გამოძახება ამ ინფორნმაციას შეიტანს ცხრილში.
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB;
use App\Article;

class ArticlesController extends Controller
{
    public function getArticles()
    {
      $article = new Article;
      $article->name = 'New Name';
      $article->text = 'New Text';
      $article->img  = 'test.jpg';

      $article->save();
    }
}
          

create() მეთოდი

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

use Illuminate\Http\Request;

use DB;
use App\Article;

class ArticlesController extends Controller
{
    public function getArticles()
    {
      Article::create(
                        [
                         'name' => 'Article Name',
                         'text' => 'Article Text',
                        ]
                     );
    }
}

          
თუ ახლა ამ კოდსს გავუშვებთ ვიხილავთ შეცდომას, უფროსწორად ფრეიმვორკის მიერ დაგენერირებულ გამონაკლისს (MassAssignmentException), ეს იმიტომ მოხდა, რომ Article მოდელში, $fillable მეთოდის მეშვეობით არ არის აღწერილი ცხრილის იმ ველთა დასახელებები, რომლერბშიც ნებადართულია ინფორმაციის შეტანა.
namespace App;

use Illuminate\Database\Eloquent\Model;

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

firstOrCreate() მეთოდი

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

use Illuminate\Http\Request;

use DB;
use App\Article;

class ArticlesController extends Controller
{
    public function getArticles()
    {
      $article = Article::firstOrCreate(
                                          [
                                           'name' => 'Article Name',
                                           'text' => 'Article Text',
                                          ]
                                       );
    }
}
          
ინფორმაციის შეტანამდე მეთოდი გადაამოწმებს უკვე ხომ არ არსებობს ცხრილში ისეთი ჩანაწერი რომლისთვისაც name ველის მნიშვნელობა არის 'Article Name', თუ ესეთი ჩანაწერი არსებობს მაშინ მეთოდი დააბრუნებს ამ ჩანაწერის მოდელს. ხოლო თუ არ არსებობს ასეთი ჩანაწერი, მაშინ მეთოდი შექმნის მას და დააბრუნებს ამ ჩანაწერის მოდელს.

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

ინფორმაციის განახლებისათვის, ჯერ უნდა ამოირჩეს კონკრეტული ჩანაწერი, შემდეგ კი უბრალოდ თავიდან უნდა განვსაზღროთ სასურველიველების მნიშვნელობები, ბოლოს კი გამოვიძახოთ ისევ მეთოდი save().
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB;
use App\Article;

class ArticlesController extends Controller
{
    public function getArticles()
    {
      $article =  Article::find(4);
      $article->name = 'blablablabla';
      $article->save();
    }
}
          

მოდელების წაშლა, ინფორმაციის წაშლა მბში მოდელის მეშვეობით

Delete() მეთოდი

ეს მეთოდი შლის ჩანაწერებს მბს ცხრილიდა, მაგრამ იმისათვის რათა ცხრილის რომელიმე ჩანაწერი წაიშალოს, ჯერ უნდა ამოირჩეს ეს ჩანაწერი.
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB;
use App\Article;

class ArticlesController extends Controller
{
    public function getArticles()
    {
      $article = Article::find(8);
      $article->delete();
    }
}
          

destroy() მეთოდი

ამ მეთოდის მეშვეობით შესაძლებელია ჩანაწერების წაშლა ამოურჩევლად, მას პარამეტრად უნდა გადაეცეს წასაშლელი ჩანაწერის იდენტიფიკატორი (id)
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB;
use App\Article;

class ArticlesController extends Controller
{
    public function getArticles()
    {
      Article::destroy(9);
    }
}
          
თუ რამოდენიმე ჩანაწერის წაშლა გვსურს ერთდროულად, მაშინ მეთოდს პარამეტრად უნდა გადაეცეს მასივი სადაც შეტანილი იქნება ამ ჩანაწერთა იდენტიფიკატორები.

softDelete

ეს კლასი გამოიყენება ჩანაწერთა წასაშლელად, იმ განსხვავებით, რომ იგი რეალურად არ შლის ჩანაწერებს, მისი მუშაობის პრინციპი წააგავს ოპერაციულ სისტემაში ფაილების წაშლის პრინციპს, რის შედეგადაც ეს ფაილები ხვდება სანაგვე ყუთში. ამ მეთოდის გამოსაყენებლად ცხრილს უნდა დავამატოთ ახალი ველი deleted_at, რომელშიც შეინახება ჩანაწერის წაშლის მომენტის შესაბამისი დროის ნიშნული. ამისათვის გავაკეთოთ ახალი მიგრაცია php artisan make:migration change_article_table_soft --table=articles იმისათვის რათა მიგრაციაში განვსაზღვროთ აღნიშნული ველი, მიგრაციის up მეთოდში უნდა გამოვიყენოთ softDeletes მეთოდი. სწორედ ეს მეთოდი დაამატებს ცხრილში deleted_at ველს. შესაბამისად მიგრაციის down მეთოდში მოვახდინოთ მისი უგულებელყოფა.
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

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

    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.

მოდელს აგრეთვე უნდა დაემატოს ჩანაწერთა წაშლის თარიღის აღმნიშვნელი ნიშნულიც, ამის გარეშე სისტემა მუშაობს მხოლოდ ორ ნიშნულთან ესენია created_at და updated_at.


namespace App;

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


class Article extends Model
{
   use SoftDeletes;
   protected $dates = ['deleted_at'];
}
          
კონტროლერში კი ხდება შემდეგი
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB;
use App\Article;

class ArticlesController extends Controller
{
    public function getArticles()
    {
      $article = Article::find(10);
      $article->delete();
    }
}
          
თუ ახლა შევამოწმებთ ცხრილს ვნახავთ რომ id=10 ჩანაწერი განახლებული იქნება და deleted_at ველში მითითებული იქნება წაშლის თარიღი. როგორც ვხედავთ ეს ჩანაწერი წაშლილი არ არის მაგრამ იგი აღარ შევა შედეგთა ნაკრებში, თუ ამოვარჩევთ მაგალითად ცხრილის ყველა ჩანაწერს. ეს ჩანაწერი მოხვდა ერთგვარ სანაგვე ყუთში.
20. კავშირი ცხრილებს შორის
ამ თავში ვისაუბრებთ მბს ცხრილების ურთიერთკავშირზე.



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

კავშირი 'ერთი ერთთან'

ბაზაში გვაქვს ცხრილი users, მიგრაციის დახმარებით შევქმნათ კიდევ ერთი ცხრილი countries
public function up()
{
    Schema::create('countries', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name');
        $table->integer('user_id')->unsigned()->default(1);
        $table->foreign('user_id')->references('id')->on('users');
        $table->timestamps();
    });
}
          
$table->foreign('user_id')->references('id')->on('users'); ეს ჩანაწერი ნიშნავს, რომ ცხრილი countries-ის ველი user_id უკავშირდება ცხრილი users-ის ველს - id.

გაგრძელება იქნება ...

21. მონაცემთა ვალიდაცია
მომხმარებლის მიერ სერვერზე გაგზავნილ ინფორმაციას აუცილებლად ჭირდება გადამოწმება, ვალიდაცია. ამ თავში ვისაუბრებთ სწორედ ამ თემაზე. საჩვენებლად კი გამოვიყენოთ ჩვენს მიერ ადრე შექმნილი საკონტაქტო ფორმა. კონტაქტის გვერდისათვის აგრეთვე შექმნილი გვაქვს შესაბამისი მარშრუტი Route::match(['get','post'],'/contact/{id?}',['uses'=>'Admin\ContactController@show','as'=>'contact']); როგორც ვხედავთ ამ გვერდ ამუშავებს კონტროლერი ContactController და მისი მეთოდი show
namespace App\Http\Controllers\Admin;

use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;

class ContactController extends Controller
{
    public function show(Request $request, $id=False)
    {
        return view('default.contact', ['title'=>'Contacts']);
    }
}
          
ეს კონტროლერ, ისევე როგორც ყველა სხვა კონტროლერი, არის 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.

დავუბრუნდეთ ჩვენს კონტროლერსა და მარშრუტს :)) როგორც ვხედავთ, მარშრუტი ამუშავებს get და post ტიპის მოთხოვნებს, სერვერზე კი ინფორმაცია იგზავნება მხოლოდ post მეთოდით, ამიტომ კონტროლერში მოვახდინოთ იმის გადამოწმება, არის თუ არა მოთხოვნა ამ ტიპის, შემდეგ კი მივმართოთ მიმდინარე კონტროლერის ობიექტს და გამოვიძახოთ მისი მეთოდი validate(). ამ მეთოდს პირველ პარამეტრად უნდა გადაეცეს მოთხოვნის ობიექტი $request, ინფორმაცია კი, როგორც გვახსოვს განთავსებულია ამ ობიექტის თვისებებში, თვისებები კი html ფორმის ელემენტებთან დაკავშირებულია შემდეგი ლოგიკით: თვისება ასოცირდება html ფორმის იმ ელემენტთან, რომლის name ატრიბუტის მნიშვნელობაც არის ამ თვისების დასახელების ტოლი, მეორე პარამეტრად უნდა გადაეცეს $rules მასივი რომელშიც აღწერილი იქნება ვალიდაციის წესები, კონკრეტული ველებისათვის, მესამე პარამეტრად კი - შეტყობინებების შემცველი მასივი $messages, ამ უკანასკნელის შესახებ ცოტა მოგვიანებით ვისაუბრებთ.

namespace App\Http\Controllers\Admin;

use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;

class ContactController extends Controller
{
    public function show(Request $request, $id=False)
    {
        if ($request->isMethod('post'))
        {
          $this->validate($request, $rules);
        }

        return view('default.contact', ['title'=>'Contacts']);
    }
}
          

$rules პარამეტრი

ეს პარამეტრი არის ჩვეულებრივი მასივი, რომელიც შეიცავს ვალიდაციის წესებს ფორმის სხვადასხვა ველებისათვის, მაგალითად გვინდა 'name' და 'email' ველების ვალიდაცია. შესაბამისად $rules მასივის გასაღებები იქნება name და email, ხოლო ამ გასაღებთა მნიშვნელობები კი სტრიქონის სახით ჩაწერილი, ერთმანეთისაგან '|' სეპარატორით გამოყოფილი ვალიდაციის წესები. ამ წესების სრული ჩამონათვალის ნახვა შეგიძლიათ აქ, ძირითად წესებს გავეცნობით ეტრაპობრივად.

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

namespace App\Http\Controllers\Admin;

use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;

class ContactController extends Controller
{
    public function show(Request $request, $id=False)
    {
        if ($request->isMethod('post'))
        {
          
          $rules = [
            'name' => 'required|max:10',
            'email' => 'required|email'
          ];

          $this->validate($request, $rules);

          dump($request->all());

        }

        return view('default.contact', ['title'=>'Contacts']);
    }
}
          
თუ სავალდებულო ველებს არ შევავსებთ ან ჩვენს მიერ განსაზღვრულ წესებს დავარღვევთ, ვნახავთ, რომ ფრეიმვორკი იგივე გვერდზე დაგვტოვებს, და ამასთანავე აკრეფილი ინფორმაცია არ დაიკარგება, ხოლო თუ ყველაფერს სორად შევავსებთ, ველები გასუფთავდება და იმუშავებს ვალიდაციის შემდეგ მითიტებული კოდი ანუ : dump($request->all());

შეტყობინებები შეცდომების შესახებ

როგორც ვთქვით, შეტყობინებები შეცდომების შესახებ ინახება $errors ცვლადში. აუცილებელია, რომ ეს ცვლადი ხელმისაწვდომი გავხადოთ საჭირო შაბლონებისათვის. ამას უზრუნველჰყოფს სპეციალური შუამავალი ShareErrorsFromSession, რომელიც მითითებულია app/Http/Kernel.php ფაილში აღწერილი კლასის $middlewareGroups თვისებაში
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:60,1',
        'bindings',
    ],
];

          
იმისათვის რათა შეცდომები ვიხილოთ წარმოდგენის შაბლონში, შაბლონის კოდში სადმე მაგალითად ფორმის წინ უნდა მივუთითოთ რაიმე ამდაგვარი
@if(count($errors) > 0)
  <div class="alert alert-danger">
    <ul>
       @foreach($errors->all() as $error)
        <li>{{ $error }}</li>
       @endforeach
    </ul>
  </div>
@endif
          
კოდი საკმაოდ მარტივია და ამიტომ აღარ დავწვრილმანდებით. შედეგად, ვალიდაციის წესების დარღვევის შემთხვევაში უნდა ვიხილოთ ასეთი სურათი



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

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

use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;

use Validator;

class ContactController extends Controller
{
    public function show(Request $request, $id=False)
    {
        if ($request->isMethod('post'))
        {
            $messages = [];
            $validator = Validator::make($request->all(), ['name'=>'required'], $messages);
        }

        return view('default.contact', ['title'=>'Contacts']);
    }
}
          
როგორც ვხედავთ ვალიდაციის წესებში მივუთითეთ რომ 'name' ველი არის აუცცილებელი ველი, მაგრამ თუ ახლა მას არ შევავსებთ და ფორმას ისე გავგზავნით, არანაირ ცვლილებას არ ვიხილავთ, თითქოს არც იმუშავებს ვალიდატორი, სინამდვილეში ეს ასე არაა, ვალიდატორმა გააკეთა თავის საქმე, მაგრამ კონტროლერში არ გვაქვს მითითებული ინსტრუქცია, რომელიც უნდა შესრულდეს ვალიდაციის შემდეგ. იმის გასაგებად წარმატებით ჩაიარა თუ არა ვალიდაციამ გამოიყენება Validator ფასადის fails მეთოდი, რომელიც აბრუნებს ჭეშმარიტ მნიშვნელობას იმ შემთხვევაში, თუ ვალიდაცია წარუმატებელია. აღვწეროთ ინსტრუქცია რომლის მიხედვითაც ვალიდაციის წარუმატებლობის შემთხვევაში გადავმისამართდებით შემდეგ კონტაქტის გვერდის მარშრუტზე Route::match(['get','post'],'/contact/{id?}',['uses'=>'Admin\ContactController@show','as'=>'contact']); ამ მარშრუტის ფსევდონიმი როგორც ვხედავთ არის - contact, ამასთანავე გადამისამართებისას ვალიდაციის შეცდომები შევინახოთ სესიაში witwErrors მეთოდის დახმარებით, ამ მეთოდს კი არგუმენტად უნდა გადაეცეს იმ ვალიდაციის ობიექტი, რომლის შეცდომების შენახვაც გვსურს სესიაში. სესიაში აგრეთვე უნდა შევინახოთ აკრეფილი ინფორმაცია რათა ფორმა არ გასუფთავდეს, ამაში დაგვეხმარება withInput მეთოდი.
namespace App\Http\Controllers\Admin;

use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;

use Validator;

class ContactController extends Controller
{
    public function show(Request $request, $id=False)
    {
        if ($request->isMethod('post'))
        {
            $messages = [];
            $validator = Validator::make($request->all(), ['name'=>'required'], $messages);
            if ($validator->fails())
            {
                return redirect()->route('contact')->withErrors($validator)->withInput();
            }
        }

        return view('default.contact', ['title'=>'Contacts']);
    }
}
          
ახლა უკვე ვიხილავთ შეტყობინებას შეცდომის შესახებ.

შეცდომათა სამომხმარებლო შეტყობინებები

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

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

'custom' => [
    'name' => [
        'required' => 'სახელის ველი (name) აუცილებლად უნდა შეავსოთ',
    ],
]
          
22. მომხმარებელთა აუტენთიფიკაცია
ვებ-აბლიკავიების შექმნისას ხშირად აუცილებელია, რომ აპლიკაციის კონკრეტული ნაწილი დაიმალოს საერთო თვალთახედვიდან (მაგალითად ადმინისტრატორის პანელი) და მასზე ხელი მიწვდებოდეს რეგისტრირებულ მომხმარებლებს, ამისათვის გამოიყენება მომხმარებელთა აუტენთიფიკაცია, რომელიც ჩაშენებულია ფრეიმვორკი ლარაველის სტანდარტულ ფუნქციონალში.

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

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

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

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

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

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

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

აუტენტიფიკაციის სისტემასთან მუშაობისთვის საჭიროა წარმოდგენის შესაბამისი ფაილი სადაც მომხმარებელს შეეძლება შეიყვანოს გადასამოწმებელი ინფორმაცია (მაგ: სახელი და პაროლი). რა თქმა უნდა შესაძლებელია რომ ეს ფაილები ჩვენ შევქმნათ , მაგრა ფრეიმვორკი გვაძლევს საშუალებას ეს გავაკეთოთ უფრო მარტივად, კონსოლის გამოყენებით. იმისათვის რათა შევქმნათ აუტენტიფიკაციისათვის საჭირო მაკეტები, კონსოლში უნდა ავკრიფოთ შემდეგი ბრძანება php artisan make:auth ეს ბრძანება შექმნის resources/views/auth საქაღალდეს შესაბამის მკეტებთან ერთად, აგრეთვე დამხმარე კონტროლერს - HomeController. ახლადშექმნილი ფაილები login.blade.php და register.blade.php გამოიყენება მომხმარებლის ავტორიზაცია/რეგისტრაციისათვის, ინფორმაციის შენახვა კი მოხდება ჩვენს მიერ პირველი მიგრაციის გაშვებისას ბაზაში ავტომატურად შექმნილ ცხრილებში users და password_resets.

ახლადშექმნილ კონტროლერს კი ექნება შემდეგი სახე

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class HomeController extends Controller
{
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
    }

    /**
     * Show the application dashboard.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        return view('home');
    }
}
          
როგორც ვხედავთ იგი ტვირთავს წარმოდგენის home ფაილს. ეს ფაილი წარმოადგენს პროექტის დაცული, ანუ ისეთი ნაწილის ფრაგმენტს, რომლის ნახვაც ყველას არ შეუძლიან (ერთგვარი ადმინისტრატორის პანელი :) ).

თუ გადავხედავთ routes/web.php ფაილს ვნახავთ, რომ ბოლოში აღწერილი იქნება შემდეგი მარშრუტი

Auth::routes();
Route::get('/home', 'HomeController@index')->name('home');
          
ეს არის აუტენტიფიკაციის მარშრუტი. Auth::routes() ჩანაწერით კი ხდება Auth დამხმარე კლასის routes მეთოდის გამოძახება, რომელიც გვეხმარება დავაგენერიროთ მარშრუტები იმ გვერდებისათვის, რომელთა ნახვაც მხოლოდ აუტენტიფიცირებულ მომხმარებლებს შეუძლიათ.

პ.ს : შექმნილი მარშრუტების სიის ნახვა შესაძლებელია შემდეგი ბრძანებით php artisan route:list შუ შევეცდებით შევიდეთ home გვერდზე http://127.0.0.1:8000/home სისტემა გადაგვამისამართებს ავტორიზაციის გვერდზე http://127.0.0.1:8000/login რომლის ფორმირებასაც უზრუნველჰყოფს წარმოდგენის ახლადშექმნილი ფაილი login.blade.php.



გადავიდეთ რეგისტრაციის გვერდზე და მბს users ცხრილში დავამატოთ ახალი მომხმარებელი. ამის შემდეგ კი სისტემა გადაგვამისამართებს ზემოთ აღნიშნულ, ე.წ დახურულ განყოფილებაში, რომლის ფორმირებასაც უზრუნველჰყოფს resources/views/home.blade.php ფაილი, რომელთან წვდომაც მხოლოდ დარეგისტრირებულ მომხმარებლებს შეუძლიათ.

იმისათვის რათა შევზღუდოთ რომელიმე სხვა გვერდთან წვდომა, შესაბამის კონტროლერის კონსტრუქტორ მეთოდში უნდა გამოვიძახოთ შუამავალი auth, მაგალითად ეს გავაკეთოთ articles გვერდისათვის ArticlesController.php ფაილში

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB;
use App\Article;

class ArticlesController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }

    public function getArticles()
    {
      
    }
}
          
იგივეს გაკეთება შესაძლებელია მარშრუტშიც Route::get('articles',['uses'=>'ArticlesController@getArticles','middleware'=>['auth']]);

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

წარმოვიდგინოთ, რომ გვაქვს პროექტი და მის კონკრეტულ დირექტორიაში, რომელსაც პირობითად დავარქვათ admin, გვაქვს მხოლოდ ადმინისტრატორისათვის ხელმისაწვდომი ფაილები (სიახლის დამატება, წაშლა და ა.შ), შევქმნათ მარშრუტთა ჯგუფი, რომელში შემავალი თითოეული მარშრუტიც გადამისამართდება აუტენტიფიკაციის გვერდზე, არ უნდა დაგვავიწყდეს, რომ აუცილებელია მარშრუტების ფაილში გამოძახებული იყოს დამხმარე
Auth::routes(); // დამხმარე კლასის  მეთოდი
Route::group(['prefix'=>'admin','middleware'=>['auth']],function(){
  Route::get('/',['uses'=>'Admin\AdminController@show','as'=>'admin_index']);
  Route::get('/add/post',['uses'=>'Admin\PostController@create','as'=>'admin_add_post']);
});
         
23. მომხმარებელთა ავტორიზაცია
როგორც უკვე აღვნიშნეთ, მომხმარებელთა ავტორიზაცია არის პროცესი, რომლის დროსაც ხდება მომხმარებლის ხელმისაწვდომობის, უფლების ქონა/რქონის გადამოწმება ამა თუ იმ მოქმედებაზე. კონკრეტული ქმედების ხელმისაწვდომობის განსაზღვრა ხდება ავტორიზაციის სპეციალური კლასის - Gate - ს მეშვეობით. დაწვრილებით ინფორმაცია იხილეთ პრაქქტიკული ნაწილის ... თავში.
24. სესიები
სესიათა მექანიზმის პარამეტრები აღწრილია config/session.php ფაილში. ამ ფაილში ბრუნდება მასივი, სწორედ ამ მასივშია აღწერილი სესიის პარამეტრები და პირველი პარამეტრი არის driver 'driver' => env('SESSION_DRIVER', 'file'), ეს არის სესიათა დამუშავების მექანიზმი ნაგულისხმეობის პრინციპით, და როგორც ვხედავთ ამ მექანიზმის მნიშვნელობად მითითებულია file, ეს ნიშნავს, რომ სესიები ინახება კონკრეტულ ფაილებში, კომენტარებში აღწერილია სხვა შესაძლო მნიშვნელობებიც ("cookie", "database", "apc", "memcached", "redis", "array", memcached არის ერთგვარი პროგრამული უზრუნველყოფა, რომლის მეშვეობითაც ხდება ინფორმაციის ჰეშირებული სახით შენახვა ოპერატიულ მეხსიერებაში). მასივის შემდეგი პარამეტრი არის 'lifetime' => 120, ანუ წუთების, რაოდენობა რომლის ამოწურვის შემდეგაც სესიები გაუქმდდება თუ მომხმარებელი უმოქმედოდ იქნებააპლიკაციაში ამ ხნის განმავლობაში. შემდეგი პარამეტრია 'expire_on_close' => false, გაუქმდეს თუ არა სესიები ბრაუზერის დახურვისას. შემდეგი პარამეტრია 'expire_on_close' => false, დაიშიფროს თუ არა სესიაში შენახული ინფორმაცია. შემდეგი პარამეტრია 'files' => storage_path('framework/sessions'), სესიის ინფორმაციები ინახება ამ მისამართზე განთავსებულ ფაილებში. შემდეგი პარამეტრია 'table' => 'sessions', აქ უნდა განისაზღვროს მბს ცხრილის დასახელება იმ შემთხვევაში, თუ driver პარამეტრის მნიშვნელობად ავირჩევთ database-ს. ანუ სესიის ინფორმაცუიები შეინახება მბში და კერძოდ აქ მითითებულ ცხრილში.

დრაივერი database

როგორც აღვნიშნეთ, driver პარამეტრი განსაზღვრავს, თუ რა სახით იქნეს შენახული სესიის ინფორმაციები. და თუ ამ პარამეტრის მნიშვნელობა იქნება database, მაშინ ეს ინფორმაცია შეინახება მბში. კონსოლის დახმარებით შევქმნათ შესაბამისი ცხრილი, ამისათვის უნდა გავუშვათ შემდეგი ბრძანება php artisan session:table ეს ბრძანება შექმნის მიგრაციას ახალ ფაილს დაახლოებით შემდეგი სათაურით 2017_03_04_225451_create_sessions_table.php. ახლა გავუშვათ ეს მიგრაცია 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 ობიექტის დახმარებით, აგრეთვე სპეციალური დამხმარის - session-ის მეშვეობითაც, არის მესამე ვარიანტიც - ფასად Session-ზე მიმართვა.

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

get()

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

all()

თუ გვინდა, რომ დავაბრუნოთ სესიაში შენახული ყველა ინფორმაცია უნდა გამოვიყენოთ session დამხმარეს all მეთოდი, რომელიც სესიას აბრუნებს მასივის სახით
public function show(Request $request, $id=False)
{
    $result = $request->session()->all();
    dump($result);
    return view('default.contact', ['title'=>'Contacts']);
}
          

put()

სესიაში ინფორმაციის შეტანა ხდება put მეთოდის მეშვეობით, მას პარამეტრებად უნდა გადაეცეს სესიის დასახელება და შესაბამისი მნიშვნელობა
public function show(Request $request, $id=False)
{
    $request->session()->put('key','value');
    $result = $request->session()->all();
    dump($result);
    return view('default.contact', ['title'=>'Contacts']);
}
          
ამ კოდის შედეგი იქნება დაახლოებით ამდაგვარი რამ

has()

იმის გასაგებად არსებობს თუ არა კონკრეტული დასახელების სესია, გამოიყენება has მეთოდი, რომელსაც პარამეტრად უნდა გადაეცეს საძიებელი სესიის დასახელება
public function show(Request $request, $id=False)
{
    if ($request->session()->has('key'))
    {
      dump("1");
    }
    else
    {
      dump("0");
    }
    return view('default.contact', ['title'=>'Contacts']);
}
          

სესიებთან მუშაობა Session ფასადით

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

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

Session::forget('key2');

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

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

session დამხმარე საშუალებას გვაძლევს მივწვდეთ კონკრეტულ სესიებს. მაგალითად დავაბრუნოთ key სესიის მნიშვნელობა dump(session('key')); თუ გვსურს, რომ ამავე დამხმარეს მეშვეობით შევქმნათ ახალი სესია, მაშინ მას პარამეტრად უნდა გადავცეთ სესიების დასახელებებისა და შესაბამისი მნიშვნელობების შემცველი მასივი session(['key2'=>'მნიშვნელობა 2']);
25. მოვლენათა დამუშავება (events, listeners)
26. ლოკალიზაცია (localization, lang)


პრაქტიკა - მარტივი საიტი



1. შესავალი
ეს არის ფრეიმვორკ Laravel-ის შესწავლის პრაქტიკული ნაწილის პირველი განყოფილება, რომელშიც გავაკეთებთ მარტივ, ერთგვერდიან ამდაგვარ საიტს (შაბლონის გადმოწერა)
2. ინსტალაცია
ფრეიმვორკის ინსტალაციის ინსტრუქცია შეგიძლიათ იხილოთ თეორიული ნაწილის მე-2-ე თავში, ან პრაქტიკული ნაწილის მეორე განყოფილების მე-2-ე თავში.
3. მონაცემთა ბაზა
მონაცემთა ბაზას დავარქვათ minilaravel და მასში გავაკეთოთ ცხრილი articles



.env ფაილიც გადავაკეთოთ შესაბამისად
... 

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

...
            
4. შევქმნათ ჩვენი პირველი გვერდი Laravel-ში
ფრეიმვორკის ინსტალაციის შედეგად ვღებულობთ ფაილთა და საქაღალდეთა ამდაგვარ სტრუქტურას



public საქაღალდეში განთავსებულია index.php ფაილი, რომელიც არის პროექტში შესასვლელი საკვანძო წერტილი. მომხმარებლის მიერ გაკეთებული ნებისმიერი მოთხოვნა მიემართება ამ ფაილისაკენ შემდეგ კი მართვა გადაეცემა ფრეიმვორკის მარშრუტიზატორს, მარშრუტიზატორი ამუშავებს მოთხოვნას და წყვეტს თუ რომელმა მარშრუტმა უნდა დაამუშავოს მიმდინარე მოთხოვნა. routes/web.php ფაილში აღწერილ ყველა მარშრუტს ამუშავებს შუამავალ კლასთა ჯგუფი web. ფრეიმვორკის ინსტალაციის შემდეგ ამ ფაილში აღწერილი იქნება ერთადერთი მარშრუტი
Route::get('/', function(){
  return view('welcome');
});
            
მარშრუტის შექმნა ხდება ფასად Route-ზე მიმართვით. შემდეგ ხდება ამ ფასადის get მეთოდის გამოძახება, როელიც გამოიყენება get ტიპის მოთხოვნათა დასამუშავებლად. ამ მეთოდს პირველ პარამეტრტად გადაცემული აქვს შაბლონი '/' ანუ საიტის ძირი საქაღალდე, რომლისთვისაც გენერირდება მიმდინარე მარშრუტი. ეს შაბლონი შეიძლება შედგებოდეს მუდმივი და ცვალებადი ნაწილებისაგან
project.ge/articles/show/10
project.ge/articles/show/116
project.ge/articles/show/23120
            

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

ჩვენი პირველი მარშრუტი

Route::get('page', function(){
  return "<h2>ჩვენი პირველი მარშრუტი</h2>";
});    
            
ახლა შევიდეთ შემდეგ მისამართზე (მისამართის დასაზუსტებლად გამოიყენეთ cmd და გაუშვით ბრძანება php artisan serve) http://127.0.0.1:8000/page წარმოდგენის ფაილის გამოსატანი ინსტრუქციის, get მეთოდზე პარამეტრად გადაცემულ ფუნქციაში აღწერა ყოველთვის მოსახერხებელი არ არის (მაგალითად მაშინ თუ დიდ და რთულ კოდთან გვაქვს საქმე). ასეთ შემთხვევაში საქმეში ერთვება კონტროლერი. get მეთოდს პარამეტრად უნდა გადავცეთ კონკრეტული კონტროლერისა დასახელება, აგრეთვე უნდა მივუთითოთ იმ მეთოდის დასახელებაც რომელმაც უნდა უზრუნველჰყოს გვერდის ჩატვირთვა. ამ ყველაფრის სინტაქსი შემდეგნაირია Route::get('page', 'IndexController@index'); ანუ ამ ჩანაწერით სისტემას ვეუბნებით, რომ: http://127.0.0.1:8000/page მისამართზე შესვლისას გამოიძახოს IndexController და მისი მეთოდი index. შევქმნათ ეს კონტროლერი, ამის გაკეთება app/Http/Controllers დირექტორიაში უბრალოდ IndexController.php ფაილის შექმნითაც შეიძლება მაგრამ ჯობია ეს გავაკეთოთ ბრძანებათა კონსოლის (cmd) დახმარებით, პირველ რიგში კონსოლის მეშვეობით გადავიდეთ პროექტის საქაღალდეში, შემდეგ კი გავუშვათ ბრძანება php artisan make:controller IndexController შექმნილ ფაილში აღწერილი იქნება შემდეგი კოდი
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class IndexController extends Controller
{
    //
}
            
ეს ჩანაწერი namespace App\Http\Controllers; განსაზღვრავს კონტროლერთა ადგილთა სივრცეს ანუ გზას რომელზეც განთავსებულია კონკრეტული ფაილი. ხოლო ეს ჩანაწერი use Illuminate\Http\Request; უზრუნველჰყოფს Request კლასთან წვდომას. Request კლასი არის მომხმარებლის მიერ გაკეთებული მოთხოვნების აბსტრაქცია, განზოგადოებული სახე. მისი მეშვეობით ხდება მოთხოვნათა დამუშავება.

ახლა შევქმნათ index მეთოდი

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class IndexController extends Controller
{
    public function index()
    {
      return "<h2>ჩვენი პირველი მარშრუტი, კონტროლერი და გვერდი</h2>";
    }
}
            

ახლა index მეთოდში მოვახდინოთ წარმოდგენის ფაილის გამოძახება

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class IndexController extends Controller
{
    public function index()
    {
      return view('page');
    }
}
            
შესაბამისად resources/views საქაღალდეში უნდა შევქმნათ ფაილი page.blade.php და ამ ფაილში შევიტანოთ რაიმე ტექსტი <h2>ჩვენი პირველი მარშრუტი, კონტროლერი და გვერდი</h2> შემდეგ მისამართზე შესვლისას http://127.0.0.1:8000/page ბრაუზერში ვიხილავთ შესაბამის ტექსტს.

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

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class IndexController extends Controller
{
    public function index()
    {
      $message = "Hello World !";
      return view('page')->with('message', $message);
    }
}
            
წარმოდგენის ფაილში ამ ცვლადის გამოყენება კი, როგორც ვიცით, მოხდება ასე {{ $message }}
5. Bootstrap შაბლონის დაკავშირება ფრეიმვორკთან
ავარჩიოთ Bootstrap-ის რაიმე მარტივი შაბლონი და დავაკავშიროთ ფრეიმვორკთან, მაგალითისათვის შევჩერდეთ ამ დიზაინზე. ეს შაბლონი მოიცავს, index.html ფაილს და აგრეთვე css და javascript ფაილებს. index.html ფაილის კოდი ჩავაკოპიროთ ჩვენს მიერ შექმნილ წარმოდგენის ფაილში (page.blade.php) და შევიდეთ იგივე მისამართზე რაზეც წეღან შევედით (http://127.0.0.1:8000/page).

ვნახავთ, რომ შეტანილი კოდი იმუშავებს, მაგრამ იგი დაკავშირებული არ იქნება css ინსტრუმენტებთან, რომლებიც უზრუნველჰყოფენ გვერდის კორექტულად და ლამაზად ჩატვირთვას. ამდაგვარი ინსტრუმენტების შენახვა ხდება ფრეიმვორკის public საქაღალდეში. აღნიშნული css ფაილები მოვათავსოთ public/css საქაღალდეში (javascript არ გვაინტერესებს ამ ეტაპზე). ამის შემდეგ გვერდი მაინც არ იმუშვებს სწორად იმიტომ, რომ page.blade.php ფაილში css ფაილებთან წვდომა განსაზღრულია შემდეგი კოდით

<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/heroic-features.css" rel="stylesheet">
წარმოდგენის ჩვენი ფაილი კი იმყოფება საქაღლდეების იერარქიის სხვა განყოფილებაში, და ამიტომ იგი ვერ აღიქვამს public/css საქაღალდეში შენახულ სტილებს. ამ პრობლემის გადასაჭრელად გამოვიყენოთ დამხმარე ფუნქცია asset, რომელიც აგენერირებს გზას public საქაღალდემდე. შედეგად მივიღებთ: <link href="{{ asset('css/bootstrap.min.css') }}" rel="stylesheet">
<link href="{{ asset('css/heroic-features.css') }}" rel="stylesheet">
ამის შემდეგ კი ყველაფერი კორექტულად ჩაიტვირთება.
6. მონაცემთა ბაზაში შენახული ინფორმაციის გამოტანა მთავარ გვერდზე
მარშრუტები გადავაკეთოთ ისე, რომ ჩვენს მიერ გადმოწერილი და ფრეიმვორკთან დაკავშირებული bootstrap შაბლობი გაიხსნას მთავარ (http://127.0.0.1:8000) გვერდზე და არა 'page' (http://127.0.0.1:8000/page) გვერდზე Route::get('/', 'IndexController@index');

ინფორმაციის ამოღება მბ-დან

როგორც ვიცით მბ-სთან სამუშაოდ გამოიყენება MVC შაბლონის ერთ-ერთი კომპონენტი მოდელი. მოდელს კი სახელი (როგორც წესი და არა აუცილებლობა) ერქმევა მბ-ს ცხრილის სახელის მიხედვით, ჩვენს ცხრილს ჰქვია articles ესეიგი მოდელს უნდა დავარქვათ Article. php artisan make:model Article მოდელები ინახება app საქაღალდეში.
namespace App;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    //
}
            
თუ მოდელს სახელს არ დავარქმევთ ზემოთ შენიშნული კანონზომიერების მიხედვით, მაშინ მოდელში მბ-ს ცხრილის განსაზღვრა მოგვიწევს $table თვისების მეშვეობით ptotected $table = 'articles'; კიდევ ერთხელ ჩამოვაყალიბოთ მოდელისათვის სახელის დარქმევის სასურველი კანონზომიერება რა ინახება მბ-ს ცხრილში ? მაგალითად ინფორმაცია რამოდენიმე არტიკლის (article) შესახებ, 'რამოდენიმე' ნიშნავს მრავლობით ფორმას, ე.ი სასურველია ცხრილს დავარქვათ 'articles', მოდელს კი დავარქვათ 'Article' ანუ ცხრილის მრავლობით ფორმაში ნაწარმოები სახელის, ლათინური ანბანის დიდი ასოთი დაწყებული მხოლობითი ფორმა. როგორც ვხედავთ ჩვენს მიერ შექმნილი მოდელი არის Model მშობელი მოდელის მემკვიდრე, ამ მშობელ მოდელთან წვდომა კი ხორციელდება ამ ჩანაწერით use Illuminate\Database\Eloquent\Model;

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

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

use Illuminate\Http\Request;
use App\Article;

class IndexController extends Controller
{
    public function index()
    {
        /* 
          მივმართეთ მოდელის კლასს და მის 'all' მეთოდს, რომელიც 'articles'  
          ცხრილიდან ამოარჩევს ყველა ჩანაწერის ყველა ველს
        */
        $articles = Article::all();

      return view('page')->with('message', $message);
    }
}
            
თუ გვინდა, რომ ამოვარჩიოთ მხოლოდ კონკრეტული ველების მნიშვნელობები, მაშინ გამოვიყენოთ მოთხოვნათა კონსტრუქტორის მეთოდი select, რომელიც ექმნის მოთხოვნის ტანს, ხოლო პროცესის დამასრულებელი და შექმნილი მოთხოვნის გამშვები კი არის get მეთოდი. select მეთოდს არგუმენტად უნდა გადაეცეს მასივი, რომელშივ შევიტანთ სასურველი ველების დასახელებებს
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Article;

class IndexController extends Controller
{
    public function index()
    {
      $articles = Article::select(['id','title','desc'])->get();

      return view('page');
    }
}
            
ახლა ბაზიდან წამოღებული და $articles ცვლადში შენახული ინფორმაცია გადავცეთ წარმოდგენის ფაილს
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Article;

class IndexController extends Controller
{
    public function index()
    {
      $articles = Article::select(['id','title','desc'])->get();

      return view('page')->with('articles',$articles);
    }
}
            
ახლა ეს ინფორმაცია გამოვიტანიოთ წარმოდგენის ფაილში, კერძოდ კი ამ მონაკვეთში
<!-- Page Features -->
<div class="row text-center">

...

</div>
<!-- /.row -->
            
ეს უნდა გავაკეთოთ foreach ციკლის დახმარებით, რომლის გამოყენებაც შაბლონიზატორ ბლეიდში შესაძლებელია @foreach დირექტივით
<!-- Page Features -->
<div class="row text-center">

    @foreach($articles as $article)

    <div class="col-md-3 col-sm-6 hero-feature">
        <div class="thumbnail">
            <img src="http://placehold.it/800x500" alt="">
            <div class="caption">
                <h3>{{ $article->title }}</h3>
                <p>{{ $article->desc }}</p>
                <p>
                    <a href="#" class="btn btn-default">More Info</a>
                </p>
            </div>
        </div>
    </div>

    @endforeach

</div>
<!-- /.row -->
            
7. შაბლონის დაყოფა მაკეტებად
თუ მთავარი გვერდის კოდს დავაკვირდებით შევამჩნევთ, რომ მასში არის ისეთი ფრაგმენტები, რომლებიც უცვლელი სახით, ანუ სტატიკურად დაგვჭირდება სხვა გვერდზებზეც. მაგალითად css ფაილებთაბ დაკავშირება ან საიტის ძირი (footer). ასეთი ფრაგმენტები სასურველია, რომ გატანილ იქნეს ცალკე ფაილებში, რომლებსაც მაკეტებსაც უწოდებენ. და შემდეგ მათი ჩართვა მოხდეს საჭირო დროსა და საჭირო ადგილას.

შევქმნათ საქაღალდე resources/views/layouts რომელშიც შევინახავთ ჩვენი პროექტის გლობალურ მაკეტს. ამ საქაღალდეში შევქმნათ ფაილი site.blade.php. შემდეგ resources/views/page.blade.php ფაილიდან ამოვჭრათ აბსოლიტურად ყველაფერი გარდა იმ ფრაგმენტისა, რომელშიც ბაზიდან წამოღებული ინფორმაცია გამოგვაქვს და ჩავაკოპიროთ ახლადშექმნილ resources/views/layouts/site.blade.php ფაილში

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <title>Heroic Features - Start Bootstrap Template</title>
    <link href="{{ asset('css/bootstrap.min.css') }}" rel="stylesheet">
    <link href="{{ asset('css/heroic-features.css') }}" rel="stylesheet">
</head>

<body>

    <!-- Navigation -->
    <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
        <div class="container">
            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="#">Start Bootstrap</a>
            </div>
            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <ul class="nav navbar-nav">
                    <li>
                        <a href="#">About</a>
                    </li>
                    <li>
                        <a href="#">Services</a>
                    </li>
                    <li>
                        <a href="#">Contact</a>
                    </li>
                </ul>
            </div>
            <!-- /.navbar-collapse -->
        </div>
        <!-- /.container -->
    </nav>

    <!-- Page Content -->
    <div class="container">

        <!-- Jumbotron Header -->
        <header class="jumbotron hero-spacer">
            <h1>A Warm Welcome!</h1>
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsa, ipsam, eligendi.</p>
            <p><a class="btn btn-primary btn-large">Call to action!</a>
            </p>
        </header>

        <hr>

        <!-- Title -->
        <div class="row">
            <div class="col-lg-12">
                <h3>Latest Features</h3>
            </div>
        </div>
        <!-- /.row -->



        <!-- აქ გამოგვქონდა ინფორმაცია ბაზიდან ... -->


        

        <hr>

        <!-- Footer -->
        <footer>
            <div class="row">
                <div class="col-lg-12">
                    <p>Copyright © Your Website 2014</p>
                </div>
            </div>
        </footer>

    </div>
    <!-- /.container -->

</body>

</html>

            
resources/views/page.blade.php ფაილში კი დაგვრჩება მხოლოდ ეს ფრაგმენტი
<!-- Page Features -->
<div class="row text-center">

    @foreach($articles as $article)

    <div class="col-md-3 col-sm-6 hero-feature">
        <div class="thumbnail">
            <img src="http://placehold.it/800x500" alt="">
            <div class="caption">
                <h3>{{ $article->title }}</h3>
                <p>{{ $article->desc }}</p>
                <p>
                    <a href="#" class="btn btn-default">More Info</a>
                </p>
            </div>
        </div>
    </div>

    @endforeach
   

</div>
<!-- /.row -->
            
ამგვარად resources/views/page.blade.php მაკეტი გახდა resources/views/layouts/site.blade.php მაკეტის მემკვიდრე მაკეტი. მაკეტებში მემკვიდრეობითობას კი განსაზღვრავს extends დირექტივა, რომელსაც პარამეტრად უნდა გადავცეთ გზა მშობელ მაკეტამდე. ამიტომ შვილობილ მაკეტს გადავაკეთებთ ასე
@extends('layouts.site')


<!-- Page Features -->
<div class="row text-center">

    @foreach($articles as $article)

    <div class="col-md-3 col-sm-6 hero-feature">
        <div class="thumbnail">
            <img src="http://placehold.it/800x500" alt="">
            <div class="caption">
                <h3>{{ $article->title }}</h3>
                <p>{{ $article->desc }}</p>
                <p>
                    <a href="#" class="btn btn-default">More Info</a>
                </p>
            </div>
        </div>
    </div>

    @endforeach
   

</div>
<!-- /.row -->
            

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

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <title>Heroic Features - Start Bootstrap Template</title>
    <link href="{{ asset('css/bootstrap.min.css') }}" rel="stylesheet">
    <link href="{{ asset('css/heroic-features.css') }}" rel="stylesheet">
</head>

<body>

    <!-- Navigation -->
    <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
        <div class="container">
            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="#">Start Bootstrap</a>
            </div>
            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <ul class="nav navbar-nav">
                    <li>
                        <a href="#">About</a>
                    </li>
                    <li>
                        <a href="#">Services</a>
                    </li>
                    <li>
                        <a href="#">Contact</a>
                    </li>
                </ul>
            </div>
            <!-- /.navbar-collapse -->
        </div>
        <!-- /.container -->
    </nav>

    <!-- Page Content -->
    <div class="container">

        <!-- Jumbotron Header -->
        <header class="jumbotron hero-spacer">
            <h1>A Warm Welcome!</h1>
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsa, ipsam, eligendi.</p>
            <p><a class="btn btn-primary btn-large">Call to action!</a>
            </p>
        </header>

        <hr>

        <!-- Title -->
        <div class="row">
            <div class="col-lg-12">
                <h3>Latest Features</h3>
            </div>
        </div>
        <!-- /.row -->

        @yield('content')

        <hr>

        <!-- Footer -->
        <footer>
            <div class="row">
                <div class="col-lg-12">
                    <p>Copyright © Your Website 2014</p>
                </div>
            </div>
        </footer>

    </div>
    <!-- /.container -->

    <script src="js/jquery.js"></script>
    <script src="js/bootstrap.min.js"></script>

</body>

</html>

            
ანუ მშობელ მაკეტში ამოჭრილი ადგილი შეივსო ამ ჩანაწერით @yield('content') ახლა შვილობილმა მაკეტმაც ხომ უნდა გაიგოს, რომ მას მშობელი სახელად ეძახის 'content'-ს ? :)) ამისათვის შვილობილ მაკეტში უნდა გამოვიყენოთ section დირექტივა, რომელსაც უნდა გადავცეთ ის სახელი რომლითაც მშობელი ეძახის შვილს :)))
@extends('layouts.site')

@section('content')

<!-- Page Features -->
<div class="row text-center">

    @foreach($articles as $article)

    <div class="col-md-3 col-sm-6 hero-feature">
        <div class="thumbnail">
            <img src="http://placehold.it/800x500" alt="">
            <div class="caption">
                <h3>{{ $article->title }}</h3>
                <p>{{ $article->desc }}</p>
                <p>
                    <a href="#" class="btn btn-default">More Info</a>
                </p>
            </div>
        </div>
    </div>

    @endforeach
   

</div>
<!-- /.row -->

@endsection
            
ამის შემდეგ ყველაფერი დალაგდება თავის ადგილას და ყველა ბედნიერი იქნება - მშობელიც და შვილიც :))
8. კონკრეტული ჩანაწერის გვერდი
ბუნებრივია კონკრეტული სიახლის სანახავად საჭიროა ცალკე გვერდი, ე.ი აუცილებელია ახალი მარშრუტის შექმნა. იმისათვის რათა სისტემამ გაიგოს თუ რომელი სიახლე უნდა გამოიტანოს, მარშუტის შაბლონის ცვალებად ანუ დინამიურ ნაწილში უნდა განვსაზღვროთ რაიმე პარამეტრი, სიახლეთა იდენტიფიკატორი, რომლის მიხედვითაც მოხდება შესაბამისი სიახლის გამოტანა კონკრეტული სიახლის გვერდზე. ამ პარამეტრის მითითება ხდება ფიგურული ფრჩხილების მეშვეობით '{პარამეტრი}'.

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

მარშრუტს მივცეთ სახელიც, ანუ შევუქმნათ ფსევდონიმი, ეს ხდება name მეთოდის დახმარებით. ჩნდება კითხვა: რა საჭიროა ეს ? პასუხი მარტივია: შესაძლებელია მოხდეს ისე, რომ დაგვჭირდეს ბმულის გენერირება, რომელიც გადამისამართდება კონკრეტულ გვერდზე, შესაბამისად საქმეში ჩაერთვება კონკრეტული მარშრუტი, სწორედ ამ საქმეს აადვილებს მარშრუტთა ფსევდონიმები. ახლა ჯერ ვაჩვენოთ თუ რა სახე მიიღო ახალმა მარშრუტმა საბოლოოდ, შემდეგ კი უფრო დაწვრილებით ვისაუბროთ ბმულების გენერირებაზე და მარშრუტთა ფსევდონიმებზე Route::get('article/{id}','IndexController@show')->name('articleShow'); როგორც ვიცით სიახლეების გამოტანისას არ მოგვიხდენია შესაბამისი ბმულების გენერირება, რედაქტირება
@extends('layouts.site')

@section('content')

<!-- Page Features -->
<div class="row text-center">

    @foreach($articles as $article)

    <div class="col-md-3 col-sm-6 hero-feature">
        <div class="thumbnail">
            <img src="http://placehold.it/800x500" alt="">
            <div class="caption">
                <h3>{{ $article->title }}</h3>
                <p>{{ $article->desc }}</p>
                <p>
                    <a href="#" class="btn btn-default">More Info</a>
                </p>
            </div>
        </div>
    </div>

    @endforeach
   

</div>
<!-- /.row -->

@endsection
            
სწორედ ამ ბმულებმა უნდა განსაზღრონ ის იდენტიფიკატორი, რომელიც უნდა გადაეცეს კონკრეტული სიახლის გვერდის მარშრუტს. ეს მოხდება დამხმარე ფუნქციის route-ს დახმარებით, რომელსაც პირველ პარამეტრად უნდა გადაეცეს სწორედ მარშრუტის ფსევდონიმი, მეორე პარამეტრად კი მასივი რომელშიც მოთავსდება სიახლეთა იდენტიფიკატორის სახელი და მნიშვნელობა
@extends('layouts.site')

@section('content')

<!-- Page Features -->
<div class="row text-center">

    @foreach($articles as $article)

    <div class="col-md-3 col-sm-6 hero-feature">
        <div class="thumbnail">
            <img src="http://placehold.it/800x500" alt="">
            <div class="caption">
                <h3>{{ $article->title }}</h3>
                <p>{{ $article->desc }}</p>
                <p>
                    <a href="{{ route('articleShow',['id'=>$article->id]) }}" class="btn btn-default">More Info</a>
                </p>
            </div>
        </div>
    </div>

    @endforeach
   

</div>
<!-- /.row -->

@endsection
            
ამ ყველაფრის შედეგად გაგენერირდება შემდეგნაირი ბმულები
http://127.0.0.1:8000/article/1
http://127.0.0.1:8000/article/2
http://127.0.0.1:8000/article/3
http://127.0.0.1:8000/article/4

...
            
ახლა IndexController-ში შევქმნათ მეთოდი show. ამ მეთოდს პარამეტრად უნდა გადაეცეს ის იდენტიფიკატორი, რომელსაც ვიყენებთ მარშრუტში
public function show($id)
{
  dd($id); 
}
            
თუ ახლა შევალთ მაგალითად ამ მისამართზე http://127.0.0.1:8000/article/4, ეკრანზე ვიხილავთ '4'-ს, ანუ კონტროლერმა მიიღო $id პარამეტრი, dd ფუნქციამ კი ეკრანზე გამოიტანა იგი (dd ანუ dump & die).

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

public function show($id)
{
  $article = Article::find($id);
}
            
იგივეს გაკეთება შესაძლებელია მოთხოვნათა კონსტრუქტორის მეშვეობითაც
public function show($id)
{
  $article = Article::select(['id','title','text'])->where('id','=',$id)->first();
}
            
შემდეგი ჩანაწერი Article::select(['id','title','text'])->where('id','=',$id)->first(); იგივეა რაც SELECT id,title,text FROM articles WHERE id='$id' LIMIT 1 როცა where პირობაში პირობითი ოპერატორად გვჭირდება ტოლობა, შესაძლებელია, რომ where მეთოდს მეორე პარამეტრი საერთოდ არ მივუთითოთ. Article::select(['id','title','text'])->where('id',$id)->first(); ახლა ბაზიდან ამოღებული ინფორმაცია გადავცეთ წარმოდგენის ფაილს public function show($id) { $article = Article::select(['id','title','text'])->where('id',$id)->first(); return view('article')->with(['article' => $article]); } ახლა შევქმნათ resources/views/article.blade.php წარმოდგენის ფაილი შემდეგი კოდით
@extends('layouts.site')

@section('content')

<!-- Page Features -->
<div class="row">

    @if($article)

    <div class="col-md-12">
        
        <h3>{!! $article->title !!}</h3>
        <p>{!! $article->text !!}</p>
                
    </div>

    @endif
   

</div>
<!-- /.row -->

@endsection
            
ახლა გავხსნათ რომელიმე ჩანაწერი, მაგალითად შევიდეთ მე-3-ე ჩანაწერის გვერდზე http://127.0.0.1:8000/article/3 სულ ესაა.. :))
9. სტატიის დამატება, მონაცემთა ვალიდაცია
დავიწყოთ მარშრუტების შექმნით , პირველ რიგში შევქმნათ იმ გვერდის მარშრუტი, რომელზეც სიახლის დასამატებელი ფორმა გამოჩნდება. // http://127.0.0.1:8000/add Route::get('add','IndexController@add'); ახლა შევქმნათ მარშრუტი ამავე გვერდისათვის, უბრალოდ ამ შემთხვევაში გვერდმა უნდა დაამუშავოს ფორმიდან გაგზავნილი ინფორმაცია, ინფორმაცია კი გაიგზავნება post მეთოდით Route::post('add','IndexController@store')->name('articleStore'); IndexController კონტროლერის add მეთოდმა უნდა გამოიტანოს html ფორმა, ხოლო store მეთოდმა ამ ფორმიდან გაგზავნილი ინფორმაცია უნდა შეიტანოს მონაცემთა ბაზაში.
public function add()
{
    return view('add');
}
            
შევქმნათ წარმოდგენის ფაილი resources/views/add.blade.php ფაილი შემდეგი კოდით
@extends('layouts.site')

@section('content')


<div class="row">

    <div class="col-md-12">
        
        <form class="form-horizontal" action="{{ route('articleStore') }}" method="post">
        <div class="form-group">
            <label class="control-label col-sm-2" for="title">სათაური: </label>
            <div class="col-sm-10">
                <input type="text" class="form-control" id="title" name="title">
            </div>
        </div>
        <div class="form-group">
            <label class="control-label col-sm-2" for="alias">ფსევდონიმი: </label>
            <div class="col-sm-10">
                <input type="text" class="form-control" id="alias" name="alias">
            </div>
        </div>
        <div class="form-group">
            <label class="control-label col-sm-2" for="desc">მოკლე აღწერა: </label>
            <div class="col-sm-10">
                <textarea class="form-control" id="desc" name="desc"></textarea>
            </div>
        </div>
        <div class="form-group">
            <label class="control-label col-sm-2" for="text">სრული ტექსტი: </label>
            <div class="col-sm-10">
                <textarea class="form-control" id="text" name="text"></textarea>
            </div>
        </div>
        <div class="form-group">
            <div class="col-sm-offset-2 col-sm-10">
                <button type="submit" class="btn btn-default">შენახვა</button>
            </div>
        </div>

        {{ csrf_field() }}


    </form>
                
                
    </div>


</div>

@endsection

       
            

csrf_field ფუნქცია

ეს ფუნქცია აგენერირებს შემდეგნაირ ველს <input type="hidden" name="_token" value="შემთხვევითად გენერირებული გასაღები"> შემთხვევითად გენერირებული გასაღები გასაღები ინახება სესიაში და ფორმის გაგზავნის შემდეგ ფრეიმვორჯი პირველ რიგში ამოწმებს ემთხვევა თუ არა სესიაში შენახული გასაღები და ფორმის გაგზავნისას გენერირებული ახალი გასაღები ერთმანეთს, თუ ემთხვევა მაშინ გრძელდება მონაცემთა დამუშავება, თუ არა - სისტემის მუშაობა ჩერდება. ეს გამოიყენება CSRF ტიპის თავდასხმათაგან თავდასაცავად.

***

ახლა store მეთოდში აღვწეროთ ინფორმაციის შესანახი ლოგიკა, პირველ რიგში მეთოდს პარამეტრად გადავცეთ Request გლობალური კლასის ობიექტი $request. გლობალური კლასი Request წარმოადგენს მომხმარებლის მიერ გაკეთებული მოთხოვნების აბსტრაქციას ანუ განზოგადოებულ სახეს, მისი მეშვეობით ხდება მოთხოვნათა დამუშავება. სწორედ $request ობიექტში შეინახება ის ინფორმაციები, რომლებსაც მომხმარებელი აკრეფს ფორმაში. ამ ინფორმაციის სანახავად კი გამოიყენება ამ ობიექტის all() მეთოდი

public function store(Request $request)
{
    dd($request->all());
}
            
იმისათვის რათა გამოვიყენოთ ფრეიმვორკში ჩადგმული ვალიდაციის სტრუქტურა, უნდა მივმართოთ კონტროლერის ობიექტის validate მეთოდს. ამ მეთოდს პირველ პარამეტრად უნდა გადავცეთ $request ცვლადი, რათა გაიგოს თუ რა ინფორმაციის ვალიდაცია გვინდა, მეორე პარამეტრად უნდა გადავცეთ მასივი, რომელშივ აღწერილი იქნება ვალიდაციის წესები, ამ მასივის გასაღებები იქნებიან ფორმის ელემენტთა დასახელებები, ხოლო გასაღებთა მნიშვნელობები - კი შესაბამისი წესები ამ ველებისათვის
public function store(Request $request)
{
    $this->validate($request, [

        'title' => 'required|max:255',
        'alias' => 'required|unique:articles,alias',
        'text' => 'required'

    ]);

    // შემდეგი კოდი
}
            
თუ ვალიდაციის ერთი წესი მაინც დაირღვევა მაშინ სისტემა გადაგვამისამართებს ისევ ფორმის გვერდზე, ამასთანავე შეტყობინებები შეცდომათა შესახებ შეინახება $errors ცვლადში. ამ შეტყობინებების ხილვა წარმოდგენის ფაილში შეიძლება შემდეგნაირად
@extends('layouts.site')

@section('content')


<div class="row">

    <div class="col-md-12">

        @if(count($errors) > 0)
        <div class="alert alert-danger">
          <ul>
              @foreach($errors->all() as $error)
                <li>{{ $error }}</li>
              @endforeach
            </ul>
        </div>
        @endif
        
        <form class="form-horizontal" action="{{ route('articleStore') }}" method="post">
        <div class="form-group">
            <label class="control-label col-sm-2" for="title">სათაური: </label>
            <div class="col-sm-10">
                <input type="text" class="form-control" id="title" name="title">
            </div>
        </div>
        <div class="form-group">
            <label class="control-label col-sm-2" for="alias">ფსევდონიმი: </label>
            <div class="col-sm-10">
                <input type="text" class="form-control" id="alias" name="alias">
            </div>
        </div>
        <div class="form-group">
            <label class="control-label col-sm-2" for="desc">მოკლე აღწერა: </label>
            <div class="col-sm-10">
                <textarea class="form-control" id="desc" name="desc"></textarea>
            </div>
        </div>
        <div class="form-group">
            <label class="control-label col-sm-2" for="text">სრული ტექსტი: </label>
            <div class="col-sm-10">
                <textarea class="form-control" id="text" name="text"></textarea>
            </div>
        </div>
        <div class="form-group">
            <div class="col-sm-offset-2 col-sm-10">
                <button type="submit" class="btn btn-default">შენახვა</button>
            </div>
        </div>

        {{ csrf_field() }}


    </form>
                
                
    </div>


</div>

@endsection

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

ვალიდაციის შემდეგ მოთხოვნაში ჩადებული ინფორმაცია უნდა მოვათავსოთ რაიმე ცვლადში მაგ: $data ცვლადში, შემდეგ შევქმნათ Article კლასის ობიექტი ანუ ცარიელი მოდელი (როგორც ვიცით Article კლასი არის 'articles' ცხრილთან სამუშაო კლასი), შემდეგ ეს მოდელი, fill მეთოდის დახმარებით შევავსოთ $data ცვლადში შენახული ინფორმაციით, ბოლოს კი შევიტანოთ ინფორმაცია ბაზაში save მეთოდის დახმარებით.

fill მეთოდის გამოიყენებისას მოდელში უნდა განვსაზღვროთ ცხრილის ის ველები, რომლებშიც ნებადართულია ინფორმაციის შეტანა, ეს ხდება დახურული თვისება $fillable-ს მეშვეობით
namespace App;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    protected $fillable = ['title','alias','desc','text'];
}
            
საბოლოო ჯამში მეთოდი store მიიღებს ასეთ სახეს
public function store(Request $request)
{
    $this->validate($request, [

        'title' => 'required|max:255',
        'alias' => 'required|unique:articles,alias',
        'text' => 'required'

    ]);

    // მოთხოვნაში ჩადებული ინფორმაცია
    $data = $request->all();
    // ცარიელი მოდელი
    $article = new Article;
    // ცარიელი მოდელის შევსება ინფორმაციით
    $article->fill($data);
    // ინფორმაციის შენახვა
    $article->save();

    // დამატების შემდეგ გადავმისამართდეთ მთავარ გვერდზე
    return redirect('/');
}
            
10. სტატიის წაშლა
ამჯერადაც დავიწყოთ მარშრუტის შექმნით, ჩანაწარეთა წასაშლელად გამოიყენება delete ტიპის მოთხოვნები, მარშრუტშივე აღვწეროთ წაშლის ფუნქციაც. ამასთანავე წარმოდგენის ფაილში, სიახლეთა განყოფილებებს დავანატოთ წაშლის ღილაკები, რომელთა დახმარებითაც მოვახდენთ delete ტიპის მოთხოვნათა იმიტირებას, იმიტირებას იმიტომ, რომ სინამდვილეში გავაგზავნით post ტიპის მოთხოვნას, სპეციალური ველის მეშვეობით კი მოხდება აღნიშნული delete ტიპის მოთხოვნის იმიტირება
@extends('layouts.site')

@section('content')

<!-- Page Features -->
<div class="row text-center">

    @foreach($articles as $article)

    <div class="col-md-3 col-sm-6 hero-feature">
        <div class="thumbnail">
            <img src="http://placehold.it/800x500" alt="">
            <div class="caption">
                <h3>{{ $article->title }}</h3>
                <p>{{ $article->desc }}</p>
                <p>
                    <a href="{{ route('deleteArticle',['id'=>$article->id]) }}" class="btn btn-default">More Info</a>
                    <form action="{{ route('deleteArticle',['article'=>$article->id]) }}" method="post">

                        <input type="hidden" name="_method" value="DELETE">
                        <button type="submit" class="btn btn-danger">წაშლა</button>

                        {{ csrf_field() }}
                        
                    </form>
                </p>
            </div>
        </div>
    </div>

    @endforeach
   

</div>
<!-- /.row -->

@endsection

       
            
მარშრუტს კი ექნება ასეთი სახე
// პარამეტრად უნდა გადავცეთ წასაშლელი ჩანაწერის იდენტიფიკატორი 'article'
Route::delete('article/delete/{article}', function($article){

  // მოდელთან მისამართავად უნდა მივუთითო ადგილთა სივრცე ამ მოდელამდე
  $article_tmp = \App\Article::where('id',$article)->first();
  $article_tmp->delete();

  return redirect('/');

})->name('deleteArticle');
            


პრაქტიკა - ერთგვერდიანი საიტი (ე.წ 'Landing Page')



1. შესავალი
ეს არის ფრეიმვორკ Laravel-ის შესწავლის პრაქტიკული ნაწილის პირველი განყოფილება, რომელშიც გავაკეთებთ მარტივ, ერთგვერდიან ამდაგვარ საიტს (შაბლონის გადმოწერა)
2. ფრეიმვორკის ინსტალაცია (WINDOWS, XAMPP)
Laravel-ის ინსტალაციისათვის აუცილებელია, რომ ჩვენს კომპიუტერში დაინსტალირებული იყოს სპეციალური ინსტრუმენტი Composer-ი.

რა არის Composer ?

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

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



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



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

ამის შემდეგ ბრძანებათა ველის მეშვეობით გადავდივართ C:\xampp\htdocs დირექტორიაში და ვუშვებთ Composer-ის ბრძანებას create-project-ს.

composer create-project --prefer-dist laravel/laravel landing ბოლოს მითითებული სიტყვა landing განსაზღვრავს ჩვენი პროექტის სახელს. ბრძანების გაშვების შემდეგ დაიწყება Laravel-ის ინსტალაცია და აგრეთვე შეიქმნება landing დირექტორია პროექტის შესაბამისი ფაილებისა და საქაღალდეების სტრუქტურაით, თუ ახლა შევალტ http://localhost/landing/ მისამართზე, ვნახავთ ახლადშექმნილი landing საქაღალდის, ფრეიმვორკის საქაღალდეებითა და ფაილებით შევსებულ სტრუქტურას



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

იმისათვის რათა გავიგოთ თუ რომელ დომეინზე ან ip-ზეა გაშვებული ჩვენს მიერ შექმნილი პროექტი ბრძანებათა ველიდან უნდა შევიდეთ ახლად შექმნილ პროექტში - landing და გავუშვათ ბრძანება php artisan serve შედეგი იქნება, რაიმე ამის მსგავსი



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



3. მონაცემთა ბაზა
მონაცემთა ბაზას დავარქვათ land, ცხრილების შესაქმნელად კი გამოვიყენოთ მიგრაციები, მაგრამ ჯერ გავარკვიოთ რა და რა ცხრილები გვჭირდება, ამისათვის დავაკვირდეთ შაბლონს. საიტის პირველი ორი განყოფილება არის home და about us, მათი შიგთავსის შესანახად უნდა შევქმნათ ცხრილი pages, გავაკეთოთ შესაბამისი მიგრაციის ფაილი create_table_pages, ამისათვის ბრძანებათა კონსოლში გავუშვათ შემდეგი ბრძანება php artisan make:migration create_table_pages --create=pages შაბლონის შემდეგი განყოფილება არის Services, უნდა შევქმნათ ცხრილი services, გავაკეთოთ მიგრაციის ფაილი create_table_services php artisan make:migration create_table_services --create=services შემდეგი განყოფილება არის Portfolio, უნდა შევქმნათ ცხრილი portfolios, გავაკეთოთ მიგრაციის ფაილი create_table_portfolios php artisan make:migration create_table_portfolios --create=portfolios შემდეგი განყოფილება არის Clients, მაგრამ აქ ახალი არაფერია და ამიტომ მასთან მუშაობაზე დროს არ დავკარგავთ, გადავიდეთ შემდეგ განყოფილება Team-ზე, მისთვის უნდა შევქმნათ ცხრილი peoples, გავაკეთოთ შესაბამისი მიგრაციის ფაილი create_table_peoples php artisan make:migration create_table_peoples --create=peoples როგორც ვიცით მიგრაციის ფაილები შეინახებოდა database/migrations სქაღალდეში.

create_table_pages მიგრაცია

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateTablePages extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('pages', function (Blueprint $table) {
            $table->increments('id'); // რიცხვითი ტიპის AI, PRIMARY_KAY 'id' ველი
            $table->string('name',100); // სტრიქონული ტიპის, მაქს. 100 სიმბოლოიანი ველი 'name'
            $table->string('alias',100); // სტრიქონული ტიპის, მაქს. 100 სიმბოლოიანი ველი 'alias'
            $table->text('text'); // ტექსტური ტიპის ველი 'text'
            $table->string('images',100); // სტრიქონული ტიპის, მაქს. 100 სიმბოლოიანი ველი 'images'
            $table->timestamps(); // created_at და updated_at ველები
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('pages');
    }
}
            

create_table_services მიგრაცია

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateTableServices extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('services', function (Blueprint $table) {
            $table->increments('id'); // რიცხვითი ტიპის AI, PRIMARY_KAY 'id' ველი
            $table->string('name',100); // სტრიქონული ტიპის, მაქს. 100 სიმბოლოიანი ველი 'name'
            $table->text('text'); // ტექსტური ტიპის ველი 'text'
            $table->string('icon',100); // სტრიქონული ტიპის, მაქს. 100 სიმბოლოიანი ველი 'icon'
            $table->timestamps(); // created_at და updated_at ველები
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('services');
    }
}

            

create_table_portfolios მიგრაცია

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateTablePortfolios extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('portfolios', function (Blueprint $table) {
            $table->increments('id'); // რიცხვითი ტიპის AI, PRIMARY_KAY 'id' ველი
            $table->string('name',100); // სტრიქონული ტიპის, მაქს. 100 სიმბოლოიანი ველი 'name'
            $table->string('images',100); // სტრიქონული ტიპის, მაქს. 100 სიმბოლოიანი ველი 'images'
            $table->string('filter',100); // სტრიქონული ტიპის, მაქს. 100 სიმბოლოიანი ველი 'filter'
            $table->timestamps(); // created_at და updated_at ველები
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('portfolios');
    }
}
            

create_table_peoples მიგრაცია

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateTablePeoples extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('peoples', function (Blueprint $table) {
            $table->increments('id'); // რიცხვითი ტიპის AI, PRIMARY_KAY 'id' ველი
            $table->string('name',255); // სტრიქონული ტიპის, მაქს. 255 სიმბოლოიანი ველი 'name'
            $table->string('position',150); // სტრიქონული ტიპის, მაქს. 150 სიმბოლოიანი ველი 'position'
            $table->string('images',100); // სტრიქონული ტიპის, მაქს. 100 სიმბოლოიანი ველი 'images'
            $table->text('text'); // ტექსტური ტიპის ველი 'text'
            $table->timestamps(); // created_at და updated_at ველები
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('peoples');
    }
}

            

წვდომა mysql სერვერთან

ჩვენ ჯერ არ გვითქვამს ფრეიმვორკისთვის, თუ მონაცემთა რომელ ბაზსთან ვმუშაობთ. ამისათვის .env ფაილში უნდა განვსაზღვროთ კონკრეტული კონფიგურაციული პარამეტრები:
...       
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=land
DB_USERNAME=root
DB_PASSWORD=
...
            
ახლა უკვე შეგვიძლია გავუშვათ მიგრაციის ბრძანება php artisan migrate ეს ბრძანება შექმნის მბ-ს ცხრილებს, რომლებიც აღწერილია მიგრაციის ფაილებში. ისღა დაგვრჩენია შევავსოთ ეს ცხრილები რაიმე ინფორმაციით (ეს საკმაოდ მარტივი პროცესია და ამიტომ დროს აღარ დავკარგავთ განმარტებებით)
4. მარშრუტები

routes/web.php ფაილი

/*
|--------------------------------------------------------------------------
| სამომხმარებლო მარშუტები
|--------------------------------------------------------------------------
| შევქმნათ მარშრუტთა ჯგუფი, ამ ჯგუფში შემავალ ყველა მარშრუტს უხეშად, რომ ვთქვათ 
| მოუწევს შუამავალ web-ში გავლა,
*/


Route::group(['middleware'=>'web'],function(){

    /*
      მთავარი გვერდის მარშრუტი, post ტიპი საჭიროა იმიტომ რომ ამ 
      გვერდზე გვხვდება სკონტაქტო ფორმაც. ამ გვერდს დაამუშავებს IndexController
      კონტროლერის მეთოდი execute, კონტროლერის ფსევდონიმი  იქნება home
    */ 
  Route::match(['get','post'],'/',['uses'=>'IndexController@execute','as'=>'home']);

  /*
      შაბლონის home განყოფილებაში არის სლაიდის მაგვარი რაღაც, რომელსაც აქვს 
      სხვა გვერდზე გადასასვლელი ღილაკი, get ტიპის ეს მარშრუტი უზრუნველყოფს 
      ამ გვერდების გახსნას: მაგ: landing.ge/page/about. ამას გააკეთებს
      PageController კონტროლერის მეთოდი execute, კონტროლერის ფსევდონიმი  იქნება page
    */ 
  Route::get('/page/{alias}',['uses'=>'PageController@execute','as'=>'page']);

  // Route::auth();


});


/*
|--------------------------------------------------------------------------
| ადმინისტრატორის განყოფილების მარშუტები
|--------------------------------------------------------------------------
| შევქმნათ მარშრუტთა ჯგუფი, ამ ჯგუფში შემავალ ყველა მარშრუტს უხეშად, 
| რომ ვთქვათ მოუწევს შუამავალ web-ში გავლა,
*/

/*
  ამ ჯგუფში შემავალი მარშრუტები დაამუშავებენ მხოლოდ ადმინისტრატორისათვის 
  ხელმისაწვდომ გვერდების მოთხოვნებს, ამ გვერდების პრეფიქსი იქნება admin, 
  მაგალითად : landing.ge/admin/services. რადგან ამ გვერდზე წვდომა 
  შეზღუდულია დაგვჭირდება შუამავალი auth
*/ 
Route::group(['prefix'=>'admin','middleware'=>'auth'], function(){

    // ადმინ. განყოფილების მთავარი გვერდი: landing.ge/admin
    Route::get('/', function(){

  });

    // გვერდების განყოფილება ადმინში
  Route::group(['prefix'=>'pages'],function(){

        // ამ გვერდზე იქნება გვერდების ჩამონათვალი landing.ge/admin/pages
        Route::get('/',['uses'=>'PagesController@execute','as'=>'pages']);

        /* 
          გვერდების დამატების განყოფილება landing.ge/admin/pages/add   get მეთოდი საჭიროა 
          იმიტომ რომ გვერდი გაიხსნას და  post მეთოდი კი საჭიროა იმიტომ, რომ დამუშავდეს 
          დასამატებელ ფორმაში აკრეფილი ინფორმაცია.
        */
        Route::match(['get','post'],'/add',['uses'=>'PagesAddController@execute','as'=>'pagesAdd']);
        /* 
          გვერდების რედაქტირების განყოფილება landing.ge/admin/pages/edit/2   get მეთოდი 
          საჭიროა იმიტომ რომ გვერდი გაიხსნას და post მეთოდი კი საჭიროა იმიტომ, რომ დამუშავდეს 
          დასამატებელ ფორმაში აკრეფილი ინფორმაცია, delete მეთოდი კი ჩანაწერთა წასაშლელად
        */
        Route::match(['get','post','delete'],'/edit/{page}',['uses'=>'PagesEditController@execute','as'=>'pagesEdit']);

  });


  // პორტფოლიოს განყოფილება ადმინში
  Route::group(['prefix'=>'portfolio'],function(){

        Route::get('/',['uses'=>'PortfolioController@execute','as'=>'portfolio']);

        Route::match(['get','post'],'/add',['uses'=>'PortfolioAddController@execute','as'=>'portfolioAdd']);
        Route::match(['get','post','delete'],'/edit/{portfolio}',['uses'=>'PortfolioEditController@execute','as'=>'portfolioEdit']);

  });


  // სერვისების განყოფილება ადმინში
  Route::group(['prefix'=>'services'],function(){

        Route::get('/',['uses'=>'ServiceController@execute','as'=>'services']);

        Route::match(['get','post'],'/add',['uses'=>'ServiceAddController@execute','as'=>'serviceAdd']);
        Route::match(['get','post','delete'],'/edit/{service}',['uses'=>'ServiceEditController@execute','as'=>'serviceEdit']);

  });

});
            
5. მთავარი კონტროლერი და წარმოდგენა
მთავარი გვერდის ჩატვირთვა უნდა უზრუნველჰყოს IndexController კონტროლერმა. შევქმნათ იგი ბრძანებათა კონსოლის მეშვეობით, php artisan make:controller IndexController იმისათვის რათა დავრწმუნდეთ, რომ მთავარი გვერდის მარშრუტიც სწორად დავწერეთ და კონტროლერშიც ყველაფერი რიგზეა, საწყის ეტაპზე ამ კონტროლერის execute მეთოდს გამოვატანინოთ laravel-ის მისასალმებელი წარმოდგენის ფაილი welcome
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class IndexController extends Controller
{
    public function execute (Request $request) 
    {

      return view('welcome');
    }
}
            
ამის შემდეგ http://127.0.0.1:8000/ (ჩემს შემთხვევაში ამ ip-ზეა განთავსებული პროექტი, არ ვიცი თქვენ როგორ დააკონფიგურირებთ სისტემას) მისამართზე შესვლისას უნდა ვნახოთ welcome წარმოდგენის ფაილი.

მაკეტის გამზადება

დავაკვირდეთ სამიზნე საიტის საქაღალდეთა და ფაილთა სტრუქტურას



index.html ფაილის გარდა აქ არის სხვა ისეთი საქაღალდეები და ფაილებიც, რომლებიც ხელმისაწვდომია ყველასათვის და რომლებიც გვერდის სწორად და კორექტულად გახსნისათვისაა საჭირო (css, js და ა.შ). ამდაგვარი ფაილებისა და საქაღალდეების განსათავსებლად, ფრეიმვორკ laravel-ში გამოიყენება public დირექტორია, მასში შევქმნათ ჩვენი საკუთარი საქაღალდე assets და ზემოთ აღნიშნული ფაილები და საქაღალდეები ჩავაკოპიროთ აქ.

resources/views საქაღალდეში შევქმნათ ახალი საქაღალდე layouts. ამ საქაღალდეში შევქმნათ ფაილი site.blade.php, რომელიც მომავალში იქნება პროექტის მთავარი გვერდის მაკეტი. მასში ჩავაკოპიროთ სამიზნე საიტის index.html გვერდის კოდი და კონტროლერიც გადავაკეთოთ შესაბამისად

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class IndexController extends Controller
{
    public function execute (Request $request) 
    {

      return view('layouts.site');
    }
}
            
თუ ახლა პროექტის მთავარ გვერდს გავხსნით ვიხილავთ, რომ ჩვენს მიერ ჩაკოპირებული html სტრუქტურა აღქმული ექნება სისტემას, მაგრამ ეს გვერდი არ იქნება დაკავშირებული public/assets საქაღალდეში შენახულ, გვერდის კორექტულად ჩატვირთვისათვის საჭირო საქაღალდეებთან და ფაილებთან, მათთან დაკავშირება (მაგალითად css-თან) ხდება კოდის ამ ფრაგმენტით
<link href="css/bootstrap.min.css" rel="stylesheet" type="text/css">
<link href="css/style.css" rel="stylesheet" type="text/css"> 
<link href="css/font-awesome.css" rel="stylesheet" type="text/css"> 
<link href="css/animate.css" rel="stylesheet" type="text/css">
            
როგორც ვხედავთ აქ მითითებულია, რომ css ფაილები განთავსებულია css საქაღალდეში, მაგრამ წარმოდგენის ჩვენი ფაილი site.blade.php და ეს css ფაილები იერარქიულად სხვადასხვა საფეხურებზე შენახულ დირექტორიებში ინახება, და სწორედ ამიტომ ვერ უკავშირდებიან ერთმანეთს. ამ პრობლემის მოსაგვარებლად გამოვიყენოთ ფრეიმვორკში ჩადგმული დამხმარე asset(), რომელიც აგენერირებს URL-ებს იმ ელემენტებისათვის, რომლებიც განთავსებულია ფრეიმვორკის public საქაღალდეში. ამ დამხმარეს არგუმენტად უნდა გადაეცეს გზა უშუალოდ public საქაღალდიდან, ამავე საქაღალდეში განთავსებულ სამიზნე ელემენტამდე ჩვენს შემთხვევაში ეს ელემენტები განთავსებულია assets საქაღალდეში ამიტომ :
<link href="{{ asset('assets/css/bootstrap.min.css') }}" rel="stylesheet" type="text/css">
<link href="{{ asset('assets/css/style.css') }}" rel="stylesheet" type="text/css"> 
<link href="{{ asset('assets/css/font-awesome.css') }}" rel="stylesheet" type="text/css"> 
<link href="{{ asset('assets/css/animate.css') }}" rel="stylesheet" type="text/css">
            
ზუსტად ანალოგიურად უნდა მოვიქცეთ სხვა ხელსაწყოებთან მიმარტებაშიც (js, სურათები, ფონტები და ა.შ).
6. მოდელების შექმნა, მონაცემთა ამოღება მბ-დან
წინა თავში შექმნილი მაკეტი დავყოთ ფრაგმენტებად, გავაგრძელოთ მთავარი გვერდის კონტროლერთან მუშაობა და შევქმნმათ მოდელები მბ-დან ინფორმაციის ამოსაღებად.

მოდელები

მბს ცხრილ pages-თან სამუშაოდ შევქმნათ მოდელი Page php artisan make:model Page მბს ცხრილ portfolios-თან სამუშაოდ შევქმნათ მოდელი Portfolio php artisan make:model Portfolio მბს ცხრილ peoples-თან სამუშაოდ შევქმნათ მოდელი People php artisan make:model People მბს ცხრილ services-თან სამუშაოდ შევქმნათ მოდელი Service php artisan make:model Service ეს მოდელები, როგორც ვიცით, შეინახება app საქაღალდეში. რასაკვირველია ამ მოდელებთან კავშირი უნდა დავამყაროთ მთავარი გვერდის კონტროლერიდან - IndexController-იდან.
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Page;
use App\Portfolio;
use App\Service;
use App\People;

class IndexController extends Controller
{
    public function execute (Request $request) 
    {

      return view('layouts.site');
    }
}
            
ახლა კი ბაზიდან ამოვიღოთ საჭირო ინფორმაციები საჭირო ცხრილებიდან. თეორიული ნაწილის გახსენების მიზნით, ეს გავაკეთოთ სხვადასხვანაირად
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Page;
use App\Portfolio;
use App\Service;
use App\People;

class IndexController extends Controller
{
    public function execute (Request $request) 
    {
      // ყველა ჩანაწერი Pages ცხრილიდან
      $pages = Page::all();
      // ყველა ჩანაწერის 'name','filter' და 'images' ველები Portfolios ცხრილიდან
      $portfolios = Portfolio::get(array('name','filter','images'));
      // ყველა ის ჩანაწერი Services ცხრილიდან რომელთათვისაც id < 20
      $services = Service::where('id','<',20)->get();
      // პირველი სამი ჩანაწერი Peoples ცხრილიდან 
      $peoples = People::take(3)->get();

      return view('layouts.site');
    }
}
            
ამ კოდმა მოგვცა ასეთი შეცდომა : SQLSTATE[42S02]: Base table or view not found: 1146 Table 'land.people' doesn't exist ანუ სისტემამ, ჩემთვის გაურკვეველი მიზეზების გამო, ჩათვალა, რომ ვმუშაობთ people ცხრილთან და არა peoples ცხრილთან (რატომ არ მოხდა იგივე სხვა ცხრილებისთვის ?!..). ეს პრობლემა შეიძლება მოგვარდეს ერთი იმით, რომ ცხრილს გადავარქვათ სახელი და დავარქვათ people, ან შესაბამის მოდელში აღვწეროთ დახურული თვისება, რომელშიც თავიდან განვსაზღვრავთ, მოდელისათვის საჭირო ცხრილის სახელს
namespace App;

use Illuminate\Database\Eloquent\Model;

class People extends Model
{
    protected $table = 'peoples';
}

            
ახლა ეს ინფორმაციები განვათავსოთ, მაკეტში, მაგრამ მანამდე გავამარტივოთ მაკეტის სტრუქტურა და დავყოთ იგი ფრაგმერნტებად. ცალკე ფრაგმენტებში გავიტანოთ საიტის მენიუ და ძირითადი შიგთავსი საიტის ძირთან ერთად. views საქაღალდეში გავაკეთოთ ახალი საქაღალდე site და ეს ფრაგმენტები მოვათავსოთ მასში. მენიუსათვის გავაკეთოთ header.blade.php ფაილი და მასში მოვათავსოთ, მთავარი გვერდის ფაილის - site.blade.php-ის header (Header_section) სექციიდან ამოჭრილი ეს ფრაგმენტი
<div class="container">
  <div class="header_box">
    <div class="logo"><a href="#"><img src="{{ asset('assets/img/logo.png') }}" alt="logo"></a></div>
    <nav class="navbar navbar-inverse" role="navigation">
    <div class="navbar-header">
      <button type="button" id="nav-toggle" class="navbar-toggle" data-toggle="collapse" data-target="#main-nav"> 
<span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span> </button> </div> <div id="main-nav" class="collapse navbar-collapse navStyle"> <ul class="nav navbar-nav" id="mainNav"> <li class="active"><a href="#hero_section" class="scroll-link">Home</a></li> <li><a href="#aboutUs" class="scroll-link">About Us</a></li> <li><a href="#service" class="scroll-link">Services</a></li> <li><a href="#Portfolio" class="scroll-link">Portfolio</a></li> <li><a href="#clients" class="scroll-link">Clients</a></li> <li><a href="#team" class="scroll-link">Team</a></li> <li><a href="#contact" class="scroll-link">Contact</a></li> </ul> </div> </nav> </div> </div>
site.blade.php ფაილში კი იმ ადგილას სადაც მენიუ იყო ამოჭრამდე ანუ header ბლოკში, გამოვიძახოთ სექცია yield დირექტივის მეშვეობით.
<!--Header_section-->
<header id="header_wrapper">
  @yield('header')
</header>
<!--Header_section--> 
            

ანალოგიურად მოვიქცეთ საიტის ძირითადი შიგთავსისათვისაც. შაბლონის Hero_Section - დან მოყოლებული ამოვჭრათ ყველაფერი საიტის ძირის ჩათვლით (footer), ჯავასკრიპტის წყაროების მითითებამდე, views/site საქაღალდეში გავაკეთოთ ახალი ფაილი content.blade.php და ეს ამოჭრილი კოდი მოვათავსოთ იქ.

ამოჭრილი კოდის ადგილას კი მივუთითოთ სექციის გამოძახება
<!--Hero_Section-->
  @yield('content')
            
თუ ახლა გვერდს დავარეფრეშებთ, სიცარიელეს ვიხილავთ, ეს იმიტომ, რომ ამჟამად გვერდის კოდში მხოლოდ html სტრუქტურის ჩონჩხია (head განფოფილება და ჯავასკრიპტის წყაროების მიმთითებელი ელემენტები), ამაში ადვილად დავრწმუნდებით, თუ გავხსნით გვერდის კოდს (Ctrl + U). ჩნდება კითხვა რატომ არ არის შიგთავსი გვერდის კოდში? ეს იმიტომ რომ ამ მომენტისათვის კონტროლერში ხდება წარმოდგენის შემდეგი ფაილის გამოძახება return view('layouts.site'); წარმოდგენის ამ ფაილიდან კი ჩვენ ამოვჭერით შიგთავსი და გავიტანეთ ცალკე მაკეტებში. views/site საქაღალდეში გავაკეთოთ ძირითადი წარმოდგენის მემკვიდრე წარმოდგენის შემცველი ახალი ფაილი index.blade.php, მასში გავაერთიანოთ ეს მაკეტები
@extends('layouts.site')

@section('header')
  @include('site.header')
@endsection

@section('content')
  @include('site.content')
@endsection
            
და კონტროლერიდანაც სწორედ ამ შაბლონის ჩატვირთვა მოვახდინოთ. return view('site.index');
7. ბაზიდან ამოღებული ინფორმაციის ეკრანზე გამოტანა
დავიწყოთ მენიუდან. როგორც ვიცით ერთგვერდიან საიტებზე ნავიგაციის სქემა ჯავასკრიპტის დახმარებით დაახლოებით ამდაგვარია : მენიუს კონკრეტულ ბმულზე მაუსის დაჭერისას ფიქსირდება მისი რომელიმე ატრიბუტის მნიშვნელობა, შემდეგ კი იძებნება ისეთი სექცია ან სხვა html ელემენტი, რომლისთვისაც მაგალითად id-ის მნიშვნელობა არის ზემოთ ნახსენები ბმულის კონკრეტული ატრიბუტის მნიშიშვნელობის ტოლი და შემდეგ ხდება ბრაუზერის ჩასრიალება, ე.წ "ჩასქროლვა" ამ ელემენტამდე. მაგალითად ჩვენს შემთხვევაში
<ul class="nav navbar-nav" id="mainNav">
  <li class="active"><a href="#home" class="scroll-link">Home</a></li>
  <li><a href="#aboutUs" class="scroll-link">About Us</a></li>
  <li><a href="#service" class="scroll-link">Services</a></li>
  <li><a href="#Portfolio" class="scroll-link">Portfolio</a></li>
  <li><a href="#clients" class="scroll-link">Clients</a></li>
  <li><a href="#team" class="scroll-link">Team</a></li>
  <li><a href="#contact" class="scroll-link">Contact</a></li>
</ul>
            
ბმულზე დაჭერისას ფიქსირდება href ატრიბუტის მნიშვნელობა, შემდეგ იძებნება ისეთი ელემენტი, რომლის id არის ამ ნაპოვნი მნიშვნელობის ტოლი (# სიმბოლოს გარეშე), და ბრაუზერშიც ხდება "ჩასრიალება" ამ ელემენტამდე. მენიუს პირველი ორი პუნქტი დინამიურია და შენახული გვაქვს ბაზაში, დანარჩენები კი სტატიკური ელემენტებია pages ცხრილში ამჟამად ასეთი მდგომარეობა უნდა გვქონდეს



კონტროლერში გავაკეთოთ მასივი $menu, რომელშიც შევინახავთ pages ცხრილიდან ამოღებულ name და alias მნიშვნელობებს, შემდეგ კი ეს მასივი უნდა გადავცეთ view მეთოდს წარმოდგენის ფაილთან ერთად (მასთან ერთად ბარემ გადავცეთ სხვა ცვლადებიც).
 namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Page;
use App\Portfolio;
use App\Service;
use App\People;

class IndexController extends Controller
{
    public function execute (Request $request) 
    {
      // ყველა ჩანაწერი Pages ცხრილიდან
      $pages = Page::all();
      // ყველა ჩანაწერის 'name','filter' და 'images' ველები Portfolios ცხრილიდან
      $portfolios = Portfolio::get(array('name','filter','images'));
      // ყველა ის ჩანაწერი Services ცხრილიდან რომელთათვისაც id < 20
      $services = Service::where('id','<',20)->get();
      // პირველი სამი ჩანაწერი Peoples ცხრილიდან 
      $peoples = People::take(3)->get();

        $menu = array();
        foreach ($pages as $page)
        {
            $item = array('title'=>$page->name,'alias'=>$page->alias);
            array_push($menu,$item);
        }

      return view('site.index',array(
                                    'pages'=>$pages,
                                    'portfolios'=>$portfolios,
                                    'services'=>$services,
                                    'menu'=>$menu
                                ));
    }
}
            
ახლა შევიტანოთ ცვლილებები resources/views/site/header.blade.php ფაილში
<div class="container">
  <div class="header_box">
    <div class="logo"><a href="#"><img src="{{ asset('assets/img/logo.png') }}" alt="logo"></a></div>

    @if(isset($menu))
      <nav class="navbar navbar-inverse" role="navigation">
      <div class="navbar-header">
        <button type="button" id="nav-toggle" class="navbar-toggle" data-toggle="collapse" data-target="#main-nav"> 
<span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span> </button> </div> <div id="main-nav" class="collapse navbar-collapse navStyle"> <ul class="nav navbar-nav" id="mainNav"> @foreach($menu as $item) <li><a href="#{{ $item['alias'] }}" class="scroll-link">{{ $item['title'] }}</a></li> @endforeach <li><a href="#service" class="scroll-link">Services</a></li> <li><a href="#Portfolio" class="scroll-link">Portfolio</a></li> <li><a href="#clients" class="scroll-link">Clients</a></li> <li><a href="#team" class="scroll-link">Team</a></li> <li><a href="#contact" class="scroll-link">Contact</a></li> </ul> </div> </nav> @endif </div> </div>
ახლა გამოვიტანოთ Home და About განყოფილებების შიგთავში. ამისათვის resources/views/site/content.blade.php ფაილში შესაბამისი ბლოკები დავარედაქტიროთ შემდეგნაირად
@if(isset($pages) && is_object($pages))

  @foreach($pages as $key => $value)

    @if($key%2 === 0)
      <section id="home" class="top_cont_outer">
        <div class="hero_wrapper">
          <div class="container">
            <div class="hero_section">
              <div class="row">
                <div class="col-lg-5 col-sm-7">
                  <div class="top_left_cont zoomIn wow animated"> 
                    {!! $value->text !!}
                    <a href="{{ route('page',array('alias'=>$value->alias)) }}" class="read_more2">Read more</a> </div>
                </div>
                <div class="col-lg-7 col-sm-5">
                  {!! Html::image('assets/img/'.$value->images) !!}
                </div>
              </div>
            </div>
          </div>
        </div>
      </section>
      <!--Hero_Section--> 
    @else
      <section id="about"><!--Aboutus-->
        <div class="inner_wrapper">
          <div class="container">
            <h2>About Us</h2>
            <div class="inner_section">
          <div class="row">
              <div class=" col-lg-4 col-md-4 col-sm-4 col-xs-12 pull-right">
                {!! Html::image('assets/img/'.$value->images,'',array('class'=>'img-circle delay-03s animated wow zoomIn')) !!}
              </div>
                <div class=" col-lg-7 col-md-7 col-sm-7 col-xs-12 pull-left">
                  <div class=" delay-01s animated fadeInDown wow animated">
                  {!! $value->text !!}
                  <div class="work_bottom"> 
                    <span>Want to know more..</span> 
                    <a href="{{ route('page',array('alias'=>$value->alias)) }}" class="contact_btn">Contact Us</a> 
                  </div>       
             </div>
                
              </div>
            
              
            </div>
          </div> 
          </div>
      </section>
      <!--Aboutus--> 
    @endif

  @endforeach

@endif
            
გავარჩიოთ ეს კოდი.

პირველ რიგში მოვახდინეთ იმის გადამოწმება არსებობს თუ არა $pages ცვლადი და შეიცავს თუ არა იგი ობიექტს. ამ ცვლადში, როგორც ვიცით, შენახულია Home და About სექციებში განსათავსებელი ინფორმასია, მაგრამ ამ სექციების html წყობა და სინტაქსი, როგორც შაბლონიდანაც ჩანს, განსხვავებულია და ამიტომ foreach ციკლში $key%2 === 0 ჩანაწერით ვამოწმებთ $pages მასივის მიმდინარე ინექსის ლუწ-კენტობას, და შედეგის მიხედვით გამოგვაქვს html სტრუქტურა, ამ მასივში სექციების შიგთავსი ასეთი თანმიმდევრობითაა შენახული

[
  0 => 'Home',  // ლუწი ინდექსი
  1 => 'About', // კენტი ინდექსი
]
            

{!! $value->text !!} ეს ჩანაწერი, როგორც ვიცით, გამოიყენება html ტეგების აღსაქმელად, სექციების ტექსტები ხომ შეიცავენ html ტეგებს

<h2>WE CREATE AWESOME WEB TEMPLATES</h2>
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry...</p>
...
            
შემდეგი ჩანაწერი კი route დამხმარეს მიხედვით ახდენს ბმულის გენერირებას <a href="{{ route('page',array('alias'=>$value->alias)) }}" class="read_more2">Read more</a> შემდეგი ჩანაწერი კი მიმართავს Html ფასადს და ასე აგენერირებს img ელემენტს, ამ ფასადის გამოსაყენებლად გააქტიურებული უნდა გვქონდეს შესაბამისი სერვის-პროვაიდერი. გასააქტიურებელი ინსტრუქცია იხილეთ აქ. {!! Html::image('assets/img/'.$value->images) !!}
8. მთავარ გვერდზე მუშაობა

სერვისების სექცია

@if(isset($services) && is_object($services))

<!--Service-->
<section  id="service">
  <div class="container">
    <h2>Services</h2>
    <div class="service_wrapper">

      <div class="row">

        @foreach($services as $key => $service)

        <div class="col-lg-4 {{ $key>2 ? 'mrgTop' : '' }} {{ ($key%3)!=0 ? 'borderLeft' : '' }}">
            <div class="service_block">
              <div class="service_icon delay-03s animated wow  zoomIn"> <span><i class="fa {{ $service['icon'] }}"></i></span> </div>
              <h3 class="animated fadeInUp wow">{{ $service['name'] }}</h3>
              <p class="animated fadeInDown wow">{{ $service['text'] }}</p>
            </div>
          </div>

        @endforeach

      </div>

    </div>
  </div>
</section>
<lt;!--Service-->

@endif
            

პორტფოლიოს სექცია

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

use Illuminate\Http\Request;

use App\Page;
use App\Portfolio;
use App\Service;
use App\People;
use DB;

class IndexController extends Controller
{
    public function execute (Request $request) 
    {
      // ყველა ჩანაწერი Pages ცხრილიდან
      $pages = Page::all();
      // ყველა ჩანაწერის 'name','filter' და 'images' ველები Portfolios ცხრილიდან
      $portfolios = Portfolio::get(array('name','filter','images'));
      // ყველა ის ჩანაწერი Services ცხრილიდან რომელთათვისაც id<20
      $services = Service::where('id','<',20)->get();
      // პირველი სამი ჩანაწერი Peoples ცხრილიდან 
      $peoples = People::take(3)->get();
      // 'filter' ველის უნიკალური მნიშვნელობების ამოღება Portfolios ცხრილიდან
      $filters = DB::table('portfolios')->select('filter')->distinct()->get();

      $menu = array();
      foreach ($pages as $page)
      {
          $item = array('title'=>$page->name,'alias'=>$page->alias);
          array_push($menu,$item);
      }

      return view('site.index',array(
                                    'pages'=>$pages,
                                    'portfolios'=>$portfolios,
                                    'services'=>$services,
                                    'menu'=>$menu,
                                    'filters' => $filters
                                ));
    }
}
            
შაბლონიზატორის portfolio სექცია მიიღებს ასეთ სახეს
@if(isset($portfolios) && is_object($portfolios))
<!-- Portfolio -->
<section id="Portfolio" class="content"> 
  
  <!-- Container -->
  <div class="container portfolio_title"> 
    
    <!-- Title -->
    <div class="section-title">
      <h2>Portfolio</h2>
    </div>
    <!--/Title --> 
    
  </div>
  <!-- Container -->
  
  <div class="portfolio-top"></div>
  
  <!-- Portfolio Filters -->
  <div class="portfolio"> 
    
    <div id="filters" class="sixteen columns">
      <ul class="clearfix">
        <li>
          <a id="all" href="#" data-filter="*" class="active">
            <h5>All</h5>
          </a>
        </li>
        @foreach($filters as $filter)
        <li>
          <a class="" href="#" data-filter=".{{ $filter->filter }}">
            <h5>{{ $filter->filter }}</h5>
          </a>
        </li>
        @endforeach
      </ul>
    </div>
    <!--/Portfolio Filters --> 
    
    <!-- Portfolio Wrapper -->
    <div class="isotope fadeInLeft animated wow" style="position: relative; overflow: hidden; height: 480px;" id="portfolio_wrapper"> 
      
      @foreach($portfolios as $portfolio)
      <!-- Portfolio Item -->
      <div style="position: absolute; left: 0px; top: 0px; transform: translate3d(0px, 0px, 0px) scale3d(1, 1, 1); width: 337px; opacity: 1;"  
class="portfolio-item one-four {{ $portfolio->filter }} isotope-item"> <div class="portfolio_img"> {!! Html::image('assets/img/'.$portfolio->images, $portfolio->name) !!} </div> <div class="item_overlay"> <div class="item_info"> <h4 class="project_name">{{ $portfolio->name }}</h4> </div> </div> </div> <!--/Portfolio Item --> @endforeach </div> <!--/Portfolio Wrapper --> </div> <!--/Portfolio Filters --> <div class="portfolio_btm"></div> <div id="project_container"> <div class="clear"></div> <div id="project_data"></div> </div> </section> <!--/Portfolio --> @endif
ზუსტად ანალოგიოურად მოხდება clients და team სექციების გამოტანა, ამიტომ აღარ დავკონკრეტდებით.
9. კონტაქტის სექცია, ელ_ფოსტის გაგზავნის მექანიზმი

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

საკონტაქტო ფორმა აღწერილია გვერდის შაბლონის <footer ბლოკში მოთავსებულ contact კლასის მქონე div ელემენტში. მაგრამ აქ მითიტებულია მხოლოდ ტექსტური ელემენები და გასაგზავნი ღილაკი. ჩავასწოროთ კოდი ამდგაგვარად და შემდეგ გავარჩიოთ იგი
<form action="{{ route('home') }}" method="post">
    <input class="input-text" name="name" type="text" name="" value="Your Name *" onFocus="if(this.value==this.defaultValue)this.value='';"  
onBlur="if(this.value=='')this.value=this.defaultValue;"> <input class="input-text" name="email" type="text" name="" value="Your E-mail *" onFocus="if(this.value==this.defaultValue)this.value='';"
onBlur="if(this.value=='')this.value=this.defaultValue;"> <textarea name="text" class="input-text text-area" cols="0" rows="0" onFocus="if(this.value==this.defaultValue)this.value='';"
onBlur="if(this.value=='')this.value=this.defaultValue;">Your Message *</textarea> {{ csrf_field() }} <input class="input-btn" type="submit" value="send message"> </form>
განვსაზღვრეთ form ელემენტი და route დამხმარე ფუნქციის მეშვეობით განვუსაზღვრეთ action ატრიბუტი action="{{ route('home') }}" ეს ჩანაწერი ნიშნავს, რომ ფორმიდან გაგზავნილი ინფორმაცია დაამუშავოს იმ მარშრუტის შესაბამისმა გვერდმა, რომლის სახელიცაა home, ეს კი, როგორც ვიცით, არის მთავარი გვერდი.

შემდეგ ტექსტურ ველებს განვუსაზღვრეთ name ატრიბუტები.

რაც სეეხება ამ ჩანაწერს {{ csrf_field() }} ეს ჩანაწერი შეგვეძლო ჩაგვენაცვლებინა მისივე ტოლფასი შემდეგი ჩანაწერით <input type="hidden" name="_token" value="{{ csrf_token() }}"> ეს გამოსახულებები ახდენენ დამალული ტექსტური ველის გენერირებას, რომლის value ატრიბუტის მნიშვნელობა არის შემთხვევითად გენერირებული გასაღები (token) <input type="hidden" name="_token" value="rOhYh7ERdvXlpQzu1SZ03O8RNV0sEJktKhnfJEiq"> ეს გასაღები ანუ ე.წ token გამოიყენება CSRF-სგან თავდასაცავად (CSRF იშიფრება, როგორც Cross-site request forgery, ეს არის საიტთან მუშაობის სახიფათო მიდგომა, რომლის დროსაც ხდება არაავტორიზებული ბრძანებების გაშვება მომხმარებლის მიერ)

კონტროლერი

IndexController კონტროლერში აღწერილი გვაქვს მეთოდი execute, ამ მეთოდში უნდა გადავამოწმოთ არის თუ არა მოთხოვნა post ტიპის. ამისათვის შევქმნათ პირობითი ოპერატორი, რომელშიც მოთხოვნის ობიქტის $request-ის isMethod() მეთოდის დახმარებით გავიგებთ თუ რა სახისაა მოთხოვნა. თუ მოთხოვნა post ტიპისაა მაშინ უნდა მოვახდინოთ მონაცემთა ვალიდაცია. ვალიდაციისათვის კი, $this სიტყვაგასაღებით უნდა მივმართოთ მიმდინარე კონტროლერის ობიექტს და გამოვიძახოთ ამ ობიექტის მეთოდი validate, ამ მეთოდს კი თავის მხრივ უნდა გადავცეთ გადასამოწმებელი ინფორმაციები და მათი გადამოწმების წესები. მოთხოვნაში ჩადებული ინფორმაციები შევინახოთ $data ცვლადში და სატესტოდ დავაბეჭდინოთ ეს ცვლადი.
class IndexController extends Controller
{
    public function execute (Request $request) 
    {

        if ($request->isMethod('post'))
        {
            $messages = [
                'required' => 'ველი :attribute აუცილებლად უნდა შეავსოთ',
                'email' => 'აკრიფეთ სწორი ელ_ფოსტა'
            ];

            $this->validate($request, [

                'name' => 'required|max:100',
                'email' => 'required|email',
                'text' => 'required'

            ], $messages);

            $data = $request->all();
            dd($data);
        }

        // ....
}

            

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

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

ელ_ფოსტის გაგზავნის კონფიგურაციული პარამეტრები აღწერილია config/mail.php ფაილში. პირველი პარამეტრი არის 'driver' => env('MAIL_DRIVER', 'smtp'), იგი განსაზღვრავს თუ რომელი დრაივერით ხდება ელ_ფოსტის გაგზავნა და იქვე მითითებულია ამ პარამეტრის შესაძლო მნიშვნელობები ("smtp", "sendmail", "mailgun", "mandrill", "ses", "sparkpost", "log", "array"). უნდა აღინიშნოს, რომ ამ პარამეტრის და ასევე სხვა პარამეტრების მნიშვნელობათა გასარკვევად სისტემა პირველ რიგში მიმართავს .env ფაილს env ფუნქციის დახმარებით, თუ ამ ფაილში არ იქნება განსაზღვრული მნიშვნელობები მაშინ სისტემა გამოიყენებს იმ მნიშვნელობებს, რომლებიც მეორე პარამეტრებად არის გადაცემილი env ფუნქციისათვის.

config/mail.php ფაილში აღწერილი პარამეტრები მორგებულია smtp დრაივერზე, რომელიც ჩვენთვის ხელმისაწვდომი არაა ამ ეტაპზე, იმდენად რამდენადაც ვმუშაობთ ლოკალურ სისტემაში, ამიტომ .env ფაილში შევიტანოთ შესაბამისი ცვლილებები

გაგრძელება იქნება ...

10. კონკრეტული მატერიალის გვერდი
შაბლონს თუ დავაკვირდებით ვნახავთ, რომ Home და About სექციებში არის სხვა გვერდზე გადასასვლელი ბმულები (მათი რეალიზება მოვახდინეთ მე-7-ე თავში). შევქმნათ ცალკე გვერდისათვის საჭირო წარმოდგენები, კომტროლერები და მოდელები. რაც შეეხება მარშრუტს, იგი უკვე შექმნილი გვაქვს Route::get('/page/{alias}',['uses'=>'PageController@execute','as'=>'page']); შევქმნათ შესაბამისი კონტროლერი php artisan make:controller PageController ამ კონტროლერში დავამყაროთ წვდომა გვერდების მოდელ Page-სთან . აგრეთვე შევქმნათ კონტროლერის მეთოდი execute, რომელსაც პარამეტრად უნდა გადავცეთ საჭირო გვერდის დასახელება (alias). კონტროლერის ამავე მეთოდში ჯერ გადავამოწმოთ არსებობს თუ არა აღნიშნული პარამეტრი, შემდეგ კი გადავამოწმოთ თუ არსებობს პარამეტრის შესაბამისი წარმოდგენის ფაილი. შემდეგ შესაბამის კლასზე მიმართვით მოვახდენთ საჭირო გვერდის შესაბამისი ინფორმაციის ამოღებას ბაზიდან.
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Page;

class PageController extends Controller
{
    public function execute($alias)
    {
      if(!$alias)
      {
        abort(404);
      }

      if(view()->exists('site.page'))
      {
        
        // SELECT * FROM PAGES WHERE alias='$alias' LIMIT 1
        $page = Page::where('alias',strip_tags($alias))->first();
       
        $data = [
          'title' => $page->name,
          'psge' => $page
        ];

        return view('site.page',$data);
      }
    }
}
            
ახლა შევქმნათ resources/views/site/page.blade.php წარმოდგენის ფაილი, რომელიც იქნება ძირითადი წარმოდგენის ფაილის resources/views/layouts/site.blade.php-ის მემკვიდრე ფაილი. როგორტც ვიცით resources/views/layouts/site.blade.php ფაილში გვაქვს ორი სექცია header და content, ამიტომ ისინი უინდა განვსაზღროთ ახლადშექმნილ შვილობილ resources/views/site/page.blade.php მაკეტშიც.
@extends('layouts.site')

@section('header')

@include('site.header')

@endsection


@section('content')

@include('site.content_page')

@endsection
            
როგორც ვხედავთ content სექციაში ზდება site/content_page წარმოდგენის გამოძახება, შევქმნათ იგი და სწორედ მასში გამოვიტანოთ მბ-დან ამოღებული ინფორმაცია
<section>
  <div class="inner_wrapper">
        <div class="container">
            <h2>{{ $title }}</h2>
            <div class="inner_section">
              <div class="row">
                <div class=" col-lg-4 col-md-4 col-sm-4 col-xs-12 pull-right">
                  {!! Html::image('assets/img/'.$page->images,'',array('class'=>'img-circle delay-03s animated wow zoomIn')) !!}
                    </div>
                    <div class=" col-lg-7 col-md-7 col-sm-7 col-xs-12 pull-left">
                      <div class=" delay-01s animated fadeInDown wow animated">
                        {!! $page->text !!}
                            <div class="work_bottom"> 
                              {!! link_to(route('home'), 'Back') !!}
                            </div>       
                        </div>
                    </div>
                </div>
            </div> 
        </div>
</section>
            
{!! link_to(route('home'), 'Back') !!} ამ ჩანაწერში გამოყენებულია დამხმარე ფუნქცია link_to, რომელიც აგენერირებს html <a> ელემენტს, პირველ პარამეტრად გადაეცა თუ სად უნდა წავიდეს ბმული, ხოლო მეორე პარამეტრად ბმულის ხილვადი ნაწილი, ტექსტი.
11. ადმინისტრატორის განყოფილება
როგრც გვახსოვს პარშრუტები იმდაგვარად გვაქვს დაწერილი, რომ admin პრეფიქსიან ნებისმიერ url მისამართის შესაბამის მოთხოვნას, მოუწევს auth შუამავლთან მოხვედრა, ანუ აუტენტიფიკაციის გარეშე მომხმარებელი ვერ შევა მაგალითად შემდეგ მისამართზე http://127.0.0.1:8000/admin თავად აუტენტიფიცირების მექანიზმის ჩართვა კი მოვახდინეთ ამ ჩანაწერით Route::auth(); ამ მომენტისათვის თუ ამ მისამართზე შევალთ http://127.0.0.1:8000/admin ვიხილავთ შემდეგ შეტყობინებას View [auth.login] not found. ანუ არ არის შექმნილი წარმოდგენის ფაილი, რომელშიც მომხმარებელს შეეძლება აუტენტიფიკაციის გავლა. შევქმნათ იგი კონსოლის დახმარებით php artisan make:auth ახლა უკვე http://127.0.0.1:8000/admin მისამართზე შესვლისას ვნახავთ შესაბამის წარმოდგენას, მაგრამ ამჟამად არცერთი მომხმარებელი არ გვყავს მბ-ს ცხრილ users-ში ამიტომ გავიაროთ რეგისტრაცია, დავამატოთ მომხმარებელი. ამისათვის უნდა შევიდეთ შემდეგ მისამართზე http://127.0.0.1:8000/register ადმინისტრატორის განყოფილებისათვის შევქმნათ ახალი საქაღალდე resources/views/admin ამ საქაღალდეში კი index.blade.php ფაილი, რომელიც იქნება ადმინისტრატორის განყოფილების ძირითადი მაკეტის resources/views/layouts/admin.blade.php-ის მემკვიდრე მაკეტი.

resources/views/layouts/admin.blade.php ფაილში შევიტანოთ შემდეგი კოდი

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, maximum-scale=1">
  <title>{{ $title }}</title>
  <link href="{{ asset('assets/css/bootstrap.min.css') }}" rel="stylesheet" type="text/css">
  <link href="{{ asset('assets/css/style.css') }}" rel="stylesheet" type="text/css"> 

  <script type="text/javascript" src="{{ asset('assets/js/jquery-1.11.0.min.js') }}"></script>
    <script type="text/javascript" src="{{ asset('assets/js/bootstrap.min.js') }}"></script>
</head>
<body>

<header id="header_wrapper">
  
@yield('header')

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

@if(session('status'))
<div class="alert alert-success">
  {{ session('status') }}
</div>
@endif

</header>

@yield('content')

</body>
</html>
            
ხოლო resources/views/admin/index.blade.php ფაილში კი შემდეგი კოდი
@extends('layouts.admin')

@section('header')

  @include('admin.header')

@endsection
            
ახლა შევქმნათ resources/views/admin/header.blade.php ფაილი და შევიტანოთ შემდეგი კოდი
<div class="container portfolio_title">

  <!-- Title-->
  <div class="section-title">
    <h2>{{ $title }}</h2> <!-- ამ ცვლადს ვიხილავთ ცოტა ქვემოთ, მარშუტის აღწერისას -->
  </div>

  <div class="portfolio">

    <div id="filters" class="sixteen columns">

      <ul style="padding: 0px 0px 0px 0px;">
        <li>
          <a href="{{ route('pages') }}">
            <h5>გვერდები</h5>
          </a>
        </li>
        <li>
          <a href="{{ route('portfolios') }}">
            <h5>პორტფოლიო</h5>
          </a>
        </li>
        <li>
          <a href="{{ route('services') }}">
            <h5>სერვისები</h5>
          </a>
        </li>
      </ul>      

    </div>
    
  </div>
  
</div>
            
ამ კოდში ბევრი არაფერია ასახსნელი, უბრალოდ დროის ეკონომიის მიზნით ვიყენებთ ელემენტთა იმ id და class ატრიბუტებს, რომლებიც მითითებულია ძირითად შაბლონში, რათა შედარებით ლამაზად დალაგდეს ყველაფერი. ახლა ჩავასწოროთ ის მარშრუტი, რომელიც ადმინისტრატორის მთავარი გვერდის გახსნას უზრუნველყოფს
Route::group(['prefix'=>'admin','middleware'=>'auth'], function(){

  ...

  // ადმინ. განყოფილების მთავარი გვერდი: landing.ge/admin
  Route::get('/', function(){

    if (view()->exists('admin.index'))
    {
      $data = ['title' => 'ადმინისტრატორის განყოფილება'];
      return view('admin.index',$data);
    }

  });

  ...

});
            
თუ ახლა შევალთ შემდეგ მისამართზე http://127.0.0.1:8000/admin უნდა ვიხილოთ შემდეგი სურათი



12. ახალი მატერიალის დასამატებელი ფორმა, წაშლის ღილაკი
routes/web.php ფაილიდან ამოვიღოთ ის ფრაგმენტი, რომელიც უზრუნველჰყოფს ადმინისტრატორის განყოფილებიდან საიტის გვერდებთან სამუშაო ბმულების მარშრუტების გენერირებას
Route::group(['prefix'=>'pages'],function(){

      // ამ გვერდზე იქნება გვერდების ჩამონათვალი http://127.0.0.1:8000/admin/pages
      Route::get('/',['uses'=>'PagesController@execute','as'=>'pages']);

      Route::match(['get','post'],'/add',['uses'=>'PagesAddController@execute','as'=>'pagesAdd']);
      
      Route::match(['get','post','delete'],'/edit/{page}',['uses'=>'PagesEditController@execute','as'=>'pagesEdit']);

});
            
ანუ პირველ რიგში უნდა შევქმნათ PagesController კონტროლერი php artisan make:controller PagesController ამ კონტროლერის execute მეთოდში გადავამოწმოთ არსებობს თუ არა შესაბამისი წარმოდგენის ფაილი resources/views/admin/pages.blade.php, (რომელიც ამ მომენტისათვის არ არსებიბს და შესაქმნელი გვაქვს). ამ გადამოწმების შემდეგ კი $pages ცვლადში შევინახოთ მბ-ს ცხრილ pages-დან ამოღებული ინფორმაცია და ეს ინფორმაცია გადავცეთ შესაბამის წარმოდგენის ფაილს. ბაზიდან ინფორმაციის ამოსაღებად კი უნდა მივმართოთ შესაბამის მოდელს, ამისათვის კი ჯერ ამ მოდელთან უნდა დავამყაროთ წვდომა.

შევქმნათ resources/views/admin/pages.blade.php წარმოდგენის ფაილი, რომელშიც აღიწერება resources/views/layouts/admin.blade.php ფაილში აღწერილი მაკეტის მემკვიდრე მაკეტი

@extends('layouts.admin')

@section('header')

  @include('admin.header')

@endsection

@section('content')

  @include('admin.content_pages')

@endsection
            
ახლა შევქმნათ resources/views/admin/content_pages.blade.php წარმოდგენის ფაილი, რომელმაც ეკრანზე უნდა გამოიტანოს მბ-ს ცხრილ pages-ში არსებული ჩანაწერები, ეს ჩანაწერები კი ამ მომენტისათვის შენაახული გვაქვს PagesController კონტროლერში აღწერილ $pages ცვლადში.
<div class="container">

@if($pages)

<table class="table table-hover table-striped">
  <thead>
    <tr>
      <th>N</th>
        <th>სათაური</th> 
        <th>ფსევდონიმი</th>
        <th>ტექსტი</th>
        <th>შექმნის თარიღი</th>
        <th>წაშლა</th>
    </tr>
  </thead>
  <tbody>
    @foreach($pages as $page)
    <tr>
        <td>{{ $page->id }}</td>
        <td>{!!  Html::link(route('pagesEdit',['page'=>$page->id]), $page->name, ['alt'=>$page->name])  !!}</td> 
        <td>{{ $page->alias }}</td>
        <td>{{ $page->text }}</td> 
        <td>{{ $page->created_at }}</td>
        <td></td>
    </tr>  
    @endforeach 
  </tbody>
</table>

@endif

</div>
            
ამ უჯრებში განვსაზღვროთ ფორმა, რომელიც გააგზავნის delete ტიპის მოთხოვნებს და წაშლის ჩანაწერებს, როგორც ვიცით მარშრუტში აღწერილი გვაქვს ეს მეთოდიც Route::match(['get','post','delete'],'/edit/{page}',['uses'=>'PagesEditController@execute','as'=>'pagesEdit']); ფორმას შევქმნით Form ფასადზე მიმართვით და გავეცნობით მის ინსტრუმენტებს, თავად ფასადის გამოყენებისთვის საჭირო სერვისპროვაიდერის გააქტიურების ინსტრუქცია კი შეგიძლიათ იხილოთ აქ.
<td>

<!-- <form action='pages/edit/1' method='post' class='form-horizontal'> -->
{!! Form::open(['url'=>route('pagesEdit',['page'=>$page->id]), 'class'=>'form-horizontal','method'=>'post']) !!}

  <!-- <input type='hidden' name='_method' value='DELETE'> -->
  {{ method_field('DELETE') }}

  <!-- <input type='submit' value='წაშლა' class='btn btn-danger'> -->
  {!! Form::button('წაშლა',['class'=>'btn btn-danger','type'=>'submit']) !!}

<!-- </form> -->
{!! Form::close() !!}

</td>
            
ახლა გვერდს დავამატოთ ახალი ჩანაწერის დასამატებელი ბმული
<!-- <a href="http://127.0.0.1:8000/admin/pages/add">ჩანაწერის დამატება</a> -->
{{ Html::link(route('pagesAdd'),'ჩანაწერის დამატება') }}
            
შევქმნათ pagesAdd მარშრუტის შესაბამისი კონტროლერი php artisan make:controller PagesAddController კონტროლერის კოდი
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PagesAddController extends Controller
{
    public function execute() 
    {
      if (view()->exists('admin.pages_add'))
      {
        $data = [
          'title' => 'ჩანაწერის დამატება'
        ];

        return view('admin.pages_add', $data);
      }
    }
}
            
შევქმნათ resources/views/admin/pages_add.blade.php ფაილი
@extends('layouts.admin')

@section('header')

  @include('admin.header')

@endsection

@section('content')

  @include('admin.content_pages_add')

@endsection
            
შევქმნათ resources/views/admin/content_pages_add.blade.php ფაილი
<div class="container container-fluid">

<!-- <form action='pages/add' method='post' class='form-horizontal' enctype='multipart/form-data'> -->
{!! Form::open(['url'=>route('pagesAdd'), 'class'=>'form-horizontal','method'=>'post', 'enctype'=>'multipart/form-data']) !!}

  <div class="form-group">

    <!-- <label for='name' class='col-xs-2 control-label'>დასახელება</label> -->
    {!! Form::label('name','დასახელება',['class' => 'col-xs-2 control-label'])  !!}
    <div class="col-xs-8">
      <!-- <input type='text' name='name' value='სესიაში შენახული ძველი მნიშვნელობა' class='form-control' placeholder='დასახელება'> -->
        {!! Form::text('name', old('name'), ['class'=>'form-control', 'placeholder'=>'დასახელება']) !!}
    </div>

  </div>

  <div class="form-group">

    <!-- <label for='alias' class='col-xs-2 control-label'>ფსევდონიმი</label> -->
    {!! Form::label('alias','ფსევდონიმი',['class' => 'col-xs-2 control-label'])  !!}
    <div class="col-xs-8">
      <!-- <input type='text' name='alias' value='სესიაში შენახული ძველი მნიშვნელობა' class='form-control' placeholder='ფსევდონიმი'> -->
        {!! Form::text('alias', old('alias'), ['class'=>'form-control', 'placeholder'=>'ფსევდონიმი']) !!}
    </div>

  </div>


  <div class="form-group">

    <!-- <label for='text' class='col-xs-2 control-label'>ტექსტი</label> -->
    {!! Form::label('text','ტექსტი',['class' => 'col-xs-2 control-label'])  !!}
    <div class="col-xs-8">
      <!-- <textarea name='text' class='form-control'>სესიაში შენახული ძველი მნიშვნელობა</textarea -->
        {!! Form::textarea('text', old('text'), ['class'=>'form-control', 'placeholder'=>'ტექსტი']) !!}
    </div>

  </div>


  <div class="form-group">

    <!-- <label for='text' class='col-xs-2 control-label'>ტექსტი</label> -->
    {!! Form::label('images','ფოტო',['class' => 'col-xs-2 control-label'])  !!}
    <div class="col-xs-8">
      <!-- <input type='file' name='images' class='form-control'> -->
        {!! Form::file('images',['class'=>'form-control']) !!}
    </div>

  </div>


  <div class="form-group">
    
    <div class="col-xs-offset-2 col-xs-10">
      <!-- <input type='submit' value='დამატება' class='btn btn-primary'> -->
        {!! Form::button('დამატება',['class'=>'btn btn-primary','type'=>'submit']) !!}
    </div>

  </div>

  

 

<!-- </form> -->
{!! Form::close() !!}
  
</div>
            
13. ახალი მატერიალის დასამატებელი ლოგიკა
როგორც ვიცით, მბ-ში ახალი გვერდების დასამატებელი გვერდის მარშრუტი არის შემდეგი // landing.ge/admin/pages/add
Route::match(['get','post'],'/add',['uses'=>'PagesAddController@execute','as'=>'pagesAdd']);
ასე, რომ საქმე გვაქვს PagesAddController კონტროლერთან და მის მეთოდ execute-სთან. ამ ეტაპზე ამ კონტროლერის ეს მეთოდი უზრუნველჰყოფს, get ტიპის მოთხოვნის გაშვებას, ეს მოთხოვნა კი უშუალოდ ჩანაწერის დასამატებელი ფორმის გამოსატანად გამოიყენება.
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PagesAddController extends Controller
{
    public function execute() 
    {
      if (view()->exists('admin.pages_add'))
      {
        $data = [
          'title' => 'ჩანაწერის დამატება'
        ];

        return view('admin.pages_add', $data);
      }
    }
}
            
აღვწეროთ ჩანაწერის დასამატებელი ლოგიკა ამავე კონტროლერში. პირველ რიგში გადავამოწმოთ არის თუ არა მოთხოვნა post ტიპის
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PagesAddController extends Controller
{
    public function execute(Request $request) 
    {
        if ($request->isMethod('post'))
        {
            dd($request);
        }

        if (view()->exists('admin.pages_add'))
        {
          $data = [
            'title' => 'ჩანაწერის დამატება'
          ];

          return view('admin.pages_add', $data);
        }
    }
}
            
თუ ახლა ფორმას შევავსებთ და გავაგზავნით ბრაუზერში ვიხილავთ ამდაგვარ სურათს



საბოლოოდ PagesAddController კონტროლერი მიიღებს ასეთ სახეს
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use Validator;
use App\Page;

class PagesAddController extends Controller
{
    public function execute(Request $request) 
    {
      // არის თუ არა მოთხოვნა post ტიპის
        if ($request->isMethod('post'))
        {
            // გაგზაბნილი ინფორმაცია (_token-ის გარდა) მოვათავსოთ ამ ცვლადში
            $input = $request->except('_token');

            // ვალიდაცია
            $validator = Validator::make($input, [

                'name' => 'required|max:255',
                'alias' => 'required|unique:pages|max:255', // უნიკალური ველი ცხრილში - pages
                'text' => 'required'

            ]);

            // TRUE  თუ ვალიდაციის რომელიმე წესი დაირღვა
            if ($validator->fails())
            {
                /* 
                  გადავმისამართდეთ იგივე გვერდზე,  მიმდინარე ვალიდაციისას დაშვებული შეცდომები 
                  და ველებში აკრეფილი ინფორმაცია შენახულ იქნეს სესიებში
                */
                return redirect()->route('pagesAdd')->withErrors($validator)->withInput();
            }

            /* 
              TRUE თუ მოთხოვნაში შესულია ფაილი, მეთოდს არგუმენტად უნდა გადეცეს 'file' ტიპის ველის 
              'name' ატრიბუტის მნიშვნელობა
            */
            if ($request->hasFile('images'))
            {
                
                /* 
                  file მეთოდი აბრუნებს სპეციალური კლასის uploadedfile-ს ობიექს, ეს კლასი 
                  გამოიყენება ატვირთულ ფაილებთან სამუშაოდ და აღწერილია შემდეგ ფაილში 
                  vendor/simfony/http-foundation/File/UploadedFile.php,
                  file მეთოდს პირველ პარამეტრად უნდა გადეცეს 'file' ტიპის ველის 'name' ატრიბუტის მნიშვნელობა, 
                */
                $file = $request->file('images');

                /*
                  თუ  $input ცვლადს დავბეჭდავთ, ვნახავთ, რომ მასში შესულია ატვირთული ფაილის uploadedfile კლასის ობიექტი,
                  კონკრეტულად ეს ობიექტი შენახული იქნება $input მასივის 'images' უჯრაში, მაგრამ ატვირთული ფაილის შესახებ 
                  ინფორმაციის ამ სახით მიღება მოსახერხებელი არ არის, სასურველია ამ  უჯრაში შევინახოთ ასატვირთი ფაილის
                  რეალური დასახელება, ამისათვის გამოვიყენოთ uploadedfile კლასის getClientOriginalName მეთოდი.
                */

                $input['images'] = $file->getClientOriginalName();

                /*
                  move ფუნქცია გამოიყენება ფაილების ასატვირთად, პირველ პარამეტრად უნდა გადაეცეს
                  იმ დირექტორიის დასახელება სადაც ვტვირთავთ ფაილს, მეორე პარამეტრად კი ფაილის სახელი.
                  public_path() ფუნქცია აგენერირებს url-ს public დირექტორიამდე, ჩვენ კი ფაილის ატვირთვა 
                  გვინდა public/assets/img საქაღალდეში
                */
                $file->move(public_path().'/assets/img', $input['images']);


                /* 
                  შევინახოთ ინფორმაცია ბაზაში, ასეთი ხერხით შენახვისას Page მოდელში, დახურული
                  თვისების მეშვეობით უნდა მივუთითოთ მბს ცხრილის იმ ველების დასახელებები,
                  რომლებშიც შეგვაქვს ინფორმაცია, ამ კოდს მოვიყვანთ დაბლა
                */
                $page = new Page();
                $page->fill($input);

                if ($page->save())
                {
                    return redirect('admin')->with('status','გვერდი დაემატა');
                }


            }

        }

        if (view()->exists('admin.pages_add'))
        {
          $data = [
            'title' => 'ჩანაწერის დამატება'
          ];

        return view('admin.pages_add', $data);
        }
    }
}

            
Page.php მოდელი
namespace App;

use Illuminate\Database\Eloquent\Model;

class Page extends Model
{
    protected $fillable = ['name','alias','text','images'];
}
            
14. მატერიალის რედაქტირების გვერდი
როგორც ვიცით, მბ-ში ჩანაწერის რედაქტირების გვერდის მარშრუტი არის შემდეგი Route::match(['get','post','delete'],'/edit/{page}',['uses'=>'PagesEditController@execute','as'=>'pagesEdit']); ასე, რომ საქმე გვაქვს PagesEditController კონტროლერთან და მის მეთოდ execute-სთან. მარშრუტს პარამეტრად გადაცემული აქვს page, ეს პარამეტრი განსაზღვრავს თუ რომელი ჩანაწერის რედაქტირება გვსურს, ამასთანავე რედაქტირების ღილაკები განვსაზღრეთ შემდეგნაირად {!! Html::link(route('pagesEdit',['page'=>$page->id]), $page->name, ['alt'=>$page->name]) !!} ასე რომ მაგალითად landing.ge/admin/pages/edit/1 ამ მისამართზე შესვლისას გამოჩნდება იმ ჩანაწერის შიგთავსი, რომლის id=1.

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

php artisan make:controller PagesEditController იმისათვის რათა კონტროლერის მეთოდმა მოახდინოს კონკრეტული ჩანაწერის ამოღება მბ-დან, საჭიროა ამ მეთოდს პარამეტრად გადავცეთ ამ ჩანაწერის რაიმე იდენტიფიკატორი, ანუ ისეთ რამ რაც სხვა ჩანაწერებისაგან განასხვბავებს მას. ამ შემთხვევაში ეს არის id
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Page;

class PagesEditController extends Controller
{
    public function execute($id)
    {
      $page = Page::find($id);

      dd($page);
      
    }
}
            
თუმცა არსებობს ჩანაწერის იდენტიფიცირების სხვა, უკეთესი ვარიანტიც. როგორც ვიცით execute მეთოდის მუშაობა დამოკიდებულია Request ობიექტზე, იმიტომ, რომ მან უნდა დაამუშავოს post (რედაქტირებისათვის) get (რედაქტირების შაბლონის გასახსნელად) delete (ჩანაწერთა წასაშლელად) ტიპის მოთხოვნები, აქედან გამომდინარე მეთოდმა უნდა დაამუშავოს მოთხოვნის შიგთავსი. ამასთანავე შესაძლებელია მეთოდს არგუმენტად გადავცეთ სასურველი მოდელის ობიექტი და ამ შემთხვევაში ფრეიმვორკი ავტომატურად გამოიყენებნს კონკრეტული ჩანაწერის იდენტიფიკატორს, კონკრეტული მოთხოვნის გაკეთებისას.

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

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Page;

class PagesEditController extends Controller
{
    public function execute(Page $page, Request $request)
    {
       // $page = Page::find($id); 
      dd($page);
      
    }
}
            
ახლა მოვითხოვოთ საჭირო მაკეტი და გადავცეთ მას საჭირო ინფორმაცია
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Page;

class PagesEditController extends Controller
{
    public function execute(Page $page, Request $request)
    {
      // გარდავქმნად მასივად ამორჩეული ჩანაწერი და შევინახიოთ ცვლადში $old
      $old = $page->toArray();
      
      // გადავამოწმოთ არსებობს თუ არა ჩანაწერის რედაქტირებისათვის საჭირო შაბლონი
      if (view()->exists('admin.page_edit'))
      {
        $data = [
          'title' => 'გვერდის რედაქტირება - ' . $old['name'],
          'data' => $old
        ];

        return view('admin.page_edit', $data);
      }

    }
}
            
შევქმნათ მაკეტი resources/views/admin/page_edit.blade.php, რომელიც, რა თქმა უნდა, იქნება resources/views/layouts/admin.blade.php მაკეტის მემკვიდრე მაკეტი.
@extends('layouts.admin')

@section('header')

  @include('admin.header')

@endsection

@section('content')

  @include('admin.content_pages_edit')

@endsection
            
ასხლა შევქმნათ მაკეტი resources/views/admin/content_pages_edit.blade.php
<div class="container container-fluid">

<!-- <form action='pages/edit/2' method='post' class='form-horizontal' enctype='multipart/form-data'> -->
{!! Form::open(['url'=>route('pagesEdit',array('page'=>$data['id'])), 'class'=>'form-horizontal','method'=>'post', 'enctype'=>'multipart/form-data']) !!}

  <div class="form-group">

    <!-- <input type='hidden' name='id' value='2'> -->
    {!! Form::hidden('id', $data['id']) !!}
    <!-- <label for='name' class='col-xs-2 control-label'>დასახელება</label> -->
    {!! Form::label('name','დასახელება',['class' => 'col-xs-2 control-label'])  !!}
    <div class="col-xs-8">
        <!-- <input type='text' name='name' value='მიმდინარე სათაური' class='form-control' placeholder='დასახელება'> -->
        {!! Form::text('name', $data['name'], ['class'=>'form-control', 'placeholder'=>'დასახელება']) !!}
    </div>

  </div>

  <div class="form-group">

    <!-- <label for='alias' class='col-xs-2 control-label'>ფსევდონიმი</label> -->
    {!! Form::label('alias','ფსევდონიმი',['class' => 'col-xs-2 control-label'])  !!}
    <div class="col-xs-8">
        <!-- <input type='text' name='alias' value='სესიაში შენახული ძველი მნიშვნელობა' class='form-control' placeholder='ფსევდონიმი'> -->
        {!! Form::text('alias', $data['alias'], ['class'=>'form-control', 'placeholder'=>'ფსევდონიმი']) !!}
    </div>

  </div>

  <div class="form-group">

    <!-- <label for='text' class='col-xs-2 control-label'>ტექსტი</label> -->
    {!! Form::label('text','ტექსტი',['class' => 'col-xs-2 control-label'])  !!}
    <div class="col-xs-8">
      <!-- <textarea name='text' class='form-control'>ძველი ტექსტი</textarea -->
        {!! Form::textarea('text', $data['text'], ['class'=>'form-control', 'placeholder'=>'ტექსტი']) !!}
    </div>

  </div>


  <div class="form-group">

    <!-- <label for='old_img' class='col-xs-2 control-label'>ფოტო</label> -->
    {!! Form::label('old_images','ფოტო',['class' => 'col-xs-2 control-label'])  !!}
    <div class="col-xs-8">
        <!-- <input type='hidden' name='old_images' value='უკვე არსებული ფოტოს დასახელება'> -->
        {!! Form::hidden('old_images', $data['images']) !!}
        <!-- <img src='assets/img/ძველი სურათი' class='img-responsive'> -->
        {!! Html::image('assets/img/'.$data['images'],'',['class'=>'img-responsive']) !!}
    </div>

  </div>

  <div class="form-group">
    
  </div>


  <div class="form-group">

    <!-- <label for='text' class='col-xs-2 control-label'>ტექსტი</label> -->
    {!! Form::label('images','ფოტო',['class' => 'col-xs-2 control-label'])  !!}
    <div class="col-xs-8">
        <!-- <input type='file' name='images' class='form-control'> -->
        {!! Form::file('images',['class'=>'form-control']) !!}
    </div>

  </div>


  <div class="form-group">
    
    <div class="col-xs-offset-2 col-xs-10">
      <!-- <input type='submit' value='წაშლა' class='btn btn-primary'> -->
        {!! Form::button('განახლება',['class'=>'btn btn-primary','type'=>'submit']) !!}
    </div>

  </div>

  

 

<!-- </form> -->
{!! Form::close() !!}
  
</div>
            
15. მატერიალის რედაქტირება
მას შემდეგ რაც კონტროლერში ჩავამატებთ ჩანაწერის განახლების ლოგიკას, იგი კიიღებს ასეთ სახეს
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Page;
use Validator;

class PagesEditController extends Controller
{
    public function execute(Page $page, Request $request)
    {
      
        if ($request->isMethod('post'))
        {
          $input = $request->except('_token');

          $validator = Validator::make($input, [

            'name' => 'required|max:255',
            // უნიკალური alias ველი მხოლოდ მიმდინარე ჩანაწერის იგნორირებით
            'alias' => 'required|max:255|unique:pages,alias,' . $input['id'],  
            'text' => 'required'

          ]);

          if ($validator->fails())
          {
            return redirect()
                   ->route('pagesEdit',['page' => $input['id']])
                   ->withErrors($validator);
          }

          if ($request->hasFile('images'))
            {
              $file = $request->file('images');
              $file->move(public_path().'/assets/img', $file->getClientOriginalName());
              $input['images'] = $file->getClientOriginalName();
            }
            else
            {
              $input['images'] = $input['old_images'];
            }

            // აღარ გვჭირდება
            unset($input['old_images']);

            $page->fill($input);

            if($page->update())
            {
              return redirect('admin')->with('status','ჩანაწერი განახლდა');
            }


          
        }


      // გარდავქმნად მასივად ამორჩეული ჩანაწერი და შევინახიოთ ცვლადში $old
      $old = $page->toArray();
      
      // გადავამოწმოთ არსებობს თუ არა ჩანაწერის რედაქტირებისათვის საჭირო შაბლონი
      if (view()->exists('admin.page_edit'))
      {
        $data = [
          'title' => 'გვერდის რედაქტირება - ' . $old['name'],
          'data' => $old
        ];

        return view('admin.page_edit', $data);
      }

    }
}
            
16. მატერიალის წაშლა
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Page;
use Validator;

class PagesEditController extends Controller
{
    public function execute(Page $page, Request $request)
    {
        ...
        
        if ($request->isMethod('delete'))
        {
            $page->delete();
            return redirect('admin')->with('status','ჩანაწერი წაიშალა');
        }

        ...

    }
}