NOTE: due to the limitations of the conent, I am unable to post all of my notes but I have attached a file to this post of all the notes: Scroll all the way down to this page to download: 20-p5032-laragigsnotes.txt
THIS IS A LARAVEL 9 TUTORIAL I AM FOLLOWING TO LEARN HOW LARAVEL 9 WORKS. THE APPLICATION IS GREATE BECAUSE YOU ARE POSTING JOBS AND USES LOGIN TO CREATE JOB POSTINGS.
install laravel on linux:
https://laravel.com/docs/9.x#getting-started-on-linux
open terminal$ cd ~/Desktop/local-laravel/tutorial/laragigs
$ curl -s https://laravel.build/laragigs | bash
# THIS WILL TAKE A WHILE AND GET THIS MESSAGE:
Thank you! We hope you build something incredible. Dive in with: cd laragigs && ./vendor/bin/sail up$ cd laragigs
# CREATE ALIAS FOR SAIL$ alias sail='bash vendor/bin/sail'
# START SAILing$ sail up -d
# TO STOP:$ sail down
# Sail without alias:$ ./vendor/bin/sail up -d
#################### TIPS #########################
Laravel Sail: Execute And Send Terminal Command To Docker Container : https://www.webune.com/forums/azpyxw.html
Now you can execute any sail command to the contairner from the host machine:$ sail php --version
Docker Command To Access Bast Terminal Inside A Container
https://www.webune.com/forums/zmpywz.html
First, find the container id with the following command:$ docker ps -a
Now that you have the container id, you can use the following command:$ sudo docker exec -i -t [DOCKERID] /bin/bash
#################### END TIPS #########################
open browser http://localhost
https://youtu.be/MYyJ4PuL4pY?t=381
open a new tab in terminal:
open vs code:$ code .
open terminal: control + `$ touch MyNotes.txt
# INSTALL EXTENSIONS:
1. laravel blade snippets by Winni Lin
2. PHP NameSpace Resolver by mehedi Hassan // https://youtu.be/MYyJ4PuL4pY?t=1425
3. PHP Intelephense by Ben Mewborn
ROUTING: https://youtu.be/MYyJ4PuL4pY?t=830
/routes/web.php
// THIS ROUTE POINTS TO: /resources/views/welcome.blade.php
Route::get('/', function () {
return view('welcome');
});
// SIMPLE HELLO WORLD:
Route::get('/hello', function () {
return 'Hello World';
});
// with response() HELLO WORLD:
Route::get('/hello', function () {
return return response('Hello World');
});
// with 404 response() HELLO WORLD:
Route::get('/hello', function () {
return response('Hello World',404);
});
// WITH HEADERS and CUSTOM HEADERS
Route::get('/hello', function () {
return response('Hello World',200)
// specify content type
->header('Content-Type', 'text-plain')
// customer header
->header('foo', 'bar');
});
// PARAMS
// http://localhost/post/47
Route::get('/post/{post_id}', function ($post_id) {
return response('Post Id:' . $post_id);
// add contraints to only accept numbers. http://localhost/post/dhs WILL GIVE 404 ERROR
})->where('post_id','[0-9]+');
# DEBUGINGG: Dump, Die,
// http://localhost/post/47
Route::get('/post/{post_id}', function ($post_id) {
dd($post_id); // Die and Dump. OUTPUT: "47" // routes/web.php:29
return response('Post Id:' . $post_id);
// add contraints to only accept numbers. http://localhost/post/dhs WILL GIVE 404 ERROR
})->where('post_id','[0-9]+');
# DEBUGINGG: Dump, Die, Debug
// http://localhost/post/47
Route::get('/post/{post_id}', function ($post_id) {
ddd($post_id); // Die and Dump
return response('Post Id:' . $post_id);
// add contraints to only accept numbers. http://localhost/post/dhs WILL GIVE 404 ERROR
})->where('post_id','[0-9]+');
//http://localhost/search?name=edwin&city=sfo
Route::get('/search', function (Request $request) {
//dd($request); // show all
dd($request->name); // show only the params OUTPUT: "edwin" // routes/web.php:38
});
## JSON API
// http://localhost/api/posts
Route::get('/posts', function () {
//return JSON
return response() ->json([
'posts' => [
'title' => 'Posts One'
]
]);
});
BLADE TEMPLATES:
open /resources/views/welcome.blade.php and remove the default HTML to:
<h1>Listings</h1>
open browser to http://localhost
TIP: you can rename and will work the same
FROM: /resources/views/welcome.blade.php
TO: /resources/views/listings.php
PASSING DATA
http://localhost
>>>>>>>>>>>>> routes/web.php
Route::get('/', function () {
return view('listings',[
'heading' => "Latest Listings",
'listings' => [
[
'id' => 1,
'title' => 'Listing One',
'description' => 'This is the one description'
],
'listings' => [
'id' => 1,
'title' => 'Listing Two',
'description' => 'This is the two description'
]
],
]);
});
>>>>>>>>>>> views/listings.php
<h1><?php echo $heading; ?></h1>
<?php foreach($listings as $listing): ?>
<h2><?php echo $listing['title'] ?></h2>
<p><?php echo $listing['description'] ?></p>
<?php endforeach; ?>
#CHANGE TO A BLADE TEMPLATE:
rename
FROM: views/listings.php
TO: views/listings.blade.php
CLEAN IT UP:
<h1>{{$heading}}</h1>
@foreach($listings as $listing)
<h2>{{$listing['title']}}</h2>
<p>{{$listing['description']}}</p>
@endforeach
//https://youtu.be/MYyJ4PuL4pY?t=2038
REFRESH BROWSER: http://localhost and you will get same results
# EMBED PHP INTO BLADE TEMPLATE:
<h1>{{$heading}}</h1>
// php DIRECTIVE
@php
$foo = 1;
@endphp
{{$foo}}
@foreach($listings as $listing)
<h2>{{$listing['title']}}</h2>
<p>{{$listing['description']}}</p>
@endforeach
CONDITIONALS: in BLADE TEMPLATES
<h1>{{$heading}}</h1>
@if(count($listings == 0))
<p>No Listings Found</p>
@endif
// USING UNLESS
<h1>{{$heading}}</h1>
@unless( count($listings)==0 )
@foreach($listings as $listing)
<h2>{{$listing['title']}}</h2>
<p>{{$listing['description']}}</p>
@endforeach
@else
<p>No listings found</p>
@endunless
# MODELS https://youtu.be/MYyJ4PuL4pY?t=2202
# eloquent
manually create a model
$ touch app/Models/Listins.php
$ code app/Models/Listing.php
listings.php:
<?php
namespace App\Models;
class Listing
{
public static function all(){
return [
[
'id' => 1,
'title' => 'Listing One',
'description' => 'This is the one description'
],
[
'id' => 2,
'title' => 'Listing Two',
'description' => 'This is the two description'
]
];
}
}
web.php:
ADD:
use App\Models\Listing;
Route::get('/', function () {
return view('listings',[
'heading' => "Latest Listings",
'listings' => Listing::all()
]);
});
REFRESH BROWSER: http://localhost and you will get same results
LEFT OFF: https://youtu.be/MYyJ4PuL4pY?t=2378
create each $id page for each listings
web.php ADD:
// Single Listing
Route::get('/listings/{id}', function ($id) {
return view('listing',[
'listing' => Listing::find($id)
]);
});
ADD: Listings.php
public static function find($id){
$listings = self::all();
foreach ($listings as $listing ) {
if($listing['id']==$id){
return $listing;
}
}
}
CHANGE listings.blade.php:
FROM:
<h2>{{$listing['title']}}</h2>
TO:
<h2><a href="/listings/{{$listing['id']}}">{{$listing['title']}}</a></h2>
CREATE new file: listing.blade.php and ADD this code:
<h2>{{$listing['title']}}</h2>
<p>{{$listing['description']}}</p>
REFRESH BROWSER: http://localhost
CLICK ON EACH LINK:
MYSQL DATABASE:
left off: https://youtu.be/MYyJ4PuL4pY?t=2711
Laravel sail: login as root or create an root user$ sail root-shell
# STOP sail to make db configuration changes:$ sail down
DB Configurations at: /config/database.php
SET THE DEFAULT DATABASE:
1. 'default' => env('DB_CONNECTION', 'mysql'),
2. go to .env and set the variables:
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=[CHANGE THIS TO sqlite if needed]
DB_USERNAME=root
DB_PASSWORD=
EXAMPLE, to change to sqlite:
a. Change to: 'default' => env('DB_CONNECTION', 'sqlite'),
b. create a file in /database/database.sqlite
Add phpmyadmin
open docker-compose.yml file and add the following code after mailhog to install phpmyadmin in the docker container using port 8081 for the local and remote (ie Heroku) port$ code ./docker-compose.yml
phpmyadmin:
image: phpmyadmin/phpmyadmin
restart: always
depends_on:
- mysql
ports:
- "8081:80"
environment:
PMA_HOST: mysql
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
networks:
- sail
# MORE INFO ABOUT PHPMYADMIN INTO DOCKER WITH LARAVEL:
https://www.webune.com/forums/api7.html
#REBUILD laravel in docker because we made changes to .env file:$ sail down -v
# rebuild option 1, FASTER$ sail build
# option 2 - THIS WILL TAKE LONGER AND DOWNLOADS THE FILES AGAIN$ sail build --no-cache
$ sail up -d
PHPMYADIN:
Open your browswer to: http://localhost:8081/index.php
user: sail
password: password
http://localhost/listings/2
https://youtu.be/MYyJ4PuL4pY?t=2777
# ACCESS THE MYSQL DATABASE IN THE DOCKER CONTAINER:
https://gist.github.com/jjsquady/e12ce89c9029d520ce08f60a9ff8f304
Run this command in sail project folder:$ docker-compose exec mysql bash
# mysql -u root -p
provide the default password: password
> SELECT User, Host FROM mysql.user;
# CREATE A NEW USER:
> CREATE USER 'edwin'@'localhost' IDENTIFIED BY 'password';
> GRANT ALL PRIVILEGES ON * . * TO 'edwin'@'localhost';
> FLUSH PRIVILEGES;
# validate newly created user:
> SELECT User, Host FROM mysql.user;
> exit
# login to mysql with new user:$ mysql -u edwin -p
# create a new database, you should already have this database created in mysql, Rund this command to show the databases:
> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| laragigs |
| mysql |
| performance_schema |
| sys |
| testing |
+--------------------+
If not, go ahead and create it now.
> CREATE DATABASE laragigs;
UPDATE .env file with your new user and credentials:
DB_DATABASE=laragigs
DB_USERNAME=edwin
DB_PASSWORD=password
# EXIT MYSQL
> exit
# exit
#LARAVEL MIGRATIONS
open /dtabase/migrations/2014_10_12_000000_create_users_table.php$ code /dtabase/migrations/2014_10_12_000000_create_users_table.php
UP = will create users table
DOWN = drop users tables
### MIGRATIONS
Create the database migration model in the host, not the docker container, so be sure to have PHP and artisan already installed in the host machine.
for this example, I am using a windows 10 PC with virtuabox and Ubuntu with docker.
Machine Name: Docker-ubuntu-100G - USE THIS ONE$ sail artisan make:migration create_listings_table
############################## ERROR:
Composer detected issues in your platform:
Your Composer dependencies require a PHP version ">= 8.1.0". You are running 7.4.3.
PHP Fatal error: Composer detected issues in your platform: Your Composer dependencies require a PHP version ">= 8.1.0". You are running 7.4.3. in /home/developer/Desktop/local-laravel/tutorial/laragigs/laragigs/vendor/composer/platform_check.php on line 24
####################### SOLUTION: UPGRADE PHP 7 to 8 in UBUNTU LINUX - as of 12/15/2022, Laravel 9 runs on PHP 8$ php -v
PHP 7.4.3 (cli) (built: Jun 13 2022 13:43:30) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies with Zend OPcache v7.4.3, Copyright (c), by Zend Technologies
NOTE: If you are running PHP 7.x, you can continue with this guide to upgrade to PHP 8.
FOLLOW THIS GOOD TUTORIAL: https://www.cloudbooklet.com/how-to-upgrade-php-version-to-php-8-0-on-ubuntu/$ sudo apt install software-properties-common
ERROR: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem.$ sudo dpkg --configure -a
$ sudo apt install software-properties-common
$ sudo add-apt-repository ppa:ondrej/php
$ sudo apt update
# THE MOST STABLE VERSION CURRENTLY$ sudo apt install php8.2
# INSTALL EXTENSIONS
sudo apt install php8.0-common php8.0-mysql php8.0-xml php8.0-xmlrpc php8.0-curl php8.0-gd php8.0-imagick php8.0-cli php8.0-dev php8.0-imap php8.0-mbstring php8.0-opcache php8.0-soap php8.0-zip php8.0-intl -y$ php -v
PHP 8.2.0 (cli) (built: Dec 10 2022 10:52:42) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.0, Copyright (c) Zend Technologies
with Zend OPcache v8.2.0, Copyright (c), by Zend Technologies
####################### END
lets try again:$ sail artisan make:migration create_listings_table
ANOTHER ERROR:
Class "DOMDocument" not found
at vendor/nunomaduro/termwind/src/HtmlRenderer.php:32
28â–• * Parses the given html.
29â–• */
30â–• public function parse(string $html): Components\Element
31â–• {
➜ 32▕ $dom = new DOMDocument();
33â–•
34â–• if (strip_tags($html) === $html) {
35â–• return Termwind::span($html);
36â–• }
+21 vendor frames
22 artisan:35
Illuminate\Foundation\Console\Kernel::handle()
SOLUTION #1:
SOURCE: https://stackoverflow.com/a/14395414$ sudo apt-get install php-dom
ERROR:
Reading package lists... Done
Building dependency tree
Reading state information... Done
Package php-dom is a virtual package provided by:
php8.2-xml 8.2.0-3+ubuntu20.04.1+deb.sury.org+1
php8.1-xml 8.1.13-1+ubuntu20.04.1+deb.sury.org+1
php8.0-xml 1:8.0.26-1+ubuntu20.04.1+deb.sury.org+1
php7.4-xml 1:7.4.33-1+ubuntu20.04.1+deb.sury.org+1
php7.3-xml 7.3.33-8+ubuntu20.04.1+deb.sury.org+1
php7.2-xml 7.2.34-36+ubuntu20.04.1+deb.sury.org+1
php7.1-xml 7.1.33-50+ubuntu20.04.1+deb.sury.org+2
php7.0-xml 7.0.33-63+ubuntu20.04.1+deb.sury.org+2
php5.6-xml 5.6.40-63+ubuntu20.04.1+deb.sury.org+2
You should explicitly select one to install.
E: Package 'php-dom' has no installation candidate
SOLUTION #2 -$ sudo apt-get install php8.2-xml
Try again:$ sail artisan make:migration create_listings_table
SUCCESS!!! FINALLY!!!!!
INFO Migration [2022_12_17_050042_create_listings_table] created successfully.$ code database/migrations/2022_12_17_050042_create_listings_table.php
https://youtu.be/MYyJ4PuL4pY?t=3053
Add the following after id:
Schema::create('listings', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('tags');
$table->string('company');
$table->string('location');
$table->string('email');
$table->longText('description');
$table->string('website');
$table->timestamps();
});
RUN THE NEWLY CREATED MIGRATION IN THE DOCKER CONTAINER WITH SAIL$ sail artisan migrate
ERROR: SQLSTATE[HY000] [1045] Access denied for user 'edwin'@'172.18.0.7' (using password: YES) (SQL: select * from information_schema.tables where table_schema = laragigs and table_name = migrations and table_type = 'BASE TABLE')
SOLUTION: restart sail because we need to update the user MYSQL password from the .env file$ sail down
$ sail build
$ sail up -d
LETS TRY AGAIN:$ sail artisan migrate
GOT ERROR AGAIN :
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=laragigs
DB_USERNAME=sail
DB_PASSWORD=password
SOLUTION:$ sail down
& make sure you have these in .env file:
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=laragigs
DB_USERNAME=sail
DB_PASSWORD=password
# THIS TIME IT WORKED!!$ sail up -d
$ sail artisan migrate
INFO Preparing database.
Creating migration table ............................................................................................ 83ms DONE
INFO Running migrations.
2014_10_12_000000_create_users_table ............................................................................... 330ms DONE
2014_10_12_100000_create_password_resets_table ...................................................................... 69ms DONE
2019_08_19_000000_create_failed_jobs_table ......................................................................... 130ms DONE
2019_12_14_000001_create_personal_access_tokens_table ............................................................... 84ms DONE
2022_12_17_050042_create_listings_table ............................................................................. 28ms DONE
# OPEN PHP MYADMIN TO CHECK THE NEW TABLE WAS CREATED:
http://localhost:8081/tbl_structure.php?db=laragigs&table=listings
OR USE MYSQL COMMANDS:$ docker-compose exec mysql bash
# mysql -u sail -p
# create a new database, you should already have this database created in mysql, Rund this command to show the databases:
> use laragigs;
> SHOW TABLES;
+------------------------+
| Tables_in_laragigs |
+------------------------+
| failed_jobs |
| listings |
| migrations |
| password_resets |
| personal_access_tokens |
| users |
+------------------------+
6 rows in set (0.00 sec)
>exit
# exit
# SEEDINGS: OPEN /database/seeders/DatabaseSeeder.php$ code database/seeders/DatabaseSeeder.php
LOOK AT DatabaseSeeder.php YOU CAN SEE A LINE:
THIS LINE CREATE 10 DUMMY USERS FROM THE FILE: /database/factories/UserFactory.php
UNCOMMENT:
// \App\Models\User::factory(10)->create();$ sail artisan db:seed
CHECK PHPMYADMIN YOU WILL SEE 10 NEW FAKE USERS CREATED
another option to phpmyadmin is dbeaver or mysql workbench
you got undo the 10 fake users simply by commenting the users factory and run the migrate command:
// \App\Models\User::factory(10)->create();$ sail artisan migrate:refresh
ucomment: // \App\Models\User::factory(10)->create();
NOTE: you can refresh and seed:$ sail artisan migrate:refresh --seed
CHECK the users table and all 10 fake users should be gone :)
LETS SEED SOME LISTSINGS
RENAME/DELETE THE Listing.php MODEL WE CREATED$ mv app/Models/Listing.php app/Models/ListingV1.php
in the host machine to create a Listing.php model in app/Models/Listing.php$ sail artisan make:model Listing
$ code app/Models/Listing.php
https://youtu.be/MYyJ4PuL4pY?t=3544
try http://localhost/ (you wont get errrors)
Why no errors: because, if you look in web.php the all() and find() are alonquent methods.
// ADD HARD CODED SEEDERS DATA
open DatabaseSeeder.php and add the following after \App\Models\User::factory(10)->create();
Listing::create(
[
'title' => 'Laravel Senior Developer',
'tags' => 'laravel, javascript',
'company' => 'Acme Corp',
'location' => 'Boston, MA',
'email' => '[email protected]',
'website' => 'https://www.acme.com',
'description' => 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Ipsam minima et illo reprehenderit quas possimus voluptas repudiandae cum expedita, eveniet aliquid, quam illum quaerat consequatur! Expedita ab consectetur tenetur delensiti?'
]
);
Listing::create(
[
'title' => 'Full-Stack Engineer',
'tags' => 'laravel, backend ,api',
'company' => 'Stark Industries',
'location' => 'New York, NY',
'email' => '[email protected]',
'website' => 'https://www.starkindustries.com',
'description' => 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Ipsam minima et illo reprehenderit quas possimus voluptas repudiandae cum expedita, eveniet aliquid, quam illum quaerat consequatur! Expedita ab consectetur tenetur delensiti?'
]
);
generate the seeder:$ sail artisan migrate:refresh --seed
CHECK PHPMYADMIN FOR THE NEW LISTSINGS:
http://localhost:8081/sql.php?db=laragigs&table=listings&pos=0
CHECK THE WEBPAGE AND YOU WILL SEE THE TWO NEW LISTINGS:
http://localhost/
http://localhost/listings/1
NOW, LETS CREATE SOME FAKE LISTINGS WITH FACTORY;$ sail artisan make:factory ListingFactory
$ code database/factories/ListingFactory.php
change TO:
public function definition()
{
return [
'title' => $this->faker->sentence(),
'tags' => 'laravel, api, backend',
'company' => $this->faker->company(),
'email' => $this->faker->companyEmail(),
'website' => $this->faker->url(),
'location' => $this->faker->city(),
'description' => $this->faker->paragraph(5),
];
}
$ code database/seeders/DatabaseSeeder.php
COMMENT the two Listing::create(
ADD after \App\Models\User::factory(10)->create();
Listing::factory(6)->create();
NOW YOU ARE READY TO MIGRATE$ sail artisan migrate:refresh --seed
CHECK THE WEBPAGE AND YOU WILL SEE THE TWO NEW LISTINGS:
http://localhost/
http://localhost/listings/1
SAVE TO GIT
git init
code .gitignore
git add .
git commit -m "WORKS: Basic with MyQSL Output to HTML finished at: https://youtu.be/MYyJ4PuL4pY?t=4045"
COMMIT: 4fd8c16
L A Y O U T S
https://youtu.be/MYyJ4PuL4pY?t=4045
views> layout.blade.php$ touch resources/views/layout.blade.php
$ code resources/views/layout.blade.php
add HTML 5 template
https://youtu.be/MYyJ4PuL4pY?t=4354$ mkdir public/images
// PLACE THE FOLLOWING IMAGES FROM THE TEMPLATE IN THIS FOLDER:
https://github.com/bradtraversy/laragigs/tree/main/_laragigs_theme/images
laravel-logo.png
no-image.png
logo.png
wget https://raw.githubusercontent.com/bradtraversy/laragigs/main/_laragigs_theme/images/logo.png -P ./public/images/
wget https://raw.githubusercontent.com/bradtraversy/laragigs/main/_laragigs_theme/images/no-image.png -P ./public/images/
wget https://raw.githubusercontent.com/bradtraversy/laragigs/main/_laragigs_theme/images/laravel-logo.png -P ./public/images/
with layout, in the blade template, you can two ways to enacapsulation:
1. {{$listing['title']}}
2. {{$listing->title}} // Using eloquent collection
images asset helper for public images:
FROM: src="path/imag.jpg"
TO: src="{{asset('path/image.jpg')}}"
PARTIALS: https://youtu.be/MYyJ4PuL4pY?t=4778$ mkdir resources/views/partials
$ touch resources/views/partials/_hero.blade.php
$ code resources/views/partials/_hero.blade.php
$ touch resources/views/partials/_search.blade.php
$ code resources/views/partials/_search.blade.php
// TO INCLUDE ABOVE PARTIALS
@include('partials._hero')
@include('partials._search')
ROUTE MODEL BINDING:
https://youtu.be/MYyJ4PuL4pY?t=5162
EXAMPLE: if you go to url: http://localhost/listings/NotExists - YOU GET AN ERROR:
SOLUTION: SHOW A 404 PAGE
OPEN web.php
###########################################
WITHOUT ROUTE MODEL BINDING:
###########################################
CHANGE FROM:
Route::get('/listings/{id}', function ($id) {
return view('listing',[
'listing' => Listing::find($id)
]);
});
CHANGE TO:
Route::get('/listings/{id}', function ($id) {
$listing = Listing::find($id);
if ($listing) {
return view('listing', [
'listing' => $listing
]);
} else {
abort('404');
}
});
NOW WHEN YOU GOTO http://localhost/listings/NotExists, YOU WILL GET A 404 ERROR
###########################################
WITH ROUTE MODEL BINDING:
###########################################
Route::get('/listings/{listing}', function (Listing $listing) {
return view('listing', [
'listing' => $listing
]);
});
NOW WHEN YOU GOTO http://localhost/listings/NotExists, YOU WILL GET A 404 ERROR
git commit -am "WORKS: Has styling using LAYOUTS: NEXT WILL USE COMPONENTS: https://youtu.be/MYyJ4PuL4pY?t=5298"
af4c106
COMPONENTS WITH PROPS
https://youtu.be/MYyJ4PuL4pY?t=5298
# CREATE A COMPONENTS FOLDER:$ mkdir resources/views/components
$ touch resources/views/components/listing-card.blade.php
$ code resources/views/components/listing-card.blade.php
to consume the compent you will add in the blade template:
@foreach($listings as $listing)
<x-listing-card :listing="$listing"/>
@endforeach
https://youtu.be/MYyJ4PuL4pY?t=5447
# CREATE A CARD COMPONET TO WRAP CONTENT TO:$ touch resources/views/components/card.blade.php
$ code resources/views/components/card.blade.php
{{$slot}}
<x-card> </x-card>
https://youtu.be/MYyJ4PuL4pY?t=5662
PASS ATTRIBUTTONES TO SLOTS
CHANGE FROM:
<div class="bg-gray-50 border border-gray-200 rounded p-6">
{{$slot}}
</div>
TO:
<div {{$attributes->merge(['class'=>'bg-gray-50 border border-gray-200 rounded p-6'])}} >
{{$slot}}
</div>
USAGE: <x-card class="p-14">
THIS WILL PASS A CLASS OF 9-14 TO THIS DIV
git commit -am "WORKS: USING components and props: NEXT WILL USE CONTROLLERS: https://youtu.be/MYyJ4PuL4pY?t=5720"
master e341ed6]
HOW TO ADD A NEW COMPONENT IN LARAVEL: EXAMPLEl TAGS:
1. CREATE A NEW FILE CALLED: listing-tags.blade.php$ touch resources/views/components/listing-tags.blade.php
$ code resources/views/components/listing-tags.blade.php
2. ADD THE DESIRED PROPS AND CODE TO listing-tags.blade.php
@props(['tagsCvs']) // receiving an array from the props, This is a value from the database
HTML.....
if you have an array, you can use a foreach loop:
@foreach ($tags as $tag)
@endforeach
3. Use the newly created component in a blade template. Example: listing-card.blade.php
<x-listing-tags :tagsCsv="$listing->tags" />
NOTE: "listing-tags" refers to file: resources/views/components/listing-tags.blade.php
PASSING PROP tagsCsv is the name of the variabl listing-tags.blade.php can use and its value.
DONE:
CONTROLLERS: https://youtu.be/MYyJ4PuL4pY?t=6033
CREATE A CONTROLLER:$ sail artisan make:controller ListingController
RESULTS: a controller will be created in: app/Http/Controllers/ListingController.php
OPEN NEW CONTROLLER: https://youtu.be/MYyJ4PuL4pY?t=6107$ code app/Http/Controllers/ListingController.php
1. ListingController.php - create a method for each get
// show all listings
public function index() {
}
public function show() {
}
2. web.php cut the following code:
Route::get('/', function () { // DON"T CUT THIS LINE
return view('listings', [
'listings' => Listing::all() // getting data by using the App\Models\Listing; and the all() moethod
]);
});// DON"T CUT THIS LINE
3. ListingController.php index method should look like this:
// IMPORT CLASSES:
use App\Models\Listing;
use Illuminate\Http\Request;
use App\Http\Controllers\ListingController;
// UPDATE THE INDEX AND SHOW METHODS
class ListingController extends Controller {
// show all listings
public function index() {
return view('listings', [
'listings' => Listing::all() // getting data by using the App\Models\Listing; and the all() moethod
]);
}
// show single listing
public function show(Listing $listing) {
return view('listing', [
'listing' => $listing
]);
}
}
4. web.php remove the functions and add the contorllers
CHANGE FROM:
Route::get('/', function () {
});
Route::get('/listings/{listing}', function (Listing $listing) {
});
CHANGE TO:
Route::get('/', [ListingController::class, 'index']);
Route::get('/listings/{listing}', [ListingController::class, 'show']);
DID NOT WORK:
ERROR: Target class [ListingController] does not exist.
SOLUTION: NEEDED TO ADD use App\Http\Controllers\ListingController; in web.php
git commit -am "WORKS: Added 'index' and 'show' CONTROLLERS. finished at: https://youtu.be/MYyJ4PuL4pY?t=6238"
COMMIT: 0422b8c
###########################################################################################
// CONTROLLERS NAMING CONVETIONS:
// 7 Common Resource Routes:
// index - Show all listings
// show - SHOW single listing
// create - Show form to create new listing (POST)
// edit - show form to edit listing
// update - update listing (POST)
// destroy - Delete Listing
TO MAKE THIS WORK IN OUR APPLICATION, WE WILL NEED TO CREATE A NEW FOLDER IN VIEWS: views/listings and move the two files inside:
mkdir resources/views/listings
mv resources/views/listing.blade.php resources/views/listings/show.blade.php
mv resources/views/listings.blade.php resources/views/listings/index.blade.php
developer@developer-Docker:~/Desktop/local-laravel/tutorial/laragigs/laragigs
$ ls resources/views/listings
index.blade.php show.blade.php
ListingController.php
CHANGE FROM:
public function index() {
return view('listings', [
'listings' => Listing::all() // getting data by using the App\Models\Listing; and the all() moethod
]);
}
// show single listing
public function show(Listing $listing) {
return view('listing', [
'listing' => $listing
]);
}
CHANGE TO:
// show all listings
public function index() {
return view('listings.index', [
'listings' => Listing::all() // getting data by using the App\Models\Listing; and the all() moethod
]);
}
// show single listing
public function show(Listing $listing) {
return view('listings.show', [
'listing' => $listing
]);
}
REFRESH BROWSER: http://localhost/listings/1
[OK]
###########################################################################################
LAYOUT OPTION:
https://youtu.be/MYyJ4PuL4pY?t=6392
LAYOUT option 1:
1. create a file in resources/views/layout.blade.php
2. in add @yield('content') where the dynamic content will go from resources/views/listings/index.blade.php
3. in index.blade.php add @extends('layout') at the top of the file
4. in index.blade.php add wrap the content you wan to render for the layout with:
@section('content')
@endsection
LAYOUT option 2 (as a component)
1. mv resources/views/layout.blade.php resources/views/components/layout.blade.php
2. in layout.blade.php CHANGE:
FROM: @yield('content')
TO: {{$slot}}
3. in index.blade.php, REMOVE:
@extends('layout')
@section('content')
.... content
@endsection
REPLACE WITH:
<x-layout>
.... content
</x-layout>
git commit -am "WORKS: change LAYOUT TO COMPONENT TYPE. finished at: https://youtu.be/MYyJ4PuL4pY?t=6507"
COMMIT: ce4df60
###########################################################################################
F I L T E R I N G https://youtu.be/MYyJ4PuL4pY?t=6545
GET URL PARAMS: http://localhost/?tag=laravel
open web.php
CHANGE: FROM:
public function index() {
return view('listings.index', [
'listings' => Listing::all()
]);
}
CHANGE TO:
public function index(Request $request) {
dd($request->query);
return view('listings.index', [
'listings' => Listing::all() // getting data by using the App\Models\Listing; and the all() moethod
]);
}
OPTION 2 CHANGE TO:
public function index() {
dd(request('tag')); // OUTPUTS 'laravel'
//or
// dd(request()->tag); // OUTPUTS 'laravel' https://youtu.be/MYyJ4PuL4pY?t=6693
return view('listings.index', [
'listings' => Listing::all() // getting data by using the App\Models\Listing; and the all() moethod
]);
}
SCOPE FILTER: https://youtu.be/MYyJ4PuL4pY?t=6710
code app/Models/Listing.php
ADD after HasFactory
public function scopeFilter($query, array $filters) {
//dd($filters['tag']); //OUTPUT 'laravel' from http://localhost/?tag=laravel
// check if tag is FOUND
if($filters['tag'] ?? false){
// database query
$query->where('tags', 'like', '%' . request('tag') . '%');
}
}
}
in file app/Http/controllers/ListingController.php
CHANGE FROM: 'listings' => Listing::all()
// sort by the latest and filter whatever the tag PARAM value is
TO: 'listings' => Listing::latest()->filter(request(['tag']))->get()
FILTER BY SEARCH
URL: http://localhost/?search=Incidunt
in file app/Http/controllers/ListingController.php
CHANGE: FROM:
'listings' => Listing::latest()->filter(request(['tag']))->get()
TO: 'listings' => Listing::latest()->filter(request(['tag','search']))->get()
in file app/Models/Listing.php
ADD in scopeFilter()
if($filters['search'] ?? false){
// database query
$query->where('title', 'like', '%' . request('search') . '%')
->orWhere('description', 'like', '%' . request('search') . '%')
->orWhere('tags', 'like', '%' . request('search') . '%');
}
Try the search bar, it should work:
Example: http://localhost/?search=Architecto
1 result
git commit -am "WORKS: Added filtering for tags and search bar keyword. finished at: https://youtu.be/MYyJ4PuL4pY?t=7253"
COMMIT: 995ec35
###########################################################################################
https://youtu.be/MYyJ4PuL4pY?t=7289
CLOCK WORK
https://chrome.google.com/webstore/detail/clockwork/dmggabnehkmmfmdffgajcflpdjlnoemp?hl=en
composer require itsgoingd/clockwork
###########################################################################################
POST JOBS using the POST FORM
https://youtu.be/MYyJ4PuL4pY?t=7451
web.php add new route with create
ListingController.php add new create() method
create view create.blade.php and <x-layout>
ADD A NEW PAGE: Post new Listing
1. SET VARIABLES:
#########################
ADD STORE TO SAVE THE FORM DATA:
NEWPAGENAME='store'
PAGETYPE='post'
COMPONENTNAME='listings'
2. COPY AND PASTE COMMANDS TO TERMINAL:
######################################
echo "Route::$PAGETYPE('/$COMPONENTNAME/$NEWPAGENAME', [ListingController::class, '$NEWPAGENAME']);" >> routes/web.php
CONTROLERCODE="public function $NEWPAGENAME() {\n\t\t\treturn view('$COMPONENTNAME.$NEWPAGENAME');\n\t\t}"
sed -i "\/\/\list/a $CONTROLERCODE" app/Http/Controllers/ListingController.php
touch resources/views/listings/$NEWPAGENAME.blade.php
VIEWCODE=$'<x-layout>\n\t... content\n</x-layout>'
echo "$VIEWCODE" > resources/views/listings/$NEWPAGENAME.blade.php
code resources/views/listings/$NEWPAGENAME.blade.php
xdg-open http://localhost/$COMPONENTNAME/$NEWPAGENAME
echo done
SAME COMMANDS ABOVE BUT MORE DETAILS AND EXPLANATION
###################################
workflow to add a new functionality example: 'create'
###################################$ NEWPAGENAME='create'
$ PAGETYPE='get'
$ COMPONENTNAME='listings'
$ echo NEWPAGENAME
###### 1. ADD ROUTE ######
1. Route - web.php
// APEND A NEW ROUTE
$ echo "Route::$PAGETYPE('/$COMPONENTNAME/$NEWPAGENAME', [ListingController::class, '$NEWPAGENAME']);" >> routes/web.php
###### 2. ADD CONTROLLER METHOD ######
2. In the Class Controller, add new method - App\Http\Controllers\ListingController.php
// ListingController.php - create methods for FORM USING THISE COMMANDS:
$ CONTROLERCODE="public function $NEWPAGENAME() {\n\t\t\treturn view('$COMPONENTNAME.$NEWPAGENAME');\n\t\t}"
$ sed -i "\/\/\list/a $CONTROLERCODE" app/Http/Controllers/ListingController.php
THE ABOVE TWO COMMAND WILL THIS METHOD TO ListingController.php
public function create() {
return view('listings.create');
}
###### 3. ADD VIEW ######
3. View, createa a new file :
$ touch resources/views/listings/$NEWPAGENAME.blade.php
$ VIEWCODE=$'<x-layout>\n\t... content\n</x-layout>'
$ echo "$VIEWCODE" > resources/views/listings/$NEWPAGENAME.blade.php
$ code resources/views/listings/$NEWPAGENAME.blade.php
the above commands will add these HTML to Wrap your code with the Layout:
<x-layout>
... content
</x-layout>
###### 4. CONFIRM NEW PAGE ######
4. View the new component: http://localhost/listings/create
IMPORTANT: if you get a '404 Not Found' - look at ListingController.php to make sure the routes are in order.
the system will dow down to each down the list and will render the first match whatever the url is.
EXAMPLE: URL: /listings/1 will match 'listings/create' and 'listings/1'
CHECK IT OUT: https://youtu.be/MYyJ4PuL4pY?t=7667
CREATE FORM TIPS:
* every input must have a name="" to setup the input variables
* must have action (example: action="/listings")
* SECURITY: for method="POST", in laravel you MUST use the @CSRF directive to prevent cross site scripting attacks - https://youtu.be/MYyJ4PuL4pY?t=7884
# FORM VALIDATION:
ListingController.php
// VALIDATION: https://laravel.com/docs/9.x/validation
$formFields = $request->validate([
'title'=>'required'
]);
ERROR:
I TRIED TO IMPLEMENT JQUERY V1 OR V3 FOR THE CREATE FORM, USING A BUTTON WHEN ONCLICK TO RUN THIS CODE BUT THE FIELD WOULD NOT EMPTY ONLY THE CSSS?
$('#description').css('background-color','yellow').val('');
BUT WHEN I DO IN THE CONSOLE IT WORKS??
PHP SPREAD OPERATOR:
$arr1 = [1,2,3];
$arr2 = [4,5,6];
$arr3 = [1,2,3 ...$arr2];
ouput: [1,2,3,4,5,6]
ERROR after submit form: https://youtu.be/MYyJ4PuL4pY?t=8609
Illuminate \ Database \ Eloquent \ MassAssignmentException
Add [company] to fillable property to allow mass assignment on [App\Models\Listing].
SOLUTION:
#1. Add a $fillable array variable in app/Models/Listing.php just below use HasFactory;
#2. Another solution: open app/Providers/AppServiceProvider.php
ADD Model::unguard(); in boot() function
IMPORT use Illuminate\Database\Eloquent\Model;
COMMENT OUT the array from option #1 above
TRY IT AGAIN AND IT SHOULD WORK:
git commit -am "WORKS: Added POST submit form and enter into database. finished at: https://youtu.be/MYyJ4PuL4pY?t=8840"
COMMIT: 6eab779
###########################################################################################
FLASH MESSAGE AFTER FORM SUBMITTED - this is a temporary message when the form has been submitted successcully
https://youtu.be/MYyJ4PuL4pY?t=8840"
1. firs way with session
open ListingController.php
in the store method:
CHANGE FROM: return redirect('/');
CHANGE TO: return redirect('/')->with('message','Listing created successfuly!');
2. create a component callmed message:
touch resources/views/components/flash-message.blade.php
code resources/views/components/flash-message.blade.php
3. add Alpine.js <script src="//unpkg.com/alpinejs" defer></script>
4. Addthe following to the tag for the message to stay showing for 3 seconds long
<div
x-data="{show: true}"
x-init="setTimeout(() => show = false, 3000)"
x-show="show"
git commit -am "WORKS: added a flash message after form submit with alpine.js : https://youtu.be/MYyJ4PuL4pY?t=9392"
d4d4b7e
###########################################################################################
KEEP OLD DATE IN FORM. https://youtu.be/MYyJ4PuL4pY?t=9392
by default, if you submit the laravel form and there is an error, the fields will become blank. one way to this is to add the value="" attribute as the following:
<input value="{{old('NAME_OF_FIELD')}}"
git commit -am "WORKS: when form has errors, keep the old submitted data in the form : https://youtu.be/MYyJ4PuL4pY?t=9529"
5d31278
###########################################################################################
PAGINATION
1. open ListingController.php
2. in the index controller,
CHANGE FROM: get()
CHANGE TO: paginate()
3. ADD
// SHOW THE OBJECT PROPERTY AVAILABLE, SUCH AS HOW MANY PAGES ARE AVAILABLE
//simplePaginate() is also available
dd(Listing::latest()->filter(request(['tag', 'search']))->paginate(2));
OUTPUT:
Illuminate\Pagination\LengthAwarePaginator {#1238 â–¼ // app/Http/Controllers/ListingController.php:16
#items: Illuminate\Database\Eloquent\Collection {#618 â–¶}
#perPage: 2
#currentPage: 1
#path: "http://localhost"
#query: []
#fragment: null
#pageName: "page"
+onEachSide: 3
#options: array:2 [â–¶]
#total: 12
#lastPage: 6
}
4. ADD THE PAGES NUMBER NAVIGATION
in index.blade.php add the following for the NAVIGATION pagination bar:
<div class="mt-6 p-4">
{{$listings->links()}}
</div>
5. To style the NAVIGATION PAGINATION bar, you will need to publish the project:$ sail artisan vendor:publish
ERROR: Call to undefined function Termwind\ValueObjects\mb_strimwidth()
SOLUTION: sudo apt-get install php-mbstring
SOURCE: https://laracasts.com/discuss/channels/laravel/call-to-undefined-function-mb-strimwidth
SELECT 4 : Provider: Illuminate\Pagination\PaginationServiceProvider
6. a new directory is created in resources/views/vendor you can look at the files in this directory to customer the tailwind classes
git commit -am "WORKS: Added Paginations Completed to: https://youtu.be/MYyJ4PuL4pY?t=9920"
84d5cfe
###########################################################################################
UPLOAD FILES IN FORM: https://youtu.be/MYyJ4PuL4pY?t=9922
1. open create.blade.php$ code resources/views/listings/create.blade.php
create.blade.php should look like this: https://raw.githubusercontent.com/bradtraversy/laragigs/main/resources/views/listings/create.blade.php
2. add enctype to <form method="POST" action="/listings/store" enctype="multipart/form-data">
3. The form is submitted to ListingController.php, so open file$ code app/Http/Controllers/ListingController.php
go to the store method and add the following to test out the REQUEST['file'] properties
dd($request->file('logo'));
4. submit the form and look for the following properties:
-originalName: "logo.png"
-mimeType: "image/png"
-error: 0
#hashName: null
5. by default, the uploaded files go to laragigs/storage/app/
6. Open configs/filesystem.php$ code config/filesystems.php
look for the line for the default disk, example: local
'default' => env('FILESYSTEM_DISK', 'local'),
Scroll down and look for the disk => [] array for 'local' you will see the 'root' => storage_path('app'),
to change the uploads to the public folder, look for the 'public' property or AMAZON
CHANGE FROM: 'default' => env('FILESYSTEM_DISK', 'local')
CHANGE TO: 'default' => env('FILESYSTEM_DISK', 'public')
5. Add the new logo field to the database migrations:
a. open 2022_12_17_050042_create_listings_table.php
$ code database/migrations/2022_12_17_050042_create_listings_table.php
b. ADD the following to the up() Schemma:
$table->string('logo')->nullable(); // nullable means i