php-mohamed-nabil / marrow-framework
marrow是一个PHP MVC框架,用于构建具有良好MVC模式结构的PHP Web应用,使开发更简单。
Requires
- php: >=8.0
- doctrine/inflector: 2.0.x-dev
- filp/whoops: ^2.15
- httpsoft/http-server-request: dev-master
- intervention/image: ^2.7
- league/booboo: dev-main
- league/oauth2-facebook: dev-main
- league/pipeline: dev-master
- nesbot/carbon: ^2.67
- optimus/onion: ~1.0
- php-mohamed-nabil/style: dev-master
- rakit/validation: dev-master
- respect/validation: ^2.2
- spatie/ignition: ^1.9
- symfony/password-hasher: 5.4.x-dev
- verot/class.upload.php: dev-master
- vlucas/phpdotenv: 5.6-dev
- dev-main
- v1.0.2
- v1.0.1
- v1.0
- dev-PHPMohamedNabil-patch-13
- dev-PHPMohamedNabil-patch-12
- dev-PHPMohamedNabil-patch-11
- dev-PHPMohamedNabil-patch-10
- dev-PHPMohamedNabil-patch-9
- dev-PHPMohamedNabil-patch-8
- dev-PHPMohamedNabil-patch-7
- dev-PHPMohamedNabil-patch-6
- dev-PHPMohamedNabil-patch-5
- dev-PHPMohamedNabil-patch-4
- dev-PHPMohamedNabil-patch-3
- dev-PHPMohamedNabil-patch-2
- dev-PHPMohamedNabil-patch-1
This package is auto-updated.
Last update: 2024-09-20 10:07:20 UTC
README
A php框架 使用MVC设计模式从头开始构建,具有(命令行微服务、路由、模板引擎、容器、服务提供者模式、mysql数据库、中间件)等功能,帮助您了解Poupler框架及其工作原理和内部操作。从新项目开始。
请查看以下存储库以创建新骨架项目。 https://github.com/PHPMohamedNabil/marrow
这是第一个版本,目前正在测试中。
目录
安装
composer create-project php-mohamed-nabil/marrow --prefer-dist myapp
请求生命周期
所有请求都指向public/index.php文件,该文件作为所有Web应用请求的前端控制器。
<?php define('CoreStart',microtime()); use Core\Request; use Core\Response; use Core\http\Kernal; require('autoload.php'); $app= require_once __DIR__.'/../bootstrap'.DS.'bootstrap.php'; $kernal = new Kernal; $kernal->lightOn(); $kernal->handle(new Request,$app); $kernal->lightOff();
首先创建一个新的应用程序实例,然后使用内核类运行所需的类或服务(位于startups文件夹下的启动项)来处理应用程序请求,然后将响应返回给客户端。
内核文件
内核文件就像主板一样,负责传递、配置和准备所有应用程序设置,并运行应用程序服务:请检查core/http/kernel.php内核文件
<?php namespace Core\Http; use Core\Request; use Optimus\Onion\Onion; use Core\App; use Core\Lightes\LightesFaced; use Core\Lightes\Lightes; use Dotenv\Dotenv; use Core\Session\Storage\SessionStorage; use Core\Session\SessionFactory; use Spatie\Ignition\Ignition; use Core\Configs\Config; class Kernal{ protected $app_middlewares=[]; public $lightes; public function __construct() { $dot_env = Dotenv::createMutable(ROOT_PATH); $dot_env->load(); app()::$config = Config::getInstance(); app()->session = SessionFactory::create(SessionStorage::class,require_once(SESSION_CONFIG)); $light_start = new Lightes(require_once(CONFIG_CONSTAN.'startups.php')); $this->lightes = new LightesFaced($light_start); app()->_csrftoken = session_token(); config()->load(CONFIG.DS.'app.php'); }
最轻组件
此类实现了设计模式,您可以选择或实现所有服务在应用程序请求开始时运行,并在响应返回后运行服务:请检查core/lightes
应用外观模式
<?php namespace Core\Lightes; use Core\Lightes\LightesInterface; class Lightes implements LightesInterface{ private $service_rooms; public function __construct(array $rooms) { $this->setRoom($rooms); } public function setRoom($rooms) { $this->service_rooms=$rooms; } public function on() { foreach($this->service_rooms as $service) { $service = app()::$container->get($service); app()::$container->resloveClassMethod($service,'register'); app()::$container->resloveClassMethod($service,'startup'); } } public function off() { } }
使用lightes接口创建自己的外观类实现
<?php namespace Core\Lightes; interface LightesInterface{ public function on(); public function off(); }
内核内部
请查看内核处理函数接受两个参数,第一个是请求对象,第二个是应用程序实例
在应用程序请求之前和之后运行中间件,然后将请求路由到资源
public function handle(Request $request,App $app) { $onion = new Onion; $onion->layer($this->middlewares())->peel($request, function($request){ return $request; }); return $app->run(); }
内核的开关方法
您可以看到这些方法在请求之前和响应输出之后运行
public function lightOn() { $this->enviroment(); $this->lightes->turnOn(); $this->setTimeZone(); } public function lightOff() { //after output services here return $this->lightes->turnOff(); }
迁移命令
要安装数据库模式,请运行:php migrate
运行所有迁移 php create_migration (迁移名称)
在迁移文件夹中创建新的迁移文件 php migrate role=(all)
回滚所有迁移 php migrate role=(迁移名称)
回滚迁移名称文件
控制器和模型命令
php create_controller (控制器名称)
在控制器文件夹下创建新的控制器文件
php create_controller (controlername) resource
在控制器文件夹下创建新的资源控制器
php create_controller (controlername) resource model
在控制器文件夹和模型文件夹下创建新的资源控制器和模型文件
php create_controller (controlername) model
在控制器文件夹和模型文件夹下创建新的控制器和模型文件
php create_model (模型名称)
在模型文件夹下创建新的模型文件
php create_repo (仓库名称)
在仓库文件夹下创建新的仓库文件
env文件
您可以通过浏览.env文件来检查和配置数据库连接、Web应用程序设置和会话设置。
APP_NAME=MyFIRSTAPP
SECRET_KEY=4fe8895cff6b23cd1f49b1c14c34a5a161248d1fba2d55392d3ef7d3d6296811
ENVIROMENT=development
DB=mysql
HOSTNAME=localhost
USERNAME=root
PASSWORD=
DBNAME=native_api
SESSION_LIFE_TIME=1800
SESSION_IDLE_TIME=1000
请随意编辑上述设置以适应您的环境设置。
生成应用程序密钥
此密钥非常重要,因为它在哈希数据算法中非常重要,它使用哈希应用程序名称并使用哈希过程作为密钥。
运行命令 php generate_key
您将看到生成的密钥,将其复制到 .env 文件中的 SECERET_KEY 值
路由
支持 GET、POST、HEAD、PUT、DELETE、OPTIONS
路由位于 app\routes 文件夹中:1-web.php 用于 web 路由
在我们的项目中,我们正在处理的路由,您可以按需更改它
use App\Core\Route\Router as Route; use App\Controllers\ProductController; use App\Controllers\UserController; Route::get('/',function(){ return view('home'); }); Route::middlewares('api',function(){ Route::prefix('api/',function(){ Route::resource(['product'=>ProductController::class]); Route::post('/user/register',[UserController::class,'store']); Route::get('/users/',[UserController::class,'allUsers'])->middleware('checktoken'); Route::post('/user/login',[UserController::class,'userAuth']); Route::get('/user/profile',[UserController::class,'profile'])->middleware('checktoken'); }); });
路由占位符
创建路由占位符,只需在占位符前加上 : 即可
use App\Core\Route\Router as Route; use App\Controllers\ProductController; use App\Controllers\UserController; Route::get('/user/:id',[UserController::class,'profile']);
路由正则表达式
使用正则表达式方法创建正则表达式路由,只需编写自己的正则表达式(不带正则表达式分隔符)
use App\Core\Route\Router as Route; use App\Controllers\ProductController; use App\Controllers\UserController; Route::get('/user/:id',[UserController::class,'profile'])->regx('(\d+)$');
应用程序路由列表
运行命令 **php route_list** 查看应用程序路由
样式模板引擎
marrow 使用样式模板引擎,这是一个快速且强大的基于原生代码的 PHP 模板引擎,具有强大的功能,如(模板继承、模板部分和硬编译功能),请参阅样式文档:[style](https://github.com/PHPMohamedNabil/Style)
应用程序 URL
打开 app\config\config_constants.php 文件:您将看到所有应用程序常量,最重要的是 SITE_URL
//webiste address and routes define('ROUTES_WEB',APP.'routes'); define('SITE_URL','https://:8000/'); define('SITE_AD_URL','https://:8000/admin/'); define('VENDOR',ROOT_PATH.'vendor'.DS);
将 SUTE_URL 常量更改为您的网站或本地主机 URL,该 URL 在公共文件夹中有文档根目录。
_tcsrf
这是一个 CSRF 令牌参数,您必须在任何 POST 请求中发送它(检查 cookie 获取完整的 CSRF 令牌)如下所示
中间件
从中间件数组中创建应用程序通用中间件或路由中间件,从 config/middlewares.php 中删除 CSRF 中间件。
<?php use App\Middlewares\csrf; use App\Middlewares\PostSize; use App\Middlewares\test; use App\Middlewares\XcsrfCookie; use App\Middlewares\ViewValidationError; use App\Middlewares\ApiMiddlware; use App\Middlewares\isLogedIn; return[ //startup application middleware here 'web'=>[ ViewValidationError::class, csrf::class, XcsrfCookie::class, ], //routes middlewares here example: ['middleware_name'=>'middleware'] 'route'=>[ 'test' => test::class, 'api' => ApiMiddlware::class, 'checktoken' => isLogedIn::class ] ];
服务提供者
创建应用程序服务提供者(类和服务在应用程序引导之前运行)。您可以在 startup 文件夹下创建这些类,并将其分配给 app\config\startup.php 中的 startups 数组。
应用容器模式(控制反转)
转到 startup 文件夹并创建新文件,例如:TimeZoneStartup.php,用于在应用程序启动之前设置默认时区(在每次请求应用程序之前)类似于 Laravel 框架中的服务提供者
<?php namespace App\Startups; use App\Repositories\BookInterface; use App\Repositories\BookRepository; use App\Core\Container\Container; use App\Startups\StartupInterface; use App\Core\Database\NativeDB; use App\Core\Request; class TimeZoneStartup implements StartupInterface { //timezone service provider if you are saving timezone in db //and wants to change it before application startup public function startup() { config()->set('date_default_timezone_set','Europe/Moscow'); //example:'Europe/Moscow' } public function register() { } }
这意味着每次请求应用程序时,都会将 date_default_timezone_set 设置为 'Europe/Moscow',或者您可以使用 date_default_timezone_set() 内置 PHP 函数编写自己的其他方法来更改时区。
所有启动项都是逐个运行的,实例化每个类并运行(引导)启动方法,然后运行注册方法
<?php use App\Startups\ProductStartup; use App\Startups\TimeZoneStartup; return[ ProductStartup::class, TimeZoneStartup::class ];
控制器
类似于 Laravel 中的控制器系统(模拟大多数),您可以在构造函数中分配中间件
<?php namespace App\Controllers; use Core\Controller; use Style\Style; use Core\Request; class HomeController extends Controller { public function __construct() { //middleware_array,except_methods array(optional) $this->middleware(['test',['home']]); }
模型-数据库
只需像任何框架一样创建模型,但这里使用的是原生数据库(没有 ORM 库)。
<?php namespace App\Models; use Core\Model; class UserModel extends Model { //you have to set table attributes her $id,$column_2,$column_3 ... //you should set table name attribute or we can predict it like User to be users ,UserCategory user_categories protected $mass = ['username','email']; // for mass assignment }
连接到数据库如下
所有模型都返回模型数据的对象
// $model = new user(12); //$model->columns['model_title']='updated'; //$model->columns['model_price']=2500000; //$model->create(['model_title'=>'coding model']); //for mass assignment //$model->save(); //for insert //$model->amend();// for update //$model->purge(); //for delete //$model->deleteSoft(12); //for soft delete
或如下
$user = new user; $user->get() // all users $user->get(12) //user with id = 12 $user->create(['username'=>'hambola','password'=>123]); // create new user hambola with new password $user->purge(12); remove user number 12 with (id=12) $user->update($this->model->table,['username'=>'hmobla edited'],['id'=>12]); edit user hambola with id =12
NativeDB 类
您可以使用此类轻松快速地创建自定义查询
<?php namespace App\Repositories; use App\Repositories\ProductRepositoryInterface; use App\Models\Product; use App\Core\Database\NativeDB;
$users = NativeDB::getInstance()->table('users')->paginate(10); returns array first element is data object ,seconde is key 'links' which has pagination links $links = $users?$users['links']:[]; foreach($users[0] as $user) { echo $user->username.':'.$user->id; }
NativeDB::getInstance()->table('users')->select('username')->limit(10)->run(); //username from users table limi 10 records NativeDB::getInstance()->table('users')->select('username')->where('id','=',12)->run(); //username from users table where id =12 NativeDB::getInstance()->table('users')->select('username')->where('id','=',12)->where('username','=','hambola')->run(); //username from users table where id =12 and username = hambola NativeDB::getInstance()->table('users')->select('username')->group_by('id')->run(); //username from users table groub by id NativeDB::getInstance()->table('users')->insertInto(['username'=>'hambola brother'])->run(); //insert new user from users table NativeDB::getInstance()->table('users')->deleteRow(['username'=>'hambola brother'])->run(); // delete where username hambola borhter NativeDB::getInstance()->table('users')->updateRow(['username'=>'hambola sister'],['id'=>13],$whereoperator='',$soft_delete=false)->run(); // update where id = 13 (keep two last params as example till further updates).
创建迁移文件
首先 运行命令 php create_migration users_table(将 users_table 替换为您自己的迁移文件名)。它将在迁移文件夹中创建一个新文件 users_table_date_time_000
<?php namespace App\Migrations; use Core\Database\NativeDB; class users__2023_09_03_17_56_59{ //$db for database object public function up($db) { $db->query('CREATE TABLE IF NOT EXISTS `users` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `username` varchar(256) NOT NULL, `password` VARCHAR(255) NOT NULL , `created` datetime NOT NULL, `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) )'); } public function down($db) { $db->query('DROP TABLE users'); }
在创建带有 SQL 方案的迁移文件后,运行 **php migrate** 将运行所有迁移文件并将它们全部提交。要回滚迁移,运行 **php migrate rollback**,回滚迁移运行 **php migrate roll=users__2023_09_03_17_56_59**,要回滚所有迁移,运行 php migrate roll=all
异常
使用了点火库(ignition library)具有特殊的自定义样式。
大框架(中间件,管道,存储库,命令,迁移,容器,配置,模板引擎)的概念
最后运行php marrow以在本地主机8000端口启动您的项目,或者例如运行php marrow(端口号)php marrow 4500