เพื่อความสะดวกในการพัฒนา Application อีกทั้งยังเป็นการปรับปรุงคุณภาพของ Workflow ในขั้นตอนการ Development ปัจจุบันคงไม่มีใครปฎิเสธที่จะใช้งาน Docker และ สำหรับโปรเจค PHP นั้น Docker ช่วยให้พวกเราลดปัญหาเรื่อง Environment จริงตอน Deploy ขึ้น Production ได้เป็นอย่างมาก
ซึ่งการใช้ docker-compose
เพื่อ Setup โปรเจคนั้นเป็นวิธีที่พวกเรานิยมใช้กัน โดยมักจะมีโครงสร้างสำหรับโปรเจค PHP ประมาณนี้
Path
|-docker-compose.yml
+-php
| |-Dockerfile
| +-src
| | |-index.php
docker-compose.yml
version: "3.3"
services:
php:
build:
context: ./php
container_name: web
ports:
- "80:80"
restart: always
volumes:
- ${PROJECT_PATH}/php/src:/var/www/html
สำหรับโปรเจค PHP นั้นเราต้องการให้โฟลเดอร์ vendor
อยู่ที่ Path php/src/vendor
จึงทำให้เมื่อเราต้องการติดตั้ง Dependencies ยกตัวอย่างเช่น slim/slim
จะต้องทำการเปลี่ยน Path ซะก่อน
Terminal
cd php/src
composer require slim/slim
ปัญหาคือเมื่อเราเปิด Terminal จาก Editor เช่น Visual Studio Code เจ้า Default Working Directory จะอยู่ที่ Root Path ดังนั้นหากเราลืมเปลี่ยน Working Directory จะต้องมาเสียเวลา Cleanup ไฟล์ที่เกิดจากการติดตั้งผิดที่ผิดทาง
vendor
โชคดีที่เราสามารถตั้งค่า Custom Path สำหรับ โฟลเดอร์ vendor
ได้ โดยเราจะเพิ่มไฟล์ composer.json
ไว้ที่ Root Path
Path
|-composer.json
|-docker-compose.yml
+-php
composer.json
{
"config": {
"vendor-dir": "php/src/vendor"
}
}
หลังจากทำการตั้งค่า Custom Path ให้กับ vendor
แล้วเราสามารถใช้คำสั่งติดตั้ง Dependencies จาก Root Path ได้เลย
Terminal
composer require slim/slim
โฟลเดอร์ vendor
เกิดขึ้นในตำแหน่งที่เราต้องการ
Path
|-composer.json
+-php
| +-src
| | |-index.php
| | +-vendor
ซึ่งการบันทึกข้อมูล Dependencies ที่ได้ถูกติดตั้งไว้กับโปรเจค ยังคงถูกบันทึกไว้ที่ไฟล์ composer.json
ในตำแหน่ง Root Path
composer.json
{
"config": {
"vendor-dir": "php/src/vendor"
},
"require": {
"slim/slim": "^3.9"
}
}
ลองทดสอบการเรียกใช้ Dependencies โดยทดลองเขียนโค้ด PHP ง่ายๆ ตามตัวอย่างด้านล่าง
php/src/index.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Slim\App;
$app = new App;
var_dump($app);
สมมุติผมต้องการจะมีไฟล์ HomeController.php
ตามโครงสร้างด้านล่าง
Path
|-composer.json
+-php
| +-src
| | |-index.php
| | +-app
| | | +-Controllers
| | | | |-HomeController.php
| | +-vendor
ซึ่งผมจะใช้การทำ Autoload แบบ psr-4
เพื่อรองรับการใช้งาน namespace
php/src/app/Controllers/HomeController.php
<?php
namespace App\Controllers;
class HomeController
{
public function __construct()
{
echo 'Hello World';
}
}
หากยังไม่มีการทำ Autoload โค้ด PHP ด้านล่างจะต้องแสดง Error อย่างแน่นอน
php/src/index.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Slim\App;
use App\Controllers\BaseController;
$app = new App;
$c = new BaseController;
ซึ่งในการทำ Autoload นั้นเราจะเพิ่มไฟล์ composer.json
ไฟล์ที่ 2 ไว้ที่ Path ตามโครงสร้างด้านล่าง
Path
|-composer.json
+-php
| +-src
| | |-composer.json
| | |-index.php
เขียนโค้ดในไฟล์ composer.json
ตามตัวอย่างด้านล่าง เพื่อตั้งค่า Autoload
php/src/composer.json
{
"autoload": {
"psr-4": {
"App\\": "app"
}
}
}
composer
Custom Scriptปัญหาตอนนี้คือหากเราใช้คำสั้ง composer dump-autoload
จากตำแหน่ง Root จะไม่มีผลใดๆ เกิดขึ้นเพราะ composer
จะอ่านเพียงแค่ไฟล์ composer.json
ในตำแหน่ง Working Directory เท่านั้น
ซึ่งเราสามารถจะทำการเปลี่ยน Working Directory ด้วยคำสั่ง cd src/php
ก่อนใช้คำสั่ง composer dump-autoload
ก็ย่อมได้ แต่มันคงเหมือนจะเป็นการถอยหลังนะสิ เราจึงจะแก้ปัญหานี้ด้วย composer
Custom Script
แก้ไขไฟล์ composer.json
โดยเพิ่มโค้ดส่วนของ scripts
Section ตามตัวอย่างด้านล่าง
composer.json
{
"config": {
"vendor-dir": "php/src/vendor"
},
"require": {
"slim/slim": "^3.9"
},
"scripts": {
"autoload": "cd php/src && @composer dump-autoload"
}
}
การตั้งชื่อ Custom Script นั้นเราสามารถตั้งชื่ออะไรก็ได้ที่ไม่ไปซ้ำกับ Sub Command ของ
composer
หากเราอยากดูว่าcomposer
มี Sub Command อะไรบ้าง สามารถดูได้คร่าวๆ จากคำสั่งcomposer --help
หลังจากแก้ไขโค้ดในไฟล์ composer.json
เรียบร้อยแล้ว เราก็สามารถเรียกใช้ Custom Script ได้จากตำแหน่ง Root Path ด้วยตัวอย่างคำสั่งด้านล่างได้เลย
Terminal
composer autoload
เพียงแค่นี้เราก็สามารถกลับไปทดสอบโค้ด PHP ตามตัวอย่างข้างล่างได้อย่างไม่มี Error แล้วหล่ะ
php/src/index.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Slim\App;
use App\Controllers\BaseController;
$app = new App;
$c = new BaseController;
วิธีการที่ได้นำเสนอในบทความนี้ อาจจะมีการตั้งค่าที่ยุ่งย่างพอสมควร แต่เพื่อลดปัญหาในเรียกใช้คำสั่งผิดที่ ผู้เขียนคิดว่าเทคนิตนี้มีความคุ้มค่าที่จะทำ ซึ่งสุดท้ายเราสามารถทำเป็น Repository ไว้เพื่อใช้ในการ Scaffold โปรเจคที่จะเกิดขึ้นใหม่ต่อไป
อย่างไรก็ตามเทคนิคนี้ยังคงมีข้อจำกัดหากเราต้องการจะมีโปรเจค PHP มากกว่า 1 โปรเจค ภายใต้โปรเจค Docker เนื่องจากเราสามารถตั้งค่า Custom Path สำหรับ โฟลเดอร์ vendor
ได้เพียงค่าเดียวเท่านั้น