Elemental เป็นเฟรมเวิร์ก PHP ที่พัฒนาขึ้นตั้งแต่เริ่มต้นสำหรับประสบการณ์การเข้ารหัสแบบไดนามิกที่ใช้งานง่าย มันรวมคุณสมบัติเช่นการฉีดพึ่งพาและติดตามสถาปัตยกรรม MVC เพื่อปรับปรุงการพัฒนาเว็บและปรับปรุงองค์กรรหัส ออกแบบด้วยความหลงใหลในความเรียบง่ายและความยืดหยุ่นมันเชิญชวนให้นักพัฒนาเข้าสู่อาณาจักรที่พวกเขาสามารถใช้การควบคุมที่ไม่มีใครเทียบและได้รับความเข้าใจอย่างลึกซึ้งเกี่ยวกับเครื่องมือในการกำจัดของพวกเขา
เพื่อแสดงความสามารถของ Elemental แพลตฟอร์มการทำงานที่เรียกว่า Inkwell ได้รับการพัฒนาโดยใช้ Elemental Inkwell เป็นพื้นที่ที่ไม่เหมือนใครซึ่งอุทิศให้กับสาระสำคัญของการเล่าเรื่อง สอดคล้องกับเป้าหมายของ Elemental ที่ไม่มีการพึ่งพาภายนอก Inkwell ได้รับการออกแบบโดยใช้ HTML, CSS, JS และ PHP ธรรมดาเท่านั้น
อย่าลังเลที่จะเจาะลึกทั้งแพลตฟอร์มสดและ codebase ที่เกี่ยวข้อง สำรวจคุณสมบัติของ Inkwell เพื่อทำความเข้าใจว่าองค์ประกอบสามารถควบคุมได้อย่างไรสำหรับโครงการของคุณเอง
ดูแรงบันดาลใจเบื้องหลังการสร้าง องค์ประกอบ
Elemental ได้รับการออกแบบโดยมีเป้าหมายที่จะไม่มีสาย ไม่มีการพึ่งพาห้องสมุดภายนอกหรือเฟรมเวิร์ก จุดมุ่งหมายคือการให้ความรู้สึกควบคุมอย่างแท้จริงแก่นักพัฒนา - ประตูเปิดเพื่อสำรวจอย่างอิสระและเข้าใจสิ่งมหัศจรรย์ที่ทรงพลัง
เป้าหมายที่ครอบคลุม? ให้นักพัฒนายอมรับอย่างเต็มที่และใช้ประโยชน์จากความสง่างามของบทคัดย่อที่ทรงพลังเช่นภาชนะบรรจุ DI, Orms, Middlewares และอื่น ๆ แต่นี่คือนักเตะ - องค์ประกอบไม่ได้เป็นเพียงการชี้ทาง มันกำลังส่งกุญแจให้คุณเพื่อคลี่คลายความลึกลับช่วยให้คุณสำรวจว่า abstractions เหล่านี้ถูกวางไว้ในรหัสอย่างไร
ในความเป็นจริงคุณได้รับการสนับสนุนไม่เพียง แต่จะไปตามเส้นทางเท่านั้น ดำดิ่งลงไปใน codebase ผ่า abstractions และเข้าใจการทำงานภายในของพวกเขา อย่าลังเลที่จะปรับแต่งและการทดลองเพราะองค์ประกอบไม่ได้เป็นเพียงกรอบการทำงาน - เป็นคำเชิญแบบเปิดเพื่อกำหนดรูปทรงและหล่อหลอมเครื่องมือตามการกำจัดของคุณ เพราะการเข้ารหัสไม่ควรเป็นเขาวงกต มันควรจะเป็นการเดินทาง มาเดินทางด้วยกันกันเถอะ
ซึ่งแตกต่างจากเฟรมเวิร์กอื่น ๆ องค์ประกอบไม่พึ่งพานักแต่งเพลงหรือไลบรารีภายนอก มันง่ายเหมือนการโคลนนิ่งที่เก็บและเริ่มต้นด้วยการติดตั้ง PHP ที่ดีในระบบของคุณ
เปิดเทอร์มินัลของคุณและดำเนินการคำสั่งต่อไปนี้:
git clone https://github.com/aneesmuzzafer/elemental.gitไม่ต้องกังวลเกี่ยวกับผู้จัดการแพ็คเกจหรือการพึ่งพา - องค์ประกอบถูกสร้างขึ้นตั้งแต่เริ่มต้นเพื่อปลดปล่อยคุณจากข้อกังวลดังกล่าว
สำหรับผู้ที่ชอบเส้นทางนักแต่งเพลงการสร้างแอพองค์ประกอบใหม่เป็นเพียงคำสั่งที่อยู่ห่างออกไป:
composer create-project fragment/elemental sample-app สิ่งนี้จะสร้างโครงการด้วยไฟล์ composer.json
เมื่อโครงการของคุณพร้อมแล้วให้เริ่มต้นเซิร์ฟเวอร์การพัฒนาท้องถิ่นด้วยคำสั่ง ignite โดยใช้เครื่องมือบรรทัดคำสั่งของเรา เทียน :
cd sample-app
php candle ignitevoila ตอนนี้แอปพลิเคชันของคุณสามารถเข้าถึงได้ที่ http://127.0.0.1:8000
เราได้ดูแลการตั้งค่าพื้นฐานเพื่อให้คุณสามารถมุ่งเน้นไปที่เวทมนตร์
ปล่อยให้ความลุ่มหลงเริ่มต้นขึ้น!
คุณลักษณะที่สำคัญที่สุดขององค์ประกอบคือภาชนะฉีดพึ่งพาซึ่งใช้สำหรับการจัดการการพึ่งพาคลาสและการฉีดพึ่งพาการพึ่งพา
การฉีดพึ่งพาเป็นรูปแบบการออกแบบในการพัฒนาซอฟต์แวร์ที่เกี่ยวข้องกับวิธีการที่ส่วนประกอบได้รับการพึ่งพาของพวกเขา ในระบบดั้งเดิมชั้นเรียนมีหน้าที่รับผิดชอบในการสร้างการพึ่งพาของตัวเอง ด้วย DI ความรับผิดชอบในการสร้างและให้การพึ่งพานั้นถูกย้ายออกนอกชั้นเรียน แทนที่จะเป็นคลาสที่สร้างการพึ่งพาพวกเขาจะ "ฉีด" ลงในชั้นเรียนจากแหล่งภายนอก
DI ช่วยในการบรรลุรหัสคู่และบำรุงรักษาได้มากขึ้น มันส่งเสริมการแยกข้อกังวลโดยอนุญาตให้แต่ละชั้นเรียนมุ่งเน้นไปที่ฟังก์ชั่นเฉพาะของมันโดยไม่ต้องกังวลเกี่ยวกับวิธีการสร้างหรือรับการอ้างอิง
การฉีดขึ้นอยู่กับการพึ่งพาคือการดำเนินการเฉพาะของแนวคิดที่กว้างขึ้นที่เรียกว่าการผกผันของการควบคุม (IOC) IOC แสดงถึงกระบวนทัศน์การออกแบบที่การควบคุมการไหลของโปรแกรมกลับด้านหรือส่งไปยังเอนทิตีภายนอกภาชนะหรือเฟรมเวิร์ก
ในองค์ประกอบเมื่อคุณใช้การฉีดพึ่งพา (DI) หากคลาสไม่พึ่งพาคลาสอื่น ๆ หรือขึ้นอยู่กับคลาสคอนกรีตเท่านั้น (ไม่ใช่ส่วนต่อประสานนามธรรม) คุณไม่จำเป็นต้องบอก DI คอนเทนเนอร์อย่างชัดเจนถึงวิธีการสร้างอินสแตนซ์ของคลาสนั้น คอนเทนเนอร์ DI จะคิดออกโดยอัตโนมัติ
คอนเทนเนอร์จะพยายามสร้างอินสแตนซ์ของคลาสและหากคลาสนั้นมีการพึ่งพาคลาสอื่น ๆ คอนเทนเนอร์จะพยายามแก้ไขการพึ่งพาเหล่านั้นอีกครั้งเช่นกัน กระบวนการนี้จะดำเนินต่อไปจนกว่าคลาสที่จำเป็นทั้งหมดจะได้รับการแก้ไขสำเร็จ ดังนั้นคุณไม่จำเป็นต้องระบุวิธีการสร้างแต่ละชั้นเรียนด้วยตนเอง - คอนเทนเนอร์ DI จะดูแลคุณ
<?php
class MailService {
public function __construct ( private MailerAgent $ mailer ) {
}
}
// Inside some other class
class UserController {
public function sendMail ( MailService $ mailService )
{
$ mailService -> sendMail ();
}
} ที่นี่โดยพิมพ์การพิมพ์ MailService ภายในอาร์กิวเมนต์เมธอด Elemental สามารถแก้ไขคลาสและสร้างอินสแตนซ์ของคลาสนี้และส่งผ่านไปยัง sendMail เพื่อให้คุณสามารถใช้งานได้โดยไม่ต้องกังวลเกี่ยวกับการพึ่งพาของคลาส MailService อย่างที่คุณเห็น MailService นั้นขึ้นอยู่กับ MailerAgent คลาสอื่น ๆ อย่างไรก็ตาม Elemental ดูแลการแก้ไขคลาส MailerAgent ที่อยู่เบื้องหลังฉากส่งผ่านไปยัง MailService ในขณะที่สร้างอินสแตนซ์และให้อินสแตนซ์นั้นสำหรับการใช้งานของคุณ
"ดังนั้นการพึ่งพาการฉีดแบบนี้จะเพียงแค่พิมพ์ชื่อคลาสทำงานในองค์ประกอบ" ฟังก์ชั่น constructor คลาสทั้งหมด controller methods ทั้งหมดและวิธี handle ของคลาสการสร้างคำสั่ง
เบื้องหลัง Elemental จะแก้ไขคลาสหรืออินเทอร์เฟซเป็นอินสแตนซ์คอนกรีตโดยดูที่การเชื่อมโยงใด ๆ ที่ได้รับการลงทะเบียน กล่าวอีกนัยหนึ่งเพื่อบอกกรอบอย่างชัดเจนว่าจะแก้ไขอินสแตนซ์ของคลาสหรืออินเทอร์เฟซโดยเฉพาะคุณจะต้องลงทะเบียนการเชื่อมโยงของคลาสหรืออินเตอร์เฟสนั้นโดยใช้วิธี bind บน Application ซ์แอปพลิเคชันผ่านคลาสหรือชื่ออินเทอร์เฟซที่เราต้องการลงทะเบียนพร้อมกับการปิด
app ()-> bind (MailService::class, function () {
// Run some logic, for example, decide on the mail agent to be passed to its constructor depending on some factors.
return new MailService ( app ()-> make (MailAgent::class));
});โปรดทราบว่าโดยทั่วไปคุณจะต้องผูกคลาสเฉพาะเมื่อคุณต้องการเรียกใช้ตรรกะเพิ่มเติมบางอย่างสำหรับการแก้ไขคลาสหรือคุณต้องผูกอินเทอร์เฟซกับการใช้งานที่เป็นรูปธรรม มิฉะนั้นองค์ประกอบจะแก้ไขคลาสโดยไม่ต้องให้คุณผูกมัดอย่างชัดเจน
เมธอด singleton ผูกคลาสหรืออินเทอร์เฟซกับคอนเทนเนอร์เพื่อให้แน่ใจว่าได้รับการแก้ไขเพียงครั้งเดียว หลังจากความละเอียดเริ่มต้นการเรียกใด ๆ ที่ตามมาไปยังคอนเทนเนอร์สำหรับการเชื่อมโยงเดียวกันจะส่งคืนอินสแตนซ์ของวัตถุเดียวกัน
app ()-> singleton (DatabaseConnection::class, function () {
return new DatabaseConnection ( ' localhost ' , ' username ' , ' password ' );
});
// Later in the code
$ databaseConnection1 = app ()-> make (DatabaseConnection::class);
$ databaseConnection2 = app ()-> make (DatabaseConnection::class);
// $databaseConnection1 and $databaseConnection2 will reference the same instance ในขณะที่การลงทะเบียนการเชื่อมโยงทุกที่ในแอพมักจะต้องผูกมันในขณะที่แอปพลิเคชันเป็น bootstrapping เพื่อให้ส่วนประกอบอื่น ๆ ของแอพสามารถเริ่มใช้งานได้ Elemental จัดเตรียมสถานที่พิเศษในการลงทะเบียนการผูกทั้งหมดของแอพและดำเนินการตรรกะ bootstrapping อื่น ๆ ที่แอปพลิเคชันของคุณต้องการ นี่คือ AppBootstrapAppServiceProvider ผู้ให้บริการแอพมี register และวิธีการ boot
ภายในวิธี register คุณควรผูกสิ่งต่าง ๆ ไว้ในภาชนะฉีดพึ่งพา อย่างไรก็ตามคุณไม่ควรพยายามแก้ไขการผูกมัดใด ๆ เส้นทางหรือเรียกใช้ฟังก์ชันการทำงานอื่น ๆ ภายในวิธี register มิฉะนั้นคุณอาจใช้บริการภายในภาชนะที่ยังไม่ได้โหลดโดยไม่ได้ตั้งใจ
วิธีนี้เรียกว่าหลังจากผู้ให้บริการรายอื่นทั้งหมดได้รับการลงทะเบียนแล้วอนุญาตให้เข้าถึงบริการทั้งหมดที่ลงทะเบียนโดยเฟรมเวิร์ก ตรรกะการเริ่มต้นใด ๆ ที่คุณต้องการดำเนินการควรวางไว้ที่นี่
<?php
namespace App Bootstrap ;
use App Services Auth ;
class AppServiceProvider
{
public function register (): void
{
app ()-> singleton (Auth::class, function () {
return new Auth ();
});
}
public function boot (): void
{
// Additional initialization logic can be placed here
}
} คุณสามารถใช้เมธอด make เพื่อแก้ไขอินสแตนซ์คลาสจากคอนเทนเนอร์ DI วิธี make บนอินสแตนซ์แอปพลิเคชันยอมรับชื่อของคลาสหรืออินเทอร์เฟซที่คุณต้องการแก้ไข:
use App Services MailService ;
$ mailService = app ()-> make (MailService::class); คุณอาจได้รับอินสแตนซ์แอปพลิเคชันโดยใช้อินสแตน instance วิธีการคงที่โดยตรงในคลาส Application
use Core Main Application ;
use App Services MailService ;
$ mailService = Application:: instance ()-> make (MailService::class); วิธี make นั้นมีประโยชน์อย่างยิ่งเมื่อพยายามแก้ไขคลาสจากภายในองค์ประกอบรหัสซึ่งไม่สามารถฉีดพึ่งพาได้โดยใช้การปรับพิมพ์ประเภท ในสถานการณ์เช่นนี้คุณสามารถขอคอนเทนเนอร์ฉีดพึ่งพาของแอปพลิเคชันเพื่อแก้ไขอินสแตนซ์ให้คุณได้อย่างชัดเจน
เส้นทางถูกกำหนดไว้ในไฟล์ approutes.php ช่วยให้นักพัฒนาสามารถลงทะเบียนเส้นทางต่าง ๆ เพื่อจัดการคำขอ HTTP ที่แตกต่างกันได้อย่างง่ายดาย
เส้นทางจะลงทะเบียนโดยการเรียกใช้วิธีการที่เกี่ยวข้องบนซุ้มเส้นทางเช่น Route::get() และเกี่ยวข้องกับการระบุรูปแบบ URI เป็นอาร์กิวเมนต์แรก อาร์กิวเมนต์ที่สองอาจเป็นการปิดหรืออาร์เรย์ที่กำหนดคอนโทรลเลอร์และวิธีการที่รับผิดชอบในการจัดการคำขอ
ตัวอย่างเช่น:
<?php
use App Controllers AuthController ;
use Core Facade Route ;
Route:: get ( " /settings " , function () {
// handling logic goes here
});
Route:: post ( " /register " , [AuthController::class, " register " ]);เมื่อใดก็ตามที่การร้องขอ URI มีการจับคู่วิธีการปิดที่สอดคล้องกันหรือคอนโทรลเลอร์จะถูกดำเนินการและการตอบกลับจะถูกสร้างขึ้นและส่งกลับไปยังเบราว์เซอร์
คุณสามารถลงทะเบียนเส้นทางที่ตอบสนองต่อคำกริยา HTTP ใด ๆ โดยใช้วิธีการต่อไปนี้:
Route::get($uri, $callback);Route::post($uri, $callback);Route::put($uri, $callback);Route::patch($uri, $callback);Route::delete($uri, $callback);Route::options($uri, $callback); บางครั้งคุณจะต้องจับส่วนของ URI ภายในเส้นทางของคุณ ตัวอย่างเช่นคุณอาจต้องจับ ID ของผู้ใช้จาก URL คุณสามารถทำได้โดยการกำหนดพารามิเตอร์เส้นทาง:
Route:: get ( ' /user/{id} ' , function ( string $ id ) {
return ' User ' . $ id ;
});
Route:: get ( " /story/{id} " , function ( $ id ) { /*...*/ });คุณสามารถกำหนดพารามิเตอร์เส้นทางได้มากเท่าที่กำหนดไว้ในเส้นทางของคุณ:
Route:: post ( " story/edit/{id} " , [StoryController::class, " edit " ]);
Route:: get ( " story/{story_id}/comment/{comment_id} " , [StoryController::class, " comment " ]);สิ่งเหล่านี้จะถูกส่งผ่านไปยังวิธีการควบคุมเช่นกัน
องค์ประกอบจัดการการฉีดการพึ่งพาที่จำเป็นสำหรับวิธีการควบคุมของคุณอย่างราบรื่น สิ่งนี้ช่วยให้คุณสามารถระบุการพึ่งพาที่ต้องการโดยเส้นทางของคุณในลายเซ็นการโทรกลับโดยใช้การแวะน้ำประเภท Elemental ดูแลการแก้ไขโดยอัตโนมัติและฉีดพึ่งพาที่ประกาศไว้ในการโทรกลับ
ตัวอย่างเช่นหากคุณพิมพ์ Hint CoreRequestRequest ภายในการโทรกลับ Elemental ทำให้มั่นใจได้ว่าคำขอ HTTP ปัจจุบันจะถูกฉีดลงในเส้นทางการโทรกลับของคุณโดยอัตโนมัติ:
<?php
use Core Request Request ;
Route:: get ( ' /users ' , function ( Request $ request ) {
// ...
});คุณสามารถใส่การพึ่งพาที่พิมพ์และพารามิเตอร์เส้นทางในลำดับใดก็ได้
เมื่อคุณผ่านรหัสโมเดลเป็นพารามิเตอร์ไปยังเส้นทางหรือการกระทำของคอนโทรลเลอร์วิธีการทั่วไปจะเกี่ยวข้องกับการสืบค้นฐานข้อมูลเพื่อดึงโมเดลที่สอดคล้องกันตาม ID นั้น Elemental ทำให้กระบวนการนี้ง่ายขึ้นผ่านการผูกโมเดลเส้นทางนำเสนอวิธีที่สะดวกในการฉีดอินสแตนซ์โมเดลลงในเส้นทางของคุณโดยตรงโดยอัตโนมัติ
ตัวอย่างเช่นแทนที่จะฉีดเพียงแค่ ID ของผู้ใช้ในเส้นทางของคุณคุณมีตัวเลือกในการฉีดอินสแตนซ์รุ่นผู้ใช้ทั้งหมดที่สอดคล้องกับ ID ที่กำหนด
ในบริบทของเส้นทางหรือการกระทำของคอนโทรลเลอร์แบบจำลองจะถูกกำหนดโดยใช้ชื่อตัวแปรชนิดที่ปรับเปลี่ยนที่ตรงกับเซ็กเมนต์เฉพาะในเส้นทาง ตัวอย่างเช่น:
use App Models User ;
Route:: get ( ' /users/{user} ' , function ( User $ user ) {
return $ user -> email ;
}); บางครั้งคุณอาจต้องการแก้ไขโมเดลโดยใช้คอลัมน์อื่นที่ไม่ใช่ id ในการทำเช่นนั้นคุณสามารถระบุคอลัมน์ในนิยามพารามิเตอร์เส้นทาง:
use App Models User ;
Route:: get ( ' /users/{user:email} ' , function ( User $ user ) {
return $ user ;
});ในสถานการณ์นี้ Elemental จะฉีดอินสแตนซ์รุ่นที่มีอีเมลที่ตรงกับค่าที่สอดคล้องกันจาก URI คำขอ
แน่นอนว่าการผูกมัดแบบจำลองเส้นทางยังทำงานร่วมกับวิธีการควบคุม
หากไม่พบอินสแตนซ์ของแบบจำลองการจับคู่ในฐานข้อมูล ModelNotFoundException จะถูกโยนโดยแอป คุณสามารถจัดการกับข้อยกเว้นดังกล่าวและควบคุมพฤติกรรมของข้อยกเว้นดังกล่าวและข้อยกเว้นอื่น ๆ ที่แอพพลิเคชั่นในคลาส ExceptionsHandler เพิ่มเติมในภายหลัง
การใช้วิธี Route::fallback คุณอาจกำหนดเส้นทางที่จะดำเนินการเมื่อไม่มีเส้นทางอื่นตรงกับคำขอที่เข้ามา
Route:: fallback ( function () {
// ...
}); คำสั่ง route:list เทียนจะให้รายการเส้นทางทั้งหมดที่กำหนดไว้ในแอปพลิเคชัน:
php candle route:list แทนที่จะรวบรวมตรรกะการจัดการคำขอทั้งหมดภายในไฟล์เส้นทางของคุณให้พิจารณาการจัดโครงสร้างพฤติกรรมนี้ผ่านคลาส "คอนโทรลเลอร์" คอนโทรลเลอร์ช่วยให้คุณจัดระเบียบตรรกะการจัดการคำขอที่เกี่ยวข้องในชั้นเรียนที่มีความเหนียว ตัวอย่างเช่นคลาส UserController สามารถจัดการคำขอที่เข้ามาต่าง ๆ ที่เกี่ยวข้องกับผู้ใช้เช่นการแสดงการสร้างการอัปเดตและการลบผู้ใช้ คลาสคอนโทรลเลอร์เหล่านี้จะถูกจัดเก็บตามอัตภาพในไดเรกทอรี app/Controllers
ในการสร้างคอนโทรลเลอร์ใหม่คุณสามารถเรียกใช้คำสั่ง build:controller Candle
php candle build:controller UserController สิ่งนี้จะสร้างไฟล์ใหม่ที่ชื่อว่า "usercontroller.php" ภายในไดเรกทอรี app/Controllers
คอนโทรลเลอร์อาจมีวิธีการสาธารณะจำนวนมากซึ่งจะตอบสนองต่อคำขอ HTTP ที่เข้ามา:
<?php
use App Services Auth ;
namespace App Controllers ;
class AuthController
{
public function showRegister ()
{
return view ( " Register " )-> withLayout ( " layouts.DashboardLayout " );
}
public function logout ()
{
Auth:: logout ();
redirect ( " / " );
}
}หลังจากสร้างคลาสคอนโทรลเลอร์และวิธีการแล้วคุณสามารถกำหนดเส้นทางไปยังวิธีการควบคุมดังนี้:
use App Controllers UserController ;
Route:: get ( " /register " , [AuthController::class, " showRegister " ]); เมื่อคำขอที่ได้รับตรงกับเส้นทาง URI ที่กำหนดวิธี showRegister ในคลาส AppControllersUserController จะถูกเรียกและวิธีการจะได้รับพารามิเตอร์เส้นทางที่สอดคล้องกัน
คอนเทนเนอร์บริการองค์ประกอบมีหน้าที่รับผิดชอบในการแก้ไขอินสแตนซ์ของตัวควบคุมทั้งหมด ดังนั้นคุณสามารถใช้การแวะน้ำประเภทในตัวสร้างคอนโทรลเลอร์ของคุณเพื่อระบุการพึ่งพาใด ๆ ที่อาจต้องใช้ การพึ่งพาที่ระบุไว้จะได้รับการแก้ไขโดยอัตโนมัติและฉีดลงในอินสแตนซ์คอนโทรลเลอร์
<?php
namespace App Controllers ;
use Core Database Database ;
class UserController
{
/**
* Create a new controller instance.
*/
public function __construct (
public Database $ db ,
) {}
} นอกเหนือจากการพึ่งพาการฉีดผ่านตัวสร้างแล้วคุณยังสามารถใช้การแวะน้ำประเภทสำหรับการพึ่งพาในวิธีการของคอนโทรลเลอร์ของคุณ กรณีการใช้งานทั่วไปสำหรับการฉีดวิธีการกำลังฉีด CoreRequestRequest หรืออินสแตนซ์บริการใด ๆ ลงในวิธีการควบคุมของคุณ:
สร้างและจัดการคอนโทรลเลอร์เพื่อจัดการคำขออย่างมีประสิทธิภาพ
<?php
namespace App Controllers ;
use Core Request Request ;
use App Services Auth ;
class StoryController
{
public function create ( Request $ request )
{
$ data = $ request -> data ();
$ user = Auth:: user ();
$ story = Story:: create ([...]);
return redirect ( " /story/ $ story -> id " );
}
}f วิธีการคอนโทรลเลอร์ของคุณคาดการณ์อินพุตจากพารามิเตอร์เส้นทางคุณมีความยืดหยุ่นในการแสดงรายการอาร์กิวเมนต์ของคุณในลำดับใด ๆ ตัวอย่างเช่นพิจารณานิยามเส้นทางต่อไปนี้:
Route:: post ( " story/update/{id} " , [StoryController::class, " update " ]); คุณยังสามารถพิมพ์ Hint The CoreRequestRequest และเข้าถึงพารามิเตอร์ id ของคุณโดยกำหนดวิธีคอนโทรลเลอร์ของคุณดังนี้:
<?php
namespace App Controllers ;
use Core Request Request ;
class StoryController
{
public function update ( string $ id , Request $ request )
{
// Update $story
return redirect ( " /story/ $ story -> id " );
}
} คลาส CoreRequestRequest ใน Elemental เสนอวิธีการเชิงวัตถุสำหรับการมีส่วนร่วมกับคำขอ HTTP ปัจจุบันที่จัดการโดยแอปพลิเคชันของคุณ มันอำนวยความสะดวกในการดึงข้อมูลอินพุตคุกกี้และไฟล์ที่ส่งไปพร้อมกับคำขอ
ในการรับอินสแตนซ์การร้องขอ HTTP ปัจจุบันผ่านการฉีดพึ่งพาคุณสามารถใช้ประเภทการแช่แข็งสำหรับคลาส CoreRequestRequest ในการปิดเส้นทางหรือวิธีการควบคุมของคุณ คอนเทนเนอร์บริการจะส่งอินสแตนซ์คำขอขาเข้าโดยอัตโนมัติ
<?php
namespace App Controllers ;
use App Models Category ;
use Core Request Request ;
class CategoryController
{
public function store ( Request $ request )
{
$ name = $ request -> data ()[ " name " ];
$ category = Category:: where ([ " name " => $ name ]);
if ( $ category ) {
return view ( " Category " , [ " categories " => Category:: all (), " msg " => " Category already exists! " ])-> withLayout ( " layouts.DashboardLayout " );
}
Category:: create ( $ request -> data ());
redirect ( " /category " );
}
}คอนเทนเนอร์บริการจะส่งคำขอเข้ามาในการปิดเส้นทางโดยอัตโนมัติเช่นกัน
หากเมธอดคอนโทรลเลอร์ของคุณคาดการณ์อินพุตจากพารามิเตอร์เส้นทางคุณมีความยืดหยุ่นในการแสดงรายการอาร์กิวเมนต์ของคุณในลำดับใด ๆ ตัวอย่างเช่นพิจารณานิยามเส้นทางต่อไปนี้:
Route:: post ( " story/update/{id} " , [StoryController::class, " update " ]); คุณยังสามารถพิมพ์ Hint The CoreRequestRequest และเข้าถึงพารามิเตอร์ id ของคุณโดยกำหนดวิธีคอนโทรลเลอร์ของคุณดังนี้:
<?php
namespace App Controllers ;
use Core Request Request ;
class StoryController
{
public function update ( string $ id , Request $ request )
{
// Update $story
return redirect ( " /story/ $ story -> id " );
}
} คุณอาจได้รับข้อมูลอินพุตของคำขอที่เข้ามาทั้งหมดเป็น array โดยใช้เมธอด data() วิธีนี้อาจใช้ไม่ว่าคำขอที่เข้ามานั้นมาจากแบบฟอร์ม HTML หรือเป็นคำขอ XHR:
$ data = $ request -> data (); คุณสามารถเข้าถึงอินพุตของผู้ใช้ทั้งหมดจากอินสแตนซ์ Request ของคุณโดยไม่ต้องกังวลเกี่ยวกับคำกริยา HTTP ที่ใช้สำหรับคำขอ โดยไม่คำนึงถึงคำกริยา HTTP วิธี data อาจใช้ในการดึงข้อมูลผู้ใช้:
$ name = $ request -> data ()[ " name " ]; อินสแตนซ์ CoreRequestRequest มีวิธีการที่หลากหลายสำหรับการตรวจสอบคำขอ HTTP ที่เข้ามา มาพูดคุยกันสองสามวิธีที่สำคัญที่สุดด้านล่าง
คุณสามารถเรียกคืนส่วนหัวคำขอจากอินสแตนซ์ CoreRequestRequest โดยใช้เมธอด headers
$ headers = $ request -> headers (); คุณสามารถเรียกคืนวิธีการร้องขอโดยใช้ method การเรียกใช้อินสแตนซ์ CoreRequestRequest
$ method = $ request -> method (); คุณสามารถเรียกคืนคำขอ URI จากอินสแตนซ์ CoreRequestRequest โดยใช้วิธี uri
$ uri = $ request -> uri (); คุณสามารถเรียกคืนคุกกี้คำขอจากอินสแตนซ์ CoreRequestRequest โดยใช้วิธี cookies
$ cookies = $ request -> cookies (); คุณสามารถดึงเนื้อหาดิบจากอินสแตนซ์ CoreRequestRequest โดยใช้วิธี rawContent
$ content = $ request -> rawContent ();ระวังเมื่อต้องรับมือกับเนื้อหาดิบของคำขอ
คุณสามารถเรียกคืนไฟล์จากอินสแตนซ์ CoreRequestRequest โดยใช้วิธี files
$ files = $ request -> files (); วิธี ip อาจใช้เพื่อดึงที่อยู่ IP ของไคลเอนต์ที่ส่งคำขอไปยังแอปพลิเคชันของคุณ:
$ ipAddress = $ request -> ip (); วิธี port อาจใช้เพื่อดึงที่อยู่พอร์ตของไคลเอนต์ที่ส่งคำขอไปยังแอปพลิเคชันของคุณ:
$ port = $ request -> port (); คุณสามารถดึงอินสแตนซ์ประเภทเนื้อหาจากอินสแตนซ์ CoreRequestRequest โดยใช้เมธอด contentType
$ contentType = $ request -> contentType (); คุณสามารถดึงสตริงแบบสอบถามของคำขอโดยใช้วิธี queryString
$ query = $ request -> queryString (); คุณสามารถเรียกคืนเนื้อหาข้อความของคำขอโดยใช้วิธี text ที่มีการตั้งค่าประเภทเนื้อหาเป็น text/plain
$ text = $ request -> text (); คุณสามารถเรียกคืนเนื้อหา JS ของคำขอโดยใช้วิธี js หากเนื้อหาประเภทเนื้อหาถูกตั้งค่าเป็น application/javascript
$ js = $ request -> js (); คุณสามารถดึงเนื้อหา HTML ของคำขอโดยใช้วิธี html ได้หากตั้งค่าประเภทเนื้อหาเป็น text/html
$ js = $ request -> html (); คุณสามารถเรียกคืนเนื้อหา JSON ของคำขอโดยใช้วิธี json หากเนื้อหาประเภทเนื้อหาถูกตั้งค่าเป็น application/json $request->data() ส่งคืนข้อมูล JSON ทั้งหมดที่ส่งผ่านไปยังคำขอ อย่างไรก็ตาม,
$ jsonData = $ request -> json (); $request->data() มีข้อมูล JSON ทั้งหมดพร้อมกับอินพุตที่ส่งผ่านพารามิเตอร์แบบสอบถามในคำขอ อย่างไรก็ตาม $request->json() สามารถใช้เพื่อดึงเนื้อหา JSON เท่านั้น
คุณสามารถดึงเนื้อหา XML ของคำขอโดยใช้วิธี xml ได้หากตั้งค่าประเภทเนื้อหาเป็น application/json
$ xmlData = $ request -> xml ();ทุกเส้นทางและคอนโทรลเลอร์คาดว่าจะให้คำตอบสำหรับการส่งมอบให้กับเบราว์เซอร์ของผู้ใช้ Elemental นำเสนอวิธีการต่าง ๆ สำหรับการสร้างการตอบสนอง รูปแบบการตอบสนองที่ง่ายที่สุดเกี่ยวข้องกับการส่งคืนสตริงโดยตรงจากเส้นทางหรือคอนโทรลเลอร์ เฟรมเวิร์กจะแปลงสตริงนี้ให้เป็นการตอบกลับ HTTP ที่สมบูรณ์
Route:: get ( ' / ' , function () {
return ' Hello World ' ;
});นอกเหนือจากการส่งคืนสตริงจากเส้นทางและตัวควบคุมของคุณแล้วคุณอาจส่งคืนอาร์เรย์หรือวัตถุ เฟรมเวิร์กจะแปลงเป็นคำตอบ JSON โดยอัตโนมัติ:
Route:: get ( ' / ' , function () {
return [ 1 , 2 , 3 ];
}); โดยปกติแล้วคุณจะไม่เพียงแค่คืนสตริงหรืออาร์เรย์ที่ตรงไปตรงมาจากการกระทำเส้นทางของคุณ แต่คุณมักจะส่งคืนอินสแตนซ์ที่สมบูรณ์ของ CoreResponseResponse หรือมุมมอง
การส่งคืนอินสแตนซ์ Response กลับแบบเต็มช่วยให้คุณปรับแต่งรหัสสถานะและส่วนหัวของ HTTP ของการตอบกลับ คุณสามารถฉีดอินสแตนซ์การตอบกลับได้โดยพิมพ์อินสแตนซ์การตอบกลับภายในคอนโทรลเลอร์หรือการปิดเส้นทางของคุณ
use Core Response Response ;
Route:: get ( ' /home ' , function ( Response $ response ) {
$ response -> setHeader ( " content-type " , " text/plain " )
-> setStatusCode ( 200 )
-> setContent ( " Hello World " );
return $ response ;
}); แน่นอนว่าคุณสามารถส่งคืน view จากคอนโทรลเลอร์ อย่างไรก็ตามหากคุณต้องการควบคุมสถานะและส่วนหัวของการตอบกลับ แต่ยังต้องส่งคืน view เป็นเนื้อหาของการตอบกลับคุณสามารถทำได้ดังต่อไปนี้:
use Core Response Response ;
class UserController {
public function register ( Response $ response ){
$ response -> setHeader ( " x-is_register " , " true " );
return view ( " Register " );
}
}สิ่งนี้จะตั้งค่าส่วนหัวโดยอัตโนมัติในการตอบกลับมุมมองที่จะถูกส่งไปยังเบราว์เซอร์
โปรดทราบว่าวิธีการตอบสนองส่วนใหญ่สามารถเป็นโซ่ได้ช่วยให้สามารถสร้างอินสแตนซ์การตอบสนองได้อย่างคล่องแคล่ว
คุณสามารถตั้งค่าเนื้อหาของการตอบกลับโดยใช้วิธี setContent บนอินสแตนซ์การตอบกลับ
$ response -> setContent ( " ... " ); อย่างไรก็ตามหากคุณต้องการผนวกเนื้อหาของการตอบกลับคุณสามารถทำได้โดยใช้วิธีการต่อ appendContent ในอินสแตนซ์การตอบกลับ
$ response -> appendContent ( " ... " ); คุณสามารถตั้งค่าส่วนหัวในอินสแตนซ์การตอบกลับโดยใช้วิธี setHeader
$ response -> setHeader ( " content-type " , " text/plain " ); อย่างไรก็ตามหากคุณต้องการตั้งส่วนหัวหลาย ๆ ตัวพร้อมกันคุณสามารถทำได้โดยใช้วิธี setHeaders และผ่านอาร์เรย์ของส่วนหัว
$ response -> setHeaders ([ " content-type " => " text/html " , ...]); คุณสามารถตั้งค่ารหัสสถานะของการตอบกลับโดยตรงโดยใช้วิธี setHeader บนอินสแตนซ์การตอบกลับ
$ response -> setStatusCode ( 301 );ข้อความสถานะจะถูกตั้งค่าโดยค่าเริ่มต้นสำหรับรหัสสถานะทั่วไป
คุณสามารถสร้างการตอบสนองการเปลี่ยนเส้นทางที่มีส่วนหัวที่เหมาะสมที่จำเป็นในการเปลี่ยนเส้นทางผู้ใช้ไปยัง URL อื่นโดยการเรียกใช้วิธีการคง redirect บนคลาส CoreResponseResponse Class
use Core Response Response ;
Route:: get ( ' /dashboard ' , function () {
return Response:: redirect ( ' home/dashboard ' );
}); อย่างไรก็ตามเพื่อความเรียบง่ายวิธีการช่วย redirect() ยังมีให้บริการทั่วโลกเพื่อให้ได้ฟังก์ชั่นเดียวกัน
use Core Response Response ;
Route:: post ( ' /story/create ' , function () {
if (! $ someCondition )
return redirect ( ' /story ' , 204 );
}); นอกจากนี้คุณยังสามารถสร้างการตอบสนอง JSON ได้โดยเรียกใช้วิธีการคงที่ JSON บนคลาส CoreResponseResponse Class ข้อมูลที่ส่งผ่านไปยังวิธีการจะถูกแปลงเป็น JSON ที่เหมาะสม นอกจากนี้คุณยังสามารถเลือกรหัสสถานะและอาร์เรย์ส่วนหัวเป็นอาร์กิวเมนต์ที่สองและสามไปยังฟังก์ชัน
use Core Response Response ;
Route:: post ( ' /post ' , function () {
$ post = ( . . . );
return Response:: JSON ( $ post , 201 , [ " header " => " value " ]);
});มิดเดิลแวร์นำเสนอกลไกที่สะดวกในการตรวจสอบและกรองคำขอ HTTP ที่เข้ามาในแอปพลิเคชันของคุณ ตัวอย่างเช่นคุณสามารถพัฒนามิดเดิลแวร์เพื่อตรวจสอบสถานะการรับรองความถูกต้องของผู้ใช้แอปพลิเคชันของคุณ หากผู้ใช้ไม่ได้รับการรับรองความถูกต้องมิดเดิลแวร์จะเปลี่ยนเส้นทางไปยังหน้าจอเข้าสู่ระบบ ในทางกลับกันหากผู้ใช้ได้รับการรับรองความถูกต้องมิดเดิลแวร์จะอนุญาตให้มีการร้องขอให้เข้าสู่แอปพลิเคชันที่ลึกซึ้งยิ่งขึ้น
คุณมีความยืดหยุ่นในการสร้างมิดเดิลแวร์เพิ่มเติมเพื่อดำเนินงานที่หลากหลายนอกเหนือจากการรับรองความถูกต้อง ในฐานะที่เป็นภาพประกอบมิดเดิลแวร์ที่เข้าสู่ระบบสามารถบันทึกคำขอที่เข้ามาทั้งหมดไปยังแอปพลิเคชันของคุณ ส่วนประกอบมิดเดิลแวร์เหล่านี้ตั้งอยู่ภายในไดเรกทอรี app/middlewares
ในการสร้างมิดเดิลแวร์ใหม่ให้ใช้คำสั่ง build:middleware Candle:
php candle build:middleware IsAuthenticated การดำเนินการคำสั่งนี้จะสร้างคลาสมิดเดิลแวร์ใหม่ที่มีชื่อว่า "Isauthenticated" ในไดเรกทอรี app/middlewares ภายในคลาสนี้วิธีการที่ชื่อ handle ถูกสร้างขึ้นโดยที่คุณสามารถเชื่อมโยงตรรกะสำหรับมิดเดิลแวร์
ที่นี่เราจะอนุญาตให้เข้าถึงเส้นทางหากผู้ใช้ได้รับการรับรองความถูกต้องมิฉะนั้นเราจะเปลี่ยนเส้นทางผู้ใช้กลับไปที่ URI login :
<?php
namespace App Middlewares ;
use App Services Auth ;
use Closure ;
use Core Request Request ;
class IsAuthenticated
{
public function handle ( Request $ request , Closure $ next )
{
if (!( /* authentication logic */ )) {
return redirect ( " /login " );
}
return $ next ( $ request );
}
} หากต้องการส่งคำขอลึกลงไปในแอปพลิเคชันคุณควรโทรไปที่ $next ด้วย $request
พิจารณามิดเดิลแวร์เป็นลำดับของ "เลเยอร์" ที่ HTTP ร้องขอการสำรวจก่อนถึงแอปพลิเคชันของคุณ แต่ละเลเยอร์มีความสามารถในการตรวจสอบคำขอและอาจปฏิเสธได้
แน่นอนมิดเดิลแวร์สามารถทำงานก่อนหรือหลังส่งคำขอลึกลงไปในแอปพลิเคชัน ตัวอย่างเช่นมิดเดิลแวร์นี้จะทำงาน หลังจาก คำขอได้รับการจัดการโดยแอปพลิเคชัน:
<?php
namespace App Middlewares ;
use Closure ;
use Core Request Request ;
class AfterMiddleware
{
public function handle ( Request $ request , Closure $ next )
{
$ response = $ next ( $ request );
// Perform action
return $ response ;
}
} หากคุณต้องการกำหนดมิดเดิลแวร์ให้กับเส้นทางที่เฉพาะเจาะจงคุณสามารถเรียกใช้วิธี middleware เมื่อกำหนดเส้นทาง:
Route:: get ( ' /profile ' , function () {
// ...
})-> middleware (IsAuthenticated::class); คุณสามารถกำหนดมิดเดิลแวร์หลายตัวไปยังเส้นทางโดยผ่านอาร์เรย์ของชื่อมิดเดิลแวร์ไปยังวิธี middleware :
Route:: get ( ' / ' , function () {
// ...
})-> middleware ([First::class, Second::class]); คุณสามารถกำหนดมิดเดิ้ลแวร์ให้กับกลุ่มเส้นทางโดยผ่านอาร์เรย์ของชื่อมิดเดิลแวร์ไปยังแอตทริบิวต์ middlewares เมื่อกำหนดกลุ่ม:
Route:: group ([ " middleware " => [HasSession::class]], function () {
Route:: get ( " / " , [StoryController::class, " index " ]);
Route:: get ( " /story/{story} " , [StoryController::class, " show " ]);
}); คุณสามารถใช้กลุ่มเส้นทางที่ซ้อนกันเพื่อรวมมิดเดิ้ลแวร์เข้ากับกลุ่มหลักของพวกเขา ในตัวอย่างที่ตามมามิดเดิลแวร์ "hassession" จะถูกนำไปใช้กับเส้นทาง "/" และ "/story/{story}" ในขณะที่ "Hassession," "Isauth," และ "Log" Middlewares ถูกนำไปใช้กับเส้นทางที่เหลือ:
Route:: group ([ " middleware " => [HasSession::class]], function () {
Route:: get ( " / " , [StoryController::class, " index " ]);
Route:: get ( " /story/{story} " , [StoryController::class, " show " ]);
Route:: group ([ " middleware " => [IsAuth::class, Log::class]], function () {
Route:: get ( " /compose " , [StoryController::class, " compose " ]);
Route:: post ( " /compose " , [StoryController::class, " create " ]);
});
});ในเฟรมเวิร์ก Elemental PHP มันไม่สามารถส่งคืนสตริงเอกสาร HTML ทั้งหมดได้โดยตรงจากเส้นทางและตัวควบคุม มุมมองเป็นวิธีที่สะดวกในการวาง HTML ทั้งหมดในไฟล์แยกต่างหาก
การดูมีบทบาทสำคัญในการแยกตรรกะคอนโทรลเลอร์/แอปพลิเคชันออกจากความกังวลการนำเสนอและจัดเก็บไว้ในไดเรกทอรี app/views ไฟล์มุมมองเหล่านี้เขียนด้วย PHP ห่อหุ้มมาร์กอัป พิจารณาตัวอย่างพื้นฐานของมุมมอง:
<html>
<body>
<h1>Hello, <?= $ name ?> </h1>
</body>
</html> หากมุมมองนี้ถูกเก็บไว้ที่ app/views/Welcome.php สามารถส่งคืนได้โดยใช้ Global view Helper ในเส้นทาง:
Route:: get ( ' / ' , function () {
return view ( ' Welcome ' , [ ' name ' => ' Ahmed ' ]);
}); อาร์กิวเมนต์แรกที่ส่งผ่านไปยังตัวช่วย view สอดคล้องกับชื่อของไฟล์มุมมองในไดเรกทอรี resources/views อาร์กิวเมนต์ที่สองสามารถเป็นอาร์เรย์ของคู่คีย์-ค่าที่ส่งผ่านไปยังมุมมอง ตัวอย่างเช่นในรหัสด้านบน $name จะสามารถเข้าถึงได้โดยตรงและมีค่า 'Ahmed'
มุมมองสามารถส่งคืนได้โดยใช้วิธี make คงที่ในคลาส CoreViewView :
Route:: get ( ' / ' , function () {
return View:: make ( " Post " , $ params );
}); มุมมองอาจซ้อนกันภายในไดเรกทอรีย่อยของไดเรกทอรี app/views สัญกรณ์ "DOT" อาจใช้เพื่ออ้างอิงมุมมองที่ซ้อนกัน ตัวอย่างเช่นหากมุมมองของคุณถูกเก็บไว้ที่ app/views/layouts/MainLayout.php คุณสามารถส่งคืนจากเส้นทาง/คอนโทรลเลอร์เช่น So:
return view ( ' layouts.MainLayout ' , $ data ); Elemental เป็นวิธีที่สะดวกในการรักษาเค้าโครงเดียวกันในหลายมุมมองลดการทำซ้ำรหัส เค้าโครงเป็นไฟล์มุมมองที่มีตัวยึด {{ content }} เมื่อมุมมองถูกส่งคืนพร้อมเค้าโครงมุมมองสุดท้ายจะถูกรวบรวมโดยใส่มุมมองภายในเนื้อหาของเค้าโครง
Elemental เป็นวิธีที่สะดวกในการรักษาเค้าโครงเดียวกันในหลายมุมมองลดการทำซ้ำรหัส เค้าโครงเป็นไฟล์มุมมองที่รวมตัวยึดตำแหน่งที่กำหนดโดยแสดงโดย {{ content }} เมื่อมุมมองถูกส่งคืนโดยใช้เค้าโครงเฉพาะองค์ประกอบจะทำได้โดยการฝังเนื้อหาของมุมมองภายในตัวยึดตำแหน่งที่กำหนดในเค้าโครง วิธีการนี้ปรับปรุงองค์กรของมุมมองและเพิ่มความสามารถในการบำรุงรักษาโค้ดโดยการรวมองค์ประกอบเค้าโครงทั่วไป
ด้านล่างเป็นตัวอย่างพื้นฐาน:
<!DOCTYPE html >
< html lang =" en " >
< head >
<!-- Head content -->
</ head >
< body >
< ?= component("components.Navbar") ? >
< div style =" min-height: calc(100vh - 140px); " >
{{ content }}
</ div >
</ body >
</ html >มุมมองสามารถส่งคืนด้วยเลย์เอาต์เช่นนี้:
public function compose ()
{
return view ( " Compose " )-> withLayout ( " layouts.DashboardLayout " );
}Elemental นำเสนอวิธีการที่มีประสิทธิภาพในการสร้างมุมมอง ทุกมุมมองเป็นส่วนประกอบเป็นหลักและมุมมองใด ๆ สามารถประกอบจากส่วนประกอบอื่น ๆ มันเป็นซิมโฟนีขององค์ประกอบที่แต่ละชิ้นมีส่วนช่วยในการสร้างความกลมกลืนและมีชีวิตชีวาทั้งหมด
ตัวอย่างไฟล์องค์ประกอบ ( views/components/Logo.php ):
<a class="logo" href="/ " >
<span class= " logo-img">
<img src="logo.png" class ="logo-text">
LOGO
</span>
</a> ส่วนประกอบนี้สามารถใช้ภายในไฟล์มุมมองอื่น ๆ ตัวอย่างเช่นใน views/Login.php :
<div>
<?= component ( " components.Logo " ) ?>
<p>Welcome Back!</p>
<!-- Other login form elements -->
</div>ดังนั้นองค์ประกอบจะช่วยให้คุณมีทั้งรูปแบบและการสร้างส่วนประกอบช่วยให้คุณสามารถเขียนมุมมองของคุณด้วยความชำนาญของวิธีการจากบนลงล่างและล่างขึ้นบน ความยืดหยุ่นนี้ช่วยให้ฟิวชั่นที่ไร้รอยต่อซึ่งคุณสามารถผสมผสานและรวมองค์ประกอบเข้ากับส่วนต่อประสานผู้ใช้ที่สง่างามและซับซ้อนสำหรับแอปพลิเคชันของคุณได้อย่างง่ายดาย
ในเว็บแอพพลิเคชั่นที่ทันสมัยการโต้ตอบฐานข้อมูลเป็นสิ่งพื้นฐาน Elemental ได้รับการออกแบบมาเพื่อปรับปรุงการโต้ตอบนี้อย่างราบรื่นตลอดความหลากหลายของฐานข้อมูลที่รองรับใช้ประโยชน์จากความสามารถโดยธรรมชาติของ PDD PDO ด้วย Elemental คุณมีความยืดหยุ่นในการดำเนินการค้นหาหรือธุรกรรมที่ซับซ้อนโดยใช้คลาสฐาน CoreDatabaseDatabase
Elemental นำเสนอ Mapper-Relational Object-Relational (ORM) ที่มีประสิทธิภาพซึ่งมีความซับซ้อนหลายอย่างได้อย่างมีประสิทธิภาพ อย่างไรก็ตาม CoreDatabaseDatabase สามารถใช้เพื่อเรียกใช้การสืบค้น SQL ขั้นสูงมากขึ้น
การกำหนดค่าทั้งหมดสำหรับแอพองค์ประกอบของคุณจะอยู่ในไฟล์การกำหนดค่า app/config/config.php ของแอปพลิเคชันของคุณ ที่นี่คุณสามารถกำหนดการเชื่อมต่อฐานข้อมูลทั้งหมดของคุณรวมถึงระบุการเชื่อมต่อที่ควรใช้โดยค่าเริ่มต้น ตัวเลือกการกำหนดค่าส่วนใหญ่ภายในไฟล์นี้ถูกขับเคลื่อนด้วยค่าตัวแปรสภาพแวดล้อมของแอปพลิเคชันของคุณ
การกำหนดค่าทั้งหมดสำหรับแอพองค์ประกอบของคุณจะอยู่ในไฟล์การกำหนดค่า app/config/config.php ของแอปพลิเคชันของคุณ ที่นี่คุณสามารถกำหนดการเชื่อมต่อฐานข้อมูลทั้งหมดของคุณรวมถึงระบุการเชื่อมต่อที่ควรใช้โดยค่าเริ่มต้น ตัวเลือกการกำหนดค่าส่วนใหญ่ภายในไฟล์นี้ถูกขับเคลื่อนด้วยค่าตัวแปรสภาพแวดล้อมของแอปพลิเคชันของคุณ
<?php
return [
" db " => [
" driver " => getenv ( " DB_DRIVER " ) ?? " mysql " ,
" host " => getenv ( " DB_HOST " ) ?? $ _SERVER [ ' SERVER_ADDR ' ],
" port " => getenv ( " DB_PORT " ) ?? " 3306 " ,
" database " => getenv ( " DB_DATABASE " ) ?? " elemental " ,
" username " => getenv ( " DB_USERNAME " ) ?? " root " ,
" password " => getenv ( " DB_PASSWORD " ) ?? "" ,
],
]; Elemental ใช้ PDO เป็นคลาสการจัดการฐานข้อมูลพื้นฐาน ฟังก์ชั่น PDO ทั้งหมดมีอยู่โดยตรงในคลาส CoreDatabaseDatabase คุณสามารถฉีดอินสแตนซ์ของ CoreDatabaseDatabase ลงในคอนสตรัคเตอร์หรือคอนโทรลเลอร์ใด ๆ เพื่อเรียกใช้วิธี PDO การกำหนดค่าเริ่มต้นสำหรับองค์ประกอบถูกตั้งค่าสำหรับฐานข้อมูล MySQL แต่คุณสามารถเปลี่ยนไดรเวอร์ภายในไฟล์ config
นี่คือตัวอย่างของการเรียกใช้แบบสอบถามผ่านอินสแตนซ์ Database :
public function tokens ( Database $ db ) {
$ user_id = 1 ;
$ sql = " SELECT * FROM access_tokens WHERE user_id = :user_id " ;
$ stmt = $ db -> prepare ( $ sql );
$ stmt -> bindValue ( " :user_id " , $ user_id );
$ stmt -> execute ();
$ tokens = $ stmt -> fetchAll ();
}สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ PDO คุณสามารถอ้างถึงเอกสาร PDO ของ PHP
Elemental รวมถึง Mapper-Relational-Relational Mapper (ORM) ที่กำหนดเองซึ่งทำให้สนุกกับการโต้ตอบกับฐานข้อมูล เมื่อใช้ ORM แต่ละตารางฐานข้อมูลมี "โมเดล" ที่สอดคล้องกันซึ่งใช้ในการโต้ตอบกับตารางนั้น นอกเหนือจากการดึงเร็กคอร์ดจากตารางฐานข้อมูลแล้วรุ่นยังช่วยให้คุณสามารถแทรกอัปเดตและลบระเบียนออกจากตารางได้เช่นกัน
โมเดลมีอยู่ในไดเรกทอรี app/models และขยายคลาส CoreModelModel คุณสามารถสร้างโมเดลใหม่ได้โดยใช้คำสั่ง build:model Candle
php candle build:model Post โมเดลที่สร้างขึ้นโดยคำสั่ง build:model จะถูกวางไว้ในไดเรกทอรี app/Models แบบจำลองพื้นฐานมากมีโครงสร้างดังต่อไปนี้:
<?php
namespace App Models ;
use Core Model Model ;
class Post extends Model
{
// ...
} ชื่อตาราง: ตามการประชุมชื่อ "กรณีงู" ชื่อพหูพจน์ของคลาสจะถูกใช้เป็นชื่อตารางเว้นแต่ชื่ออื่นจะถูกระบุอย่างชัดเจน ดังนั้นในกรณีนี้ Elemental จะถือว่า Post โมเดลเก็บบันทึกในตาราง posts
คุณสามารถระบุชื่อตารางของโมเดลด้วยตนเองโดยกำหนดคุณสมบัติ tableName ในรุ่น:
<?php
namespace App Models ;
use Core Model Model ;
class Post extends Model
{
protected $ tableName = ' elemental_posts ' ;
}คีย์หลัก:
Elemental จะสมมติว่าตารางฐานข้อมูลที่สอดคล้องกันของแต่ละรุ่นมีคอลัมน์คีย์หลักชื่อ id หากจำเป็นคุณอาจกำหนดคุณสมบัติ $primaryKey ที่ได้รับการป้องกันบนโมเดลของคุณเพื่อระบุคอลัมน์อื่นที่ทำหน้าที่เป็นคีย์หลักของโมเดลของคุณ:
<?php
namespace App Models ;
use Core Model Model ;
class Post extends Model
{
protected $ primaryKey = ' elemental_id ' ;
}คุณสามารถคิดว่าแต่ละรุ่นเป็นตัวสร้างแบบสอบถามที่ทรงพลังช่วยให้คุณสามารถสอบถามตารางฐานข้อมูลที่เกี่ยวข้องกับโมเดลได้อย่างคล่องแคล่ว
วิธี all ของโมเดลจะดึงบันทึกทั้งหมดจากตารางฐานข้อมูลที่เกี่ยวข้องของโมเดล:
use App Models Story ;
foreach (Story:: all () as $ story ) {
echo $ story [ " content " ];
}โดยค่าเริ่มต้นระเบียนที่ดึงมาจะแสดงเป็นอาร์เรย์ อย่างไรก็ตามคุณสามารถผ่านอาร์กิวเมนต์โหมดซึ่งควบคุมวิธีการแสดงแต่ละระเบียน อาร์กิวเมนต์โหมดใช้โหมดการดึง PDO ใด ๆ ตัวอย่างเช่น
use App Models Story ;
foreach (Story:: all () as $ story ) {
echo $ story -> content ;
} วิธีการ allWhere เป็นนามธรรมที่ทรงพลังในโมเดลที่อนุญาตให้ดำเนินการสืบค้นที่ซับซ้อน วิธีนี้ใช้เวลาสามข้อโต้แย้ง: conditions options และ fetchMode
public static function allWhere( array $ conditions , array $ options = [], int $ fetchMode = PDO :: FETCH_ASSOC ) เงื่อนไข: พารามิเตอร์ conditions เป็นอาร์เรย์ของข้อที่บันทึกจะต้องตอบสนองที่จะดึง แต่ละเงื่อนไขสามารถเป็นคู่ [key => value] หรือ [key => [operator, value]] คู่
key สอดคล้องกับคอลัมน์เฉพาะในตาราง[key => value] ตัวดำเนินการเริ่มต้นคือ = และ value คือข้อมูลภายในคอลัมน์นั้นสำหรับบันทึก[key => [operator, value]] คุณสามารถระบุตัวดำเนินการสำหรับแต่ละเงื่อนไข ผู้ให้บริการที่ได้รับการสนับสนุนคือ:['=', '!=', '<', '>', '<=', '>=', 'LIKE', 'IS NULL', 'IS NOT NULL'] ตัวเลือก: พารามิเตอร์ options คืออาร์เรย์ที่กำหนดอาร์กิวเมนต์การสืบค้นเพิ่มเติมเช่น order by limit ฯลฯ โครงสร้างที่รองรับในอาร์กิวเมนต์ตัวเลือกรวมถึง:
"orderBy""limit""offset""sortDir" FetchMode: พารามิเตอร์ fetchMode ควบคุมวิธีการบันทึกการดึงข้อมูลแต่ละรายการ อาร์กิวเมนต์โหมดใช้โหมดการดึง PDO ใด ๆ :
PDO::FETCH_ASSOCPDO::FETCH_NUMPDO::FETCH_BOTHPDO::FETCH_OBJPDO::FETCH_CLASSPDO::FETCH_INTOPDO::FETCH_LAZYPDO::FETCH_KEY_PAIRตัวอย่างจะทำให้ชัดเจนยิ่งขึ้น:
use Core Request Request ;
class StoryController {
const PAGE_SIZE = 10 ;
public function index ( Request $ request )
{
$ search = $ request -> search ;
$ categoryId = $ request -> category_id ;
$ sortBy = $ request -> sort_by ; // ASC or DESC, Default = ASC
$ page = $ request -> page ;
$ orderBy = $ request -> order_by ;
return Story:: allWhere (
[
" category_id " => $ categoryId ,
" title " => [ " LIKE " , " % $ search $ " ],
],
[
" limit " => static :: PAGE_SIZE ,
" orderBy " => $ orderBy ,
" sortDir " => $ sortBy ,
" offset " => ( $ page - 1 ) * static :: PAGE_SIZE ,
],
PDO :: FETCH_OBJ
);
}
} นอกเหนือจากการดึงบันทึกทั้งหมดที่ตรงกับการสืบค้นที่กำหนดคุณอาจดึงระเบียนเดี่ยวโดยใช้วิธี find และวิธี where แทนที่จะส่งคืนอาร์เรย์ของบันทึกวิธีการเหล่านี้ส่งคืนอินสแตนซ์รุ่นเดียว:
ค้นหา: สิ่งนี้จะดึงบันทึกแรกที่ตรงกับคีย์หลักของตาราง
$ flight = Story:: find ( 1 ); สถานที่: วิธีการที่ใช้เวลาของเงื่อนไขที่บันทึกจะต้องเป็นไปตามที่จะนำมาใช้ แต่ละเงื่อนไขสามารถเป็นคู่ [key => value] หรือ [key => [operator, value]] คู่
key corresponds to a specific column in the table.[key => value] , the default operator is = and the value is the data inside that column for the record.[key => [operator, value]] , you can specify the operator for each condition. The supported operators are:['=', '!=', '<', '>', '<=', '>=', 'LIKE', 'IS NULL', 'IS NOT NULL'] .ตัวอย่างเช่น
$ user = User:: where ([ " email " => $ email ]);
$ liked = Like:: where ([ " user_id " => $ user -> id , " story_id " => $ story_id ]); To insert a new record into the database, you can instantiate a new model instance and set attributes on the model. Then, call the save method on the model instance:
<?php
namespace App Controllers ;
use App Models Story ;
use Core Request Request ;
class StoryController
{
public function store ( Request $ request )
{
$ story = new Story ;
$ story -> name = $ request -> name ;
$ story -> save ();
return redirect ( ' /story ' );
}
} In this example, we assign the name field from the incoming HTTP request to the name attribute of the AppModelsStory model instance. When we call the save method, a record will be inserted into the database. The model's created_at timestamp will automatically be set when the save method is called, so there is no need to set it manually.
Alternatively, you may use the static create method to "save" a new model using a single PHP statement. The inserted model instance will be returned to you by the create method:
use App Models Story ;
$ story = Story:: create ([
' name ' => ' A tale of elemental magic ' ,
]); The save method may also be used to update models that already exist in the database. To update a model, you should retrieve it and set any attributes you wish to update. Then, you should call the model's save method.
use App Models Story ;
$ story = Story:: find ( 10 );
$ story -> name = ' An elemental tale of magic ' ;
$ story -> save (); Alternatively, you may use the static update method to update a model instance. The first argument is the id of the model, and the second argument needs to be the array of column value pair.
use App Models Story ;
$ story = Story:: update ( 10 , [ " name " => " A tale " , " content " => " Once upon a time .... " ]); To delete a model, you may call the destroy method on the model instance:
use App Models Story ;
$ story = Story:: find ( 12 );
$ story -> destroy (); However, if you know the primary key of the model, you may delete the model without explicitly retrieving it by calling the delete method. The id of the deleted record is returned.
use App Models Story ;
Story:: delete ( 12 ); You may call the data method on the model to retrieve all the attributes of a modal instance in an array form.
$ user = User:: find ( 10 );
$ user_data = $ user -> data (); Candle is the command line engine of the Elemental. Candle exists at the root of your application as the candle script and provides a number of helpful commands designed to aid you in the development process of your application. To view a list of all available Candle commands, you may use the help command:
php candle helpThis will also display the custom commands that you may have created yourself.
By now, you must have already ignited the the Elemental's candle to run your app. This ignite command serves the app at the IP Address 127.0.0.1, searching for a free port starting from 8000. If Port 8000 is occupied, Elemental automatically attempts to bind to the next available port (eg, 8001) and so forth.
php candle igniteYou have the flexibility to customize the server setup according to your requirements.
Custom Host Specify a specific IP address using the --host argument. ตัวอย่างเช่น:
php candle ingite --host=192.168.1.10 Custom Port If you prefer binding to a specific port, use the --port argument:
php candle ingite --port=8080 To serve your application at a custom IP and port simultaneously, provide both the --host and --port arguments:
php candle ingite --host=192.168.1.10 --port=8080 The --host and --port arguments can be placed in any order.
To obtain a comprehensive view of all registered routes within your application, utilize the route:list command provided by Candle:
ทุบตี
php candle route:list You can use the Candle build command to generate files for your models, controllers, middleware and commands.
To create a model, execute the following command:
php candle build:model Story This command will generate a file named Story.php within the appmodels directory, containing the Story class.
For generating a controller, the build command is similarly employed:
php candle build:controller StoryController Executing this command will generate a file named StoryController.php in the appcontrollers directory, featuring the MyController class.
To generate a middleware, utilize the build command as follows:
php candle build:middleware HasSession This will create a file named HasSession.php within the appmiddleware directory, housing the handle method.
For command generation, execute the build command with the appropriate arguments:
php candle build:command Migration Executing this command will generate a file named Migration.php in the appcommands directory, containing the Migration class and the handle method.
Generating custom commands is where the Candle's power can be experienced. Commands are stored in the app/commands directory, and it's essential to load them inside the array returned in appcommandsCommands.php for proper registration within the app.
After generating a command, define values for the key and description properties of the class. The key is used as the argument for the command, while description will be displayed in the help screen. The handle method will be called when the command is executed, and you can place your command logic in this method.
You can type-hint any dependencies required for your command handling. Elemental's DI Container will automatically inject all dependencies type-hinted in the handle method's signature.
Let's take a look at an example command:
<?php
namespace App Commands ;
use App Models User ;
use App Service MailService ;
use Core Console Command ;
class SendEmails extends Command
{
protected $ key = ' mail:send ' ;
protected $ description = ' Send mails to all users ' ;
public function handle ( MailService $ mailService ): void
{
$ mailService -> send (User:: all ());
}
}To execute the command in the command line:
php candle mail:send You can use Elemental's CoreConsoleCommander to retrieve any inputs passed through the command line. The CoreConsoleCommander provides a method named getArgs that returns an array of inputs passed from the command line. The Commander instance can be type-hinted through the handler method and used as required.
A concrete example will make it clear:
<?php
namespace App Commands ;
use Core Console Command ;
use Core Console Commander ;
class Migration extends Command
{
protected $ key = " migrate " ;
protected $ description = " Custom migration handler. " ;
private $ commander ;
public function handle ( Commander $ commander , Database $ db )
{
$ args = $ commander -> getArgs ();
if (! isset ( $ args [ 1 ])) {
$ this -> up ();
return ;
}
switch ( $ args [ 1 ]) {
case " fresh " :
$ this -> downThenUp ();
break ;
case " delete " :
$ this -> down ();
break ;
default :
$ this -> up ();
}
}
public function up ()
{
$ sql = " CREATE TABLE IF NOT EXISTS users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
bio TEXT,
image VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) " ;
try {
$ db -> exec ( $ sql );
console_log ( " Table 'users' created successfully! " );
} catch ( PDOException $ e ) {
console_log ( " Table creation error: " . $ e -> getMessage ());
}
}
public function down ()
{
$ sql = " DROP TABLE IF EXISTS users " ;
try {
$ db -> exec ( $ sql );
console_log ( " Table 'users' deleted successfully! " );
} catch ( PDOException $ e ) {
console_log ( " Table deletion error: " . $ e -> getMessage ());
}
}
public function downThenUp ()
{
$ this -> down ();
$ this -> up ();
}
}It is recommended to type-hint dependencies inside the handle method as opposed to inside the constructor of the command class.
To execute these migration commands in the command line:
php candle migrate
php candle migrate fresh
php candle migrate deleteAs you can see, generating commands are very powerful and can be helpful to achieve a variety of functionalities. Here, a custom migration handler has been built. You can expand and organize the above structure or create a custom Migration Service that can handle your migration logic.
Commands can also be used for handling task scheduling. You may create a command that executes some logic, and then pass the command to your operating systems CRON handler.
Elemental includes a variety of global "helper" PHP functions. You can use these functions in any way that is convenient to you.
The app function returns the Application instance:
$ app = app ();This is pretty useful when you want to register your own services as well as resolve any framework or custom service.
app ()-> bind (CustomService::class, function () {
return new CustomService ( new anotherService ());
});
$ service = app ()- make (CustomService::class); The dump function dumps the variable passed as the first argument. You can also pass an additional second argument that can serve as the identifier on screen:
dump ( $ value );
dump ( $ user , " user " ); The dd function dumps the given variable and ends the execution of the script:
dd ( $ value );
dd ( $ user , " user " ); The console_log function serves as a unique tool for logging variables, distinct from the dump function. Notably, it doesn't return output to the browser; instead, it directs information to the console initiated by the script. You can pass any variable number of arguments to the console_log function.
console_log ( $ value );
console_log ( $ user , $ post , $ image , $ comment ); The router function returns the returns the Router instance.
The view function is used to return a view from the controller method:
return view ( ' Login ' ); The component function is used to return a view as a component to be used inside another view:
<body>
<?= component ( " Logo " ) ?>
//...
</body> The redirect function returns a redirect HTTP response and is used to redirect to any other route.
return redirect ( ' /home ' );Elemental provides a convenient way to handle all the exceptions thrown by the app.
The handle method of AppExceptionsHandler class is where all exceptions thrown by your application pass through before being rendered to the user. By default, exceptions thrown by the app will be formatted, and a structured response will be sent back to the browser. However, inside the handle method, you can intercept any exception and perform custom logic before the response is sent back.
You can even send back a custom view or a response.
<?php
namespace App Exceptions ;
use Core Exception ExceptionHandler ;
class Handler extends ExceptionHandler
{
public function handle ( $ e )
{
// Perform some processing here
// You can customize the handling of exceptions based on your requirements
}
}Elemental has defined some specific exception classes by default:
AppExceptionModelNotFoundExceptionRouteNotFoundExceptionRouterExceptionViewNotFoundException If you need to handle different types of exceptions in different ways, you can modify the handle method accordingly:
<?php
class Handler extends ExceptionHandler
{
public function handle ( $ e )
{
if ( $ e instanceof ModelNotFoundException || $ e instanceof RouteNotFoundException) {
return view ( " 404 " )-> withLayout ( " layouts.DashboardLayout " );
}
if ( $ e instanceof ViewNotFoundException) {
return view ( " Home " );
}
// Handle other specific exceptions as needed
}
} You are free to create your own exception classes by extending from the base Exception class, which can then be handled as required.
Feel free to customize the handle method based on your application's specific needs.
All configuration settings for the application are centralized in the appconfigconfig.php file. These configurations cover various aspects such as database connection information and other core settings essential for your app.
To cater to different environments where the application might run, a .env.example file is provided in the root directory. This file outlines common environment variables that can be configured. If you are working in a team, it's recommended to include the .env.example file with placeholder values. This makes it clear to other developers which environment variables are required to run the application.
When your application receives a request, all the variables listed in the .env file will be loaded into the $_ENV PHP super-global. You can then use the getenv function to retrieve values from these variables in your configuration files.
$ appName = getenv ( " APP_NAME " ); To access configuration values, you can use type-hinting and inject the CoreConfigConfig class into your constructors, controller methods, or route closures.
use Core Config Config ;
class YourClass {
public function __construct ( Config $ config ) {
$ driver = $ config -> db [ " driver " ];
$ host = $ config -> db [ " host " ];
$ port = $ config -> db [ " port " ];
}
// Your other methods or code here
}By doing this, you have a clean and organized way to retrieve configuration values within your application.
This approach keeps your configuration centralized and allows for easy changes based on the environment. It also promotes a clean and maintainable codebase.
Elemental introduces a Facade system inspired by Laravel, providing a convenient and expressive static interface to classes within the application's Dependency Injection (DI) container. Facades act as static proxies to classes in the service container, offering a balance between a concise syntax and the testability and flexibility of traditional static methods.
In Elemental, the CoreFacadeRoute serves as a Facade, offering a static interface to the application's Router instance enabling you to use it like this in the routes.php file:
// routes.php
<?php
use Core Facade Route ;
Route:: get ( " /register " , [AuthController::class, " showRegister " ]);
Route:: get ( " /login " , [AuthController::class, " showLogin " ]);
Route:: get ( " /logout " , [AuthController::class, " logout " ]);
Route:: post ( " /register " , [AuthController::class, " register " ]);To create a custom Facade for any class, follow these steps:
FacadeClass that extends the CoreFacadeFacade class.getFacadeAccessor , returning the class string for the associated instance in the DI container. Here's an example of creating a PaymentGateway Facade:
<?php
use Core Facade Facade ;
use Core Services PaymentGateway ;
class PaymentGatewayFacade extends Facade
{
protected static function getFacadeAccessor ()
{
return PaymentGateway::class;
}
} Now, you can access the instance methods of your custom class by calling static methods on the corresponding FacadeClass .
LARAVEL is Magic . Like any unsuspecting Muggle, it's enchantments terrify you. Until one fine day, you dare to pick up the wand and start waving it. Then, you fall in love with it.
The Elemental framework is open-sourced software licensed under the MIT License.
All contributions are welcome. Please create an issue first for any feature request or bug. Then fork the repository, create a branch and make any changes to fix the bug or add the feature and create a pull request. แค่ไหน! ขอบคุณ!
For bug reports, feature requests, or general questions, please use the issue tracker.