Youtube channel !

Be sure to visit my youtube channel
Showing posts with label laravel. Show all posts
Showing posts with label laravel. Show all posts

Thursday, April 21, 2022

Simple Laravel REST API


1) Create the user model in models/UserModel.php 

php artisan make:model User

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;

/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
];

/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];

/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}

 

2) 

create validation for the update requests:  php artisan make:request UserUpdateRequest

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UserUpdateRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}

/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name'=>'required',
'email'=>'required|email',
// 'password'=>''
];
}
}


 and for the post request:

php artisan make:request UserPostRequest

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UserPostRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}

/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name'=>'required',
'email'=>'required|email',
'password'=>'required'
];
}
}


 

 

create user controller based on the user model: php artisan make:controller UserController --model=User --resource

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Http\Requests\UserPostRequest;
use App\Http\Requests\UserUpdateRequest;
use App\Http\Resources\UserCollection;
use App\Http\Resources\UserResource;
use App\Models\User;
use Illuminate\Support\Facades\Hash;

class UserController extends Controller
{
public function index()
{
return new UserCollection(User::paginate(5));
}

public function store(UserPostRequest $request)
{
$userData = $request->validated();
$userData['password'] = Hash::make($userData['password']);
$userData['email_verified_at'] = now();

$user = User::forceCreate($userData);
return new UserResource($user);
}

public function show(User $user) //route model binding
{
return new UserResource($user);
}

public function update(User $user, UserUpdateRequest $request)
{
$user->update($request->validated());
}

public function destroy(User $user)
{
$user->delete();
return response()->noContent();
}
}



3) create resources/UserCollection:  php artisan make:resource UserCollection

to return user collection and user resource, when required by the user controller.

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class UserCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/

public function toArray($request)
{
return
[
'data'=>$this->collection,
'total_count'=> $this->total()
];
}
}

 

create UserResource: //expose which fields to be returned in the json response.

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
];
}
}

 

4) enable the requests to be performed, and add validation rules when posting and updating information, inside Requests/UserPostRequest.php

php artisan make:request UserPostRequest

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UserPostRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}

/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name'=>'required',
'email'=>'required|email',
'password'=>'required'
];
}
}

for updating info:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UserUpdateRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}

/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name'=>'required',
'email'=>'required|email',
];
}
}

 

6) add routes/api.php in order to redirect /users to the index() method of the UserController.
<?php

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

use App\Http\Resources\UserCollection;
use App\Models\User;
use App\Http\Controllers\UserController;

Route::apiResource('users', UserController::class);

Cheers!

Monday, February 22, 2021

Debug Laravel / PHP applications with XDebug in VSCODE

We will setup debugging using xdebug with PHP inside of visual studio code. 

Quick setup:

1) install php-xdebug:

sudo apt install php-xdebug

2) inside of php.ini at the end of the file set: 

[xdebug] 

xdebug.start_with_request = yes 

xdebug.mode = debug 

xdebug.discover_client_host = false 

3) install php debug extension in VSCODE and set the port of the vscode php debug extension to 9003.

Now you can press F5 and start debugging.

 

 

 

Alternatively you can install xdebug using pecl. 

The setup is valid for Ubuntu both on bare-metal as well as under Windows 10 with WSL.

Enjoy !

Monday, November 11, 2019

Laravel development environment under Ubuntu 19.10

This guide is on how to install the Laravel framework under Ubuntu and set up a local development environment. 

Reference: Practical Ubuntu Linux Server for beginners

First, we will install Apache & MariaDB:
sudo apt install apache2 mariadb-server mariadb-client
then we will setup default password for the MySQL installation:
sudo mysql_secure_installation
Next, we will log in inside MySQL with: sudo mysql -u root
to create our initial database:
create database laravel;
and create a user for the Laravel installation: laravel with password: password
CREATE USER 'laravel'@'%' IDENTIFIED BY 'password';
at the same time will and grant privileges to the user to all databases:
GRANT ALL PRIVILEGES ON *.* TO 'laravel'@'%' ;
Then we will restart the MariaDB server to activate the changes:
sudo systemctl restart mariadb.service
Now is time to install PHP support for Apache and extensions for Laravel with:
sudo apt install php libapache2-mod-php php-common php-mbstring php-xmlrpc php-soap php-gd php-xml php-mysql php-cli php-zip

optionally we can set limits inside php.ini
sudo nano /etc/php/7.3/apache2/php.ini
memory_limit = 256M
upload_max_filesize = 64M
cgi.fix_pathinfo=0


Next, we will install Curl for the composer to be able to run:
sudo apt install curl
Then to install composer we can use:
curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer


/*
only if we want to use the laravel command:
let's update the local path to be able to access composer vendor binaries and particularly being able to run laravel:
export PATH = "$HOME/.config/composer/vendor/bin:$PATH"
if you want the path change to be persistent just add the line into the .bashrc file.
*/

It is time to create our project:
cd /var/www/html/
sudo composer create-project laravel/laravel --prefer-dist 
In order for Laravel artisan, Apache and our user to be able to access, read and write to the framework will need to fix the ownership and the permissions of the installation:
we set www-data as owner and group inside the Laravel installation :

sudo chown www-data:www-data /var/www/html/laravel/ -R
Next, we will make sure that all the existing as well as the newly created files will have rwx permissions and will also belong to the www-data group:
sudo chmod +770 /var/www/html/laravel -R
sudo setfacl -d -m g:www-data:rwx /var/www/html/
All that is left is to add our current user to the www-data group:
sudo usermod -a -G www-data $USER
and will switch the current user context to the www-data group:
newgrp www-data

Let's set up the Apache web-server to serve Laravel:
disabling default Apache site configuration
sudo a2dissite 000-default.conf
enable nice URLs:
sudo a2enmod rewrite

create configuration for laravel:
sudo nano /etc/apache2/sites-available/laravel.conf
  
 ServerName laravel.local
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html/laravel/public
   
        AllowOverride All
   

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined


enable the laravel configuration site:
sudo a2ensite laravel.conf


Installing PHPMyAdmin
sudo apt install php-curl
sudo composer create-project phpmyadmin/phpmyadmin

create configuration for phpmyadmin:
sudo nano /etc/apache2/sites-available/phpmyadmin.conf
   
 ServerName phpmyadmin.local
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html/phpmyadmin
   
        AllowOverride All
   

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

enable the phpmyadmin configuration site:
sudo a2ensite laravel.conf

In order to activate changes we restart the Apache server:
systemctl restart apache2

Because both of the local domains will be accessible through the same IP 127.0.01 we will add them in the /etc/hosts file:
sudo nano /etc/hosts
127.0.0.1       laravel.local
127.0.0.1       phpmyadmin.local
(now we can browse those two host entries inside a browser)
http://laravel.local
http://phpmyadmin.local


Now let's fix some warnings. To run composer without the need of sudo, we will run:
sudo chown -R $USER ~/.config/composer/vendor/bin/ -R
this will give permissions of our user over the composer executable.

Database setup
open up .env and set our details taken from the mariadb setup:
DB_DATABASE=laravel
DB_USERNAME=laravel
DB_PASSWORD=password


Development helping utilities
We will help VSCode to recognize methods inside facades and models:

composer require --dev barryvdh/laravel-ide-helper
php artisan ide-helper:generate
php artisan ide-helper:meta
php artisan ide-helper:models --nowrite
-> in order to place the generated phpdoc to a separate file
in order when you have updates/changes inside the versions of the models/packages/facades your IDE to auto-regenerate the files, inside composer.json scripts place:
"post-update-cmd": [
        "Illuminate\\Foundation\\ComposerScripts::postUpdate",
        "@php artisan ide-helper:generate",
        "@php artisan ide-helper:meta",

        "@php artisan ide-helper:models --nowrite"
]


Navigation inside Visual Studio Code
inside /var/www/html/laravel we start the editor:
code .
Inside VSCode:
Press alt + c to toggle case sensitive highlighting and install the following extensions:
Laravel blade snippets, Laravel extra IntelliSense, Laravel goto view, PHP debug, PHP intelephense, PHP namespace resolver. (and optional: Local History)
Go to user settings" > "extensions" > "blade Configuration" use formatting
Notes on general navigation and debugging through code when developing:
With Ctrl+click we can navigate through locations such as controllers, classes, and blade templates. To return back to the previous location just press: Ctrl+Alt+-.
To search inside of all files inside the project we can use: CTRL+SHIFT+F
In order to list all available classes, methods and properties inside of a file just use:
CTRL+Shift+O
beforehand is needed from preferences to disable the integrated suggestions for php: "php.suggest.basic": false

We will install debugbar for in-browser debugging purposes:
sudo composer require barryvdh/laravel-debugbar --dev
Debugbar also very nicely displays the current ones used by our request while browsing. To debug inside the code, we can also use: dd('what we want to debug'); In case we have lots of variables just place them inside of an array:
$test[]=$var1;
$test[]=$var2;
and then dd($test); will output them all. Try also dd(__METHOD__); It will give you the invocation method location and name.
For adding/removing multiple lines comments toggle: Ctrl + /
in case you would like to know all the available routes, you can use: php artisan route:list

Let's go to the frontend part:
Let's install npm, here is how to get its latest version of:
curl https://www.npmjs.com/install.sh | sudo sh
Now follows the latest version of nodejs from nodesource:
from nodesource
curl -sL https://deb.nodesource.com/setup_13.x | sudo -E bash -
sudo apt-get install -y nodejs

We will require the user interface library and will place it inside as a development dependency:
composer require laravel/ui --dev
Now we add VUE as user interface framework (if you don't want to create the default authentication just omit --auth)
php artisan ui vue --auth
We will install the required laravel UI package dependencies using npm, and when we have them we will compile a development version of all the front-end JavaScript and CSS styles:
npm install && npm run dev
In case of problems during the packages' installation we will do:
npm cache clean --force
and then repeat the last build with npm install && npm run dev
(if you look at the contents of webpack.mix.js, you will see that they point from /resources/ to /public/ directory, so when running npm run dev, actually we grab and compile those resources and place the output inside /public/css and public/js directories)

After our DB connection is setup we can do: php artisan migrate to create our first migration. This is important because this migration will create tables for authentication. When the migration completes we can test the authentication, by creating a user and logging inside the laravel system.

Now we will discuss the simple Laravel flow. In order to protect certain route such as /home, we can use:
$this->middleware('auth');
You can see the function inside the constructor of this controller: public function __construct(){$this->middleware('auth');}
At the same time, how do we know when we type /home in our browser that exactly App/Http/Controllers/HomeController.php will be loaded?
well lets enter inside of /routes directory: web.php
let's focus on the line:
Route::get('/home', 'HomeController@index')->name('home');
which says: if we request /home the HomeController with method index will be loaded.
Then if we follow HomeController.php index.php we see:
public function index(){return view('home');}
return view('home') - simply means load up home.blade.view - this is where our HTML template resides. Go ahead make some changes inside and reload the /home URL to see them live:
Inside home.blade.php we can place:
@auth
You are logged in!
{{Auth::user()->name}}
@else
still not logged in.
@endauth
and inside welcome.blade.php:
@guest
Hi guest!
@endguest
Just save and see the change!

Congratulations!

Tuesday, October 22, 2019

Laravel inside Docker as a non root user

Laravel installation under Docker seems a painful experience but at the same time, it is a rewarding learning experience. The following are the steps for achieving the development environment for Laravel. For more information you can take a look at the Docker for web developers course, and also watch the following video for further details:


Let's assume you've installed Docker on Ubuntu or Windows 10 WSL2 with:
# sudo apt install docker
# sudo apt install docker-compose

Initially, we will get the source files of Laravel from its GIT repository. First, inside a newly created directory, we will use: git clone https://github.com/laravel/laravel.git .

Let's now run the Laravel project deployment locally:
sudo apt install composer && sudo composer install
(because we would like to develop our code locally so the changes to be reflected inside the docker container)

Then we will create our Dockerfile with the following content:
Be cautious when writing the yaml files: you will need to indent each element line: with space, incrementing the space for each sub-element

#we are copying the existing database migration files inside the docker container and are fetching and installing composer without user interaction and processing of scripts defined in composer.json
FROM composer:1.9 as vendor
COPY database/ database/
COPY composer.json composer.json
COPY composer.lock composer.lock
RUN composer install --no-scripts --ansi --no-interaction

# we are installing node, creating inside our container /app/ directory and copying the requirements as well as the js, css file resources there
# Then we install all the requirements and run the CSS and JS preprocessors

FROM node:12.12 as frontend
RUN mkdir -p /app/public
COPY package.json webpack.mix.js  /app/
COPY resources/ /app/resources/
WORKDIR /app
RUN npm install && npm run production

# get php+apache image and install pdo extension for the laravel database
FROM php:7.3.10-apache-stretch
RUN docker-php-ext-install  pdo_mysql

# create new user www which will be running inside the container
# it will have www-data as a secondary group and will sync with the same 1000 id set inside out .env file

ARG uid
RUN useradd  -o -u ${uid} -g www-data -m -s /bin/bash www

#we copy all the processed laravel files inside /var/www/html
COPY --chown=www-data:www-data . /var/www/html
COPY --chown=www-data:www-data --from=vendor /app/vendor/ /var/www/html/vendor/
COPY --chown=www-data:www-data --from=frontend /app/public/js/ /var/www/html/public/js/
COPY --chown=www-data:www-data --from=frontend /app/public/css/ /var/www/html/public/css/
COPY --chown=www-data:www-data --from=frontend /app/mix-manifest.json /var/www/html/mix-manifest.json

# allow the storage as well as logs to be read/writable by the web server(apache)
RUN chown -R www-data:www-data /var/www/html/storage

# setting the initial load directory for apache to be laravel's /public
ENV APACHE_DOCUMENT_ROOT /var/www/html/public
RUN sed -ri -e 's!/var/www/html!${APACHE_
DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf
RUN sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf

# changing 80 to port 8000 for our application inside the container, because as a regular user we cannot bind to system ports.
RUN sed -s -i -e "s/80/8000/" /etc/apache2/ports.conf /etc/apache2/sites-available/*.conf

RUN a2enmod rewrite

# run the container as www user
USER www

Here are the contents of the .env file which contains all the environment variables we would like to set and to be configurable outside of the container, while it has been build and run.

DB_CONNECTION=mysql
DB_HOST=mysql-db
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laravel
DB_PASSWORD=mysql
UID=1000

Keep in mind that we are creating a specific user inside of MySQL which is: laravel, as well as setting its UID=1000 in order to be having synchronized UIDs between our container user and our outside user.

Follows the docker-compose.yml file where we are using multi-stage container build.

version: '3.5'

services:
  laravel-app:
    build:
      context: '.'
# first we set apache to be run under user www-data
      args:
        uid: ${UID}
    environment:
      - APACHE_RUN_USER=www-data
      - APACHE_RUN_GROUP=www-data

    volumes:
      - .:/var/www/html
# exposing port 8000 for our application inside the container, because run as a regular user apache cannot bind to system ports
    ports:
      - 8000:8000
    links:
      - mysql-db

  mysql-db:
    image: mysql:8.0
# use mysql_native authentication in order to be able to login to MySQL server using user and password
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    volumes:
      - dbdata:/var/lib/mysql
    env_file:
      - .env
# setup a newly created user with password and full database rights on the laravel database
    environment:
      - MYSQL_ROOT_PASSWORD=secure
      - MYSQL_USER=${DB_USERNAME}
      - MYSQL_DATABASE=${DB_DATABASE}
      - MYSQL_PASSWORD=${DB_PASSWORD}

# create persistent volume for the MySQL data storage
volumes:
  dbdata:


Lets not forget the .dockerignore file
.git/
vendor/
node_modules/
public/js/
public/css/
run/var/

Here we are just ensuring that those directories will not be copied from the host to the container.

Et voila!

You can now run:
docker-compose up
php artisan migrate
and start browsing your website on: 127.0.0.1:8000
Inside you can also invoke: php artisan key:generate

Congratulations, you have Laravel installed as a non-root user!

Friday, February 09, 2018

Laravel quick application tutorial

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!

Subscribe To My Channel for updates

Integrating AI code helpers into Visual Studio Code

In this guide, we’ll walk through setting up a local AI-powered coding assistant within Visual Studio Code (VS Code). By leveraging tools s...