Uma estrutura de micro php adaptável que tenta ficar fora do seu caminho.
Muito um trabalho em andamento, use por sua conta e risco ...
Certeza da morte. Pequena chance de sucesso. O que estamos esperando?
composer require danc0/gimliduck-php
Crie um projeto de esqueleto com: composer create-project danc0/gimli-skeleton
Adicione os devtools com composer require --dev danc0/gimliduck-devtools
Crie um arquivo .htaccess que se parece algo assim para apontar solicitações para o seu arquivo index.php
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
Criar um aplicativo Gimliduck é simples:
declare (strict_types= 1 );
require_once __DIR__ . ' /vendor/autoload.php ' ;
use Gimli Application ;
use Gimli Router Route ;
Application:: create ( __DIR__ , $ _SERVER );
Route:: get ( ' / ' , function (){
echo " Hello World " ;
});
Application:: start ();Isso é realmente tudo o que você precisa para começar. Você pode adicionar mais como um mecanismo de modelo, um arquivo de configuração, etc., mas não precisa .
<?php
declare (strict_types= 1 );
require_once __DIR__ . ' /vendor/autoload.php ' ;
use Gimli Application ;
use App Core Config ;
use App Core Cache ;
define ( ' APP_ROOT ' , __DIR__ );
$ App = Application:: create ( APP_ROOT , $ _SERVER );
// set up your config and add it to the Application
$ config_file = parse_ini_file ( APP_ROOT . ' /App/Core/config.ini ' , true );
$ App -> Config = $ App -> Injector -> resolveFresh (Config::class, [ ' config ' => $ config_file ]);
// Register a cache class with the Injector
$ App -> Injector -> register (Cache::class, Cache:: getCache ( $ App -> Config -> admin_cache ));
// Run Application
$ App -> run (); A classe Application também registra o manipulador de eventos básicos e a aula de sessão quando é criado. Além disso, se a sua configuração incluir enable_latte o mecanismo de modelo LATTE será adicionado à instância do aplicativo usando o valor de configuração para o template_base_dir como o diretório de modelos.
Por padrão, o GIMLI exigirá quaisquer arquivos no diretório App/Routes . Você pode desativar isso definindo autoload_routes como false em seu arquivo de configuração. Você pode alterar o diretório definindo o valor do route_directory no seu arquivo de configuração. Você também pode carregar arquivos de rota adicionais com o seguinte método:
// Load routes from a file(s)
$ App -> loadRouteFiles ([
' App/routes/web.php ' ,
]);Existem algumas coisas que você pode fazer com seus retornos de chamada de rota ... Passe uma corda, uma chamada ou uma matriz.
Route::get( ' / ' , function (){
echo " Hello World "
});
// Single action controller, must use __invoke method
Route:: get ( ' / ' , Home_Controller::class);
// cli routes are single action Job classes
Route:: cli ( ' build-cache ' , Cache_Job::class);
Route:: get ( ' / ' , Home_Controller::class . ' @homePage ' );
Route:: get ( ' / ' , [Home_Controller::class, ' homePage ' ]);Qualquer um desses trabalhos, cabe a você como você faz isso.
Você pode adicionar middleware se precisar de alguma defesa extra
Route:: get ( ' / ' , [Home_Controller::class, ' homePage ' ])-> addMiddleware (Logged_In_Middleware::class); Essa deve ser uma classe que implementa GimliMiddlewareMiddleware_Interface , que requer um método process que retorne GimliMiddlewareMiddleware_Response . O Middleware tem acesso à instância do aplicativo, incluindo o injetor e o que você decidir defini -lo.
Você também pode adicionar grupos, definir um arquivo de rota padrão que deve carregar e carregar arquivos de rota adicionais para ajudar a organizar suas rotas.
Suas rotas também podem conter argumentos variáveis que atendem aos seguintes padrões:
protected array $ patterns = [
' :all ' => " ([^/]+) " ,
' :alpha ' => " ([A-Za-z_-]+) " ,
' :alphanumeric ' => " ([w-]+) " ,
' :integer ' => " ([0-9_-]+) " ,
' :numeric ' => " ([0-9_-.]+) " ,
' :id ' => " ([0-9_-]+) " ,
' :slug ' => " ([A-Za-z0-9_-]+) " ,
]; Você precisará adicionar o nome da variável usando o símbolo # na definição de rota.
Route:: get ( ' /user/:integer#id ' , [User_Controller::class, ' getUser ' ]); Esse nome de variável é passado para o roteador e definido como uma dependência para o seu método do controlador. Você deve usar o nome da variável definida como um argumento no seu método do controlador. O valor será TypeCast com base nos tipos disponíveis para settype , possíveis tipos:
integer or int
float or double
string
array
object
boolean or bool
Método do controlador de exemplo:
public function getUser ( Response $ Response , int $ id ): Response {
// do something with $id
} Os controladores devem retornar um objeto GimliHttpResponse . Existem métodos auxiliares que retornam objetos Response formatados para ajudar a limitar alguma lógica condicional:
response uma resposta básicaredirect a resposta de redirecionamentoredirect_on_success redirecionar se a resposta for bem -sucedidaredirect_on_failure redirecionar se a resposta não for bem -sucedidajson_response JSON RESPOSTA Os arquivos de trabalho também recebem os seguintes argumentos subcommand , options e flags . O argumento options é uma matriz de matrizes que contêm o nome e o valor. O argumento flags é uma matriz com os sinalizadores fornecidos. O argumento subcommand é apenas uma string se um subcomando foi dado.
Você pode usar o injetor embutido para vincular ou registrar dependências. Você também pode resolver dependências do injetor. Você pode adicionar tudo o que precisar ao injetor e acessá -lo durante todo o aplicativo através da instância Application .
O injetor incorporado será classes automaticamente e resolverá as dependências, conforme necessário. Você também pode vincular uma classe a um fechamento se precisar fazer alguma configuração antes de retornar a classe ou registrar um objeto já criado. O exemplo abaixo mostra um único controlador de ação que seria resolvido na classe do roteador. Os parâmetros do método __construct são resolvidos do injetor.
<?php
declare (strict_types= 1 );
namespace App Controllers ;
use App Logic Dashboard_Logic ;
use Gimli Http Response ;
use Gimli Application ;
use Gimli View Latte_Engine ;
class Dashboard_Landing_Controller {
/**
* Constructor
*
* @param Application $Application
*/
public function __construct (
public Application $ Application ,
protected Dashboard_Logic $ Dashboard_Logic ,
protected Latte_Engine $ View
){
//
}
/**
* Single action controller call
*
* @return Response
*/
public function __invoke ( Response $ Response ): Response {
$ template_data = $ this -> Dashboard_Logic -> getTemplateData ();
return $ Response -> setResponse ( $ this -> View -> render ( ' dashboard/dashboard.latte ' , $ template_data ));
}
}Os parâmetros do método também são resolvidos pelo injetor quando a rota despacha o método.
Existem também métodos de auxiliar injetor que reduzem algum código em linha. Normalmente, se você quiser injetar uma classe embutida, poderá fazê-lo com $this->Application->Injector->resolve(Some_Class::class) ou Application::get()->Injector->resolve(Some_Class::class) . Os métodos resolve e resolve_fresh estão disponíveis para cortar nesse código embutido.
Existe um Database básico de wrapper, bem como uma classe Pdo_Manager que você pode usar para gerenciar consultas de banco de dados. A classe Pdo_Manager retorna e a instância do PDO e pode ser usada para executar consultas diretamente. A classe Database é um invólucro na classe Pdo_Manager e fornece alguns métodos básicos de consulta. Há também uma classe base Model muito básica e métodos de auxiliar adicionais para Database , como em outros lugares, esses métodos lidam com a injeção de dependência e chamam os métodos na classe de Database injetada. Os ajudantes são:
fetch_columnfetch_rowfetch_allrow_exists Existe uma classe básica de sementes que pode ser usada para semear seu banco de dados. Isso se baseia em atributos colocados nas classes modelo para instruir o Seeder a criar os dados.
<?php
declare (strict_types= 1 );
namespace Gimli Database ;
use Gimli Database Model ;
use Gimli Database Seed ;
class User_Model extends Model {
/**
* @var string $table_name
*/
protected string $ table_name = ' users ' ;
/**
* ID
*
* @var int $id
*/
public $ id ;
/**
* Unique_Id
*
* @var string $unique_id
*/
#[Seed(type: ' unique_id ' , args: [ ' length ' => 12 ])]
public $ unique_id ;
/**
* Username
*
* @var string $username
*/
#[Seed(type: ' username ' )]
public $ username ;
/**
* Email
*
* @var string $email
*/
#[Seed(type: ' email ' )]
public $ email ;
/**
* Password
*
* @var string $password
*/
#[Seed(type: ' password ' )]
public $ password ;
/**
* Is_Active
*
* @var int $is_active
*/
#[Seed(type: ' tiny_int ' )]
public $ is_active ;
/**
* First Name
*
* @var string $first_name
*/
#[Seed(type: ' first_name ' )]
public $ first_name ;
/**
* Last Name
*
* @var string $last_name
*/
#[Seed(type: ' last_name ' )]
public $ last_name ;
/**
* Status
*
* @var int $status
*/
#[Seed(type: ' one_of ' , args: [ 0 , 1 ])]
public $ status ;
/**
* Created_At
*
* @var string $created_at
*/
#[Seed(type: ' date ' , args: [ ' format ' => ' Y-m-d H:i:s ' , ' min ' => ' 2021-01-01 ' , ' max ' => ' 2021-04-01 00:00:00 ' ])]
public $ created_at ;
/**
* Updated_At
*
* @var string $updated_at
*/
#[Seed(type: ' date ' , args: [ ' format ' => ' Y-m-d H:i:s ' , ' min ' => ' 2021-04-01 00:02:00 ' ])]
public $ updated_at ;
/**
* bio
*
* @var string $about
*/
#[Seed(type: ' paragraph ' , args: [ ' count ' => 1 ])]
public $ about ;
}Você pode semear o banco de dados com o seguinte código:
Seeder:: make (User_Model::class)
-> seed ( 123 )
-> count ( 1 )
-> create (); Em vez de criar, você pode chamar getSeededData para obter os dados que seriam inseridos no banco de dados. Isso é útil para testar ou carregar manualmente um modelo sem salvá -lo. Você também pode passar um método de retorno de chamada que receberá os dados do modelo inicial. Isso ajuda a semear dados relacionados. O retorno de chamada deve devolver uma variedade de instâncias Seeder .
Seeder:: make (User_Model::class)
-> seed ( 123 )
-> count ( 1 )
-> callback ( function ( $ data ) {
return [
Seeder:: make (User_Hobby_Model::class)-> with ([ ' user_id ' => $ data [ ' id ' ]]),
Seeder:: make (User_Group_Model::class)-> with ([ ' user_id ' => $ data [ ' id ' ]]),
]
})
-> create (); A semente passada garante que os dados permaneçam os mesmos sempre que o semeador é executado, resultando em conjuntos de dados reprodutíveis. A classe Seeder possui um método getRandomSeed que retornará um valor aleatório de semente. Isso é útil para criar dados aleatórios que você não precisa ser reproduzível ou para gerar uma semente aleatória que você pode copiar e usar.
Existem também alguns ajudantes de configuração:
get_config para obter toda a matriz de configuraçãoget_config_value para obter um valor específico da matriz de configuraçãoconfig_has para verificar se existe uma chave na matriz de configuração