Elemental es un marco PHP desarrollado desde cero para experiencias dinámicas de codificación fácil de usar. Incorpora características como la inyección de dependencia y sigue la arquitectura MVC para optimizar el desarrollo web y mejorar la organización del código. Diseñado con una pasión por la simplicidad y la flexibilidad, invita a los desarrolladores a un reino donde puedan ejercer un control incomparable y obtener una comprensión profunda de las herramientas a su disposición.
Para mostrar las capacidades de Elemental, se ha desarrollado una plataforma completamente de trabajo llamada Inkwell usando Elemental. Inkwell es un espacio único dedicado a la esencia pura de la narración. En línea con el objetivo de Elemental de no tener dependencias externas, Inkwell se ha creado utilizando solo HTML, CSS, JS y PHP.
Siéntase libre de profundizar tanto en la plataforma en vivo como en la base de código correspondiente. Explore las características de Inkwell para comprender cómo se puede aprovechar el elemental para sus propios proyectos.
Vea la inspiración detrás de la creación de Elemental .
Elemental ha sido diseñado con el objetivo de no tener cuerdas adjuntas. No hay dependencias en bibliotecas o marcos externos. El objetivo es dar a los desarrolladores un sentido de control genuino, una puerta abierta para explorar y comprender independientemente las cosas mágicas que alimenta el marco.
¿El objetivo general? Deje que los desarrolladores adopten y aprovechen completamente la elegancia de poderosas abstracciones como contenedores DI, Orms, Middlewares y más. Pero aquí está el pateador: el elemento no solo está apuntando el camino. Te está entregando las llaves para desentrañar los misterios, lo que te permite explorar cómo estas abstracciones se establecen en el código.
De hecho, se le anima no solo a seguir el camino, sino a aventurarse en la pista golpeada. Sumérgete en la base de código, disecciona las abstracciones y entiende su funcionamiento interno. Siéntase libre de ajustar y experimentar, porque Elemental no es solo un marco, es una invitación abierta para dar forma y moldear las herramientas a su disposición. Porque la codificación no debería ser un laberinto; Debería ser un viaje. Hagamos ese viaje juntos.
A diferencia de otros marcos, Elemental no se basa en bibliotecas compositor o externas. Es tan simple como clonar el repositorio y comenzar con un buen PHP instalado en su sistema.
Abra su terminal y ejecute el siguiente comando:
git clone https://github.com/aneesmuzzafer/elemental.gitNo se preocupe por los administradores o dependencias de paquetes: Elemental se construye desde cero para liberarlo de tales preocupaciones.
Para aquellos que prefieren la ruta del compositor, crear una nueva aplicación elemental está a solo un comando de distancia:
composer create-project fragment/elemental sample-app Esto generará un proyecto con un archivo composer.json .
Una vez que su proyecto esté listo, inicie el servidor de desarrollo local Elemental con el comando ignite usando nuestro motor de línea de comandos, Vela :
cd sample-app
php candle ignite¡Voila! Ahora se puede acceder a su aplicación en http://127.0.0.1:8000.
Nos hemos encargado de la configuración básica para que pueda concentrarse en la magia.
¡Que comience el encantamiento!
La característica más importante del elemental es su contenedor de inyección de dependencia que utiliza para administrar las dependencias de clases y realizar la inyección de dependencia.
La inyección de dependencia es un patrón de diseño en el desarrollo de software que se ocupa de cómo los componentes obtienen sus dependencias. En un sistema tradicional, una clase es responsable de crear sus propias dependencias. Con DI, la responsabilidad de crear y proporcionar dependencias se mueve fuera de la clase. En lugar de una clase que crea sus dependencias, se "inyectan" en la clase desde una fuente externa.
DI ayuda a lograr un código poco acoplado y más mantenible. Promueve la separación de preocupaciones al permitir que cada clase se centre en su funcionalidad específica sin preocuparse por cómo crear u obtener sus dependencias.
La inyección de dependencia es una implementación específica del concepto más amplio conocido como inversión de control (COI). El COI representa un paradigma de diseño donde el flujo de control de un programa se invierte o se entrega a una entidad externa, contenedor o marco.
En Elemental, cuando usa la inyección de dependencia (DI), si una clase no confía en ninguna otra clases o solo se basa en clases concretas (no interfaces abstractas), no necesita decirle explícitamente al contenedor DI cómo crear una instancia de esa clase. El contenedor DI lo resolverá automáticamente.
El contenedor intentará crear una instancia de la clase, y si esa clase tiene dependencias en otras clases, el contenedor también intentará resolver esas dependencias. Este proceso continúa hasta que todas las clases necesarias se resuelvan con éxito. Por lo tanto, no tiene que especificar manualmente cómo crear cada clase: el contenedor DI se encarga de él.
<?php
class MailService {
public function __construct ( private MailerAgent $ mailer ) {
}
}
// Inside some other class
class UserController {
public function sendMail ( MailService $ mailService )
{
$ mailService -> sendMail ();
}
} Aquí, al instalar el tipo MailService dentro del argumento del método, Elemental pudo resolver la clase y crear una instancia de esta clase y pasarlo a sendMail para que pueda usarlo sin preocuparse por las dependencias que la clase de MailService requiere. Como puede ver, el MailService en sí depende de alguna otra clase MailerAgent , sin embargo, Elemental se encargó de resolver la clase MailerAgent detrás de escena, lo pasó al MailService mientras creaba su instancia y proporcionó esa instancia para su uso.
"Entonces, ¿dónde funcionará este tipo de dependencias de inyección de tipo que el nombre de clase funcione en Elemental?" Todas las funciones constructor de clase, todos los controller methods y el método handle de la clase de creación de comandos.
Detrás de escena, Elemental resuelve una clase o interfaz en una instancia concreta al observar cualquier enlace que se haya registrado. En otras palabras, para decir explícitamente el marco sobre cómo resolver la instancia de una clase o interfaz en particular, necesitaría registrar una vinculación de esa clase o interfaz utilizando el método bind en la instancia Application , aprobando la clase o el nombre de la interfaz que deseamos registrar junto con un cierre que devuelve una instancia de la clase:
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));
});Tenga en cuenta que normalmente necesitará unir una clase solo cuando necesite ejecutar una lógica adicional para resolver una clase, o necesita unir una interfaz a una implementación concreta. De lo contrario, Elemental resolverá la clase sin requerir explícitamente que la vincule.
El método singleton vincula una clase o interfaz con el contenedor, asegurando que se resuelva solo una vez. Después de la resolución inicial, cualquier llamada posterior al contenedor para el mismo enlace devolverá la misma instancia de objeto.
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 Si bien está perfectamente bien registrar una vinculación en cualquier lugar de la aplicación, a menudo se requiere vincularlo mientras la aplicación es arranque, para que otros componentes de la aplicación puedan comenzar a usarla. Elemental proporciona un lugar especial para registrar todos los enlaces de la aplicación y realizar cualquier otra lógica de arranque requerida por su aplicación. Este es AppBootstrapAppServiceProvider . El proveedor de servicios de aplicaciones contiene un register y un método boot .
Dentro del método register , debe unir las cosas al contenedor de inyección de dependencia. Sin embargo, no debe intentar resolver ningún enlace. rutas, o ejecutar cualquier otra pieza de funcionalidad dentro del método register . De lo contrario, puede usar accidentalmente un servicio dentro de un contenedor que aún no se ha cargado.
Este método se llama después de que todos los demás proveedores de servicios se hayan registrado, otorgando acceso a todos los servicios registrados por el marco. Cualquier lógica de inicialización que desee ejecutar aquí debe colocarse aquí.
<?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
}
} Puede usar el método make para resolver una instancia de clase desde el contenedor DI. El método make en la instancia de la aplicación acepta el nombre de la clase o interfaz que desea resolver:
use App Services MailService ;
$ mailService = app ()-> make (MailService::class); También puede obtener la instancia de la aplicación utilizando la instance del método Static directamente en la clase Application .
use Core Main Application ;
use App Services MailService ;
$ mailService = Application:: instance ()-> make (MailService::class); El método make es particularmente útil cuando se intenta resolver una clase desde un componente de código donde no es práctico inyectar una dependencia utilizando el tipo de inicio. En tales escenarios, puede solicitar explícitamente el contenedor de inyección de dependencia de la aplicación para resolver una instancia para usted.
Las rutas se definen en el archivo approutes.php , lo que permite a los desarrolladores registrar fácilmente varias rutas para manejar diferentes solicitudes HTTP.
Las rutas se registran invocando el método relevante en la fachada de ruta, como Route::get() , e implican especificar un patrón URI como el primer argumento. El segundo argumento puede ser un cierre o una matriz que define el controlador y el método responsable de manejar la solicitud.
Por ejemplo:
<?php
use App Controllers AuthController ;
use Core Facade Route ;
Route:: get ( " /settings " , function () {
// handling logic goes here
});
Route:: post ( " /register " , [AuthController::class, " register " ]);Cada vez que se combina una solicitud URI, se ejecuta el método de cierre o controlador correspondiente y se genera una respuesta y se envía de vuelta al navegador.
Puede registrar rutas que respondan a cualquier verbo HTTP utilizando los siguientes métodos:
Route::get($uri, $callback);Route::post($uri, $callback);Route::put($uri, $callback);Route::patch($uri, $callback);Route::delete($uri, $callback);Route::options($uri, $callback); A veces necesitará capturar segmentos del URI dentro de su ruta. Por ejemplo, es posible que deba capturar la ID de un usuario de la URL. Puede hacerlo definiendo los parámetros de ruta:
Route:: get ( ' /user/{id} ' , function ( string $ id ) {
return ' User ' . $ id ;
});
Route:: get ( " /story/{id} " , function ( $ id ) { /*...*/ });Puede definir tantos parámetros de ruta como lo requiera su ruta:
Route:: post ( " story/edit/{id} " , [StoryController::class, " edit " ]);
Route:: get ( " story/{story_id}/comment/{comment_id} " , [StoryController::class, " comment " ]);Estos también se pasarán al método del controlador.
Elemental maneja sin problemas la inyección de las dependencias necesarias para los métodos de su controlador. Esto le permite especificar cualquier dependencia requerida por su ruta en la firma de devolución de llamada utilizando el tipo de inicio. Elemental se encarga de resolver e inyectar automáticamente las dependencias declaradas en la devolución de llamada.
Por ejemplo, si escribe CoreRequestRequest dentro de la devolución de llamada, Elemental asegura que la solicitud HTTP actual se inyecte automáticamente en su devolución de llamada de ruta:
<?php
use Core Request Request ;
Route:: get ( ' /users ' , function ( Request $ request ) {
// ...
});Puede poner las dependencias tipificadas y los parámetros de ruta en cualquier orden.
Cuando pasa una ID del modelo como parámetro a una ruta o acción del controlador, el enfoque típico implica consultar la base de datos para obtener el modelo correspondiente basado en esa ID. Elemental simplifica este proceso a través de la unión del modelo de ruta, ofreciendo una forma conveniente de inyectar automáticamente instancias de modelo directamente en sus rutas.
Por ejemplo, en lugar de inyectar solo la ID de un usuario en su ruta, tiene la opción de inyectar toda la instancia del modelo de usuario que corresponde a la ID dada.
En el contexto de rutas o acciones del controlador, los modelos se definen utilizando nombres variables de tipo que coincidan con un segmento específico en la ruta. Por ejemplo:
use App Models User ;
Route:: get ( ' /users/{user} ' , function ( User $ user ) {
return $ user -> email ;
}); A veces es posible que desee resolver modelos usando una columna que no sea id . Para hacerlo, puede especificar la columna en la definición de parámetros de ruta:
use App Models User ;
Route:: get ( ' /users/{user:email} ' , function ( User $ user ) {
return $ user ;
});En este escenario, Elemental inyectará sin problemas la instancia del modelo que posee un correo electrónico que coincida con el valor correspondiente del URI de solicitud.
Por supuesto, la unión del modelo de ruta también funciona con métodos del controlador.
Si no se encuentra una instancia de modelo de coincidencia en la base de datos, la aplicación arrojará un ModelNotFoundException . Puede manejar tales excepciones y controlar el comportamiento de cualquier tal y otras excepciones lanzadas por la aplicación en la clase ExceptionsHandler . Más sobre eso más tarde.
Usando el método Route::fallback , puede definir una ruta que se ejecutará cuando ninguna otra ruta coincida con la solicitud entrante.
Route:: fallback ( function () {
// ...
}); El comando de vela route:list proporcionará la lista de todas las rutas definidas en la aplicación:
php candle route:list En lugar de consolidar todas las solicitudes de manejo de la lógica dentro de los cierres en los archivos de su ruta, considere estructurar este comportamiento a través de clases de "controlador". Los controladores le permiten organizar las solicitudes relacionadas de lógica de manejo en una clase cohesiva. Por ejemplo, una clase UserController podría administrar varias solicitudes entrantes relacionadas con los usuarios, como mostrar, crear, actualizar y eliminar a los usuarios. Estas clases de controlador se almacenan convencionalmente en el directorio app/Controllers .
Para generar un nuevo controlador, puede ejecutar el comando build:controller Candle.
php candle build:controller UserController Esto generará un nuevo archivo llamado "UserController.php" dentro del directorio de app/Controllers .
Un controlador puede tener cualquier número de métodos públicos que respondan a las solicitudes HTTP entrantes:
<?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 ( " / " );
}
}Después de crear una clase de controlador y sus métodos, puede definir una ruta al método del controlador de la siguiente manera:
use App Controllers UserController ;
Route:: get ( " /register " , [AuthController::class, " showRegister " ]); Cuando una solicitud recibida coincide con la URI de ruta designada, se llamará al método showRegister dentro de la clase AppControllersUserController , y el método recibirá los parámetros de ruta correspondientes.
El contenedor de servicio Elemental es responsable de resolver instancias de todos los controladores. En consecuencia, puede usar el tipo de tipos en el constructor de su controlador para especificar cualquier dependencia que pueda requerir. Las dependencias establecidas se resolverán e inyectarán automáticamente en la instancia del controlador
<?php
namespace App Controllers ;
use Core Database Database ;
class UserController
{
/**
* Create a new controller instance.
*/
public function __construct (
public Database $ db ,
) {}
} Además de inyectar dependencias a través del constructor, también puede usar el tipo de tipos para dependencias en los métodos de su controlador. Un caso de uso común para la inyección del método es inyectar la solicitud de CoreRequestRequest o cualquier instancia de servicio en sus métodos de controlador:
Crear y administrar controladores para manejar las solicitudes de manera efectiva.
<?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 Su método del controlador anticipa la entrada de un parámetro de ruta, tiene la flexibilidad de enumerar sus argumentos en cualquier orden. Por ejemplo, considere la siguiente definición de ruta:
Route:: post ( " story/update/{id} " , [StoryController::class, " update " ]); Todavía puede escribir el CoreRequestRequest y acceder a su parámetro id definiendo su método de controlador de la siguiente manera:
<?php
namespace App Controllers ;
use Core Request Request ;
class StoryController
{
public function update ( string $ id , Request $ request )
{
// Update $story
return redirect ( " /story/ $ story -> id " );
}
} La clase CoreRequestRequest en Elemental ofrece un enfoque orientado a objetos para participar con la presente solicitud HTTP administrada por su aplicación. Facilita la recuperación de la entrada, las cookies y los archivos enviados junto con la solicitud.
Para adquirir la instancia de solicitud HTTP actual a través de la inyección de dependencia, puede utilizar el tipo de ayuda para la clase CoreRequestRequest en el cierre de su ruta o el método del controlador. El contenedor de servicio inyectará automáticamente la instancia de solicitud entrante.
<?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 " );
}
}El contenedor de servicio inyectará automáticamente la solicitud entrante al cierre de la ruta también.
Si su método de controlador anticipa la entrada de un parámetro de ruta, tiene la flexibilidad de enumerar sus argumentos en cualquier orden. Por ejemplo, considere la siguiente definición de ruta:
Route:: post ( " story/update/{id} " , [StoryController::class, " update " ]); Todavía puede escribir el CoreRequestRequest y acceder a su parámetro id definiendo su método de controlador de la siguiente manera:
<?php
namespace App Controllers ;
use Core Request Request ;
class StoryController
{
public function update ( string $ id , Request $ request )
{
// Update $story
return redirect ( " /story/ $ story -> id " );
}
} Puede obtener todos los datos de entrada de la solicitud entrante como una array utilizando el método data() . Este método se puede usar independientemente de si la solicitud entrante es de un formulario HTML o es una solicitud XHR:
$ data = $ request -> data (); Puede acceder a toda la entrada del usuario desde su instancia Request sin preocuparse por qué verbo HTTP se utilizó para la solicitud. Independientemente del verbo HTTP, el método data puede usarse para recuperar la entrada del usuario:
$ name = $ request -> data ()[ " name " ]; La instancia de CoreRequestRequest proporciona una variedad de métodos para examinar la solicitud HTTP entrante. Discutamos algunos de los métodos más importantes a continuación.
Puede recuperar los encabezados de solicitud de la instancia CoreRequestRequest utilizando el método headers .
$ headers = $ request -> headers (); Puede recuperar el método de solicitud llamando method en la instancia de CoreRequestRequest .
$ method = $ request -> method (); Puede recuperar la solicitud URI de la instancia CoreRequestRequest utilizando el método uri .
$ uri = $ request -> uri (); Puede recuperar las cookies de solicitud de la instancia CoreRequestRequest Usando el método cookies .
$ cookies = $ request -> cookies (); Puede recuperar el contenido sin procesar de la instancia CoreRequestRequest utilizando el método rawContent .
$ content = $ request -> rawContent ();Tenga cuidado al tratar con el contenido sin procesar de una solicitud.
Puede recuperar los archivos de la instancia CoreRequestRequest utilizando el método files .
$ files = $ request -> files (); El método ip se puede usar para recuperar la dirección IP del cliente que realizó la solicitud a su aplicación:
$ ipAddress = $ request -> ip (); El método port se puede utilizar para recuperar la dirección del puerto del cliente que realizó la solicitud a su aplicación:
$ port = $ request -> port (); Puede recuperar el tipo de contenido de la instancia de la CoreRequestRequest utilizando el método contentType .
$ contentType = $ request -> contentType (); Puede recuperar la cadena de consulta de la solicitud utilizando el método queryString .
$ query = $ request -> queryString (); Puede recuperar el contenido de texto de la solicitud utilizando el método text siempre que el tipo de contenido esté configurado en text/plain
$ text = $ request -> text (); Puede recuperar el contenido JS de la solicitud utilizando el método js siempre que el tipo de contenido esté configurado en application/javascript
$ js = $ request -> js (); Puede recuperar el contenido HTML de la solicitud utilizando el método html siempre que el tipo de contenido esté configurado en text/html
$ js = $ request -> html (); Puede recuperar el contenido JSON de la solicitud utilizando el método json proporcionado de que el tipo de contenido esté configurado en application/json El $request->data() devuelve todos los datos JSON pasados a la solicitud. Sin embargo,
$ jsonData = $ request -> json (); El $request->data() contiene todos los datos JSON junto con las entradas pasadas a través de los parámetros de consulta en la solicitud. Sin embargo, $request->json() se puede usar para recuperar solo el contenido JSON.
Puede recuperar el contenido XML de la solicitud utilizando el método xml siempre que el tipo de contenido esté configurado en application/json
$ xmlData = $ request -> xml ();Se espera que cada ruta y controlador produzca una respuesta para la entrega al navegador del usuario. Elemental ofrece varios métodos para generar respuestas. La forma de respuesta más simple implica devolver una cadena directamente desde una ruta o controlador. El marco convertirá perfectamente esta cadena en una respuesta HTTP completa.
Route:: get ( ' / ' , function () {
return ' Hello World ' ;
});Además de devolver cadenas de sus rutas y controladores, también puede devolver matrices u objetos. El marco los convertirá automáticamente en una respuesta JSON:
Route:: get ( ' / ' , function () {
return [ 1 , 2 , 3 ];
}); Por lo general, no volverá simplemente a cadenas o matrices directas de las acciones de su ruta. En su lugar, a menudo devolverá instancias completas de CoreResponseResponse o Vistas.
Devolver una instancia Response completa le permite personalizar el código de estado HTTP de la respuesta y los encabezados. Puede inyectar la instancia de respuesta al instalar la instancia de respuesta dentro de su controlador o cierre de ruta.
use Core Response Response ;
Route:: get ( ' /home ' , function ( Response $ response ) {
$ response -> setHeader ( " content-type " , " text/plain " )
-> setStatusCode ( 200 )
-> setContent ( " Hello World " );
return $ response ;
}); Por supuesto, puede devolver una view desde un controlador. Sin embargo, si necesita control sobre el estado y los encabezados de la respuesta, pero también necesita devolver una view como contenido de la respuesta, puede hacerlo de lo siguiente:
use Core Response Response ;
class UserController {
public function register ( Response $ response ){
$ response -> setHeader ( " x-is_register " , " true " );
return view ( " Register " );
}
}Esto establecerá automáticamente el encabezado en la respuesta de vista que se enviará al navegador.
Tenga en cuenta que la mayoría de los métodos de respuesta son cadáveres, lo que permite la construcción fluida de instancias de respuesta.
Puede establecer el contenido de la respuesta utilizando el método setContent en la instancia de respuesta.
$ response -> setContent ( " ... " ); Sin embargo, si desea agregar al contenido de la respuesta, puede hacerlo utilizando el método appendContent en la instancia de respuesta.
$ response -> appendContent ( " ... " ); Puede establecer un encabezado en la instancia de respuesta utilizando el método setHeader
$ response -> setHeader ( " content-type " , " text/plain " ); Sin embargo, si desea establecer varios encabezados simultáneamente, puede hacerlo utilizando el método setHeaders y pasando una variedad de encabezados.
$ response -> setHeaders ([ " content-type " => " text/html " , ...]); Puede establecer directamente el código de estado de la respuesta utilizando el método setHeader en la instancia de respuesta.
$ response -> setStatusCode ( 301 );Se establecerá un texto de estado de forma predeterminada para los códigos de estado comunes.
Puede generar una respuesta de redirección que contenga los encabezados adecuados necesarios para redirigir al usuario a otra URL invocando redirect del método estático en la clase CoreResponseResponse .
use Core Response Response ;
Route:: get ( ' /dashboard ' , function () {
return Response:: redirect ( ' home/dashboard ' );
}); Sin embargo, para la simplicidad, una redirect() también está disponible a nivel mundial para lograr la misma funcionalidad.
use Core Response Response ;
Route:: post ( ' /story/create ' , function () {
if (! $ someCondition )
return redirect ( ' /story ' , 204 );
}); También puede generar una respuesta JSON llamando al método estático JSON en la clase CoreResponseResponse . Los datos pasados al método se convertirán en JSON adecuado. También puede pasar opcionalmente el código de estado y la matriz de encabezados como el segundo y tercer argumento a la función.
use Core Response Response ;
Route:: post ( ' /post ' , function () {
$ post = ( . . . );
return Response:: JSON ( $ post , 201 , [ " header " => " value " ]);
});Middleware ofrece un mecanismo conveniente para examinar y filtrar solicitudes HTTP entrantes a su aplicación. Por ejemplo, puede desarrollar middleware para validar el estado de autenticación del usuario de su aplicación. Si el usuario no está autenticado, el middleware los redirigirá a la pantalla de inicio de sesión. Por el contrario, si el usuario está autenticado, el middleware permitirá que la solicitud avance más profundamente en la aplicación.
Tiene la flexibilidad de crear un middleware adicional para ejecutar diversas tareas más allá de la autenticación. Como ilustración, un middleware de registro podría registrar todas las solicitudes entrantes a su aplicación. Estos componentes del middleware se encuentran dentro del directorio app/middlewares .
Para crear un nuevo middleware, use el comando build:middleware Candle:
php candle build:middleware IsAuthenticated Ejecución de este comando generará una nueva clase de middleware llamada "isAuthenticated" en el directorio app/middlewares . Dentro de esta clase, se crea un método llamado handle donde puede articular la lógica para el middleware.
Aquí, solo permitiremos el acceso a la ruta si el usuario está autenticado, de lo contrario, redirigiremos a los usuarios al 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 );
}
} Para aprobar la solicitud más profundamente en la solicitud, debe llamar a la devolución de llamada $next con la $request .
Considere el middleware como una secuencia de "capas" que HTTP solicita Traverse antes de llegar a su aplicación. Cada capa tiene la capacidad de analizar la solicitud y potencialmente rechazarla.
Por supuesto, un middleware puede realizar tareas antes o después de pasar la solicitud más profunda en la aplicación. Por ejemplo, este middleware realizaría su tarea después de que la aplicación maneje la solicitud:
<?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 ;
}
} Si desea asignar middleware a rutas específicas, puede invocar el método middleware al definir la ruta:
Route:: get ( ' /profile ' , function () {
// ...
})-> middleware (IsAuthenticated::class); Puede asignar múltiples middleware a la ruta pasando una matriz de nombres de middleware al método middleware :
Route:: get ( ' / ' , function () {
// ...
})-> middleware ([First::class, Second::class]); Puede asignar MiddleWares a un grupo de ruta pasando una variedad de nombres de middleware al atributo middlewares al definir el grupo:
Route:: group ([ " middleware " => [HasSession::class]], function () {
Route:: get ( " / " , [StoryController::class, " index " ]);
Route:: get ( " /story/{story} " , [StoryController::class, " show " ]);
}); Puede usar grupos de ruta anidados para combinar los artículos intermedios con su grupo principal. En el ejemplo posterior, el middleware "Hassession" se aplica a las rutas "/" y "/story/{story}" , mientras que "Hassession", "Isauth" y "log" se aplican los artículos intermedios al resto de las rutas:
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 " ]);
});
});En el marco de PHP Elemental, no es práctico devolver cadenas completas de documentos HTML directamente de las rutas y controladores. Las vistas proporcionan una forma conveniente de colocar todo HTML en archivos separados.
Las vistas juegan un papel crucial en la separación de la lógica del controlador/aplicación de las preocupaciones de presentación y se almacenan en el directorio app/views . Estos archivos de vista, escritos en PHP, encapsulan el marcado. Considere un ejemplo básico de una vista:
<html>
<body>
<h1>Hello, <?= $ name ?> </h1>
</body>
</html> Si esta vista se almacena en app/views/Welcome.php , se puede devolver utilizando el ayudante view global en una ruta:
Route:: get ( ' / ' , function () {
return view ( ' Welcome ' , [ ' name ' => ' Ahmed ' ]);
}); El primer argumento pasado al ayudante view corresponde al nombre del archivo de vista en el directorio resources/views . El segundo argumento puede ser una variedad de pares de valores clave pasados a la vista. Por ejemplo, en el código anterior, se puede acceder directamente $name y contendrá el valor 'Ahmed'.
Las vistas también se pueden devolver utilizando el make CoreViewView .
Route:: get ( ' / ' , function () {
return View:: make ( " Post " , $ params );
}); Las vistas pueden estar anidadas dentro de los subdirectorios del directorio app/views . La notación "DOT" puede usarse para hacer referencia a puntos de vista anidados. Por ejemplo, si su vista se almacena en app/views/layouts/MainLayout.php , puede devolverla de una ruta/controlador como así:
return view ( ' layouts.MainLayout ' , $ data ); Elemental proporciona una forma conveniente de mantener el mismo diseño en múltiples vistas, reduciendo la duplicación de código. Un diseño es en sí mismo un archivo de vista que contiene un marcador de posición {{ content }} . Cuando se devuelve una vista con el diseño, la vista final se compila colocando la vista dentro del contenido del diseño.
Elemental proporciona una forma conveniente de mantener el mismo diseño en múltiples vistas, reduciendo la duplicación de código. Un diseño es un archivo de vista que incorpora un marcador de posición designado, denotado por {{ content }} . Cuando se devuelve una vista utilizando un diseño específico, la composición se logra incrustando el contenido de la vista dentro del marcador de posición designado en el diseño. Este enfoque optimiza la organización de vistas y mejora la mantenibilidad del código al centralizar los elementos de diseño comunes.
A continuación se muestra un ejemplo básico:
<!DOCTYPE html >
< html lang =" en " >
< head >
<!-- Head content -->
</ head >
< body >
< ?= component("components.Navbar") ? >
< div style =" min-height: calc(100vh - 140px); " >
{{ content }}
</ div >
</ body >
</ html >Se puede devolver una vista con un diseño como este:
public function compose ()
{
return view ( " Compose " )-> withLayout ( " layouts.DashboardLayout " );
}Elemental ofrece un enfoque poderoso para elaborar vistas. Cada vista es esencialmente un componente, y cualquier vista puede ensamblarse a partir de otros componentes. Es una sinfonía de composición, donde cada pieza contribuye a la creación de un todo armonioso y dinámico.
Archivo de componente de ejemplo ( views/components/Logo.php ):
<a class="logo" href="/ " >
<span class= " logo-img">
<img src="logo.png" class ="logo-text">
LOGO
</span>
</a> Este componente se puede usar dentro de cualquier otro archivo de vista. Por ejemplo, en views/Login.php :
<div>
<?= component ( " components.Logo " ) ?>
<p>Welcome Back!</p>
<!-- Other login form elements -->
</div>Por lo tanto, Elemental lo capacita con el diseño y las construcciones de componentes, lo que le permite componer sus puntos de vista con la delicadeza de los enfoques de arriba hacia abajo y de abajo hacia arriba. Esta flexibilidad permite una fusión perfecta, donde puede mezclar y combinar elementos sin esfuerzo para elaborar una interfaz de usuario elegante y sofisticada para su aplicación.
En las aplicaciones web modernas, la interacción de la base de datos es un aspecto fundamental. Elemental ha sido diseñado para optimizar esta interacción sin problemas en una amplia gama de bases de datos compatibles, aprovechando las capacidades inherentes de PDP PDO. Con Elemental, tiene la flexibilidad de ejecutar cualquier consulta o transacción compleja utilizando la clase CoreDatabaseDatabase .
Elemental ofrece un sólido mapeador de objetos relacionarios (ORM) que abstrae de manera efectiva muchas complejidades, lo que demuestra que la mayoría de las consultas de bases de datos. Sin embargo, la CoreDatabaseDatabase se puede usar para ejecutar consultas SQL más avanzadas.
Todas las configuraciones para su aplicación Elemental se encuentran en el archivo de configuración de app/config/config.php de su aplicación. Aquí puede definir todas las conexiones de su base de datos, así como especificar qué conexión debe usarse de forma predeterminada. La mayoría de las opciones de configuración dentro de este archivo están impulsadas por los valores de las variables de entorno de su aplicación.
Todas las configuraciones para su aplicación Elemental se encuentran en el archivo de configuración de app/config/config.php de su aplicación. Aquí puede definir todas las conexiones de su base de datos, así como especificar qué conexión debe usarse de forma predeterminada. La mayoría de las opciones de configuración dentro de este archivo están impulsadas por los valores de las variables de entorno de su aplicación.
<?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 usa PDO como la clase de manejo de bases de datos subyacentes. Todas las funciones PDO están directamente disponibles en la clase CoreDatabaseDatabase . Puede inyectar una instancia de CoreDatabaseDatabase en cualquier método de constructor o controlador para llamar a los métodos PDO. La configuración predeterminada para Elemental está configurada para bases de datos MySQL, pero puede cambiar el controlador dentro del archivo de configuración.
Aquí hay un ejemplo de ejecutar una consulta a través de la instancia 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 ();
}Para obtener más información sobre PDO, puede consultar la documentación PDO de PHP
Elemental incluye un mapeador de objetos personalizado (ORM) personalizado que hace que sea agradable interactuar con la base de datos. Cuando se usa el ORM, cada tabla de base de datos tiene un "modelo" correspondiente que se utiliza para interactuar con esa tabla. Además de recuperar registros de la tabla de la base de datos, los modelos le permiten insertar, actualizar y eliminar registros de la tabla también.
Los modelos están presentes en el directorio de app/models y extienden la clase CoreModelModel . Puede generar un nuevo modelo utilizando el comando build:model Vandle.
php candle build:model Post Los modelos generados por el comando build:model se colocarán en el directorio app/Models . Un modelo muy básico tiene la siguiente estructura:
<?php
namespace App Models ;
use Core Model Model ;
class Post extends Model
{
// ...
} Nombre de la tabla: por convención, el "caso de serpiente", el nombre plural de la clase se utilizará como el nombre de la tabla a menos que se especifique otro nombre explícitamente. Entonces, en este caso, Elemental asumirá los registros de tiendas Post Model en la tabla posts .
Puede especificar manualmente el nombre de la tabla del modelo definiendo una propiedad tableName en el modelo:
<?php
namespace App Models ;
use Core Model Model ;
class Post extends Model
{
protected $ tableName = ' elemental_posts ' ;
}Clave principal:
Elemental también asumirá que la tabla de base de datos correspondiente de cada modelo tiene una columna clave principal llamada id . Si es necesario, puede definir una propiedad $primaryKey protegida en su modelo para especificar una columna diferente que sirva como la clave principal de su modelo:
<?php
namespace App Models ;
use Core Model Model ;
class Post extends Model
{
protected $ primaryKey = ' elemental_id ' ;
}Puede pensar en cada modelo como un poderoso constructor de consultas que le permite consultar con fluidez la tabla de la base de datos asociada con el modelo.
El método all del modelo recuperará todos los registros de la tabla de base de datos asociada del modelo:
use App Models Story ;
foreach (Story:: all () as $ story ) {
echo $ story [ " content " ];
}Por defecto, los registros que se obtienen se representan como una matriz. Sin embargo, puede pasar un argumento de modo que controla cómo se representa cada registro. El argumento de modo toma cualquiera de los modos de búsqueda de PDO. Por ejemplo,
use App Models Story ;
foreach (Story:: all () as $ story ) {
echo $ story -> content ;
} El método allWhere es una poderosa abstracción en el modelo que permite ejecutar consultas complejas. Este método toma tres argumentos: conditions , options y fetchMode .
public static function allWhere( array $ conditions , array $ options = [], int $ fetchMode = PDO :: FETCH_ASSOC ) CONDICIONES: El parámetro conditions es una variedad de cláusulas que el registro debe satisfacer para ser obtenido. Cada condición puede ser un par [key => value] o un par [key => [operator, value]] .
key corresponde a una columna específica en la tabla.[key => value] , el operador predeterminado es = y el value es los datos dentro de esa columna para el registro.[key => [operator, value]] , puede especificar el operador para cada condición. Los operadores compatibles son:['=', '!=', '<', '>', '<=', '>=', 'LIKE', 'IS NULL', 'IS NOT NULL'] . Opciones: El parámetro options es una matriz que determina argumentos de consulta adicionales, como order by , limit , etc. Las construcciones compatibles en el argumento de opciones incluyen:
"orderBy""limit""offset""sortDir" FetchMode: el parámetro fetchMode controla cómo se representa cada registro recuperado. El argumento de modo toma cualquiera de los modos de búsqueda de PDO:
PDO::FETCH_ASSOCPDO::FETCH_NUMPDO::FETCH_BOTHPDO::FETCH_OBJPDO::FETCH_CLASSPDO::FETCH_INTOPDO::FETCH_LAZYPDO::FETCH_KEY_PAIRUn ejemplo lo dejará más claro:
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
);
}
} Además de recuperar todos los registros que coinciden con una consulta dada, también puede recuperar registros únicos utilizando el método find y where . En lugar de devolver una matriz de registros, estos métodos devuelven una sola instancia de modelo:
Encuentra: esto alcanzará el primer registro que coincida con la clave principal de la tabla.
$ flight = Story:: find ( 1 ); Dónde: El método Where toma una variedad de condiciones que el registro debe satisfacer para ser recogido. Cada condición puede ser un par [key => value] o un par [key => [operator, value]] .
key corresponde a una columna específica en la tabla.[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'] .Por ejemplo
$ 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. Por ejemplo:
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:
intento
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. ¡Eso es todo! ¡Gracias!
For bug reports, feature requests, or general questions, please use the issue tracker.