laravel

Laravel Upload File to local storage and saved to database with Postman upload client UI EP8

File Storage เป็นเรื่องนึงที่ Laravel จัดการมาให้เรียบร้อยพร้อมใช้งาน ประหยัดเวลานักพัฒนาไปได้มากเลยทีเดียว ไม่ว่าจะเป็นการดึงไฟล์ (Retrieving Files) ,อัพโหลดไฟล์ (Storing Files) ,ดาวห์โหลดไฟล์ (Downloading Files) ,ลบไฟล์ (Delete Files) เหล่านี้เป็นเรื่องง่ายมาก ๆ ถ้าแอพของเราพัฒนามาด้วย Laravel

บทความนี้จะพาทุกคนมาลองเขียนโค๊ดง่าย ๆ ทดสอบการอัพโหลดไฟล์ด้วยเครื่องมือ Postman client ที่รองรับการอัพโหลดไฟล์ (แทนการเขียนหน้าฟอร์มอัพโหลดเอง) ทำการอัพโหลดไฟล์รูปภาพไปที่ Laravel Project ที่เขียนโค๊ดการอัพโหลดไฟล์ไว้ ทำหน้าที่รับ request ที่ส่ง binary data ระบบจะทำการ Save File ลง local drive และ Save Data ลง Database

เริ่มโค๊ดเลยดีกว่า

สร้าง Table photos เพื่อเอาไว้เก็บข้อมูล photos ที่อัพโหลดเข้าระบบ

CREATE TABLE `photos` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `photo_origin_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `photo_new_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `photo_temp_path` varchar(255) NOT NULL,
  `photo_extension` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `photo_status` enum('active','inactive') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `photo_date` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

สร้าง Class Model Photo (Photo.php)

php artisan make:Model Photo

แก้ไขไฟล์ app\Models\Photo.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Photo extends Model
{
  use HasFactory;
  protected $table = 'photos';
  protected $fillable = [
    'id', 'photo_origin_name', 'photo_new_name',
    'photo_extension', 'photo_status', 'photo_date', 'photo_temp_path'
  ];
  public $timestamps = false;
}

สร้าง Class Controller UploadFileController (UploadFileController.php)

<?php

namespace App\Http\Controllers;

use App\Models\Photo;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class UploadFileController extends Controller
{

  public function simpleUplaod(Request $request)
  {
    try {
      if ($request->file('photo')->isValid()) {
        $path = $request->photo->path();
        $extension = $request->photo->extension();
        $clientOriginalName = $request->photo->getClientOriginalName();
        $newFileName = time() . $clientOriginalName;
        $uploadedFile = $request->file('photo');

        // Save File to local drive
        Storage::putFileAs('photos', $uploadedFile, $newFileName);

        //Save File to Photo table
        $photo = new Photo();
        $photo->photo_temp_path = $path;
        $photo->photo_origin_name = $clientOriginalName;
        $photo->photo_new_name = $newFileName;
        $photo->photo_extension = $extension;
        $photo->photo_status = 'ACTIVE';
        $photo->photo_date = Carbon::now();
        $photo->save();

        return [
          'path' => $path,
          'extension' => $extension,
          'clientOriginalName' => $clientOriginalName,
          'newFileName' => $newFileName
        ];
      }
    } catch (\Throwable $th) {
      return $th->getMessage();
    }
  }
}

แก้ไขไฟล์ routes.php เพิ่ม /upload

Route::post('upload', 'App\Http\Controllers\[email protected]');

เนื่องด้วยการ request ส่ง data ไปที่ laravel โดยต้องมีการส่งจำเป็นต้องส่ง @csrf ไม่เช่นนั้น ระบบจะ response (419 PAGE EXPIRED) ให้เพิ่ม ignore path “/upload” App\Http\Middleware\VerifyCsrfToken

<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware
{
  /**
   * The URIs that should be excluded from CSRF verification.
   *
   * @var array
   */
  protected $addHttpCookie = true;

  protected $except = [
    'upload'
  ];
}

start server

php artisan serve

เปิดโปรแกรม Postman ขึ้นมา กำหนดตามนี้ จากนั้นกด Send

POST : http://127.0.0.1:8000/upload 
Body : form-data
        KEY : photo (File)
        VALUE : Chose File

ตรวจสอบข้อมูลที่ Table photos

ตรวจสอบไฟล์ที่ storage/app/photos/1608200088upload-1.PNG

สรุปท้ายบทความ

จากที่ได้ทดสอบการสร้างระบบ upload ไม่ได้ยุ่งยากอย่างที่คิด ตัวอย่างโค๊ดเป็นเพียงการ Push File ลง local Storage ความสามารถของ Laravel กับเรื่อง File System สามารถศึกษาเพิ่มเติมได้ที่ลิ้งนี้ https://laravel.com/docs/7.x/filesystem หากผู้อ่านท่านใดลองทำตามแล้วไม่ได้ หรือ ติดปัญหาสามารถ ทักมาสอบถามกันได้ที่ https://www.facebook.com/poolsawat.apin/ สำหรับบทความนี้ขอจบเนื้อหาเพียงเท่านี้ครับ

Laravel connect MySQL Database ทำ RESTful API CRUD [เพิ่ม(create) ,อ่าน(read) , แก้ไข(update), ลบ(delete)] EP6

Laravel Series เดินทางมาถึง EP6 ซึ่งถ้าใครยังไม่ได้อ่านบทความ EP 1 – 5 สามารถเข้าได้ที่ลิ้งใต้ล่างนี้

  1. Laravel เริ่มติดตั้งและสร้าง route ง่าย ๆ EP1
  2. Laravel แนะนำโครงสร้างภายในโปรเจค อธิบายแต่ละส่วนการทำงาน EP2
  3. Laravel ใช้งาน views blade template engine EP3
  4. Laravel รู้จัก Routes และ การรับค่าจาก HttpRequest EP4
  5. Laravel สร้าง RESTful API ง่าย ๆ ด้วย Resource Routes Controller EP5

บทความนี้จะมาทำให้ application ของเราต่อกับฐานข้อมูล (database) ของ MySQL และเมื่อต่อได้แล้วจะมาใช้งาน migrate และมาทำระบบ CRUD ของข้อมูล Photos กัน

สร้าง Schema และ Migrate Table ด้วย artisan migrate

  1. สร้าง schema ด้วยคำสั่ง
CREATE SCHEMA `db_poolsawat` DEFAULT CHARACTER SET utf8 ;

2. แก้ไขไฟล์ .env

...
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=db_poolsawat
DB_USERNAME=root
[email protected]
...

3. ทดสอบการต่อ connection ทำตามขั้นตอนข้างล่าง ถ้าขึ้นแบบนี้แสดงว่าต่อสำเร็จ

$ php artisan tink
// Psy Shell v0.10.4 (PHP 7.3.7 — cli) by Justin Hileman

$ DB::connection()->getPdo();
/* 
PDO {#4182
     inTransaction: false,
     attributes: {
       CASE: NATURAL,
       ERRMODE: EXCEPTION,
       AUTOCOMMIT: 1,
       PERSISTENT: false,
       DRIVER_NAME: "mysql",
       SERVER_INFO: "Uptime: 433  Threads: 4  Questions: 152  Slow queries: 0  Opens: 209  Flush tables: 3  Open tables: 130  Queries per second avg: 0.351",
       ORACLE_NULLS: NATURAL,
       CLIENT_VERSION: "mysqlnd 5.0.12-dev - 20150407 - $Id: 7cc7cc96e675f6d72e5cf0f267f48e167c2abb23 $",
       SERVER_VERSION: "8.0.21",
       STATEMENT_CLASS: [
         "PDOStatement",
       ],
       EMULATE_PREPARES: 0,
       CONNECTION_STATUS: "127.0.0.1 via TCP/IP",
       DEFAULT_FETCH_MODE: BOTH,
     },
   }
*/

4. generate migrations file ด้วยคำสั่งเหล่านี้

php artisan make:migration create_photos_table

4.1 ตรวจสอบไฟล์ที่ถูกสร้างขึ้นมาที่ database/migrations/*_create_photos_table.php (* คือวันที่ generate file) จากนั้นเปิดไฟล์ขึ้นมาแก้ไข ตามนี้

<?php

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

class CreatePhotosTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('photos', function (Blueprint $table) {
            $table->id();
            $table->string('photo_name');
            $table->integer('photo_size');
            $table->string('photo_url');
            $table->enum('photo_status', ['active', 'inactive']);
            $table->dateTime('photo_date', 0);
            $table->timestamps();
        });
    }

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

ในการกำหนด datatype ของ column ตารางมีรูปแบบที่หลากหลาย มี function รองรับอยู่แล้ว สำหรับการกำหนดสร้าง สามารถดูเพิ่มเติมได้จากตารางนี้

Available Column Types

The schema builder contains a variety of column types that you may specify when building your tables:

CommandDescription
$table->id();Alias of $table->bigIncrements('id').
$table->foreignId('user_id');Alias of $table->unsignedBigInteger('user_id').
$table->bigIncrements('id');Auto-incrementing UNSIGNED BIGINT (primary key) equivalent column.
$table->bigInteger('votes');BIGINT equivalent column.
$table->binary('data');BLOB equivalent column.
$table->boolean('confirmed');BOOLEAN equivalent column.
$table->char('name', 100);CHAR equivalent column with a length.
$table->date('created_at');DATE equivalent column.
$table->dateTime('created_at', 0);DATETIME equivalent column with precision (total digits).
$table->dateTimeTz('created_at', 0);DATETIME (with timezone) equivalent column with precision (total digits).
$table->decimal('amount', 8, 2);DECIMAL equivalent column with precision (total digits) and scale (decimal digits).
$table->double('amount', 8, 2);DOUBLE equivalent column with precision (total digits) and scale (decimal digits).
$table->enum('level', ['easy', 'hard']);ENUM equivalent column.
$table->float('amount', 8, 2);FLOAT equivalent column with a precision (total digits) and scale (decimal digits).
$table->geometry('positions');GEOMETRY equivalent column.
$table->geometryCollection('positions');GEOMETRYCOLLECTION equivalent column.
$table->increments('id');Auto-incrementing UNSIGNED INTEGER (primary key) equivalent column.
$table->integer('votes');INTEGER equivalent column.
$table->ipAddress('visitor');IP address equivalent column.
$table->json('options');JSON equivalent column.
$table->jsonb('options');JSONB equivalent column.
$table->lineString('positions');LINESTRING equivalent column.
$table->longText('description');LONGTEXT equivalent column.
$table->macAddress('device');MAC address equivalent column.
$table->mediumIncrements('id');Auto-incrementing UNSIGNED MEDIUMINT (primary key) equivalent column.
$table->mediumInteger('votes');MEDIUMINT equivalent column.
$table->mediumText('description');MEDIUMTEXT equivalent column.
$table->morphs('taggable');Adds taggable_id UNSIGNED BIGINT and taggable_type VARCHAR equivalent columns.
$table->uuidMorphs('taggable');Adds taggable_id CHAR(36) and taggable_type VARCHAR(255) UUID equivalent columns.
$table->multiLineString('positions');MULTILINESTRING equivalent column.
$table->multiPoint('positions');MULTIPOINT equivalent column.
$table->multiPolygon('positions');MULTIPOLYGON equivalent column.
$table->nullableMorphs('taggable');Adds nullable versions of morphs() columns.
$table->nullableUuidMorphs('taggable');Adds nullable versions of uuidMorphs() columns.
$table->nullableTimestamps(0);Alias of timestamps() method.
$table->point('position');POINT equivalent column.
$table->polygon('positions');POLYGON equivalent column.
$table->rememberToken();Adds a nullable remember_token VARCHAR(100) equivalent column.
$table->set('flavors', ['strawberry', 'vanilla']);SET equivalent column.
$table->smallIncrements('id');Auto-incrementing UNSIGNED SMALLINT (primary key) equivalent column.
$table->smallInteger('votes');SMALLINT equivalent column.
$table->softDeletes('deleted_at', 0);Adds a nullable deleted_at TIMESTAMP equivalent column for soft deletes with precision (total digits).
$table->softDeletesTz('deleted_at', 0);Adds a nullable deleted_at TIMESTAMP (with timezone) equivalent column for soft deletes with precision (total digits).
$table->string('name', 100);VARCHAR equivalent column with a length.
$table->text('description');TEXT equivalent column.
$table->time('sunrise', 0);TIME equivalent column with precision (total digits).
$table->timeTz('sunrise', 0);TIME (with timezone) equivalent column with precision (total digits).
$table->timestamp('added_on', 0);TIMESTAMP equivalent column with precision (total digits).
$table->timestampTz('added_on', 0);TIMESTAMP (with timezone) equivalent column with precision (total digits).
$table->timestamps(0);Adds nullable created_at and updated_at TIMESTAMP equivalent columns with precision (total digits).
$table->timestampsTz(0);Adds nullable created_at and updated_at TIMESTAMP (with timezone) equivalent columns with precision (total digits).
$table->tinyIncrements('id');Auto-incrementing UNSIGNED TINYINT (primary key) equivalent column.
$table->tinyInteger('votes');TINYINT equivalent column.
$table->unsignedBigInteger('votes');UNSIGNED BIGINT equivalent column.
$table->unsignedDecimal('amount', 8, 2);UNSIGNED DECIMAL equivalent column with a precision (total digits) and scale (decimal digits).
$table->unsignedInteger('votes');UNSIGNED INTEGER equivalent column.
$table->unsignedMediumInteger('votes');UNSIGNED MEDIUMINT equivalent column.
$table->unsignedSmallInteger('votes');UNSIGNED SMALLINT equivalent column.
$table->unsignedTinyInteger('votes');UNSIGNED TINYINT equivalent column.
$table->uuid('id');UUID equivalent column.
$table->year('birth_year');YEAR equivalent column.
https://laravel.com/docs/8.x/migrations

4.2 หลังจากที่แก้ไขไฟล์ *_create_photos_table.php เป็นที่เรียบร้อยแล้ว ให้ รันคำสั่งต่อไปนี้เพิ่มเพิ่ม migrate table (artisan จะทำการไป create table ให้ที่ database )

php artisan migrate

เปรียบเหมือนว่าเรากำลังใช้คำสั่งชุดนี้เพื่อสร้างตาราง

CREATE TABLE `photos` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `photo_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `photo_size` int NOT NULL,
  `photo_url` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `photo_status` enum('active','inactive') COLLATE utf8mb4_unicode_ci NOT NULL,
  `photo_date` datetime NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

5. สร้าง Model class ด้วย artisan cli

php artisan make:model Photo

ตรวจสอบไฟล์ที่ app/Models/Photo.php

5.1 แก้ไขไฟล์ app/Models/Photo.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Photo extends Model
{
  use HasFactory;
  protected $fillable = [
    'created_at', 'id', 'photo_date', 'photo_name', 'photo_size',
    'photo_status', 'photo_url', 'updated_at'
  ];
}

6. สร้าง Controller class ด้วย artisan cli

php artisan make:controller PhotoController --resource

ตรวจสอบไฟล์ที่ app/Http/Controller/PhotoController.php

6.1 แก้ไขไฟล์ app/Http/Controller/PhotoController.php ตามข้างล่างนี้ ส่วนนี้จะได้มี function RESTful API template ที่ได้จากการ artisan cli แล้ว บทความ “Laravel สร้าง RESTful API ง่าย ๆ ด้วย Resource Routes Controller EP5” ได้อธิบายไว้บ้างแล้ว บทความนี้จะขอข้ามส่วนนี้ไป

<?php

namespace App\Http\Controllers;

use App\Models\Models\Photo as ModelsPhoto;
use App\Models\Photo;
use Carbon\Carbon;
use Illuminate\Http\Request;

class PhotoController extends Controller
{
  /**
   * Display a listing of the resource.
   *
   * @return \Illuminate\Http\Response
   */
  public function index()
  {
    return response()->json(['name' => 'index', 'photos' => Photo::all()]);
  }

  /**
   * Show the form for creating a new resource.
   *
   * @return \Illuminate\Http\Response
   */
  public function create()
  {
    $photo = new Photo();
    $photo->photo_name = 'laravel';
    $photo->photo_size = 1024;
    $photo->photo_url = 'https://laravel.com/img/logotype.min.svg';
    $photo->photo_status = 'active';
    $photo->photo_date = Carbon::now();
    return response()->json(['name' => 'create', 'status' => $photo->save()]);
  }

  /**
   * Store a newly created resource in storage.
   *
   * @param  \Illuminate\Http\Request  $request
   * @return \Illuminate\Http\Response
   */
  public function store(Request $request)
  {
    $photo = new Photo($request->all());
    $photo->photo_date = Carbon::now();
    return response()->json(['name' => 'store', 'payload' => $request->all(), 'status' => $photo->save()]);
  }

  /**
   * Display the specified resource.
   *
   * @param  int  $id
   * @return \Illuminate\Http\Response
   */
  public function show($id)
  {
    $photo = Photo::find($id);
    return response()->json(['name' => 'show', 'id' => $id, 'photo' => $photo]);
  }

  /**
   * Show the form for editing the specified resource.
   *
   * @param  int  $id
   * @return \Illuminate\Http\Response
   */
  public function edit($id)
  {
    $photo = Photo::find($id);
    return response()->json(['name' => 'edit', 'id' => $id, 'photo' => $photo]);
  }

  /**
   * Update the specified resource in storage.
   *
   * @param  \Illuminate\Http\Request  $request
   * @param  int  $id
   * @return \Illuminate\Http\Response
   */
  public function update(Request $request, $id)
  {
    $photo = Photo::find($id);
    $photo->photo_name = $request->photo_name;
    $photo->photo_size = $request->photo_size;
    $photo->photo_url = $request->photo_url;
    $photo->photo_status = $request->photo_status;
    $photo->photo_date = Carbon::now();
    return response()->json(['name' => 'update', 'status' => $photo->save(),  'payload' => $request->all(), 'id' => $id]);
  }

  /**
   * Remove the specified resource from storage.
   *
   * @param  int  $id
   * @return \Illuminate\Http\Response
   */
  public function destroy($id)
  {
    $photo = Photo::find($id);
    return response()->json(['name' => 'destroy', 'status' => $photo->delete(), 'id' => $id]);
  }
}

7. แก้ไขไฟล์ routes/api.php เพิ่มโค๊ด 1 บรรทัด

...
Route::resource('photos', 'App\Http\Controllers\PhotoController');
...

8. ทดสอบ RESTful API

ก่อนที่จะทดสอบติดตั้ง npm i -g json เพื่อ pritty json response เพื่อความสวยงาม

$ curl localhost:8000/api/photos | json

 % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    28    0    28    0     0     65      0 --:--:-- --:--:-- --:--:--    65
{
  "name": "index",
  "photos": []
}
/* fetch photos all */
$ curl localhost:8000/api/photos/create | json

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    31    0    31    0     0     73      0 --:--:-- --:--:-- --:--:--    73
{
  "name": "create",
  "status": true
}
/* create photo */
$ curl -X POST -H "Content-Type: application/json" -d "{\"photo_name\":\"laravel\",\"photo_size\":1024,\"photo_url\":\"https://laravel.com/img/logotype.min.svg\",\"photo_status\":\"active\",\"photo_date\":\"2020-10-06 10:24:01\"}" http://127.0.0.1:8000/api/photos | json

 % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   357    0   201  100   156   1116    866 --:--:-- --:--:-- --:--:--  1994
{
  "name": "store",
  "payload": {
    "photo_name": "laravel",
    "photo_size": 1024,
    "photo_url": "https://laravel.com/img/logotype.min.svg",
    "photo_status": "active",
    "photo_date": "2020-10-06 10:24:01"
  },
  "status": true
}
/* create photo with payload */
$ curl localhost:8000/api/photos/1 | json

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   286    0   286    0     0    722      0 --:--:-- --:--:-- --:--:--   722
{
  "name": "show",
  "id": "1",
  "photo": {
    "id": 1,
    "photo_name": "laravel",
    "photo_size": 1024,
    "photo_url": "https://laravel.com/img/logotype.min.svg",
    "photo_status": "active",
    "photo_date": "2020-10-06 10:32:24",
    "created_at": "2020-10-06T10:32:24.000000Z",
    "updated_at": "2020-10-06T10:32:24.000000Z"
  }
}
/* fetch photo by id */
$ curl localhost:8000/api/photos/1/edit | json

 % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   286    0   286    0     0    709      0 --:--:-- --:--:-- --:--:--   709
{
  "name": "edit",
  "id": "1",
  "photo": {
    "id": 1,
    "photo_name": "laravel",
    "photo_size": 1024,
    "photo_url": "https://laravel.com/img/logotype.min.svg",
    "photo_status": "active",
    "photo_date": "2020-10-06 10:32:24",
    "created_at": "2020-10-06T10:32:24.000000Z",
    "updated_at": "2020-10-06T10:32:24.000000Z"
  }
}
/* fetch photo by id for edit */
$ curl -X PATCH -H "Content-Type: application/json" -d "{\"id\":1,\"photo_name\":\"laravel patch\",\"photo_size\":2048,\"photo_url\":\"https://laravel.com/img/logotype.min.svg\",\"photo_status\":\"active\",\"photo_date\":\"2020-10-06 10:24:01\"}" http://127.0.0.1:8000/api/photos/1 | json

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   393    0   224  100   169   1108    836 --:--:-- --:--:-- --:--:--  1945
{
  "name": "update",
  "status": true,
  "payload": {
    "id": 1,
    "photo_name": "laravel patch",
    "photo_size": 2048,
    "photo_url": "https://laravel.com/img/logotype.min.svg",
    "photo_status": "active",
    "photo_date": "2020-10-06 10:24:01"
  },
  "id": "1"
}
/* patch photo with payload */

$ curl localhost:8000/api/photos/1 | json
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   292    0   292    0     0    707      0 --:--:-- --:--:-- --:--:--   705
{
  "name": "show",
  "id": "1",
  "photo": {
    "id": 1,
    "photo_name": "laravel patch",
    "photo_size": 2048,
    "photo_url": "https://laravel.com/img/logotype.min.svg",
    "photo_status": "active",
    "photo_date": "2020-10-06 10:36:22",
    "created_at": "2020-10-06T10:32:24.000000Z",
    "updated_at": "2020-10-06T10:36:22.000000Z"
  }
}
curl -X DELETE http://127.0.0.1:8000/api/photos/1 | json

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    41    0    41    0     0    221      0 --:--:-- --:--:-- --:--:--   221
{
  "name": "destroy",
  "status": true,
  "id": "1"
}
/* delete photo by id */

สรุปท้ายบทความ

บทความนี้ต่อยอดความสามารถของบทความ “Laravel สร้าง RESTful API ง่าย ๆ ด้วย Resource Routes Controller EP5” ที่ RESTful template แต่บทความนี้จะสอนเพิ่มเติมการต่อ MySQL เพื่อ connect database ใช้ข้อมูลภายใน เพิ่มเติมด้วยความสามารถของ migration ที่จะ create table schema ให้เองตาม code CreatePhotosTable ที่ได้ทำการสร้างไว้จาก code PHP

บทความหน้าจะมาพูดถึงเรื่องอะไรค่อยติดตามกันนะครับ ขอบคุณที่ติดตามครับ

Laravel สร้าง RESTful API ง่าย ๆ ด้วย Resource Routes Controller EP5

รูปแบบลักษณะงานเว็บไซต์ในปัจจุบัน เกิน 80 – 90 % ต้องมีการทำระบบ RESTful API เพื่อให้บริการข้อมูลกับ Application platform รูปแบบต่าง ๆ ไม่ว่าจะเป็น mobile และ web เพราะเป็นรูปแบบการพัฒนาที่ได้รับความนิยมมากในปัจจุบัน กล่าวคือการเชื่อมโยง application ด้วยข้อมูลจากแหล่งเดียวกัน นั้นเอง

การพัฒนา RESTful API Service สามารถทำได้กับหลาย ๆ ภาษาโปรแกรมมิ่งทั่วไป (ถ้าภาษาโปรแกรมมิ่งมี feature http ต้องสามารถทำ RESTful API ได้อย่างแน่นอน) แต่สิ่งที่จะทำให้การพัฒนา RESTful นั้นง่ายและสะดวกยิ่งขึ้นก็คือเครื่องมือ หรือ cli (command line user interface ) สำหรับช่วยทำให้การเขียนโปรแกรมของเราง่าย และสะดวกมากยิ่งขึ้นไปอีก

laravel มี artisan cli (symfony class console) ช่วยทำให้งาน develop สะดวกและง่ายยิ่งขึ้น บทความนี้จะพามาทำความรู้จัก cli นี้กัน

สร้าง Resource Controller RESTful API แรกกัน

laravel มี feature Resource Controllers ที่จะช่วยสร้าง RESTful function template controller ขึ้นมาให้ เราเพียงแค่ implement function ตาม RESTful action เท่านั้นก็สามารถเรียกใช้งานได้เลย โดยมีวิธีการเรียกใช้งานตามตัวอย่าง ข้างล่างนี้

$ php artisan make:controller PhotoController --resource

laravel สร้าง generate /app/Http/Controllers/PhotoController.php ภายในไฟล์จะมีการสร้าง function RESTful template มาให้

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PhotoController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        //
    }
}

มาทำความรู้จักการทำงานแต่ละ function มามีการทำงานอย่างไร ตามการอธิบายจากตารางนี้

Actions Handled By Resource Controller

VerbURIActionRoute Name
GET/photosindexphotos.index
GET/photos/createcreatephotos.create
POST/photosstorephotos.store
GET/photos/{photo}showphotos.show
GET/photos/{photo}/editeditphotos.edit
PUT/PATCH/photos/{photo}updatephotos.update
DELETE/photos/{photo}destroyphotos.destroy

เพิ่ม routes mapping ที่ไฟล์ /routes/api.php

Route::resource('photos', 'App\Http\Controllers\PhotoController');

เพิ่ม route:resource เป็น static function สำหรับการทำ RESTful routes เพิ่มเพียงบรรทัดเดียวก็สามารถเรียก http methods ต่าง ๆ เหล่านี้ GET ,POST ,PUT ,DELETE ,PATCH ได้เลย ง่ายมาก ๆ

implement PhotoController ตาม function การทำงานเพื่อใช้ตรวจสอบการ call จาก REST client

ผมจะเพิ่ม function response()->json(); เพื่อทำการ return http response คืนค่ากลับไปในรูปแบบ application/json format

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PhotoController extends Controller
{
  /**
   * Display a listing of the resource.
   *
   * @return \Illuminate\Http\Response
   */
  public function index()
  {
    return response()->json(['name' => 'index']);
  }

  /**
   * Show the form for creating a new resource.
   *
   * @return \Illuminate\Http\Response
   */
  public function create()
  {
    return response()->json(['name' => 'create']);
  }

  /**
   * Store a newly created resource in storage.
   *
   * @param  \Illuminate\Http\Request  $request
   * @return \Illuminate\Http\Response
   */
  public function store(Request $request)
  {
    return response()->json(['name' => 'store', 'payload' => $request->all()]);
  }

  /**
   * Display the specified resource.
   *
   * @param  int  $id
   * @return \Illuminate\Http\Response
   */
  public function show($id)
  {
    return response()->json(['name' => 'show', 'id' => $id]);
  }

  /**
   * Show the form for editing the specified resource.
   *
   * @param  int  $id
   * @return \Illuminate\Http\Response
   */
  public function edit($id)
  {
    return response()->json(['name' => 'edit', 'id' => $id]);
  }

  /**
   * Update the specified resource in storage.
   *
   * @param  \Illuminate\Http\Request  $request
   * @param  int  $id
   * @return \Illuminate\Http\Response
   */
  public function update(Request $request, $id)
  {
    return response()->json(['name' => 'update', 'payload' => $request->all(), 'id' => $id]);
  }

  /**
   * Remove the specified resource from storage.
   *
   * @param  int  $id
   * @return \Illuminate\Http\Response
   */
  public function destroy($id)
  {
    return response()->json(['name' => 'destroy', 'id' => $id]);
  }
}

หลังจากปรับแก้ PhotoController.php เรียบร้อย ทำการ รันคำสั่ง

$ php artisan serve
Starting Laravel development server: http://127.0.0.1:8000

ทดสอบ RESTful API

curl http://127.0.0.1:8000/api/photos

{“name”:”index”}

curl http://127.0.0.1:8000/api/photos/create

{“name”:”create”}

curl -X POST -H "Content-Type: application/json" -d "{\"name\":\"poolsawat.com\"}" http://127.0.0.1:8000/api/photos

{“name”:”store”,”payload”:{“name”:”poolsawat.com”}}

curl http://127.0.0.1:8000/api/photos/9999

{“name”:”show”,”id”:”9999″}

curl http://127.0.0.1:8000/api/photos/9999/edit

{“name”:”edit”,”id”:”9999″}

curl -X PUT -H "Content-Type: application/json" -d "{\"name\":\"poolsawat.com\"}" http://127.0.0.1:8000/api/photos/99999

{“name”:”update”,”payload”:{“name”:”poolsawat.com”},”id”:”99999″}

curl -X DELETE http://127.0.0.1:8000/api/photos/9999

{“name”:”destroy”,”id”:”9999″}

สรุปท้ายบทความ

การทำ RESTful API ด้วย Laravel จากที่ได้ใช้งานมาได้สักระยะ จากประสบการณ์ค่อนข้างชอบ เพราะด้วยตัวภาษาโปรแกรมมิ่ง เวลาจะ compile ไม่จำเป็นต้อง restart server เพราะเป็นภาษาคริป เลยถือเป็นข้อดีอย่างนึงสำหรับทำ prototype api ง่าย ๆ เพื่อนำเสนอลูกค้าหรือใช้งานกันเองภายในบริษัท ต้องการศึกษาเพิ่มเติมเกี่ยวกับการทำ Resource Controllers ของ Laravel ศึกษาได้ที่ลิ้งนี้ Resource Controllers

บทความต่อไปจะเป็นเรื่องอะไร คอยติดตามกันนะครับ

Laravel รู้จัก Routes และ การรับค่าจาก HttpRequest EP4

การพัฒาน web application ข้อที่ควรคำนึงถึงคือเรื่อง url (endpoints) ต่าง ๆ ภายใน application ของเรา อาจจะเป็น url แบบเดียวกันได้เพียงแต่กำหนด http method ไม่เหมือนกัน เช่น

  • [GET] /api/v1/user สร้างเพื่อ provide data ให้กับ client
  • [POST] /api/v1/user สร้างเพื่อกำหนดไว้สำหรับ create data ใหม่

จุดสั่งเกตุที่เห็นได้ชัดคือ ความเหมือนกันของ url แต่ต่างกันในเรื่อง method เท่านั้น ทางฝั่ง application เราเอง (กำหนด route) จะ mapping route ให้ตรงกับการ request เรียกเข้ามา request เรียกมาแบบ [GET] ก็จะเข้าไปทำงานในส่วนของ GET method , เรียกมาแบบ [POST] จะเข้าไปทำงานในส่งของ POST method เรื่องเหล่านี้ต้องมาทำความเข้าใจกัน บทความนี้จะมาอธิบาย

การกำหนด Methods มีกี่แบบ Laravel จะต้องเขียนอย่างไร

  • GET
    • มีการเก็บ cached การ request ได้
    • ไม่ควรอย่างยิ่งสำหรับการส่ง sensitive data มากับ url
    • มีข้อจำกัดเรื่องความยาวของ url + parameters
    • ใช้สำหรับขอข้อมูลเท่านั้น ไม่เหมาะกับการแก้ไขข้อมูล
  • POST
    • ไม่ถูกเก็บ cached เอาไว้ (request body) จะไม่ถูกเก็บไว้
    • ไม่อยู่ในประวัติของ browser
    • request body สามารถกำหนดได้ยาว ขนาดใหญ่
  • PUT
    • เป็นลักษณะการสร้าง (created) หรือ อัพเดท (update) ข้อมูลฝั่ง serve
  • HEAD
    • คล้ายกันกับ GET แต่ไม่มีการคืนค่ากลับ
  • DELETE
    • การลบข้อมูลที่เป็น unique โดยส่วนใหญ่จะเป็น uuid หรือ id ที่ระบุเป็นเฉพาะเจาะจง
  • PATCH
    • เพื่อปรับเปลี่ยนบางอย่างของข้อมูลฝั่ง server
  • OPTIONS
    • เพื่ออธิบายการทำงานของ data ฝั่ง server

Laravel มีการกำหนด http methods Laravel Routing จะถูกสร้างไว้ที่ไฟล์ /routes/web.php และ /routes/api.php

[GET] สำหรับ inline function
Route::get('foo', function () {
    return 'Hello World';
});
[GET] สำหรับ use controller route อื่น ๆ
Route::get('/user', '[email protected]');
[*] ลักษณะการกำหนด methods อื่น ๆ ทำตาามนี้
Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);

การกำหนด parameters ให้ทำ route ในรูปแบบต่าง ๆ

[required] การกำหนด parameters บังคับ ในรูแบบ required parameters จะกำหนดภายใต้ {} 
Route::get('user/{id}', function ($id) {
    return 'User '.$id;
});
Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) {
    //
});

[non required] กำหนด parameters แบบไม่บังคับให้ส่งเข้ามา
Route::get('user/{name?}', function ($name = null) {
    return $name;
});
Route::get('user/{name?}', function ($name = 'John') {
    return $name;
});

[regular] กำหนด parameter ด้วย rules ตาม pattern ด้วย regular expression
Route::get('user/{name}', function ($name) {
    //
})->where('name', '[A-Za-z]+');
Route::get('user/{id}', function ($id) {
    //
})->where('id', '[0-9]+');
Route::get('user/{id}/{name}', function ($id, $name) {
    //
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);

ศึกษาเพิ่มเติมเรื่อง Routes การทำ Routes Grouping จากลิ้งนี้ Laravel Routes

การรับค่าจาก HttpRequest ในรูปแบบต่าง ๆ

การที่จะได้มาของ parameters data ที่ได้จากการ request client นั้นมีได้หลายรูปแบบ ตามตัวอย่าง

การเข้าถึงค่าของ url information ที่ถูก request เข้ามา

[url path]
$uri = $request->path();

// Without Query String...
$url = $request->url();

// With Query String...
$url = $request->fullUrl();

การรับค่า (request body data) จาก HttpRequest (Payload Request Body)

[all] จะได้ค่าเป็น object ของ request data
$input = $request->all();

[name] การเข้าถึง value ด้วยการกำหนดจาก name ของ parameter
$name = $request->input('name');

[empty then value] กำหนดค่า default หากไม่พบค่าจาก parameters นั้น ๆ 
$name = $request->input('name', 'Sally');

[json array] การเข้าถึง request ที่เป็นลักาณะ raw json array ก็ทำได้
$name = $request->input('products.0.name');
$names = $request->input('products.*.name');

การรับค่า (request body data) จาก HttpRequest (Query Parameters)

[?name=hello] การเข้าถึง queryString จาก parameters
$name = $request->query('name');

[empty then value]
$name = $request->query('name', 'Helen');

ตรวจสอบค่าจาก parameters ด้วย name

[checking] ตรวจสอบ parameter ชื่อ name หากมีจะเข้าเงื่อนไขการทำงาน
if ($request->has('name')) {
    //
}
if ($request->has(['name', 'email'])) {
    //
}
if ($request->hasAny(['name', 'email'])) {
    //
}

[not empty] ตรวจสอบค่า parameter ต้องไม่เป็นค่าว่าง จะใช้ function filled ตรวจสอบ
if ($request->filled('name')) {
    //
}

รูปแบบการใช้งาน Routes และ HttpRequest ใน Laravel มีเนื้อหาเพิ่มเติมอีกมากมาย สามารถศึกษาเพิ่มเติมได้ที่ Laravel Route ,Laravel Request

ขอบคุณที่ติดตามบทความครับ

Laravel ใช้งาน views blade template engine EP3

การพัฒนาเว็บไซต์ด้วยชุด framework ต่าง ๆ จะให้ได้รับความนิยมของ framework นั้น ๆ ต้องมีความพร้อมในเรื่องการจัดการ view ก็คือเครื่องมือการพัฒนาในส่วนของงานการแสดงผลของ data ต่าง ๆ การที่ laravel มาพร้อมกับ blade template engine นี้ถือว่าครบเพียบพร้อม เหมาะแก่การใช้งานเป็นอย่างมาก บทความนี้จะพาไปรู้จักการใช้งาน blade template engine นี้กันว่ามีการทำงานร่วมกับ laravel อย่างไรได้บ้าง

การใช้งาน Blade เพื่อ displaying data จาก controller

การที่จะนำค่าที่ผ่านกระบวนการทำงานจาก controller ไปที่ views (*.blade.php) โดยไฟล์ *.blade.php ทั้งหมดจะถูกจัดเก็บไว้ที่ resources/views/*

  • สร้างไฟล์ {viewname}.blade.php ตัวอย่าง views/example/datatype.blade.php
<html>

<body>
  <h1>DataType</h1>
  <h3>String</h3>
  <p>{{$string}}</p>
  <hr />
  <h3>Boolean</h3>
  <p>{{$boolean}}</p>
  <hr />
  <h3>Integer</h3>
  <p>{{$integer}}</p>
  <hr />
  <h3>Object</h3>
  <p>{{$object['content']}}</p>
  <hr />
  <h3>Array</h3>
  <p>
    <ol>
      @foreach($array as $index=> $item)
      <li>{{$item['content']}}</li>
      @endforeach
    </ol>
  </p>
  <hr />
</body>

</html>
  • แก้ไขไฟล์ routes/web.php กำหนด view(‘datatype’,[?]) กำหนด parameter data ที่จะส่งไปที่ view ใน arg ที่ 2 [?]
Route::get('/datatype', function () {
  return view('/example/datatype', [
    'string' => 'Laravel ใช้งาน view (blade template), json ,pdf',
    'boolean' => true,
    'integer' => 9999,
    'object' => [
      'content' => 'Laravel ใช้งาน view (blade template), json ,pdf EP3',
      'author' => 'poolsawat'
    ],
    'array' => [
      ['content' => 'Laravel เริ่มติดตั้งและสร้าง route ง่าย ๆ EP1'],
      ['content' => 'Laravel แนะนำโครงสร้างภายในโปรเจค อธิบายแต่ละส่วนการทำงาน EP2'],
      ['content' => 'Laravel ใช้งาน view (blade template), json ,pdf EP3'],
    ]
  ]);
});

การใช้งาน blade ในกรณีต้องการใช้งาน control structures (IF ,ELSE ,SWITCH ,LOOP (for ,foreach ,while) ต่าง ๆ เหล่านี้ ทำอย่างไร

ในบางครั้ง บางกรณีที่ต้องการตะเช็คเงื่อนไขในการที่จะแสดงผลของ data หรืออยากที่จะแสดงผลค่าที่เป็นในลักษณะชุดข้อมูล (array) ทาง blade ก็มีคำสั่งมาให้พร้อมแล้ว โดยการที่จะเรียกคำสั่งนั้น จะมี tag @ ตามด้วย name เช่น @if ,@for เป็นต้น

  • สร้างไฟล์ views/example/control.blade.php
<!DOCTYPE html>
<html lang="en">

<body>
  <h1>Control Structures</h1>
  <p>IF ,ELSEIF ,ELSE ,LOOP (FOR,FOREACH,WHILE) ,SWITCH</p>
</body>
<h1>IF</h1>
@if (count($records) === 1)
I have one record!
@elseif (count($records) > 1)
I have multiple records!
@else
I don't have any records!
@endif
<hr />
<h1>SWITCH</h1>
@switch($case)
@case(1)
First case...
@break

@case(2)
Second case...
@break

@default
Default case...
@endswitch
<hr />
<h1>LOOP</h1>
<h3>FOR</h3>
@for ($i = 0; $i
< 4; $i++) <br />The current value is {{ $i }} @endfor
<h3>FOREACH</h3>
@foreach ($records as $rec)
<p>This is record {{ $rec }}</p>
@endforeach
<hr />
<h3>FORELSE</h3>
@forelse ($records as $rec)
<li>{{ $rec }}</li>
@empty
<p>No users</p>
@endforelse
<hr />
<h3>WHILE</h3>
@php
$i = 0
@endphp
@while ($i < 4) <p>I'm looping forever.</p>
  @php
  $i++
  @endphp
  @endwhile

</html>
  • แก้ไขไฟล์ routes/web.php โดยเพิ่ม route “control-structures” เข้าไป
Route::get('/control-structures', function () {
  return view('example/control', [
    'records' => [1, 2, 3, 4],
    'case' => 2
  ]);
});

การใช้งาน blade กับการทำ component แยกส่วน

framework ที่ได้รับความนิยมในปัจจุบัน React , Angular ,Vue มีจุดเด่นเรื่องการทำ Component management โดยทั้งสิ้น Laravel เองก็มี concept นี้ด้วยเช่นกัน (ทีมเดียวกับที่พัฒนา Vue) ถือเป็นข้อดีอีกอย่างที่อยากแนะนำให้ใช้งาน laravel

  • สร้างไฟล์ views/example/component.blade.php , views/components/alert.blade.php ,views/components/message.blade.php ,views/components/message-slot.blade.php ตาลำดับ
<!-- views/example/component.blade.php -->
<!DOCTYPE html>
<html lang="en">

<body>
  <h1>Component</h1>
  <h3>empty data</h3>
  @component('components/message',[])
  @endcomponent
  <hr />
  <h3>has data</h3>
  @component('components/message',['name' => 'poolsawat.com'])
  @endcomponent
  <hr />
  <h3>append slot</h3>
  @component('components/message-slot',[])
  <div>element slot 1</div>
  <div>element slot 2</div>
  @endcomponent
  <hr />
  <x-alert />
</body>

</html>
<!-- views/components/alert.blade.php -->
<h1>x-{component}</h1>
<!-- views/components/message.blade.php -->
<h2>
  @if (empty($name))
  component message ...
  @else
  component message {{$name}}
  @endif
</h2>
<!-- views/components/message-slot.blade.php -->
<h2>
  component message append slot
  {{ $slot }}
</h2>
  • แก้ไขไฟล์ routes/web.php เพิ่ม route “components”
Route::get('/components', function () {
  return view('example/component', []);
});
  • ดูผลลัพธ์ที่
  • components ของ laravel มีรูปแบบการเรียกได้ 2 วิธี
    1. @component(‘components/alert’,[]) @endcomponent สามารถเรียกได้แบบนี้จากหน้า views
    2. <x-alert /> สามารถเรียกได้แต่ต้องมีไฟล์ app/View/Components/Alert.php โดย genarate Component ได้ด้วยคำสั่ง artisan package นี้ php artisan make:component Alert
<?php

namespace App\View\Components;

use Illuminate\View\Component;

class Alert extends Component
{
    /**
     * Create a new component instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the view / contents that represent the component.
     *
     * @return \Illuminate\View\View|string
     */
    public function render()
    {
        return view('components.alert');
    }
}

เหล่านี้คือการเรียกใช้งาน blade template engine ง่าย ๆ ยังมีความสามารถอีกเยอะมาก ศึกษาเพิ่มเติ่มที่นี่

Laravel แนะนำโครงสร้างภายในโปรเจค อธิบายแต่ละส่วนการทำงาน EP2

หลังจากที่ได้ทำการติดตั้งตามบทความนี้แล้ว “Laravel เริ่มติดตั้งและสร้าง route ง่าย ๆ EP1” บทความนี้จะมาอธิบายเพิ่มเติมแต่ละส่วนของโครงสร้างโปรเจคว่ามีหน้าที่ทำอะไร และตัวอย่างการใช้งานอย่างไรได้บ้าง

มาทำความรู้จักโครงสร้างของ Laravel กัน

  • app/Console
  • app/Exceptions จัดการ Error Exception จากการทำงานที่ผิดพลาด
  • app/Http
    • app/Http/Controllers จัดเก็บ Controllers file (*Controller.php) สำหรับเก็บ Logic ,Route ,Repository ,ORM ต่าง ๆ จะเขียนในไฟล์เหล่านี้
    • app/Http/Middleware จัดเก็บไฟล์ middleware เข้าออกจอง Routes ต่าง ๆ เช่น การทำ Basic Authenticate ,Session Handlers เป็นต้น
    • app/Kernel
  • app/Models เก็บ Model จาก databases ต่าง ๆ กำหนด
  • app/Providers เก็บไฟล์ Providers กำหนด เช่น BroadcasProvider ,EventServiceProvider ,RouteServiceProvider เป็นต้น
  • bootstrap
    • bootstrap/cache
    • bootstrap/app.php
  • config
    • config/app.php เก็บค่า config ระดับ app เช่น ชื่อ app ,env (production) ,timezone UTC เป็นต้น
    • config/auth.php
    • config/broadcasting.php
    • config/cache.php
    • config/cors.php
    • config/databases.php เก็บ database driver ต่าง ๆ mysql , pgsql, sqlsrv ,sqlite เป็นต้น
    • config/filesystems.php
    • config/hashing.php
    • config/logging.php
    • config/mail.php
    • config/queue.php
    • config/services.php
    • config/session.php
    • config/view.php
  • database
    • database/factories
    • database/migrations เก็บไฟล์ script create table ของ database
    • database/seeders
  • public หลังจาก compile laravel mix จะถูกมาเก็บในนี้ ไฟล์ที่นี่
    • public/.htaccess
    • public/favicon.ico
    • public/index.php
    • public/rebots.txt
  • resources
    • resources/css เก็บไฟล์ css ( Cascading Style Sheets ) ต่าง ๆ
    • resources/js เก็บไฟล์ js (Javascript ) ต่าง ๆ
    • resources/lang
    • resources/views เก็บไฟล์ view (*.blade) ต่าง ๆ
  • routes
    • routes/api.php จัดการ route RESTApis ต่าง ๆ (laravel –resource )
    • routes/channels.php
    • routes/console.php
    • routes/web.php จัดการ route ทั่วไป แบบปกติจะจัดการที่ไฟล์นี้เป็นส่วนใหญ๋
  • storage
    • storage/app/public
    • storage/framework
    • storage/logs
  • tests เขียน unittest ต่าง ๆ
    • tests/Feature
    • tests/Unit
  • vender จัดการ libraries ต่าง ๆ ที่ได้จากการติดตั้ง laravel ตั้งแต่เริ่มต้น
  • .env เก็บค่า config ต่าง ๆ โดยจะแบ่งเป็น dev , prod
  • artisan
  • composer.json
  • package.json
  • webpack.mix.js จัดการไฟล์ต่าง ๆ ที่เป็น css ,js ก่อนการ compile minify จะได้ output เก็บที่ public/

ในบ้าง directory ,file ไม่ได้เข้าไปยุ่งเกี่ยวในระหว่างการใช้งาน จะขอไม่อธิบาย หากคุณต้องการศึกษาเพิ่มเติม https://laravel.com/docs/7.x/structure

Laravel เริ่มติดตั้งและสร้าง route ง่าย ๆ EP1

Laravel ปัจจุบันเดินทางมาถึงเวอร์ชั่น 8.X แล้ว ตั้งแต่เวอร์ชั่น 5 จนมาถึงปัจจุบันมีออะไรเปลี่ยนไปค่อนข้างเยอะ ที่เห็นได้ชัด ๆ เรื่องเวอร์ชั่นหลักของ PHP ที่เปลี่ยนจาก 5.X ไปเป็น 7.X เพิ่มความสามารถ ปรับปรุงเรื่องความปลอดภัยและ อื่น ๆ อีกมากมาย

เตรียมเครื่องมือ ทำความรู้จักเบื้องต้น

  • Composer เป็น PPM (PHP Packages management) จัดการ package ในภาษา PHP ส่วนของ Laravel จะให้ในการติดตั้ง global laravel/installers ศึกษาเพิ่มเติมที่นี่
    • composer global require laravel/installer
      • laravel new blog
    • composer create-project –prefer-dist laravel/laravel blog
  • VSCode เครื่องมือใช้สำหรับเขียนโค๊ด laravel ที่จะมี extensions ที่ช่วยเรื่องการเขียน Laravel ให้ดียิ่งขึ้น

เริ่มติดตั้งใช้งานเบื้องต้น

  1. ติดตั้ง composer ให้เรียบร้อย (ข้ามไป ไม่พูดถึงขั้นตอนนี้) จากนั้นตรวจสอบเวอร์ชั่น
    $ composer --version
    > Composer version 1.9.2 2020-01-14 16:30:31
    1. การติดตั้งแบบที่ 1 ติดตั้งด้วยการใช้ laravel cmd ที่ได้จากการติดตั้งจากขั้นตอนนี้
      $ composer global require laravel/installer
      $ laravel new blog
    2. การติดตั้งด้วย composer โดยตรง
      $ composer create-project --prefer-dist laravel/laravel blog
  2. ตัวอย่างใช้คำสั่ง
    $ laravel new poolsawat.com
    > Crafting application... Loading composer repositories with package information Installing dependencies (including require-dev) from lock file Package operations: 106 installs, 0 updates, 0 removals - Installing doctrine/inflector (2.0.3): Loading from cache - Installing doctrine/lexer (1.2.1): Loading from cache - Installing dragonmantank/cron-expression (3.0.1): Downloading (100%) - Installing voku/portable-ascii (1.5.3): Loading from cache ... > @php -r "file_exists('.env') || copy('.env.example', '.env');" > @php artisan key:generate --ansi [32mApplication key set successfully.[39m > Illuminate\Foundation\ComposerScripts::postAutoloadDump > @php artisan package:discover --ansi Discovered Package: [32mfacade/ignition[39m Discovered Package: [32mfideloper/proxy[39m Discovered Package: [32mfruitcake/laravel-cors[39m Discovered Package: [32mlaravel/tinker[39m Discovered Package: [32mnesbot/carbon[39m Discovered Package: [32mnunomaduro/collision[39m [32mPackage manifest generated successfully.[39m Application ready! Build something amazing.
  3. ตรวจสอบโครงสร้างไฟล์ จะได้หน้าตาแบบนี้

4. ทำการสร้าง route “hello” ที่ไฟล์ route/web.php

5. รันคำสั่ง start server
$ php artisan serve
> Starting Laravel development server: http://127.0.0.1:8000

6. เช็คผลการสร้าง route “hello” ได้ที่ http://localhost:8000/hello

นี่คือแบบที่ง่ายที่สุด สำหรับมือใหม่ บทความต่อ ๆ ไปจะมาเรียนรู้เรื่องอะไรกัน คอยติดตามด้วยนะครับ