Ok, so we have installed Laravel. Now let's start coding our CRUD (create/read/update/delete) application.
First, we will create our new application so go to a directory of choice and type:
laravel new market
Laravel will create a new directory with the name market and place all its framework files inside, ready to work. Now go to this directory with cd market and let start our web server on port 8000 with:
php artisan serve
Then open up the browser at: http://localhost:8000 to see the default laravel installation page.
Models
Now let's create our database and let laravel manage the tables inside by doing migrations and creating models around the database logic.
In order to create the database we will use our mysql client:
mysql -u root -p
(where username is root, here you can use the user which mysql is installed on your system)
Next, we will create our main database:
create database market
then exit the mysql client
and we will connect laravel to the database. For this open up the environment file: /market/.env and set up mysql user and password sections with your own.
Laravel uses ORM (
Object-relational mapping) to abstract database table operations, so it wraps models around the tables, making ordinary operations easier via php objects. Models reside in the directory: market/app/model.php.
Let's create our first model:
php artisan make:model -m Product
(here the command creates table products (in plural) and model Product, connected to it).
You can use phpmyadmin to see the newly created table.
Migrations
Next, we need to specify the fields we would like to have in our tables. By using migrations we can change the structure of our tables add/change/remove fields and their properties. Migrations are text files residing in: market/database/migrations
If you look inside a migration file there are usually two functions up()->when the table will be created and down() for when the table will be deleted.
Inside up() place:
$table->increments('id');
$table->string('title')->unique();
$table->string('description');
$table->integer('price');
$table->timestamps();
next to perform the actions described in the migration we will just refresh (redo) the performed migrations so type:
php artisan migrate:refresh
you can go ahead and check within phpmyadmin that the new table's structure is actually changed having more fields inside.
Controllers
In order to work with the data from the tables laravel uses controllers. Let's create one:
php artisan make:controller -m Product ProductController
with this command, we create ProductController file connected to our Product model. Controllers reside in app/Http/Controllers/ . We can see our file there, it is already prepared with the basic actions as functions() we would like to fill in.
Routes
One way for the user to trigger a controller action is via routes (routes/web.php). Routes connect an URL with a controller action or a view. So open up the file and replace the default: return view('welcome'); with: return 'Hello';
then refresh the browser and see the change.
Now, let's replace the file contents with:
Route::resource('products','ProductController');
this will create a so-called resource-route which will connect our ProductController to url: /products
In order to see how many rules this resource-route handles type: php artisan route:list
We see that whenever we access /products it invokes the index() method of ProductsController. From the table you can follow the rest of the urls and their representative actions.
Next, we modify the controller's index action and trigger a view from there:
$products="Hello from products"
return view('products.index',['products'=>$products]);
to decrypt :) this will invoke a view file from directory view/products called index.blade.php and pass $products as a parameter to it.
Now is time to create this directory market/resources/views/products.
As well as the index.blade.php inside, with the following content to display the products:
{{$products}}
( Using double curly braces in the view we could output parameters passed from the controller. )
Please test in the browser.
Next, create some fake products inside phpmyadmin and in order to see them just replace in our controller:
$products=Product::all();
(this is the ORM way of doing it)
Layouts
So far we have only displayed the products list, so let's extend the current view. First we will explore how to work with layouts. They allow us to include common HTML and CSS parts across multiple views, reducing potential code repetition.
In order to use layouts create app.blade.php into views/layouts folder and place all your main HTML including CSS links there. Inside put also:
yield('main'). This yield will become a placeholder where Laravel will include all information fetched from the .blade view files.
The following is our completed view index.blade.php file which uses our layouts.app layout and inside its 'main' section inserts:
@extends('layouts.app')
@section('main')
<a href="{{route('products.create')}}" class="btn">Add new product</a>
<br/>
@foreach($products as $product)
<div class="products">
<a href="{{route('products.show',$product)}}">{{ $product->title }} </a> - ${{ $product->price }} <br/>
<br />
<a href="{{route('products.edit',$product)}}" class="btn">Edit</a>
<form method="post" action={{route('products.destroy',$product)}} >
{{method_field('DELETE')}}
{{csrf_field()}}
<input class="inline btn" type="submit" value="Delete" />
</form>
<br /><br/>
</div>
@endforeach
@endsection
In short, we have added buttons for adding, editing and deleting products using a loop for each of our products. We are also using the internal Laravel function route() in order to construct user clickable urls, taken from the route list table discussed above. The route generation in some cases requires additional parameter like $product information in order for Laravel to know which product to work with. For security reasons, the delete button functionality uses a form. Inside you can see uniquely generated csrf() field to ensure that we could only send the form thus protecting it from malicious usage. Lastly in order to make the form to function Laravel requires to modify or model and add the fields allowed to be mass-modified. So in /app/Product.php add
protected $fillable=['title','description','price','image_url'];
So go ahead save, and let's move on.
Adding new products
please add to our ProductsController:
public function create()
{
return view('products.create');
}
which will show the create.blade.php:
@extends('layouts.app')
@section('main')
@if ($errors->any())
<ul>
@foreach ($errors->all() as $error)
<li>{{$error}}</li>
@endforeach
</ul>
@endif
<form action="{{ route('products.store') }}" method="post" >
{{csrf_field()}}
<label for="title">Product Name</label>
<input placeholder="product 1" type="text" name="title" id="title" />
<label for="description">Description</label>
<input placeholder="product description" type="text" name="description" id="description" />
<label for="price">Price</label>
<input placeholder="100" type="text" name="price" id="price" />
<button type="submit">Create</button>
@endsection
By far the code looks familiar, the first few lines just display if any errors occur while adding our product. We notice that when submitted, this form goes to products.store route, leading to our controller. So let's create the corresponding ProductController method:
public function store(Request $request)
{
$customMessages = [
'title.unique'=>'Please choose another product title'
];
$this->validate($request,
['title' => 'required|unique:products'],
$customMessages
);
Product::create($request->all());
return redirect('products');
}
Here we have included a custom message to be displayed when the 'title' of the product about to be entered already exists in the database ->yes Laravel do this for us automatically. If everything is ok, the product is created, using all the parameters sent from the $request and we display the product view.
Editing products
In the ProductController we would like to trigger the edit.blade.app view:
public function edit(Product $product)
{
return view('products.edit',['product'=>$product]);
}
wherein edit.blade.app:
@extends('layouts.app')
@section('main')
@if ($errors->any())
<ul>
@foreach ($errors->all() as $error)
<li>{{$error}}</li>
@endforeach
</ul>
@endif
<form action="{{ route('products.update',$product) }}" method="post" >
{{csrf_field()}}
{{method_field('patch')}}
<label for="title">Product Name</label>
<input placeholder="product 1" type="text" name="title" id="title" value="{{$product->title}}" />
<label for="description">Description</label>
<input placeholder="product description" type="text" name="description" id="description" value="{{$product->description}}" />
<label for="price">Price</label>
<input placeholder="100" type="text" name="price" id="price" value="{{$product->price}}"/>
<button type="submit">Update</button>
@endsection
The update form above is being pre-filled with information about the product we already have, using the {{$product->property}} notation. We have also included the 'patch' method, as described in the route table above in order for Laravel to trigger the ProductController update method:
public function update(Request $request, Product $product)
{
$customMessages = [
'title.unique'=>'Please choose another product title'
];
$this->validate($request,
['title' => 'required|unique:products'],
$customMessages
);
$product->update($request->all());
return redirect('products');
}
We see almost the same code as in the create method, just using the update() function.
Deleting products
For the delete button, we don't need a view, here is just its code in the controller:
public function destroy(Product $product)
{
$product->delete($product->id);
return redirect('products');
}
We believe that by now you can do the view method very easy!
That's it! Enjoy!