Kennismaking met Laravel 5 & Bootstrap 3

PHP staat momenteel gekend als een van de meest populaire server-side scripting talen in de wereld. Tegenwoordig wordt van een web-ontwikkelaar verwacht complexe websites en applicaties te kunnen bouwen in een zeer korte tijd. Omdat een project snel een grote complexiteit kan aannemen, zou het teveel tijd in beslag nemen om telkens vanaf nul te beginnen met code te schrijven. Er is dus nood aan een meer gestructureerde manier van ontwikkeling. Frameworks bieden ontwikkelaars hiervoor een passende oplossing.

Waarom een PHP framework?

Laten we eerst eens een kijkje nemen naar de belangrijkste redenen waarom veel ontwikkelaars een PHP framework zouden willen gebruiken. Het gebruik van een framework om je applicatie te ontwikkelen is zeker niet verplicht, het is gewoon een van de beschikbare tools om je te helpen beter en sneller code te schrijven. Beter, omdat je er zo voor zorgt dat je applicatie is opgebouwd volgens alle regeltjes, gestructureerd is en daarbij zowel onderhoudbaar als schaalbaar is. En sneller, omdat ontwikkelaars hierdoor telkens niet voor ieder project de basiscode die de meeste projecten nodig hebben moeten herprogrammeren. Men kan namelijk gebruik maken van de basiscode en structuur van een framework. Een framework maakt programmeren ook gemakkelijker omdat het complexe operaties integreert en mooi toegankelijk verpakt voor de gebruikers. Zo zit in het laravel framework authenticatie van gebruikers ingebouwd en moet men hier geen code voor schrijven.

Hier is wat PHP frameworks kunnen, bieden en doen:

Waarom Laravel?

Hoewel Laravel een relatief nieuw PHP framework is (het werd uitgebracht in 2011), is het, volgens een recente online enquête door Sitepoint, het meest populaire framework onder PHP ontwikkelaars. Deze grafiek is opgebouwd uit het resultaat van 7800 ondervraagden over de hele wereld. Popularity Op de website van Sitepoint is heel het onderzoek mooi uitgelegd en worden de resultaten weergegeven. Zo kan men ook vaststellen dat wanneer we naar België en Nederland kijken het Laravel framework de meeste stemmen kreeg.

Als we kijken naar de google statistieken van het voorbije jaar, stellen we vast dat de zoekterm laravel heel wat vaker wordt opgevraagd dan zijn concurrenten. De cijfers geven de zoekinteresse aan ten opzichte van het hoogste punt in het diagram voor de betreffende regio en periode. Een waarde van 100 is de piekpopulariteit voor die term. Een waarde van 50 betekent dat de term half zo populair is. Een score van 0 betekent dat de term minder dan 1% populariteit heeft ten opzichte van de piekwaarde.

Niet enkel omwille van zijn populariteit kiezen we voor dit framework. Laravel biedt heel wat voordelen in vergelijking met de andere frameworks. Laravel biedt op hun officiële website goed uitgewerkte documentatie en een heleboel gratis screencasts, Laracasts, aan. Deze bieden voldoende informatie om aan de slag te gaan en een expert te worden in PHP ontwikkeling. Op internet is dus heel wat informatie te vinden omtrent Laravel:

Laravel, dat tevens een open-source framework is, biedt veel mogelijkheden om op een snelle manier efficiënt een applicatie te ontwikkelen. Zo maakt het gebruik van Blade, een template systeem. Blade is eigenlijk niets meer dan HTML op een slimme manier verwerkt met PHP. Bij normale websites met PHP zou je bijvoorbeeld iets kunnen laten zien met: <?php echo $nummer; ?> Met Blade kunnen we dit doen met: {{ $nummer }} Het grootste voordeel hiervan is dat het veel leesbaarder en korter is om iets te maken. Het belemmert je tevens niet om gewone PHP syntax te gebruiken binnen je vieuws. Dit is een van de grootste voordelen van Laravel, het maakt het werken met de typische PHP/HTML spaghetti een stuk eenvoudiger.

Naast het voordeel van het template systeem, biedt Laravel ook de mogelijkheid om frequente zaken eenvoudiger te maken, zoals authenticatie, sessies, queueing, caching en RESTful routing (zie ook hoofdstuk 6).

Er is een out-of-the-box gebruikers model geïntegreerd in Laravel en een registratie en login systeem met wachtwoord vergeten reeds voorzien. Hierdoor wordt het beginnen van een nieuw project bijzonder eenvoudig.

Door het gebruik van het Laravel framework is je applicatie reeds voorzien van heel wat belangrijke beveiligingopties. Zo is je applicatie beveiligd tegen SQL injectie, cross-site request forgery (CSRF) en cross-site scripting.

Bij een SQL injectie zal een gebruiker in een invoerveld op de website tekens invoeren die ervoor zorgen dat er een ongewenst SQL-query kan worden uitgevoerd op de database. Laravel gebruikt 'PDO parameter binding' om dit te voorkomen.

CSRF bestaat eruit dat externe website bijvoorbeeld een request maken naar je applicatie door zelf de juiste URL op te bouwen. Hierdoor kan het zijn dat de applicatie deze request zou uitvoeren. Laravel gebruikt CSRF tokens bij ieder formulier en request zodat een externe partij zelf geen requests kan gaan initialiseren.

Een voorbeeld van cross-site scripting is wanneer een gebruiker code (bijvoorbeeld javascript) ingeeft in een invoerveld. Zonder de nodige beveiliging kan dit dan opgeslagen worden in je database, waarbij de code telkens opnieuw uitgevoerd zal worden wanneer dit opgevraagd wordt. Laravel zal elke input dan ook omzetten naar platte tekst waardoor html of andere script tags onuitvoerbaar worden. Het vergt heel wat tijd om dit alles te integreren in je applicatie. Het gebruik van het Laravel framework is dan ook sterk aan te raden.

Niet enkel bovenstaande voordelen maken het vanzelfsprekend om iets te programmeren met Laravel, maar ook vanwege de mogelijkheid tot object georiënteerd te programmeren. Dit betekent eigenlijk dat je meer functionaliteit kunt maken met minder code, mits de code goed geschreven is! Het maakt het programmeren tevens heel overzichtelijk omdat alle code netjes in stukjes opgeknipt kan worden.

Een laatste belangrijk voordeel van Laravel is het gebruik van het MVC patroon. Laravel zal onze applicatie dus in 3 delen opsplitsen.

Bovendien wordt er in Laravel gebruik gemaakt van routing, hierdoor worden de URL's van de requests doorgestuurd naar de juiste controller acties, zie volgende figuur:

MVC

Doordat Laravel dit ontwerppatroon volgt, is de applicatie logica telkens gescheiden van de presentatie logica. Deze aanpak zorgt voor een vermindering aan complexiteit in de applicatie en zal ervoor zorgen dat de applicatie heel veel code kan hergebruiken omdat alles gescheiden is van elkaar.

Bootstrap 3

De tijd dat HTML gebruikt werd voor de opmaak van webpagina's is reeds lang voorbij. Tegenwoordig heeft CSS, Cascading Style Sheets, de bovenhand en is het de dag van vandaag vanzelfsprekend om CSS te gebruiken bij het bouwen van een website. CSS is recent ernorm gevorderd en kan gebruikt worden om complexe designs en stijlen te maken. Waarom zouden we dan een CSS framework gebruiken? Het antwoord is redelijk voordehand liggend. Net als de voordelen van bovenstaand PHP framework, zal het je werk versnellen en je leven eenvoudiger maken. Bovendien is de gemiddelde ingenieur niet zo'n sterk grafisch wonder. Met een goed framework kunnen we toch gemakkelijk een site maken die er redelijk goed uit ziet zonder diep in de CSS te moeten duiken.

Bootstrap, oorspronkelijk Twitter Blueprint genaamd, werd ontwikkeld door Mark Otto en Jacob Thornton bij Twitter als een framework om een consistent ontwerp te hebben binnen de interne hulpmiddelen. Het gratis open source framework is een verzameling hulpmiddelen voor het maken van websites en webtoepassingen. Het bevat sjablonen gebaseerd op HTML en CSS voor typografie, formulieren, knoppen, navigatie en andere interfaceonderdelen. Het bootstrap- framework is bedoeld om webontwikkeling te vereenvoudigen. Bijkomend voordeel is dat je heel gemakkelijk "responsive sites" kan maken. Dit zijn sites die zich aanpassen naar het soort platform: smartphone, tablet, laptop- of desktop-scherm.

Meer informatie en documentatie kan je vinden op de officiële website van Bootstrap: http://getbootstrap.com.

Aan de slag

In deze handleiding zullen we een Laravel ontwikkeling omgeving installeren en instellen, de basiskenmerken van het framework bekijken en het Bootstrap framework integreren in Laravel. Deze technologieën kunnen dan gebruikt worden voor de eindtaak van SOA & Cloud Computing. Deze handleiding volgt voor de installatie voornamelijk de Laravel's documentatie op https://laravel.com/docs/5.3.

Installatie

Om het Laravel framework te kunnen gebruiken moet je systeem toch aan een heleboel vereisten voldoen. Om ontwikkeling in Laravel eenvoudig te maken, bieden ze een lokale ontwikkeling-omgeving aan via een virutele machine, genaamd Homestead. Ervaring met dit softwarepakket wijst erop dat de installatie wat problemen kan veroorzaken in windows. Op macOS (en linux) is dit echter zonder grote problemen. Een alternatief voor homestead is het gebruik van Laragon (https://laragon.org). Hoewel Homestead de officiële ontwikkelingsomgeving is van Laravel, is het gebruik van Laragon op windows aan te raden als de Homestead installatie mislukt. Het softwarepakket zal de nodige programma's installeren op je pc om aan de slag te gaan. Het werkt vergelijkbaar met het XAMPP softwarepakket (gezien in voorgaande opleidingsonderdelen) en maakt dus geen gebruik van een virtuele machine. Een nieuw Laravel project aanmaken is ook bijzonder eenvoudig, dit kan zelfs via het menu op de gebruikersinterface. Deze handleiding zal verdergaan met de installatie van Homestead, als je Laragon wilt gebruiken, kan je het stappenplan volgen op volgende website: https://laravelista.com/series/laravel-on-windows-with-laragon/part/1.

Homestead

Laravel Homestead is een 'voorverpakte' Vagrant box, Vagrant biedt een simpele en elegante manier om virtuele machines te beheren. Wanneer we de Homestead virtuele machine gebruiken kunnen we onze ontwikkeling beginnen zonder eerst PHP, een webserver of eender elke andere software op de lokale machine te installeren.

Homestead werkt op elk Windows, Mac of Linux systeem en biedt verschillende tools en software voorgeïnstalleerd aan, de belangrijkste hiervan zijn: Ubuntu 16.04 als het besturingssysteem voorzien van PHP 7.0 (vereist voor Laravel), Nginx als webserver, MySQL managementsysteem voor relationele databases en composer, een pakket manager voor PHP en git voor interactie met gitservers.

Installatie

De installatie van Homestead bestaat uit drie delen: eerst moet VirtualBox en Vagrant geïnstalleerd worden, daarna voegen we de Homestead Vagrant box toe aan Vagrant en uiteindelijk wordt de Homestead ontwikkelomgeving toegevoegd aan deze box.

VirtualBox en Vagrant

Voor we Homestead in gebruik kunnen nemen, moeten we eerst VirtualBox 5.x alsook Vagrant installeren. Deze twee software pakketten bieden een gebruiksvriendelijke visuele installer aan voor alle populaire besturingssystemen:

Vagrant is software om onderhoudbare en draagbare virtuele ontwikkelomgevingen te maken en te delen. Installeer eerst deze software voor je verdergaat.

Installatie Homestead Vagrant box

De installatie van Laravel Homestead vereist dat de computer voorzien is van een shell. Dit maakt de installatie op Linux en macOS systemen vrij eenvoudig dankzij de aanwezigheid van de terminal. Op Windows kan de command line interface gebruikt worden maar dit zorgt af en toe voor problemen. Aan te raden voor windows is dus het gebruik van git bash (Git for Windows). Via volgende link vindt men meer uitleg over het installatie-proces voor windows-gebruikers: https://www.in2sites.be/installatie-laravel-homestead-voor-windows/. Dit loopt voor het grootste gedeelte parallel met deze uitleg.

Vervolgens gaan we de Homestead Vagrant box toevoegen aan Vagrant via volgend commando. Het downloaden van de box zal een tijdje duren, afhankelijk van je internet connectie. Voer dit commando uit in je terminal:

vagrant box add laravel/homestead
Installatie Homestead ontwikkelomgeving

Nu kunnen we Homestead installeren door de github repository te klonen. We zetten dit best in een Homestead map binnen de "home" directory, want de Homestead Box zal dienen om al je Laravel projecten in te hosten. Zo wordt het path niet te lang, maar je kan natuurlijk ook zelf kiezen waar je het wilt zetten:

cd ~
git clone https://github.com/laravel/homestead.git Homestead

~/Homestead bevat nu je Homestead omgeving, deze map bevat dus je Vagrantfile. Run nu het bash init.shcommando vanuit deze Homestead map om het Homestead.yamlconfiguratie bestand aan te maken. Het configuratie bestand zal geplaatst worden in de verborgen ~/.homestead map:

$ cd ~/Homestead
$ bash init.sh (op unix) of init.bat (op windows)
Homestead initialized!
Configuratie

Laravel Homestead is nu geïnstalleerd op je computer. Er rest ons enkel nog de configuratie van de homestead installatie. Zoals je dadelijk zal ondervinden, zal Homestead de map met je Laravel projecten op de virtuele machine mappen met een map op je computer. Het is belangrijk dat deze configuratie dan ook juist ingesteld is. Open daarom nu het configuratie bestand ~/.homestead/Homestead.yaml in je terminal of in een teksteditor, overloop de inhoud van dit bestand en tracht te achterhalen wat er precies geconfigureerd wordt.

Bij folders worden alle mappen gezet die men wilt delen met de Homestead machine. Bestanden die gewijzigd worden in deze map, zullen dus zowel in de virtuele machine als op de lokale machine wijzigen. Je kan tevens meerdere mappen delen. Voor onze taak zullen we het houden op 1 gedeelde map. Momenteel wordt de map ~/Code gedeeld, indien deze niet bestaat maak deze dan aan op je computer:

mkdir ~/Code

Bij sites kan men de Nginx webserver configureren en eenvoudig een "domein" aan een bepaalde map in je Homestead omgeving linken. Je kan hier weer zoveel sites als nodig configureren.

Standaard wordt homestead.app gemapt naar /home/vagrant/Code/Laravel/public op je Homestead Machine. Om het homestead.app domein te gebruiken, moet je dit wel eerst toevoegen aan je hosts bestand. Hierdoor zullen requests voor je Homestead websites doorgestuurd worden naar het ip-adres van je Homestead Machine. In de configuratie wordt het IP adres van de virtuele machine standaard gezet op 192.168.10.10. Op Mac en Linux is het host bestand te vinden op /etc/hosts, op windows op C:\Windows\System32\drivers\etc\hosts. Voeg nu volgende lijn toe aan dit bestand:

192.168.10.10  homestead.app

Met deze instelling en wanneer je Vagrant box opgestart is, zal je jou site kunnen bereiken via je web browser:

http://homestead.app
Homestead Vagrant box opstarten

Wanneer je instellingen in orde zijn, voer dan volgend commando uit vanaf je Homestead map. Vagrant zal dan je virtuele machine booten en automatisch de nodige instellingen configureren voor je gedeelde mappen en nginx websites:

cd ~/Homestead
vagrant up

Je virtuele machine is nu opgestart en tevens bereikbaar via ssh. Via vagrant -h vind je alle mogelijke commando's die je kan gebruiken, enkele belangrijke commando's:

Voer deze commando's telkens uit vanuit je Homestead map. Buiten deze map kan je de commando's ook gebruiken maar moet je de id meegeven van je virtuele omgeving, deze verkrijg je via het vagrant global-status commando, bijvoorbeeld:

vagrant ssh 8c9804e

Voor verder informatie omtrent Laravel Homestead verwijs ik naar de uitgebreide documentatie op https://laravel.com/docs/5.3/homestead. Met deze ontwikkelingsomgeving gaan we nu verder om onze eerste applicatie te ontwikkelen.

Laravel project

Zoals reeds aangehaald moet de code van onze website zich bevinden in de ~/Code map van onze lokale machine. Omdat Laravel geïnstalleerd is op onze virtuele machine, werken we daarop om een nieuw project te starten, dit doen we best via ssh:

cd ~/Homestead
vagrant ssh

Onze configuratie van Nginx verwees voor onze homestead.app website naar ~/Code/Laravel/public op de virtuele machine. Dit wilt zeggen dat we een nieuw Laravel project moeten aanmaken in de Code map. Om eenvoudig een nieuw laravel project te starten, gebruiken we Composer, een ‘dependency manager’ voor PHP. Kort gezegd: Composer beheert je libraries. Composer is standaard geïnstalleerd op Homestead. Je kan via de terminal het commando composer gebruiken om te controleren of het pakket juist is geïnstalleerd.

We gebruiken Composer om een nieuw project aan te maken van een bestaand pakket, in ons geval van het Laravel pakket. Dit is het equivalent van een git clone/svn checkout te doen gevolgd door een installatie. We maken nu een nieuw Laravel project aan, met 'Laravel' als naam, met behulp van volgend commando:

composer create-project laravel/laravel Laravel

Het kan even duren voordat het project aangemaakt is. Het commando heeft nu het Laravel framework en al de afhankelijkheden gekopieerd in je Laravelmap.

De Laravel installatie biedt ook een eigen CLI aan waarmee je een nieuw project kan aanmaken, intern wordt dan composer gebruikt. Om een nieuw project te starten met naam Laravel aan de hand van de Laravel CLI, gebruik je laravel new Laravel. Dit commando zal een nieuwe map aanmaken, genaamd Laravel, die een nieuwe Laravel installatie bevat met al de afhankelijkheden voorgeïnstalleerd.

Als alles zonder fouten is verlopen, zou je nu je eerste Laravel applicatie kunnen bereiken via http://homestead.appin je browser en het standaard scherm van Laravel 5.3 te zien krijgen:

Laravel

Gelukt! Je hebt zojuist je eerste Laravel project gestart. In volgend onderdeel zullen we de basis-routing bekijken en Bootstrap integreren in ons project.

DEEL 1: Kennismaking Laravel

Nu we ons eerste Laravel project hebben kunnen aanmaken, wordt het tijd het project te personaliseren. In deze handleiding zullen we een zeer simpele 'online winkel' maken. Het is niet de bedoeling dat de website veel mogelijkheden heeft maar dat we leren hoe we Laravel kunnen gebruiken.

Deze website zal een aantal producten bevatten. Vervolgens zullen we ook enkele filter-mogelijkheden toevoegen aan de applicatie. Ook authenticatie zal bekeken worden in Laravel. We moeten dus eerst onze database voor onze applicatie in orde maken. Laravel maakt interactie met een database bijzonder eenvoudig, dankzij de ingebouwde Eloquent Object Relation Mapper (ORM). Eloquent ORM biedt een Active Record implementatie aan, hierdoor komt ieder model dat je aanmaakt in je MVC structuur overeen met een tabel in je database.

Een Item model zal dus overeenkomen met een items tabel in je database. Omdat Laravel deze conventie gebruikt is het eenvoudig om data op te vragen van je database. Door de juiste functie op te roepen, zal het framework ervoor zorgen dat de juiste SQL query wordt uitgevoerd. Enkele voorbeelden:

Beschrijving Functie
Geef alle items Item::all()
Geef bepaald item Item::find(id)
Verwijder record Item::delete(id)

Eerder dan een model te beschrijven met al zijn datamembers in een klasse, zal Laravel de tabellen en hun onderlinge relaties beschrijven. Hierdoor zal de model klasse over het algemeen een lege klasse zijn die erft van het Eloquent Model. Enkel indien je uitzonderingen wilt maken op de gebruikte conventies kan men deze beschrijven in de model klasse. Zo zal Eloquent ervan uitgaan dat de primary key van elke tabel id is, indien men dit anders wilt, kan men in het model vermelden: protected $table = 'my_items';.

Door deze werkwijze is het belangrijk dat je database gemakkelijk kan worden opgebouwd. Laravel gebruikt hiervoor migraties. Door veranderingen aan de database te omschrijven in migraties kan men goed zien wanneer welke veranderingen plaats vonden, kan men steeds terugvallen op oude migraties, nieuwe tabellen toevoegen, tabellen wijzigen en relaties tussen de tabellen overzichtelijk vermelden.

Om je database te voorzien van startdata tijdens ontwikkeling van je applicatie kan je in Laravel seeders gebruiken.

Dit is zowat de werkwijze om Laravel in gebruik te nemen. Dit zullen we dus ook doen in volgende hoofdstukken. Voor meer informatie omtrent Eloquent kan je in de documentatie van Laravel kijken https://laravel.com/docs/master/eloquent

PHP ontwikkelomgeving

Om PHP code te schrijven kunnen we de Netbeans IDE gebruiken. Met volgende stappen kunnen we ons Laravel project openen in Netbeans 8.2:

  1. Open Netbeans
  2. Start nieuw project: File > New Project
  3. Kies voor: PHP Application with Existing Sources, klik Next
  4. Browse voor je Code map en klik je Laravel project map aan om je Sources folder te kiezen
  5. Kies PHP 7.0 als PHP versie, klik Next
  6. Kies: Run as Local Web Site
  7. Project Url: http://homestead.app
  8. Index File: public/index.php
  9. Klik Finish

Het gebruik van Netbeans is zeker niet verplicht, eender welke teksteditor (eventueel met een Laravel plugin) kan ook dienen. Een handige IDE voor Laravel projecten is ook PhpStorm. PhpStorm biedt tevens de mogelijkheid om je MySql database te beheren, je project te debuggen en een SSH connectie te onderhouden met je Homestead installatie. Studenten kunnen een gratis licentie aanvragen op https://www.jetbrains.com/student/.
In Netbeans is het ook mogelijk om je PHP applicatie te debuggen. Laravel komt standaard met Xdebug geïnstalleerd. Dit moet enkel nog geactiveerd worden in je php.ini bestand op Homestead.

In een standaard Laravel Homestead installatie zijn de php.ini bestanden te vinden in /etc/php/7.0/fpm/. Open het configuratie bestand voor xdebug in je terminal via ssh:

nano /etc/php/7.0/fpm/conf.d/20-xdebug.ini

Voeg volgende regels code in dit bestand:

zend_extension=xdebug.so

xdebug.remote_enable = 1
xdebug.remote_connect_back = 1
xdebug.remote_port = 9000
xdebug.idekey=netbeans-xdebug

Herstart PHP zodat de nieuwe configuratie wordt geladen:

sudo service php7.0-fpm restart

Nu rest er enkel nog de configuratie in Netbeans. Ga naar je project-eigenschappen (rechtermuisklik op projectnaam). In de run configuratie klik je op advanced. In dit venster vink je aan om geen webbrowser te openen bij debugging en bij path mapping:

Ga nu naar je netbeans instellingen. In het venster Tools > Options > PHP > Debugging Tab:

Om je applicatie te debuggen, plaats je een breekpunt in je code en klik je op de Debug Project knop. Netbeans wacht op een connectie. Surf nu in je browser naar de gewenste URL en plaats ?xdebug_session_start achter deze url voor je op enter drukt. Verschillende browsers bieden een Xdebug plugin aan, zo hoef je niet ?xdebug_session_start manueel toe te voegen voor iedere url. Zie volgende site voor meer info https://xdebug.org/docs/remote.

Mapstructuur Laravel

In dit deel zullen we de mapstructuur van het aangemaakte project bekijken. Volgende sectie toont de mapstructuur met de onderliggende mapstructuur voor de belangrijkste mappen:

~/Code/Laravel/
├── app/
│   ├── Console/
│   ├── Exceptions/
│   ├── Http/
│   ├── Providers/
│   └── User.php
├── artisan
├── bootstrap/
├── composer.json
├── composer.lock
├── config/
├── database/
├── gulpfile.js
├── package.json
├── phpunit.xml
├── public/
│   ├── css/
│   ├── favicon.ico
│   ├── index.php
│   ├── js/
│   ├── robots.txt
│   └── web.config
├── readme.md
├── resources/
├── routes/
│   ├── api.php
│   ├── console.php
│   └── web.php
├── server.php
├── storage/
├── tests/
└── vendor/

Bekijk de mapstructuur in je eigen Laravel project en probeer te achterhalen wat het doel is van iedere map. Volgende secties bespreken een aantal belangrijke mappen voor je Laravel project. Voor meer informatie verwijs ik door naar de Laravel documentatie: https://laravel.com/docs/5.3/structure.

App map

De app-map bevat, zoals je zou verwachten met zo een naam, de belangrijkste code van jouw applicatie, zo zullen hierin al je klasses gedefiniëerd worden. De Console en Http mappen dienen als een API in de kern van je applicatie. Met behulp van het HTTP protocol, via routing de juiste controllers oproepen, en CLI, via commando's in de terminal, kan men integreren met de applicatie. In deze map worden ook je Eloquent models opgeslagen. De Console map bevat al je Artisan commando's en de Http map bevat je controllers, middleware en requests.

Artisan is de CLI bijgeleverd met Laravel. Het biedt een aantal handige commando's die je kunnen helpen tijdens het bouwen van je applicatie. Om een lijst van mogelijke Artisan commando's op te vragen, gebruik je het volgend commando in de root van je project:

php artisan list

Zo is het ook mogelijk om met Artisan verschillende PHP klassen te genereren. Je kan hiermee bijvoorbeeld je model, seeder, controller, middleware en migration klasse aanmaken. Ook je database migraties beheren en toepassen, routings aanmaken en authenticatie aanmaken. Deze klassen zullen dan gegenereerd worden in de app map van je project. Voor meer informatie omtrent Artisan, zie https://laravel.com/docs/5.3/artisan.

Bootstrap map

Deze map bevat bestanden die nodig zijn voor het Laravel framework. Opgelet: verwar deze map niet met het Bootstrap Framework dat we later in deze handleiding zullen toevoegen aan ons project.

Config map

Deze map bevat al je configuratie bestanden van je applicatie. Ga even door deze bestanden om jezelf vertrouwd te maken met de verschillende mogelijkheden.

Database map

De database map bevat je database migraties, het is ook een ideale plek om je SQLite database te plaatsen indien je hiervan gebruik wilt maken. In tegenstelling tot een MySQL database systeem is een SQLite database een enkele file, ideaal voor een eenvoudige, kleine en lokale database aan te maken.

Public map

De public map is de root van de website. Zo bevat het je index.php bestand, wat het beginpunt is van alle requests voor je applicatie. In deze map worden ook al je overige nodige bestanden geplaatst zoals afbeeldingen, JavaScript bestanden en CSS bestanden.

Resources map

In de resource map plaatsen we onze views. In de onderliggende lang map kunnen we vertalingen plaatsen voor de website.

Routes map

De routes map bevat al de route-definities van je applicatie. Standaard zijn er drie routes ingesteld met Laravel: web.php, api.php en console.php. Het api.php bestand bevat routes voor bijvoorbeeld een RESTful API te integreren in je applicatie. Wanneer je applicatie dit niet nodig heeft, zullen al je routes waarschijnlijk enkel gedefiniëerd worden in het web.php bestand.

Storage map

Deze map wordt gebruikt door het framework zelf, zo zullen hier bijvoorbeeld de gecompileerde Blade templates in bewaard worden.

Test map

In deze map kun je test bestanden terugvinden. Laravel gebruikt hiervoor PHPUnit, dit is ook standaard meegeleverd met de installatie. Voor deze handleiding gaan we dit niet bekijken. Indien nodig kan je hierover meer informatie vinden op https://phpunit.de.

Vendor map

De vendor map bevat al je Composer afhankelijkheden.

Database migraties

Zoals aangehaald zal men in Laravel 5 modellen beschrijven aan de hand van relaties, in plaats van al zijn eigenschappen en datamembers te beschrijven. De beste werkwijze hiervoor is om met migraties en seeders te werken.

Ter info: Moest je een Laravel project willen maken met een bestaande database, kan je ook backwards migrations uitvoeren, hiervoor heb je wel een extern pakket nodig: https://github.com/Xethron/migrations-generator. Je bestaande tabellen worden dan vertaald naar de overeenkomende Eloquent modellen. Wil je Eloquent modellen genereren op basis van een bestaande database kan je volgend pakket gebruiken: https://github.com/pepijnolivier/Eloquent-Model-Generator.

Dankzij het gebruik van Homestead is het zeer eenvoudig om een database te gebuiken in onze applicatie. In onze Laravel map bevindt zich een verborgen .env bestand waarin men de database connectiegegevens kan ingeven. Dit is reeds in orde in onze installatie:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

In onze webwinkel willen we items kunnen weergeven. Om het eenvoudig te houden zal onze database enkel een item tabel nodig hebben:

+--------------+------------------+------+-----+---------+----------------+
| Field        | Type             | Null | Key | Default | Extra          |
+--------------+------------------+------+-----+---------+----------------+
| id           | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| title        | varchar(255)     | NO   |     | NULL    |                |
| beschrijving | varchar(255)     | NO   |     | NULL    |                |
| foto         | varchar(255)     | NO   |     | NULL    |                |
| prijs        | int(11)          | NO   |     | NULL    |                |
| voorraad     | int(11)          | NO   |     | NULL    |                |
| created_at   | timestamp        | YES  |     | NULL    |                |
| updated_at   | timestamp        | YES  |     | NULL    |                |
+--------------+------------------+------+-----+---------+----------------+

Migratie

Deze tabel realiseren is zeer gemakkelijk in het Laravel framework. Om te beginnen kunnen we het volgende Artisan commando gebruiken om een PHP migratie-klasse te generen:

$ php artisan make:migration maak_items_tabel --create="items"
Created Migration: 2016_10_30_153319_maak_items_tabel

Dit maakt de PHP klasse /database/migrations/<datum>_maak_items_tabel.php aan waarin we verdere aanpassingen kunnen doen om ons model te beschrijven:

<?php

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

class MaakItemsTabel extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('items', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
            $table->string('beschrijving');
            $table->string('foto');
            $table->integer('prijs');
            $table->integer('voorraad');
            $table->timestamps();
        });
    }

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

Om de migratie uit te voeren gebruik je volgend commando:

php artisan migrate

Onze homestead MySQL database bevat nu een items tabel. Controleer dit via de MySQL CLI.

Seed

Om wat basisrecords in onze database te hebben, biedt Laravel ook seedersaan. We zullen een Seeder klasse aanmaken om wat items te creëren in onze database:

$ php artisan make:seeder ItemsTableSeeder
Seeder created successfully.

Dit commando maakt de PHP klasse database/seeds/ItemsTableSeeder.php aan. Open dit bestand en pas het aan met wat basisitems:

<?php

use Illuminate\Database\Seeder;

class ItemsTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        DB::table('items')->delete();
 
        $items = array(
            [   'id' => 1, 
                'title' => 'HP 15-ba051nb Azerty', 
                'beschrijving' => 'HP 15-ba051nb Azerty', 
                'foto' => 'https://image.coolblue.io/products/550141?width=170&height=170', 
                'prijs' => 550, 
                'voorraad' => 35,
                'created_at' => new DateTime, 
                'updated_at' => new DateTime],
                
            [   'id' => 2, 
                'title' => 'Lenovo IdeaPad 500-15ISK 80NT00G0MB Azerty',
                'beschrijving' => 'Lenovo IdeaPad 500-15ISK 80NT00G0MB Azerty',
                'foto' => 'https://image.coolblue.io/products/484852?width=170&height=170', 
                'prijs' => 700, 
                'voorraad' => 49,
                'created_at' => new DateTime, 
                'updated_at' => new DateTime],
                
            [   'id' => 3, 
                'title' => 'Acer Aspire ES1-731-C7TW Azerty', 
                'beschrijving' => 'Acer Aspire ES1-731-C7TW Azerty', 
                'foto' => 'https://image.coolblue.io/products/345641?width=170&height=170',
                'prijs' => 400, 
                'voorraad' => 23,
                'created_at' => new DateTime, 
                'updated_at' => new DateTime]
        );
        
        DB::table('items')->insert($items);
    }
}

We moeten deze seeder ook registreren in het /database/seeds/DatabaseSeeder.php bestand:

<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $this->call(ItemsTableSeeder::class);
    }
}

Om deze gegevens in de database te krijgen, gebruiken we volgende commando's:

$ composer dump-autoload
Generating autoload files
$ artisan db:seed
Seeded: ItemsTableSeeder

De data zal nu toegevoegd zijn in je tabel:

mysql> select * from items;
+----+--------------------------+--------------------------------------------+----------------------------------------------------------------+-------+----------+---------------------+---------------------+
| id | title                    | beschrijving                               | foto                                                           | prijs | voorraad | created_at          | updated_at          |
+----+--------------------------+--------------------------------------------+----------------------------------------------------------------+-------+----------+---------------------+---------------------+
|  1 | HP 15-ba051nb Azerty     | HP 15-ba051nb Azerty                       | https://image.coolblue.io/products/550141?width=170&height=170 |   550 |       35 | 2016-10-30 15:50:33 | 2016-10-30 15:50:33 |
|  2 | Lenovo IdeaPad 500-15ISK | Lenovo IdeaPad 500-15ISK 80NT00G0MB Azerty | https://image.coolblue.io/products/484852?width=170&height=170 |   700 |       49 | 2016-10-30 15:50:33 | 2016-10-30 15:50:33 |
|  3 | Acer Aspire ES1-731-C7TW | Acer Aspire ES1-731-C7TW Azerty            | https://image.coolblue.io/products/345641?width=170&height=170 |   400 |       23 | 2016-10-30 15:50:33 | 2016-10-30 15:50:33 |
+----+--------------------------+--------------------------------------------+----------------------------------------------------------------+-------+----------+---------------------+---------------------+
3 rows in set (0.00 sec)

Model

Om met onze items tabel te kunnen werken hebben we een equivalent Modelnodig. Dit model kunnen we ook aanmaken met een Artisan commando:

$ php artisan make:model Item
Model created successfully.

Zeer eenvoudig dus. Dit maakt een PHP Item klasse aan in /app/.

Controller

We kunnen nu bijna onze applicatie gaan bekijken in de browser. Maar hiervoor hebben we wel nog controllers en routing nodig. Laravel biedt de mogelijkheid om met één simpele regel alle nodige "CRUD" (Create, Read, Update, Delete) routings te implementeren in een controller. Om zo een controller aan te maken kunnen we volgend commando gebruiken:

$ php artisan make:controller ItemsController --resource
Controller created successfully.

Dit commando zal een controller genereren app/Http/Controller/ItemsController.php. Deze controller bevat voor iedere mogelijke "CRUD" operatie een methode.

Nu willen we natuurlijk ook een 'resourceful' route naar de controller. Hiervoor plaatsen we volgende lijn toe onderaan in routes/web.php:

Route::resource('items', 'ItemsController');

Deze enkele route declaratie maakt meerdere routings aan om de verschillende acties uit te kunnen voeren.

Een handig Artisan commando geeft de mogelijkheid om alle huidige routings weer te geven:

$ php artisan route:list
+--------+-----------+-------------------+---------------+----------------------------------------------+--------------+
| Domain | Method    | URI               | Name          | Action                                       | Middleware   |
+--------+-----------+-------------------+---------------+----------------------------------------------+--------------+
|        | GET|HEAD  | /                 |               | Closure                                      | web          |
|        | GET|HEAD  | api/user          |               | Closure                                      | api,auth:api |
|        | GET|HEAD  | items             | items.index   | App\Http\Controllers\ItemsController@index   | web          |
|        | POST      | items             | items.store   | App\Http\Controllers\ItemsController@store   | web          |
|        | GET|HEAD  | items/create      | items.create  | App\Http\Controllers\ItemsController@create  | web          |
|        | GET|HEAD  | items/{item}      | items.show    | App\Http\Controllers\ItemsController@show    | web          |
|        | PUT|PATCH | items/{item}      | items.update  | App\Http\Controllers\ItemsController@update  | web          |
|        | DELETE    | items/{item}      | items.destroy | App\Http\Controllers\ItemsController@destroy | web          |
|        | GET|HEAD  | items/{item}/edit | items.edit    | App\Http\Controllers\ItemsController@edit    | web          |
+--------+-----------+-------------------+---------------+----------------------------------------------+--------------+

Je kan nu zien dat we in principe naar http://homestead.app/items kunnen browsen. Dit is inderdaad mogelijk maar we zullen een lege witte pagina te zien krijgen. De route zal namelijk de index methode oproepen van de IndexController, dit is te zien in de bovenstaande tabel bij items.index. De actie die hiermee overeenkomt is App\Http\Controllers\ItemsController@index. We moeten dus in /app/Http/controllers/ItemsController.php onze index methode gaan aanpassen:

public function index()
{
    return view('items.index');
}

View

De index methode van de ItemsController geeft nu een view terug. Natuurlijk moeten we deze wel nog eerst aanmaken. Zoals reeds aangehaald maakt Laravel gebruik van het Blade template systeem.

Maak nu een bestand aan: /resources/views/items/index.blade.php en plaats hier willekeurige tekst in. Surf opnieuw naar http://homestead.app/items, als alles in orde is, zal je nu je ingegeven tekst te zien krijgen in je browser.

Bootstrap integratie

De inhoud van een view laten zien is natuurlijk zeer handig maar wanneer we meerdere pagina's hebben zal het nodig zijn een consistente layout over de gehele website te hebben. We gebruiken voor deze handleiding een simpele template om snel aan de slag te gaan.

git clone https://github.com/BlackrockDigital/startbootstrap-shop-homepage.git

Dit geeft je een map met een index.html bestand en de nodige CSS en JS bestanden. Om dit te integreren in onze Laravel applicatie moeten we deze webpagina efficiënt opsplitsen:

Om te beginnen plaatsen we de js, css en fonts map in /public in onze project map. Voor deze handleiding is de index.html pagina opgesplitst in de verschillende secties. Bekijk na volgend onderdeel goed van waar ieder stuk code komt uit deze index.html pagina. Moest je nog niet genoeg vertrouwd zijn met HTML en CSS syntax, stel ik voor dat je eerst hoofdstuk 7 grondig doorneemt.

Maak nu een nieuw bestand aan (views/layouts/master.blade.php) met als inhoud:

<!DOCTYPE html>
<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<html>
    <head>
        <base href="{{URL::asset('/')}}" target="_top">
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="description" content="">
        <meta name="author" content="">

        <title>PC Shop - @yield('title')</title>
        
        <link rel="stylesheet" href="{{{ URL::asset('css/bootstrap.min.css')}}}" />
        <link rel="stylesheet" href="{{{ URL::asset('css/shop-homepage.css')}}}" />
    </head>
    <body>
        @include('partials.header')
        <!-- Page Content -->
        <div class="container">
            @yield('content') 
        </div>
        <!-- /.container -->
        
        @include('partials.footer')
        
        <script type="text/javascript" src="{{{ URL::asset('js/jquery.js')}}}"></script>
        <script src="{{{ URL::asset('js/bootstrap.min.js')}}}"></script>
    </body>
</html>

Zoals je kan zien gebruiken we hierin 2 soorten Blade verwijzingen:

Ook wordt in de head sectie verwezen naar de bootstrap CSS en JS bibliotheek, voor meer info omtrent de mogelijkheden van bootstrap verwijs ik door naar http://getbootstrap.com/.

Nu hebben we een master layout bestand die dynamisch de pagina zal opbouwen aan de hand van de partiële layouts. Dat wilt dus ook wel zeggen dat we deze partiële layouts nog moeten aanmaken.

Maak nu views/partials/header.blade.php aan met volgende inhoud:

<!-- 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="#">PC Shop</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>

Maak vervolgens views/partials/footer.blade.php:

<div class="container">
    <hr>
    <!-- Footer -->
    <footer>
        <div class="row">
            <div class="col-lg-12">
                <p>Copyright &copy; SOA & Cloud Computing</p>
            </div>
        </div>
    </footer>

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

We moeten nu enkel nog onze Blade pagina bijwerken voor onze ItemsController@Index methode. Open het bestand /resources/views/items/index.blade.php en pas de inhoud aan:

@extends('layouts.master')
@section('title', 'Items Overview')
@section('content')
    <div class="row">

        <div class="col-md-3">
            <p class="lead">Laptops</p>
            <div class="list-group">
                <a href="#" class="list-group-item">Category 1</a>
                <a href="#" class="list-group-item">Category 2</a>
                <a href="#" class="list-group-item">Category 3</a>
            </div>
            
        </div>

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

            <div class="row">
                @foreach( $items as $item )
                    
                    <div class="col-sm-4 col-lg-4 col-md-4">
                        <div class="thumbnail">
                            <img src="{{ $item->foto }}" alt="">
                            <div class="caption">
                                <h4>
                                    <p><a href="#">{{ $item->title }}</p></a>
                                </h4><br>
                                <h4 class="pull-right">€ {{ $item->prijs }}</h4>
                                
                                <p>{{ $item->beschrijving }}</p>
                            </div>
                            <div class="ratings">
                               
                                <?php
                                    $score = rand(0, 5);
                                    $reviews = rand(20,250);
                                ?>
                                
                                <p class="pull-right">{{ $reviews }} reviews</p>
                                <p>
                                    @for ($i = 1; $i <= 5; $i++)
                                        @if($i<=$score) 
                                            <span class="glyphicon glyphicon-star"></span>
                                        @else
                                            <span class="glyphicon glyphicon-star-empty"></span>
                                        @endif
                                    @endfor
                                </p>
                            </div>
                        </div>
                    </div>
                    
                @endforeach

            </div>

        </div>

    </div>
@stop

Bovenaan deze file vermelden we welke layout deze pagina gebruikt. Dit is nodig omdat anders de standaard Laravel layout zal worden gebruikt. We willen natuulijk onze eigen Bootstrap layout gaan gebruiken.

Het voordeel van het blade template systeem is dat we dus onze webpagina mooi gestructureerd kunnen opdelen. Hierdoor kan men dezelfde layout integreren in alle pagina's zonder deze code in iedere view te gaan herschrijven. Zo kunnen we bijvoorbeeld ook de linkerbalk van onze webpagina als een partiële layout integreren, probeer dit zelf.

In deze pagina gebruiken we ook de $items variabele. Deze moeten we natuurlijk ook nog meegeven vanuit de controller, open de ItemsController en pas de Index methode aan:

public function index()
{
    $items = Item::all();
    return view('items.index')->with('items', $items);
}

Plaats bovenaan de ItemsController ook een importeer-verwijzing naar het Item model:

use App\Item;

Item::all() zal de huidige items uit de tabel teruggeven. Dit kunnen we ook testen aan de hand van Tinker, nog een handigheid van Artisan:

$ php artisan tinker
>App\Item::all();   

Resultaat

Als alles goed is gegaan, zou nu je basisapplicatie klaar moeten zijn.

Browse naar http://homestead.app/items om het resultaat van onze webshop applicatie te bekijken. Je zou volgend scherm moeten verkrijgen:

Resultaat

Natuurlijk ben je hier nog niet veel mee, maar het kan je wel vertrouwd maken met het Laravel framework en op weg zetten je eigen applicatie te ontwikkelen.

Bekijk de applicatie en ga grondig doorheen de HTML en PHP codes om vertrouwd te geraken met de HTML syntax, Blade syntax en het Boostrap framework.

DEEL 2: Records filteren

In dit gedeelte zullen we de applicatie uitbreiden om ook te kunnen filteren op een minimum en maximum prijs. We zullen tevens een extra database-tabel toevoegen om te kunnen filteren op het merk van de computers.

Begin met een nieuwe Laravel migratie klasse aan te maken voor de brands tabel waar we onze merken kunnen opslaan. Gebruik hiervoor het juiste commando uit voorgaande deel.

In deze brands migratie klasse schrijf je de code om de tabel aan te maken. Stel dat we gewoonweg een id en merknaam kolom willen aanmaken:

Schema::create('brands', function (Blueprint $table) {
    $table->increments('id');
    $table->string('merk');
});

Naast het aanmaken van een nieuwe tabel willen we ook onze huidige items tabel aanpassen. Geef deze tabel een nieuwe kolom voor de id van het merk en maak een verwijzende sleutel van deze kolom in items naar de id kolom van brands:

Schema::table('items', function($table) {
    $table->integer('brand_id')->unsigned();
    $table->foreign('brand_id')->references('id')->on('brands');
});

Voer deze migratie uit met het artisan commando. De tabel is nu gewijzigd naar onze aanpassingen. Eventueel moet je eerst je items tabel leegmaken voor je kan migreren.

Pas ook de seeder aan (of maak een nieuwe seeder) en voer deze erna uit, in de items array van de seeder voeg je natuurlijk de overeenkomstige id van het merk in:

...
DB::table('brands')->delete();

$brands = array(
    ['id' => 1, 'merk' => 'HP'],
    ['id' => 2, 'merk' => 'Lenovo'],
    ['id' => 3, 'merk' => 'Acer']
);

DB::table('brands')->insert($brands);
...
$items = array(
    ['id' => 1, 'brand_id' => 1, ... ],
    ['id' => 2, 'brand_id' => 2, ... ],
    ['id' => 3, 'brand_id' => 3, ... ]
);
...   

Net zoals in het eerste deel hebben we hiervoor ook een Eloquent Brand model nodig. Voeg dit toe met behulp van het juiste artisan commando.

Onze records filteren via de webbrowser kunnen we realiseren door een klein formuliertje aan te maken op onze pagina. Een ideale plaats hiervoor is de linkerbalk. Om te filteren op minimum en maximum prijs voegen we twee invoer tekstvakken toe, voor de merken voegen we checkboxen toe. Voeg volgende code in plaats van de sidebar:

<div class="col-md-3">
    <form action="{{ route('items.filter') }}" method="post">
        <input type="hidden" name="_token" value="{{ csrf_token() }}">
        <p class="lead">Prijs</p>
        <div class="form-group">
            <label for="min_value">Minimum:</label><br>
            <input type="text" name="min_price" value="0" />
        </div>
        <div class="form-group">
            <label for="max_value">Maximum:</label><br>
            <input type="text" name="max_price" value="1000"/>
        </div><br/><br/>
        <p class="lead">Merk</p>
        <input type="checkbox" name="brands[]" id="1" value="1" checked> HP<br>
        <input type="checkbox" name="brands[]" id="2" value="2" checked> Lenovo<br>
        <input type="checkbox" name="brands[]" id="3" value="3" checked> Acer<br>
        <br>
        <button type="submit" class="btn btn-default">Filter</button><br><br>
    </form>
</div>

Dit formulier zal een post doen naar items.filter route met als request parameters: min_value, max_value en de brands-array. Deze route moet nog toegevoegd worden aan web.php.

Route::post('items', 'ItemsController@filter')->name('items.filter');

We geven deze route een naam omdat de overeenkomende url dan kan gegenereerd worden met de route helper (zoals gebruikt in het formulier).

Zoals aangehaald in de inleiding zal Laravel je beschermen tegen cross-site request forgery (CSRF) aanvallen. Hiervoor genereert Laravel voor iedere actieve sessie een CSRF token. Bij ieder HTML formulier in je applicatie ben je verplicht om een verborgen CSRF token veld te integreren. De CSRF protectie middleware zal elke request dan valideren.

Onze routing verwijst naar de filter functie in ItemsController. Maak deze daar met volgende code:

public function filter(Request $request)
{
    $minPrice = $request->input('min_price');
    $maxPrice = $request->input('max_price');
    $brands = $request->input('brands');

    $items = Item::whereBetween('prijs', [$minPrice, $maxPrice])
                    ->whereIn('brand_id', $brands)
                    ->get();

    return view('items.index')->with('items', $items);
}

Zorg ervoor dat je bovenaan naar de juiste klassen refereert:

use App\Item;
use App\Brand;
use Illuminate\Http\Request;

In de eerste 3 regels zullen we de ingevulde waarden opvragen. Vervolgens gaan we onze items tabel gaan filteren met de juiste query uit te voeren. Ieder Eloquent fungeert ook als een query builder. Het is dus mogelijk om pure SQL syntax uit te voeren, maar Laravel biedt ook handige methodes die gebruikt kunnen worden in de query builder. De query builder biedt dus een handige en vloeiende manier om queries te maken en uit te voeren op een database. Het kan gebruikt worden voor zowat alle mogelijke database operaties en werkt met alle ondersteunde database systemen. Met de whereBetween kunnen we dus de records opvragen waarvan prijs tussen $minPrice en $maxPrice ligt, vervolgens verplichten we ook dat $brands-array de brand_id bevat. Uiteindelijk gebruiken we de get() methode om de resultaten te verkrijgen. Bezoek https://laravel.com/docs/5.3/queries voor meer informatie omtrent de Query Builder.

Surf naar homestead.app/items om het resultaat te bekijken. De weergegeven items zullen nu afhankelijk zijn van je ingestelde filters. Er is echter nog een nadeel dat de gebruiksvriendelijkheid van de applicatie naar beneden haalt. Zo zal het filter-formulier iedere keer gereset worden naar de standaard-waarden, dit willen we natuurlijk vermijden. Laravel heeft hier weer een handige oplossing voor, het is mogelijk om de data van een vorige request terug mee te geven met een volgende. Hiervoor kan je de flash() methode gebruiken. Roep deze functie op juist voor je de view returnt:

$request->flash();

Pas de value eigenschap van de input HTML tags aan naar deze oude data:

<input type="text" name="min_price" value="{{ old('min_price') ? old('min_price') : 0 }}" />

Dankzij deze handige schrijfwijze kan er eerst worden gekeken of er een vorige min_price ingevuld was of niet. Doe hetzelfde voor max_price.

Voor de merken-filter kunnen we dit ook toepassen, maar hier is echt nog een probleem mee. Momenteel worden de merken niet uit onze database gehaald, tijd om hier verandering in te brengen. We zorgen er eerst voor dat we een lijst van alle merken meegeven bij het laden van de webpagina. Verander je ItemsController voor index en filter naar:

public function index()
{
    $items = Item::all();
    $brands = Brand::all();

    return view('items.index')->with('items', $items)->with('brands', $brands);
}

public function filter(Request $request)
{
    $minPrice = $request->input('min_price');
    $maxPrice = $request->input('max_price');
    $brands = $request->input('brands');

    $items = Item::whereBetween('prijs', [$minPrice, $maxPrice])
                    ->whereIn('brand_id', $brands)
                    ->get();

    $brands = Brand::all();

    $request->flash();
    return view('items.index')->with('items', $items)->with('brands', $brands);
}

Vervolgens moet enkel nog de view aangepast worden. Verwijder de hard-coded checkbox input tags en voeg volgende code toe:

<p class="lead">Merk</p>
@foreach( $brands as $b )
    <input type="checkbox" name="brands[]" id="{{$b->id}}" value="{{$b->id}}" @if(in_array($b->id, old('brands') ? old('brands') : [])) checked @endif> {{$b->merk}}<br>
@endforeach
<br>

Deze foreach zal onze merken-lijst overlopen en weergeven. Dankzij de handige blade syntax @if(in_array($b->id, old('brands') ? old('brands') : [])) checked @endif is het mogelijk om te kijken welke merken juist geselecteerd waren bij het filteren. Indien old('brands')-lijst de id van het merk bevat, verandert de checkbox toestand naar checked.

Deze problemen zijn nu opgelost. Wanneer men de filter toepast, zullen ook de juiste filters behouden blijven:

filter

Zoals je kan vaststellen, zal de website telkens herladen en de juiste filtering toepassen in de controller. Alhoewel dit werkt, kan dit zeer vervelend zijn voor gebruikers. Wat we liever zouden willen, is dat er maar een bepaald gedeelte van de website wordt geupdated. Dit kan men bereiken door het gebruik van asynchrone requests te maken naar de controller. Hiervoor is javascript nodig, dit wordt besproken in sectie 9.7 (Ajax) van de cursus Cloud Computing & SOA. We kunnen de controller dan verplichten van enkel het content gedeelte als response te sturen in Laravel:

...
return view('items.index')->with('items', $items)->with('brands', $brands)->renderSections(['content']);

Met javascript kunnen we dan de oude content vervangen als we via Ajax de nieuwe content hebben ontvangen. De repons van deze request zal namelijk pure HTML syntax zijn.

DEEL 3: Nog meer Laravel features

In dit laatste gedeelte bekijken we nog een aantal handige features van het Laravel Framework. Om te beginnen gaan we een volledig gebruikers-authenticatie systeem aanmaken. Dit is echter zeer eenvoudig in Laravel. Met behulp van factories kunnen we kopies maken van modellen om onze database te vullen, dit is vergelijkbaar met een Laravel seeder maar we moeten hiervoor niet alle items volledig uitschrijven. Daarom maken we ook gebruik van het faker pakket. Met behulp van faker en factories gaan we een 100-tal gebruikers aanmaken voor onze applicatie. In dit deel zullen we ook kennismaken met mutators en accessors.

Authenticatie

Laten we starten met de authenticatie, hiervoor gebruiken we het volgende artisan commando:

$ php artisan make:auth
Authentication scaffolding generated successfully.

Voila, dat was het. Laravel heeft nu al de nodige code (routes, controllers, validatie en views) gegenereerd voor gebruikers authenticatie. Gebruikers kunnen zich registreren, inloggen en hun wachtwoord resetten. Er zijn dus heel wat view bijgekomen in Laravel/resources/views/auth en de web.php route file is aangepast met 2 nieuwe routings:

Auth::routes();
Route::get('/home', 'HomeController@index');

Bezoek de loginpagina in je browser via http://homestead.app/login. Zoals je kan zien is hierop alles aanwezig wat nodig is. Op het registratie formulier is ook de nodige validatie toegepast.

Mutators

Test of het registratie formulier ook werkt. Stel vast dat wanneer een gebruiker zijn naam registreert zonder hoofdletter, deze naam ook zo wordt opgeslagen in de database. Dit is natuurlijk iets dat we willen vermijden. In PHP kan je hiervoor de functie ucfirst(string $str) gebruiken.

Om dit aan te passen, navigeer je naar de RegisterController.php@create functie. Je kan zien dat $data['name'] rechtstreeks opgeslagen wordt als de naam eigenschap. Een oplossing is dus dat we hierop ucfirst implementeren:

protected function create(array $data)
{
    return User::create([
        'name' => ucfirst($data['name']),
        'email' => $data['email'],
        'password' => bcrypt($data['password']),
    ]);
}

Registreer een nieuwe gebruiker en stel vast dat dit probleem is opgelost. Als een nieuwe gebruiker zich registreert, zal de naam altijd met een hoofdletter starten en zo worden opgeslagen. Hoewel dit het probleem heeft opgelost, is dit niet de beste manier. Bij objectgeoriënteerde programmeertalen gebruikt men hiervoor setters. Ook in Laravel kan men dit toepassen, dit noemt men mutators. Om ervoor te zorgen dat de naam attribuut van het gebruikers-model altijd met een hoofdletter begint, voegen we een mutator toe aan het model. Open User.php en voeg volgende functie toe:

public function setNameAttribute($value)
{
    $this->attributes['name'] = ucfirst($value);
}

Verwijder natuurlijk ook de ucfirst functie uit de controller. Nu maakt het niet meer uit vanwaar je een gebruiker aanmaakt, de naam zal altijd met een hoofdletter beginnen. Laravel verplicht je om een Mutator aan te maken als een functie beginnend met set en eindigend op Attribute, tussenin plaats je de "studly-cased" naam van de kolom die je wilt bereiken.

We kunnen dit principe ook toepassen op het wachtwoord van de gebruiker. In de controller wordt hierop encryptie toegepast voordat het opgeslagen wordt. Maak een mutator aan voor het wachtwoord.

Accessors

In tegenstelling tot een mutator, die data formatteerd voor we het opslaan, kunnen we bij een accessor data formatteren wanneer we het opvragen. Om dit te oefenen, gaan we een accessor aanmaken die een euroteken plaatst voor onze items-prijzen, open hiervoor het Items model en voeg een accessor toe:

public function getPrijsAttribute($value)
{
    return "€ " . $value;
}

Vergeet je euroteken niet weg te halen in de view, anders heb je er 2 naast elkaar staan. Erg handig die mutators en accessors, hè? Voor meer informatie hierover, surf je naar https://laravel.com/docs/5.3/eloquent-mutators.

Factories & Faker

Nog een handig feature van Laravel zijn factories, dit is bijzonder handig bij het testen en ontwikkelen van je applicatie. In plaats van alle testdata volledig uit te schrijven voor iedere kolom, kunnen we model factories gebruiken om Eloquent modellen aan te maken. Net als een autofabriek, zijn er verschillende modellen waarvan kopies worden gefabriceerd. Natuurlijk willen we niet dat ieder aangemaakt model dezelfde eigenschappen heeft, daarom maken we ook gebruik van de Faker PHP bibliotheek.

Bekijk database/factories/ModelFactory.php, deze zit standaard in ieder nieuw Laravel project:

$factory->define(App\User::class, function (Faker\Generator $faker) {
    static $password;

    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'password' => $password ?: $password = bcrypt('secret'),
        'remember_token' => str_random(10),
    ];
});

Dit bestand implementeerd dus reeds een factory voor gebruikersaccounts aan te maken. Faker zal in dit geval een random naam, emailadres en rember_token aanmaken. Het wachtwoord zal voor iedere gebruiker hetzelfde zijn, namelijk "secret". Indien je de mutator voor de encryptie van het wachtwoord hebt aangemaakt, moet je de bcrypt functie uit deze factory verwijderen. Anders ga je 2x encrytie toepassen op het wachtwoord.

Om deze factory uit te voeren, gebruiken we natuurlijk een seeder. Maak een nieuwe seeder aan: $ php artisan make:seeder UserTableSeeder Seeder created successfully.

We schrijven hier de code die ervoor zorgt dat er 100 gebruikers aangemaakt worden: php public function run() { factory(App\User::class, 100) -> create(); }

We kunnen deze seeder uitvoeren met het volgende artisan commando:

php artisan db:seed --class=UserTableSeeder

Controleer je MySQL users tabel, hier zijn nu 100 gebruikers aangemaakt.

Lumen

De ontwikkelaars van Laravel bieden ook een kleinere versie van het framework aan. Deze is een stuk sneller dan het volledige framework en ideaal voor micro-services en snelle APIs. Het microframework Lumen is dus het kleinere broertje van Laravel. Doordat Lumen gebaseerd is op Laravel-componenten kan een Lumen-project relatief makkelijk naar een Laravel-project geüpgraded worden.

Vermits het een vereenvoudigde versie is van het Laravel framework, werden ook de commando's weggelaten waardoor ontwikkeling toch iets of wat trager gaat. Indien je toch commando's wilt gebruiken, importeer dan het volgende pakket: https://github.com/webNeat/lumen-generators

Indien je een API wilt ontwikkelen zonder UI, kan het gebruiken van Lumen zeker interessant zijn.

Voor meer informatie kan je de documentatie raadplegen van Lumen op https://lumen.laravel.com/docs/5.3.

Bronnen

Deze websites werden geraadpleegd om deze handleiding te schrijven: