Soli is a lightweight PHP framework, which refers to the design of the Phalcon and Laravel framework, and is intended to be loosely coupled, scalable, simple and easy to use.
MVC, dependency injection, event management, flash messages, template engine (Twig, Smarty) routing, command line application and other functions
From the above picture we can see that the processing flow of Soli request is:
Application handes the received HTTP request to the routing process and hands the routing result to the controller scheduler; the controller processes the application's business logic, calls the corresponding model and view, and returns the processing result to the Application through the scheduler to perform the final HTTP response encapsulation.
In addition, Soli provides component mechanisms provided by dependency injection containers, so developers can easily use various services in the container when developing components.
Soli's event manager allows developers to intercept some components of the framework or application by creating "hooks". In order to obtain status information, manipulate data, or change the execution flow in a certain component process.
$ composer create-project soliphp/soliphp my-project
$ cp my-project/.env.example my-project/.env
$ php -S localhost:8000 -t my-project/public
Browser access http://localhost:8000/.
upstream php-fpm
{
server unix:/tmp/php-fpm.sock;
}
server
{
listen 80 ;
server_name www.soliphp.com;
index index.html index.php;
root /path/to/soliphp/public;
location / {
try_files $uri $uri / /index.php? $query_string ;
}
location ~ .php$ {
include fastcgi.conf;
fastcgi_pass php-fpm;
}
} # Apache 2.4
< VirtualHost *:80>
ServerAdmin [email protected]
DocumentRoot " /path/to/soliphp/public "
DirectoryIndex index.php
ServerName www.soliphp.com
< Directory "/path/to/soliphp/public">
Options All
AllowOverride All
Allow from all
Require all granted
RewriteEngine on
RedirectMatch 403 /..*$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php
</ Directory >
</ VirtualHost > ├── app 应用程序目录
│ ├── Console 终端命令应用控制器目录
│ │ ├── Command.php 终端命令应用基类
│ │ └── Demo.php Demo命令
│ ├── Controllers WEB应用控制器目录
│ │ ├── Controller.php 控制器基类
│ │ ├── IndexController.php 默认控制器
│ │ └── UserController.php 和用户相关的控制器
│ ├── Events 事件目录
│ │ ├── AppEvents.php WEB应用事件
│ │ └── UserEvents.php 用户相关的事件
│ ├── Models 模型目录
│ │ ├── Model.php 模型基类
│ │ └── UserModel.php 用户模型
│ ├── Services 服务层目录
│ │ ├── Service.php 服务基类
│ │ └── UserService.php 用户相关的服务
│ └── bootstrap.php
├── bin
│ └── console 终端命令应用入口文件
├── composer.json composer配置文件
├── config 配置文件目录
│ ├── config.php 基础配置文件
│ ├── console.php 针对终端命令应用的配置文件
│ ├── routes.php 路由配置文件
│ └── services.php 容器服务配置文件
├── phpcs.xml
├── public WEB服务公共可被访问的文件目录
│ ├── css
│ ├── img
│ ├── index.php WEB程序入口文件
│ └── js
├── var 生成的文件目录
│ ├── cache 缓存文件目录
│ └── log 日志文件目录
└── views 视图文件目录
└── index IndexController 对应的视图目录
└── index.twig index 函数对应的视图文件
The directory structure is not fixed. The directory structure can be agreed upon according to actual project needs and team development habits, and the meaning of each directory can be defined and expressed.
There are two basic constants defined in bootstrap.php :
APP_PATH 对应 app 目录
BASE_PATH 项目根目录
The basic configuration information is stored in the config/config.php file by default:
<?php
// 基本配置信息
$ config = array (
// 应用
' app ' => array (
' viewsDir ' => BASE_PATH . ' /views/ ' ,
' logDir ' => BASE_PATH . ' /var/log/ ' ,
' cacheDir ' => BASE_PATH . ' /var/cache/ ' ,
),
// 数据库
' db ' => array (
' dsn ' => ' mysql:host=localhost;port=3306;dbname=test;charset=utf8 ' ,
' username ' => ' root ' ,
' password ' => ' root ' ,
),
// 更多...
);composer is an excellent package management tool and a trend, so Soli uses composer for automatic loading and dependency management.
In composer.json, the app directory is configured as the namespace at the beginning of the app:
"autoload": {
"psr-4": {
"App\": "app/"
}
}
Therefore, classes defined by PSR-4 rules in the app directory can be automatically loaded when called, like the Controllers and Console directories.
The purpose of dependency injection container is to reduce the coupling of code and improve the maintainability of the application. Transform dependencies between components into dependencies on containers, and service management (creation, configuration and positioning) is performed through containers.
The configuration of the container service is stored in the config/services.php file by default:
<?php
use Soli Di Container ;
use Soli Db Connection as DbConnection ;
use Soli Logger ;
use Soli View ;
use Soli View Engine Twig as TwigEngine ;
use Soli View Engine Smarty as SmartyEngine ;
$ container = new Container ();
// 将配置信息扔进容器
$ container -> set ( ' config ' , require BASE_PATH . ' /config/config.php ' );
// 配置数据库信息, Model中默认获取的数据库连接标志为"db"
// 可使用不同的服务名称设置不同的数据库连接信息,供 Model 中做多库的选择
$ container -> set ( ' db ' , function () {
return new DbConnection ( $ this -> config -> db );
});
// 路由
$ container -> set ( ' router ' , function () {
$ routesConfig = require BASE_PATH . ' /config/routes.php ' ;
$ router = new Soli Router ();
$ router -> setDefaults ([
// 控制器的命名空间
' namespace ' => " App \ Controllers \"
]);
foreach ( $ routesConfig as $ route ) {
list ( $ methods , $ pattern , $ handler ) = $ route ;
$ router -> map ( $ methods , $ pattern , $ handler );
}
return $ router ;
});
// TwigEngine
$ container -> set ( ' view ' , function () {
$ config = $ this -> config ;
$ view = new View ();
$ view -> setViewsDir ( $ config -> app -> viewsDir );
$ view -> setViewExtension ( ' .twig ' );
// 通过匿名函数来设置模版引擎,延迟对模版引擎的实例化
$ view -> setEngine ( function () use ( $ config , $ view ) {
$ engine = new TwigEngine ( $ view );
// 开启 debug 不进行缓存
//$engine->setDebug(true);
$ engine -> setCacheDir ( $ config -> app -> cacheDir . ' twig ' );
return $ engine ;
});
return $ view ;
});
// 如果使用 Smarty 的话,可进行如下设置:
// SmartyEngine
$ container -> set ( ' view ' , function () {
$ config = $ this -> config ;
$ view = new View ();
$ view -> setViewsDir ( $ config -> app -> viewsDir );
$ view -> setViewExtension ( ' .tpl ' );
// 通过匿名函数来设置模版引擎,延迟对模版引擎的实例化
$ view -> setEngine ( function () use ( $ config , $ view ) {
$ engine = new SmartyEngine ( $ view );
// 开启 debug 不进行缓存
$ engine -> setDebug ( true );
$ engine -> setOptions ( array (
' compile_dir ' => $ config -> app -> cacheDir . ' templates_c ' ,
' cache_dir ' => $ config -> app -> cacheDir . ' templates ' ,
' caching ' => true ,
' caching_type ' => ' file ' ,
' cache_lifetime ' => 86400 ,
));
return $ engine ;
});
return $ view ;
});In addition, SoliWebApp registers the following commonly used services by default for direct use by controllers and custom components:
| Service name | introduce | default | Is it a shared service? |
|---|---|---|---|
| router | Routing Services | SoliWebRouter | yes |
| dispatcher | Controller Scheduling Service | SoliDispatcher | yes |
| request | HTTP request environment service | SoliWebRequest | yes |
| Response | HTTP response environment service | SoliWebResponse | yes |
| session | Session Services | SoliWebSession | yes |
| flash | Flash Message Service | SoliWebFlash | yes |
Allow developers to customize services with the same name to override the default services above.
The entry files of the web application are stored in public/index.php by default, and look like this:
<?php
require dirname ( __DIR__ ) . ' /app/bootstrap.php ' ;
$ app = new Soli Web App ();
// 处理请求,输出响应内容
$ app -> handle ()-> send ();
$ app -> terminate ();The controller class defaults to "Controller" and action has no suffix.
The controller can access all services registered in the container by accessing properties.
<?php
use Soli Controller ;
use App Models User ;
class UserController extends Controller
{
/**
* 用户详情
*
* 自动渲染 views/user/view.twig 视图
*/
public function view ( $ id )
{
// 这里调用了容器中的 view 服务,设置一个模版变量
$ this -> view -> setVar ( ' user ' , User:: findById ( $ id ));
}
}The Soli model only provides some common methods for operating databases and does not implement ORM. This is determined by our data source and project architecture. It is possible that the data comes from a remote interface, and it is also possible that the team is more accustomed to using Doctrine. Soli respects developers' choices and usage habits in different application scenarios, and provides easy-to-scaling methods to enable you to implement data layers suitable for teams and actual needs.
Using the model:
<?php
use Soli Model ;
class User extends Model
{
}Here, when calling the User model, the service named "db" in the container will be called by default, and the table name of the operation is "user".
If you need to specify other database connection services, set it through the Model protected $connection property:
/**
* 当前模型访问的数据库连接服务名称
*/
protected $ connection = ' user_db ' ;Since the database connection service can be specified, multi-database operations are naturally supported.
The model will automatically convert the camel format of the class name to the underscore format of the corresponding table name, such as the RememberToken table name that is converted by the default model is remember_token.
We can also manually specify the table name through protected $table property of the Model:
/**
* 当前模型操作的表名
*/
protected $ table = ' xxx_user ' ; You can also specify the primary key through protected $primaryKey property of the Model, and the default primary key is id :
/**
* 当前模型所操作表的主键
*/
protected $ primaryKey = ' xxx_id ' ; The primary key is mainly used for findById and findByIds functions.
Please move to soliphp/db for the supported methods of Soli model.
The view file is stored in the views directory, and the directory structure corresponding to the controller and the view is:
├── app 应用程序目录
│ └── Controllers WEB应用控制器目录
│ └── UserController.php
└── views 视图文件目录
└── user UserController 对应的视图目录
└── view.twig view 函数对应的视图文件
Controller app/Controllers/UserController.php:
<?php
use Soli Controller ;
use App Models User ;
class UserController extends Controller
{
public function view ( $ id )
{
$ this -> view -> setVar ( ' user ' , User:: findById ( $ id ));
$ this -> flash -> notice ( ' user info ' );
}
}View file views/user/view.twig, here we take the twig template engine as an example:
用户姓名:{{ user . name }}
用户邮箱:{{ user . email }}
{{ flash. output () }}For more ways to use the view, please move to soliphp/view.
Thank you for reading.