Elemental은 역동적이고 사용자 친화적 인 코딩 경험을 위해 처음부터 개발 된 PHP 프레임 워크입니다. 의존성 주입과 같은 기능을 통합하고 MVC 아키텍처를 따라 웹 개발을 간소화하고 코드 조직을 개선합니다. 단순성과 유연성에 대한 열정으로 설계된이 회사는 개발자를 비교할 수없는 제어를 휘두르고 자신의 처분에 대한 도구에 대한 깊은 이해를 얻을 수있는 영역으로 초대합니다.
Elemental의 기능을 보여주기 위해 Inkwell 이라는 완전히 작동하는 플랫폼이 Elemental을 사용하여 개발되었습니다. Inkwell은 스토리 텔링의 순수한 본질에 전념하는 독특한 공간입니다. Elemental의 외부 종속성이 없다는 목표에 따라 Inkwell은 일반 HTML, CSS, JS 및 PHP 만 사용하여 제작되었습니다.
라이브 플랫폼과 해당 코드베이스를 모두 살펴보십시오. 자신의 프로젝트에 대해 Elemental이 어떻게 활용 될 수 있는지 이해하기 위해 Inkwell의 기능을 탐색하십시오.
Elemental 의 창조 뒤에 영감을 얻으십시오.
Elemental은 문자열이 부착되어 있지 않도록 설계되었습니다. 외부 라이브러리 또는 프레임 워크에는 의존성이 없습니다. 목표는 개발자들에게 진정한 통제력을주는 것입니다. 프레임 워크에 힘을주는 마법의 것들을 독립적으로 탐구하고 이해할 수있는 열린 문입니다.
가장 중요한 목표? 개발자들은 DI 컨테이너, orms, 중간 전쟁 등과 같은 강력한 추상화의 우아함을 완전히 받아들이고 활용할 수 있도록합니다. 그러나 여기에 키커가 있습니다. 요소는 단지 길을 가리키는 것이 아닙니다. 그것은 당신에게 미스터리를 풀기위한 열쇠를 건네주고, 이러한 추상화가 코드에 어떻게 배치되는지 탐구 할 수 있도록 힘을 실어줍니다.
실제로, 당신은 길을 따라 가고 구타를 막는 것이 좋습니다. 코드베이스에 뛰어 들어 추상화를 해부하고 내면의 작동을 이해하십시오. Elemental은 단순한 프레임 워크가 아니기 때문에 자유롭게 조정하고 실험하십시오. 코딩은 미로가되어서는 안됩니다. 여행이어야합니다. 그 여행을 함께합시다.
다른 프레임 워크와 달리 Elemental은 작곡가 또는 외부 라이브러리에 의존하지 않습니다. 저장소를 복제하고 시스템에 설치된 좋은 OL 'PHP를 시작하는 것만 큼 간단합니다.
터미널을 열고 다음 명령을 실행하십시오.
git clone https://github.com/aneesmuzzafer/elemental.git패키지 관리자 또는 의존성에 대한 걱정은 없습니다 - Elemental은 처음부터 그러한 우려에서 벗어날 수 있도록 구축됩니다.
Composer Route를 선호하는 사람들에게는 새로운 Elemental 앱을 만드는 것만으로도 명령입니다.
composer create-project fragment/elemental sample-app composer.json 파일로 프로젝트가 생성됩니다.
프로젝트가 준비되면 Command Line 엔진 인 Candle을 사용하여 ignite 명령으로 Elemental Local Development Server를 시작하십시오.
cd sample-app
php candle ignite짜잔! 신청서는 이제 http://127.0.0.1:8000에서 액세스 할 수 있습니다.
우리는 기본 설정을 처리하여 마법에 집중할 수 있습니다.
마법을 시작하게하십시오!
원소의 가장 중요한 특징은 클래스 종속성을 관리하고 종속성 주입을 수행하는 데 사용하는 종속성 분사 컨테이너입니다.
의존성 주입은 소프트웨어 개발의 설계 패턴으로 구성 요소가 종속성을 유지하는 방법을 다루는 것입니다. 전통적인 시스템에서 클래스는 자체 의존성을 만들어야합니다. DI를 사용하면 종속성을 창출하고 제공하는 책임은 수업 밖에서 이동됩니다. 종속성을 만드는 클래스 대신 외부 소스에서 클래스에 "주입"됩니다.
DI는 느슨하게 결합되고 유지 관리 가능한 코드를 달성하는 데 도움이됩니다. 종속성을 만들거나 얻는 방법에 대해 걱정하지 않고 각 클래스가 특정 기능에 집중할 수 있도록하여 우려 사항의 분리를 촉진합니다.
의존성 주입은 제어 역전 (IOC)으로 알려진 더 넓은 개념의 구체적인 구현입니다. IOC는 프로그램의 제어 흐름이 반전되거나 외부 엔티티, 컨테이너 또는 프레임 워크로 넘겨지는 설계 패러다임을 나타냅니다.
Elemental에서는 종속성 주입 (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은 등록 된 바인딩을 보면서 클래스 또는 인터페이스를 구체적인 인스턴스로 해결합니다. 다시 말해, 특정 클래스 또는 인터페이스의 인스턴스를 해결하는 방법에 대한 프레임 워크를 명시 적으로 알리려면 Application 인스턴스의 bind 메소드를 사용하여 해당 클래스 또는 인터페이스의 바인딩을 등록하고 클래스의 인스턴스를 반환하는 클래스와 함께 등록하려는 클래스 또는 인터페이스 이름을 전달해야합니다.
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));
});클래스를 해결하기 위해 추가 논리를 실행 해야하는 경우에만 클래스를 바인딩해야합니다. 그렇지 않으면 인터페이스를 구체적인 구현에 바인딩해야합니다. 그렇지 않으면, Elemental은 명시 적으로 묶을 필요없이 클래스를 해결합니다.
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 응용 프로그램의 어느 곳에서나 바인딩을 등록하는 것은 완벽하게 괜찮지 만 응용 프로그램이 부트 스트랩되는 동안 바인딩 해야하는 경우가 종종있어 앱의 다른 구성 요소가 사용을 시작할 수 있습니다. Elemental은 앱의 모든 바인딩을 등록하고 응용 프로그램에 필요한 다른 부트 스트랩 로직을 수행 할 수있는 특별한 장소를 제공합니다. 이것은 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); Application 클래스에서 직접 static 메소드 instance 사용하여 응용 프로그램 인스턴스를 얻을 수도 있습니다.
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의 세그먼트를 캡처해야합니다. 예를 들어 URL에서 사용자의 ID를 캡처해야 할 수도 있습니다. 경로 매개 변수를 정의하여 그렇게 할 수 있습니다.
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은 선언 된 종속성을 콜백에 자동으로 해결하고 주입합니다.
예를 들어, 콜백 내에있는 힌트 CoreRequestRequest 입력하면 Elemental은 현재 HTTP 요청이 Route Callback에 자동으로 주입되도록합니다.
<?php
use Core Request Request ;
Route:: get ( ' /users ' , function ( Request $ request ) {
// ...
});유형의 종속성 및 경로 매개 변수를 순서대로 넣을 수 있습니다.
모델 ID를 경로 또는 컨트롤러 동작으로 매개 변수로 전달하면 일반적인 접근 방식에는 해당 ID를 기반으로 해당 모델을 가져 오기 위해 데이터베이스를 쿼리하는 것이 포함됩니다. 원소는 경로 모델 바인딩을 통해이 프로세스를 단순화하여 모델 인스턴스를 경로에 직접 자동으로 주입하는 편리한 방법을 제공합니다.
예를 들어, 사용자의 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 Candle 명령은 응용 프로그램에 정의 된 모든 경로의 목록을 제공합니다.
php candle route:list 경로 파일의 클로저 내에서 모든 요청 처리 로직을 통합하는 대신 "컨트롤러"클래스를 통해이 동작을 구성하는 것을 고려하십시오. 컨트롤러를 사용하면 관련 요청 처리 로직을 응집력있는 클래스로 구성 할 수 있습니다. 예를 들어, UserController 클래스는 사용자와 관련된 다양한 수신 요청 (예 : 사용자 표시, 작성, 업데이트 및 삭제)을 관리 할 수 있습니다. 이 컨트롤러 클래스는 일반적으로 app/Controllers 디렉토리에 저장됩니다.
새 컨트롤러를 생성하려면 build:controller 캔들 명령을 실행할 수 있습니다.
php candle build:controller UserController app/Controllers 디렉토리 내부에서 "usercontroller.php"라는 새 파일이 생성됩니다.
컨트롤러에는 들어오는 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 " ]); 수신 된 요청이 지정된 Route URI와 일치하면 AppControllersUserController 클래스 내의 showRegister 메소드가 호출되며 메소드는 해당 경로 매개 변수를 수신합니다.
원소 서비스 컨테이너는 모든 컨트롤러의 해결 인스턴스를 담당합니다. 결과적으로 컨트롤러 생성자에서 유형 힌트를 사용하여 필요한 종속성을 지정할 수 있습니다. 명시된 종속성은 자동으로 해결되고 컨트롤러 인스턴스에 주입됩니다.
<?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 " ]); 컨트롤러 메소드를 다음과 같이 정의하여 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 " );
}
} Elemental의 CoreRequestRequest Class는 응용 프로그램에서 관리하는 현재 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 " ]); 컨트롤러 메소드를 다음과 같이 정의하여 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 " );
}
} data() 메소드를 사용하여 모든 수신 요청의 입력 데이터를 array 로 얻을 수 있습니다. 이 방법은 들어오는 요청이 HTML 양식에서 유행하는지 또는 XHR 요청인지에 관계없이 사용될 수 있습니다.
$ data = $ request -> data (); 요청에 사용 된 HTTP 동사에 대해 걱정하지 않고 Request 인스턴스의 모든 사용자 입력에 액세스 할 수 있습니다. HTTP 동사에 관계없이 data 방법은 사용자 입력을 검색하는 데 사용될 수 있습니다.
$ name = $ request -> data ()[ " name " ]; CoreRequestRequest Instance는 들어오는 HTTP 요청을 검사하기위한 다양한 방법을 제공합니다. 아래에서 가장 중요한 방법 중 몇 가지에 대해 논의 해 봅시다.
headers 메소드를 사용하여 CoreRequestRequest Instance에서 요청 헤더를 검색 할 수 있습니다.
$ headers = $ request -> headers (); CoreRequestRequest Instance에서 method 호출하여 요청 메소드를 검색 할 수 있습니다.
$ method = $ request -> method (); uri 메소드를 사용하여 CoreRequestRequest Instinat에서 요청 URI를 검색 할 수 있습니다.
$ uri = $ request -> uri (); cookies 메소드를 사용하여 CoreRequestRequest 인스턴스에서 요청 쿠키를 검색 할 수 있습니다.
$ cookies = $ request -> cookies (); rawContent 메소드를 사용하여 CoreRequestRequest Instinat에서 원시 콘텐츠를 검색 할 수 있습니다.
$ content = $ request -> rawContent ();요청의 원시 콘텐츠를 처리 할 때주의하십시오.
files 메소드를 사용하여 CoreRequestRequest 인스턴스에서 파일을 검색 할 수 있습니다.
$ files = $ request -> files (); ip 메소드는 응용 프로그램에 요청한 클라이언트의 IP 주소를 검색하는 데 사용될 수 있습니다.
$ ipAddress = $ request -> ip (); port 방법은 응용 프로그램에 요청한 클라이언트의 포트 주소를 검색하는 데 사용될 수 있습니다.
$ port = $ request -> port (); contentType 메소드를 사용하여 CoreRequestRequest Instinat에서 컨텐츠 유형을 검색 할 수 있습니다.
$ contentType = $ request -> contentType (); queryString 메소드를 사용하여 요청의 쿼리 문자열을 검색 할 수 있습니다.
$ query = $ request -> queryString (); 컨텐츠 유형이 text/plain 으로 설정된 경우 text 메소드를 사용하여 요청의 텍스트 내용을 검색 할 수 있습니다.
$ text = $ request -> text (); 컨텐츠 유형이 application/javascript 로 설정된 경우 js 메소드를 사용하여 요청의 JS 내용을 검색 할 수 있습니다.
$ js = $ request -> js (); 컨텐츠 유형이 text/html 로 설정된 경우 html 메소드를 사용하여 요청의 HTML 컨텐츠를 검색 할 수 있습니다.
$ js = $ request -> html (); 컨텐츠 유형이 application/json 으로 설정된 경우 json 메소드를 사용하여 요청의 JSON 컨텐츠를 검색 할 수 있습니다 $request->data() 가 요청에 전달 된 모든 JSON 데이터를 반환합니다. 하지만,
$ jsonData = $ request -> json (); $request->data() 에는 모든 JSON 데이터와 요청의 쿼리 매개 변수를 통과 한 입력과 함께 포함됩니다. 그러나 $request->json() 사용하여 JSON 컨텐츠 만 검색 할 수 있습니다.
컨텐츠 유형이 application/json 으로 설정된 경우 xml 메소드를 사용하여 요청의 XML 컨텐츠를 검색 할 수 있습니다.
$ xmlData = $ request -> xml ();모든 경로와 컨트롤러는 사용자의 브라우저로의 전달에 대한 응답을 생성해야합니다. Elemental은 응답을 생성하기위한 다양한 방법을 제공합니다. 가장 간단한 형태의 응답은 경로 나 컨트롤러에서 직접 문자열을 반환하는 것입니다. 프레임 워크는이 문자열을 완전한 HTTP 응답으로 원활하게 변환합니다.
Route:: get ( ' / ' , function () {
return ' Hello World ' ;
});경로 및 컨트롤러에서 문자열을 반환하는 것 외에도 배열 또는 객체를 반환 할 수도 있습니다. 프레임 워크는 자동으로 JSON 응답으로 변환합니다.
Route:: get ( ' / ' , function () {
return [ 1 , 2 , 3 ];
}); 일반적으로 경로 동작에서 간단한 문자열이나 배열을 반환하는 것은 아닙니다. 대신, 종종 CoreResponseResponse 또는 Views의 완전한 인스턴스를 반환합니다.
전체 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 );공통 상태 코드에 대해 상태 텍스트가 기본적으로 설정됩니다.
CoreResponseResponse Class에서 정적 메소드 redirect 호출하여 사용자를 다른 URL로 리디렉션하는 데 필요한 적절한 헤더가 포함 된 리디렉션 응답을 생성 할 수 있습니다.
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 );
}); CoreResponseResponse Class에서 정적 메소드 JSON 호출하여 JSON 응답을 생성 할 수도 있습니다. 방법으로 전달 된 데이터는 적절한 JSON으로 변환됩니다. 선택적으로 상태 코드 및 헤더 배열을 기능에 대한 두 번째 및 세 번째 인수로 전달할 수 있습니다.
use Core Response Response ;
Route:: post ( ' /post ' , function () {
$ post = ( . . . );
return Response:: JSON ( $ post , 201 , [ " header " => " value " ]);
});미들웨어는 응용 프로그램에 대한 HTTP 요청을 검사하고 필터링하는 편리한 메커니즘을 제공합니다. 예를 들어, 미들웨어를 개발하여 응용 프로그램 사용자의 인증 상태를 확인할 수 있습니다. 사용자가 인증되지 않으면 미들웨어가 로그인 화면으로 리디렉션됩니다. 반대로, 사용자가 인증을 받으면 미들웨어는 요청이 응용 프로그램을 더 깊이 전진하도록 허용합니다.
인증을 넘어서 다양한 작업을 실행하기 위해 추가 미들웨어를 만들 수있는 유연성이 있습니다. 예를 들어, 로깅 미들웨어는 모든 수신 요청을 응용 프로그램에 기록 할 수 있습니다. 이 미들웨어 구성 요소는 app/middlewares 디렉토리 내에 있습니다.
새 미들웨어를 만들려면 build:middleware 캔들 명령 :
php candle build:middleware IsAuthenticated 이 명령을 실행하면 app/middlewares 디렉토리에서 "Isauthentical"이라는 새로운 미들웨어 클래스가 생성됩니다. 이 클래스 내에서 handle 이라는 이름의 메소드는 미들웨어의 논리를 명확하게 표현할 수 있습니다.
여기서 사용자가 인증 된 경우에만 경로에 액세스 할 수 있습니다. 그렇지 않으면 사용자를 login URI로 다시 리디렉션합니다.
<?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 );
}
} 요청을 응용 프로그램에 더 깊이 전달하려면 $request 과 함께 $next Callback을 호출해야합니다.
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"중간 전위는 나머지 경로에 적용됩니다.
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 " ]);
});
});원소 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'값을 포함합니다.
CoreViewView Class에서 정적 메소드 make 사용하여 뷰를 반환 할 수도 있습니다.
Route:: get ( ' / ' , function () {
return View:: make ( " Post " , $ params );
}); 뷰는 app/views 디렉토리의 하위 디렉토리 내에 중첩 될 수 있습니다. "DOT"표기법은 중첩 된 뷰를 참조하는 데 사용될 수 있습니다. 예를 들어, 뷰가 app/views/layouts/MainLayout.php 에 저장된 경우 다음과 같은 경로/컨트롤러에서 반환 할 수 있습니다.
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은 레이아웃 및 구성 요소 구성을 모두 갖추게하여 하향식 및 상향식 접근 방식의 세밀함으로 견해를 구성 할 수 있습니다. 이 유연성을 통해 원활한 융합을 가능하게하여 요소를 쉽게 혼합하고 결합하여 응용 프로그램에 대한 우아하고 정교한 사용자 인터페이스를 만들 수 있습니다.
최신 웹 애플리케이션에서 데이터베이스 상호 작용은 근본적인 측면입니다. Elemental은 PHP PDO의 고유 기능을 활용하여 다양한 지원되는 데이터베이스 에서이 상호 작용을 원활하게 간소화하도록 설계되었습니다. Elemental을 사용하면 CoreDatabaseDatabase 클래스를 사용하여 복잡한 쿼리 또는 트랜잭션을 실행할 수있는 유연성이 있습니다.
Elemental은 많은 복잡성을 효과적으로 추상화하여 대부분의 데이터베이스 쿼리에 귀중한 것을 증명하는 강력한 객체 관계 매퍼 (ORM)를 제공합니다. 그러나 CoreDatabaseDatabase 보다 고급 SQL 쿼리를 실행하는 데 사용될 수 있습니다.
Elemental 앱의 모든 구성은 응용 프로그램의 app/config/config.php 구성 파일에 있습니다. 여기서는 모든 데이터베이스 연결을 정의하고 기본적으로 사용할 연결을 지정할 수 있습니다. 이 파일 내의 구성 옵션의 대부분은 응용 프로그램의 환경 변수 값에 의해 구동됩니다.
Elemental 앱의 모든 구성은 응용 프로그램의 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 메소드를 호출 할 수 있습니다. Elemental의 기본 구성은 MySQL 데이터베이스에 대해 설정되지만 구성 파일 내부의 드라이버를 변경할 수 있습니다.
다음은 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에 대한 자세한 내용은 PHP의 PDO 문서를 참조하십시오.
Elemental에는 맞춤형 객체 관련 매퍼 (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 Model Stores Records가 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 매개 변수는 각 Fetched 레코드가 어떻게 표현되는지 제어합니다. 모드 인수는 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 테이블의 특정 열에 해당합니다.[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.