atomdev / odinfmk
简单的PHP框架
Requires
- php: ^7.1
This package is auto-updated.
Last update: 2024-09-07 00:27:34 UTC
README
Ødin 是一个简单、实用、高效的 PHP 框架。旨在做得多,写得更少。如果您还没有许可证,请联系我们 contato@atomsi.com.br。
文档
安装
使用 Composer 安装 Ødin。
composer require atomdev/odinfmk
开始一个项目
首先,您必须在 Composer 的 autoload 文件(vendor/autoload.php)中定义常量 ODIN_SERIAL 和 ODIN_ROOT。
define("ODIN_SERIAL", "SUA_SERIAL"); define("ODIN_ROOT", "/diretorio/raiz/do/projeto");
然后,在项目根目录下,您需要定义项目的基本结构。
config/
|-- .env
http/
controllers/
|-- Aqui ficarão seus Controllers
middlewares/
|-- Aqui ficarão seus Middlewares
database/
models/
|-- Aqui ficarão seus Models
views/
|-- Aqui ficarão suas views
utils/
|-- Aqui ficarão suas classes de utilidades e seus Helpers
.htaccess
请注意,上述结构只是标准的基本模板。您可以根据需要创建自己的自定义文件夹。
定义项目配置
在 config 文件夹中,您需要创建一个名为 .env 的文件。这将作为项目的配置文件。其中将定义环境、数据库、目录和项目访问URL。以下是一个示例模型:
ENVIRONMENT = dev
DRIVER = mysql
SOURCE_DIR = src/
HTTP_ROOT = https://:8080
HTTP_ROOT_FILES = https://:8080/assets/
您可以使用两个环境:开发和生产。使用常量 ODIN_ENV 一起使用 ODIN_ROOT 和 ODIN_PATH,当设置为 dev 时,需要在配置文件夹中创建一个名为 dev.env 的文件,其中包含开发指令,而 .env 将成为生产指令。
定义应用程序的路由
在定义路由之前,您需要配置项目根目录中的 .htaccess 文件。打开文件后,您将看到以下结构:
RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [QSA,L]
ErrorDocument 403 https:///pagina/de/erro/403
Options All -Indexes
您可以为错误 403 定义一个处理页面,这些错误是在用户尝试访问受限制的文件夹时抛出的。默认情况下,所有应用程序文件夹都通过 HTTP 禁止访问。
配置 .htaccess 后,您可以在 index.php 文件中定义您的路由,如下例所示。
<?php //Incluindo o autoload do Composer require_once(dirname(dirname(__FILE__)) . "/vendor/autoload.php"); //Utilizando as classes Config e Routes da Framework use Odin\utils\Config; use Odin\routes\Routes; Config::init("projeto"); //nome da pasta do seu projeto Routes::init(); //Rota GET Routes::get("/", function(){ echo "Primeiro projeto com a Ødin Framework!"; })->name("home"); //Rota POST Routes::post("/", "Projeto\http\controllers\Classe:metodo"); //Rota PUT Routes::put("/", "Projeto\http\controllers\Classe:metodo"); //Rota DELETE Routes::delete("/", "Projeto\http\controllers\Classe:metodo"); //Definindo um grupo de rotas $instance = Routes::getInstance(); Routes::group("/grupo", function() use ($instance){ Routes::get("/", "Projeto\http\controller\sClasse:metodo"); }); Routes::run();
Ødin 支持 4 种 HTTP 请求类型,包括 GET、POST、PUT 和 DELETE。这为您创建 RESTful API 提供了极大的便利性和实用性。
控制器
控制器是 Callable,它们被传递到路由中,以便在访问时执行某些操作。您可以通过两种方式创建一个用于特定路由的控制器:
功能方式
Routes::get("/teste", function(){ echo "Olá, Mundo!"; })
面向对象方式
Routes::get("/teste", "App\http\controllers\Teste:olaMundo");
对于面向对象的方式,您需要在 controllers 文件夹中创建一个类,如下例所示。
<?php
namespace App\http\controllers; //O namespace master é o de sua preferencia
use Odin\http\controller\Controller;
class Teste extends Controller
{
public function olaMundo()
{
echo "Olá, Mundo";
}
}
在控制器中恢复动态路由的值
Ødin 也支持动态路由,即包含变量结构的路由。以下是一个示例。
Routes::get("/filme/:categoria", "App\http\controllers\Filmes:listarPelaCategoria");
要定义路由中的动态部分,您应使用 /:nomeDaVariavel。以下是一些此类路由的请求示例:
GET https:///projeto/filme/terror
GET https:///projeto/filme/acao
GET https:///projeto/filme/romance
要恢复传递到路由中的值并将其用于应用程序,只需在控制器方法中添加一个参数即可。
class Filmes extends Controller
{
public function listarPelaCategoria($categoria)
{
echo $categoria;
}
}
您也可以使用正则表达式定义传递给变量的模式,如下例所示。
Routes::get("/filme/:id", "App\http\controllers\Filmes:selecionarPeloId", ["id" => "[\d]{1,8}"]);
正则表达式将强制值遵循该模式,否则将抛出错误。
路由重定向
您还可以使用路由名称进行重定向,如下例所示。
Routes::get("/login", "App\http\controllers\Login:view")->name("loginPage");
要进行重定向,只需在上下文中使用 router 属性即可。
$this->router->redirectTo("loginPage");
使用视图
与任何 MVC 应用程序一样,您可以使用视图来渲染视觉元素,如表单、列表等。在 Ødin 中,视图是从控制器中渲染的,具体是在访问路由时调用的方法中。
Config::init("projeto");
Routes::init();
Routes::get("/login", "App\http\controllers\Login:view");
控制器将在 projeto/source/views 文件夹中查找视图。
要渲染视图,只需遵循以下模型。
use Odin\view\View;
class Login extends Controller
{
use View;
public function view()
{
View::render($this, "login_page.php");
}
}
View::render() 的参数
下表显示了可以传递给 render 方法的参数。值默认为空的参数表示必须包含一个值。
定义默认头部和尾部
您可以将文件定义为头部和尾部来存储全局上下文信息,这些文件应位于 views 文件夹中。例如,HTML 页面的 <head> 和所有 CSS 调用,或页面末尾的 <script>。以下是一个示例。
views/header.php
<!DOCTYPE html>
<html>
<head>
<title>Projeto</title>
<meta charset="utf-8"/>
<link rel="stylesheet" type="text/css" href="./css/bootstrap.css"/>
<link rel="stylesheet" type="text/css" href="./css/style.css"/>
</head>
<body>
views/footer.php
<script src="./js/jquery.js"></script>
<script src="./js/bootstrap.js"></script>
</body>
</html>
index.php
Config::init("projeto");
Routes::init();
Routes::setHF("header.php", "footer.php");
Routes::get("/login", "App\http\controllers\Login:view");
如果您有一些页面需要加载特定的头部和尾部,您可以在控制器中阻止加载默认文件,如下例所示。
public function view()
{
View::render($this, "login_page.php", [], false);
}
从控制器传递值到视图
您可以将控制器中的数据共享给视图,例如,用于制作电影列表的数据。
public function listarFilmes()
{
View::render($this, "listar_filmes.php", [
"itens" => ["Filme 1", "Filme 2", "Filme 3"]
]);
}
在视图
<div class="container">
<table class="table table-hover">
<thead>
<tr>
<th>Chave</th>
<th>Filme</th>
</tr>
</thead>
<tbody>
<?php
foreach($itens as $i => $item)
{
echo "<tr>";
echo "<td>{$i}</td>";
echo "<td>{$item}</td>";
echo "</tr>";
}
?>
</tbody>
</table>
</div>
使用相同的属性,您可以检索您在视图中定义的任何路由的 URL,从而简化页面间的导航。但为此,您需要将 router 对象作为变量传递给视图。
public function view()
{
View::render($this, "login_page.php", [
"router" => $this->router
]);
}
在视图
<a href="<?= $router->pathFor("loginPage") ?>">Login Page</a>
如果您的路由是动态的并且需要传递一个值,您可以在 pathFor() 方法的第二个参数中传递引用。
<a href="<?= $router->pathFor("listarFilmes", ["categoria" => "terror"]) ?>">Login Page</a>
全局作用域对象(依赖项)
如果您的视图需要访问某个类 utils 或 helper 的某个对象,您可以在 index.php 文件中定义全局作用域对象,如下例所示。
use Odin\Globals;
Globals::set([
new Helper(),
new Dependencia()
]);
在视图,您可以通过以下方式访问这些作为依赖项传递的对象
<div>
<?= $helper->someMethod() ?>
<?= $dependencia->algumaCoisa() ?>
</div>
中间件
Ødin 还提供了对中间件的支持,方式非常实用和简单,如下例所示。
namespace App\http\middlewares;
use Odin\http\middleware\IMiddleware;
use Odin\utils\superglobals\Session;
class Auth implements IMiddleware
{
public function handle($request, $response, $next)
{
if(Session::exists("_token"))
{
return $next($request, $response);
}
else
{
die("Você precisa fazer login para acessar esta página");
}
}
}
在 index.php 中,您通过 add() 方法定义中间件列表。
Routes::add(["home"], [
new Auth()
]);
Routes::get("/home", "App\http\controllers\Home:landing")->name("home");
您可以将中间件添加到路由、名称和组。要添加到所有路由的中间件,请使用 ["*"]。
模型
CRUD
在开始使用项目中的模型之前,请确保在 config/.env 中定义了 DRIVER 指令,并且如果在该文件夹中有一个包含连接数据的文件,则存在该文件。例如:config/mysql.env 或 config/pgsql.env。
DRIVER = mysql
HOST = 127.0.0.1
USERNAME = root
PASSWORD = root
PORT = 3306
SCHEMA = dbname
要使用模型,只需在 database/models 文件夹中创建一个类,并赋予它以下结构。
namespace App\database\models;
use Odin\database\orm\ORMMapper;
class SimpleModel extends ORMMapper
{
private $tableName = "teste";
public function __construct()
{
parent::__construct();
parent::setTableName($this->tableName);
}
}
Select
检索表中所有现有记录
use App\database\models\SimpleModel;
$model = new SimpleModel();
var_dump($model->findAll());
通过 id 检索记录
$model->findById(10);
通过 WHERE 子句检索记录
$model->where(["id" => 10], ">")->get(); // id > 10
$model->where(["id" => [10, 20]], "BETWEEN")->get(); // id BETWEEN 10 AND 20
$model->where(["id" => [10, 20]], "NOT BETWEEN")->get(); // id NOT BETWEEN 10 AND 20
$model->where(["name" => "User"], "LIKE")->get(); // name LIKE '%User%'
$model->where(["name" => "user"], "LIKE_L")->get(); // name LIKE '%User'
$model->where(["name" => "user"], "LIKE_R")->get(); // name LIKE 'User%'
$model->where(["id" => [1, 2, 3, 4, 5]], "IN")->get(); // id IN (1,2,3,4,5)
$model->where(["id" => [1, 2, 3, 4, 5]], "NOT IN")->get(); // id NOT IN (1,2,3,4,5)
$model->where(["id" => "NULL"], "IS")->get(); // id IS NULL
使用 get() 检索特定字段
$model->where(["id" => 10], "<=")->get("id, name, age");
使用 ORDER BY 排序记录
$model->where(...)->orderBy("id", "ASC")->get();
分组记录
$model->where(...)->groupBy("id")->get();
$model->where(...)->groupBy("id")->having(...)->get();
Insert
要插入记录,只需向模型对象添加新属性并使用 save() 方法。
$model->name = "New User";
$model->email = "user@email.com";
$model->age = 20;
$model->save();
如果成功插入新记录,save 方法必须返回一个 PDOStatement,如果插入失败,则返回 false。
Update
要执行更新,您将使用与插入相同的结构,但必须提供 id。它是区分 INSERT 命令和 UPDATE 命令的关键。
$model->id = 25;
$model->name = "Name Updated";
$model->save();
Delete
要执行 DELETE,您必须首先检索要删除的记录,并使用 remove() 方法。如下例所示。
$model->findById(10)->remove();
Joins
您可以为表添加别名以简化其使用,如下例所示。
class SimpleModel extends ORMMapper
{
private $tableName = "teste";
private $tableAlias = "t";
public function __construct()
{
parent::__construct();
parent::setTableName($this->tableName, $this->tableAlias);
}
}
并按如下方式使用它
$model->innerJoin("another a")->on("a.id = t.fk")->get();
$model->leftJoin("another a")->on("a.id = t.fk")->get();
$model->rightJoin("another a")->on("a.id = t.fk")->get();
$model->innerJoin("another a")
->on("a.id = t.fk")
->where(["id" => 10], ">=")
->get();
实用工具
Flash 消息
类 Odin\utils\FlashMessages 允许您定义在显示后自动销毁的消息,此功能可用于实现应用程序中的实时通知,请看以下示例。
public function simpleMethod()
{
//Define uma nova mensagem
FlashMessages::add("Teste", "Testando mensagens flash");
//Recupera o valor da mensagem
echo FlashMessages::get("Teste");
//Verifica se há uma mensagem na chave informada
var_dump(FlashMessages::has("Teste"));
}
全局变量
命名空间 Odin\utils\superglobals 包含用于处理 PHP 的原生全局变量($_GET, $_POST, $_SERVER, $_SESSION, $_COOKIE 和 $_FILES)的类。
请看以下示例。
use Odin\utils\superglobals\Post;
use Odin\utils\FlashMessages;
class Teste extends Controller
{
public function autenticar()
{
$usuario = Post::get("usuario");
$senha = Post::get("senha");
if($usuario === "user" && $senha === "pass")
{
FlashMessages::add("Sucesso", "Autenticação realizada com sucesso!");
$this->router->redirectTo("home");
}
else
{
FlashMessages::add("Erro", "Não foi possível realizar a autenticação");
$this->router->redirectTo("login");
}
}
}
数据过滤器
类 Odin\utils\Filter 提供了一系列方法用于数据过滤,无论是密码、电子邮件还是普通文本。
use Odin\utils\Filter;
...
public function filtrarDados()
{
$email = Filter::email(Post::get("email"));
$senha = Filter::clear(Post::get("senha"));
var_dump(Filter::isValidEmail($email));
}
头部信息
您还可以使用类 Odin\http\server\Header 来管理您的请求头部信息。
use Odin\http\server\Header;
...
public function getDataAsJSON()
{
Header::contentType("application/json");
return [
["name" => "John", "age" => 20],
["name" => "Doe", "age" => 22]
];
}
发送电子邮件
您可以通过使用类 Odin\utils\Mail 来简化使用 mail 函数发送电子邮件的方式,如以下示例所示。
public function enviarEmail()
{
Mail::from("sender@email.com.br");
Mail::write("to@email.com.br", "Teste de Envio de Email");
Mail::headers();
Mail::message("<b>Hey! Testando envio de email pela Ødin!</b>");
echo (Mail::send() ? "Email enviado." : "Email não enviado.");
}
集合
集合是实现基于强类型语言(如 Java 和 C#)的数据结构的类,它们被实现以简化对象数组的操作,即 Odin\utils\collections 中包含的所有集合都应与对象一起使用。在 Ødin 的这个版本中,实现了 3 个集合,它们是:ArrayList、Dictionary 和 Queue。
ArrayList
ArrayList 将多个对象组合成一个类似数字键的数组,如下面的示例所示,但它以面向对象的方式、更加组织和易于操作。
$array = [
0 => new Usuario()
];
使用 ArrayList
use App\classes\Usuario;
use Odin\utils\collections\ArrayList;
use Odin\utils\Functions;
$arraylist = new ArrayList(Usuario::class);
$arraylist->add(new Usuario());
Functions::debug($arraylist->get(0));
Dictionary
Dictionary 是一个键值对结构,也就是说,需要提供一个字符串类型的键和一个对象作为值,这就像是一个具有非数字键的数组,如下面的示例所示
$array = [
"nome" => "Odin"
"tipo" => "Framework"
];
使用 Dictionary
use App\classes\Usuario;
use Odin\utils\collections\Dictionary;
$dictionary = new Dictionary("string", Usuario::class);
$dictionary->add("user1", new Usuario());
$dictionary->add("user2", new Usuario());
echo $dictionary->toJson();
Queue
Queue 是一个队列,也就是说,首先插入的元素将是第一个被删除的元素,无法通过索引或键来检索特定元素,始终是按照升序或降序的方式。
use App\classes\Animal;
use Odin\utils\collections\Queue;
$queue = new Queue(Animal::class);
$queue->add(new Animal("Bolt"));
$queue->add(new Animal("Max"));
\Odin\utils\Functions::debug($queue->peek());