werx/core

Werx 项目使用的入口控制器和其他核心库。

2.0.0 2019-02-28 22:14 UTC

This package is auto-updated.

Last update: 2024-08-29 03:20:56 UTC


README

Werx 项目的核心库

Build Status Total Downloads Latest Stable Version

更多了解请访问 Werx 项目 或查看 werx\Skeleton 以获取参考实现。

安装

使用 Composer 安装此包非常简单。如果您不熟悉 PHP 的 Composer 依赖管理器,您应该先阅读这篇文档

{
	"require": {
        "werx/core": "dev-master"
    },
	"minimum-stability": "dev"
}

建议的目录结构

  • 您的应用程序位于 src/,并具有基本命名空间 Example\Project
  • 您的控制器位于 src/controllers/,并具有命名空间 Example\Project\Controllers
    • 您的控制器扩展 werx\Core\Controller
src/
	config/
		local/
			config.php
		test/
		prod/
		config.php
		routes.php
	controllers/
		Home.php
	models/
	views/
		home/
			index.php
		layouts/
			default.php
vendor/
	Composer's installation directory
web/
	index.php
	composer.json

入口控制器

您的 web/index.php 作为入口控制器,包含以下内容

<?php
# File: web/index.php

namespace Example\Project; // Change this to whatever base namespace you are using in your project.

$app_dir = dirname(__DIR__);

// Use Composer's autoloader.
require_once $app_dir . '/vendor/autoload.php';

// Pass a couple options to our dispatcher.
$opts = ['app_dir' => $app_dir, 'namespace' => __NAMESPACE__];

$app = new \werx\Core\Dispatcher($opts);

// Dispatch the request.
$app->dispatch();

这将使请求分发控制权转到 werx.Core 分发器。

路由

路由由 Aura Router 处理。

分发器中提供了一些合理的默认路由。

$router->add(null, null);
$router->add(null, '/');
$router->add(null, '/{controller}');
$router->add(null, '/{controller}/{action}');
$router->add(null, '/{controller}/{action}/{id}');

以下所有都会调用您的 Home 控制器的 index() 方法。

这个也会调用 index,但还会将值 "1" 传递给 index 方法。

同样,您可以像这样调用 Foo 控制的 bar() 方法

如果您想提供不同的路由,只需在源目录下创建一个名为 config 的目录,并在其中创建一个名为 routes.php 的文件,该文件定义了您需要的路由。

src/
	config/
		routes.php

有关路由选项的更多信息,请参阅 https://github.com/auraphp/Aura.Router

配置

配置管理器基于 werx\Config

基本配置用法

// Load our primary config file.
$this->config->load('config');

$something = $this->config->get('something');

// You can load any configuration file...
$this->config->load('database');

支持多环境配置

配置管理器支持不同环境的配置(本地、开发、测试、生产等)。要激活特定环境的配置,在 src/config 下创建一个与您的环境同名子目录。此目录应包含配置文件,其中包含您想要在环境中覆盖主配置的任何项目。

示例

src/config/test/database.php

您可以通过修改 src/config/environment 文件的内容来指定应用程序正在运行的环境,只需在其中包含您活动环境的名称。

然后,按正常方式加载您的配置。配置项将在默认配置和环境特定覆盖之间合并。

有关配置管理的更多信息,请参阅werx\Config 文档

额外的配置辅助方法

getBaseUrl()

返回应用程序基础的绝对URL(不包含文件名,例如 index.php)。接受一个可选参数,作为追加到基础URL的路径。

var_dump($this->config->getBaseUrl());
// http://example.com/

var_dump($this->config->getBaseUrl('image.jpg'));
// http://example.com/image.jpg

var_dump($this->config->getBaseUrl('home/index'));
// http://example.com/home/index

getSiteUrl()

返回包含文件名的应用程序基础的绝对URL(例如 index.php)。接受一个可选参数,作为追加到站点URL的路径。

var_dump($this->config->getSiteUrl('home/index'));
// http://example.com/index.php

var_dump($this->config->getSiteUrl('home/index'));
// http://example.com/index.php/home/index

模板

模板由Plates 项目提供,该项目是非凡包联盟的一部分。

在此项目中,所有主题和布局都位于src/views

基本模板使用方法

class Home extends Controller
{
	public function __construct()
	{
		// Set our default template.
		$this->template->layout('layouts/default');
	}

	public function index()
	{
		// Set some variables for all views.
		$this->template->page_title = 'Werx Skeleton';

		// Render and Display the home/index view, passing a variable named "heading".
		$this->template->output('home/index', ['heading' => 'Congratulations, it worked!']);

		// Same as above, but return the rendered content instead of displaying.
		// $content = $this->template->render('home/index', ['heading' => 'Congratulations, it worked!']);
	}
}

我在Plates的常规模板类中扩展了两种重要方式

    1. 我添加了output()方法,以便您可以在不使用echo的情况下显示渲染的视图。
    1. 在渲染/显示内容之前,所有变量都会被转义,以防止跨站脚本。

如果您有不想自动转义的变量(例如:预渲染的HTML),可以通过调用unguard('param_name')来防止转义。

$this->template->unguard('html');
$this->template->output('home/index', ['html' => '<p>Some <strong>markup</strong>.</p>']);

预填充

我为模板类添加了一些功能,以便在变量不存在时轻松从视图中获取默认值。

class Home extends Controller
{
	public function __construct()
	{
		// Set our default template.
		$this->template->layout('layouts/default');
	}

	public function index()
	{
		// Grab our prefill content from the request and mass assign.
		$this->template->setPrefill($this->input->get());
		
		// Or we can pull the prefill content from session.
		$this->template->setPrefill($this->session->get('prefill'));

		// Render and Display the home/index view.
		$this->template->output('home/index');
	}
}

然后在我们的视图中

<!-- Prefill from the 'foo' variable if it exists. If not, it will default to null. -->
<input type="text" name="foo" value="<?=$this->prefill('foo')?>" />

<!-- Prefill from the 'bar' variable if it exists. If not, it will default to 'some default value'. -->
<input type="text" name="bar" value="<?=$this->prefill('bar', 'some default value')?>" />

有关模板使用的更多信息,请参阅Plates 项目文档

HTTP 抽象

HTTP 抽象由Symfony\HttpFoundation提供。这提供了一些有用的事物,例如

  • 面向对象的访问 $_GET$_POST$_SESSION$_COOKIE 等。
  • 内部/外部重定向
  • JSON/JSONP 响应
namespace Example\Project\Controllers;

use Illuminate\Database\Capsule\Manager as Model;
use werx\Core\Controller;
use werx\Core\Database as DB;
use werx\Skeleton\Models\Widget;

class Home extends Controller
{
	// Internal Redirect (another resource in our app)
	public function internalRedirect()
	{
		$this->redirect('home/foo'); # Foo method of the Home Controller.
	}

	// External Redirect
	public function externalRedirect()
	{
		$this->redirect('http://www.google.com');
	}

	// Output data json-encoded with proper headers.
	public function getJson()
	{
		$data = (object) ['items' => ['foo', 'bar']];
		$this->json($data);
	}

	// Output data json-encoded with proper headers and callback.
	// Default callback name is 'callback'
	public function getJsonp()
	{
		$data = (object) ['items' => ['foo', 'bar']];
		$this->jsonp($data, 'callback');
	}
}

$_GET 和 $_POST

核心控制器有一个对httpFoundation Request 对象的引用,但我发现访问 $_GET$_POST 属性的语法并不理想。因此,我为 httpFoundation Request 对象构建了一个包装器,使其语法更友好。

示例

# Symfony way to access an attribute from $_POST
$foo = $this->request->request->get('foo');

# Werx way to access an attribute from $_POST
$foo = $this->input->post('foo');

# Symfony way to access an attribute from $_GET
$foo = $this->request->query->get('foo');

# Werx way to access an attribute from $_GET
$foo = $this->input->get('foo');

# Symfony way to access the entire $_POST array
$post = $this->request->request->all();

# Werx way to access the entire $_POST array
$post = $this->input->post();

# Symfony way to access the entire $_GET array
$get = $this->request->query->all();

# Werx way to access the entire $_GET array
$get = $this->input->get();

尝试从 get/post 访问不存在的属性时返回 null。如果您想得到除 null 之外的默认值,请向 $this->input->get()$this->input->post() 传递第二个参数。

// Returns 'foo'
$foo = $this->input->post('nonexistent', 'foo');

在默认的 Request 对象中,您必须将 true 作为第三个参数传递给 $this->request->query->get(),以便访问“深层”数组键。在我的覆盖中,这默认为 true

$bar = $this->input->get('foo[bar]'); 

有关 HttpFoundation 组件的更多信息,请参阅Symfony 文档

数据库

数据库抽象由Illuminate\Database处理。

您的模型

# File: src/models/Widget.php

namespace Example\Project\Models;

use Illuminate\Database\Eloquent\Model;

class Widget extends Model
{
	public $timestamps = false; # Aren't using the default timestamp columns
}

您可以直接扩展 Eloquent\Model,也可以扩展 werx\Core\Model(它扩展了 Eloquent),以获得对查询构建器的轻松访问。

# File: src/models/Widget.php

namespace Example\Project\Models;

use werx\Core\Model;

class Widget extends Model
{
	public $timestamps = false; # Aren't using the default timestamp columns
	
	public static function search($params = null)
	{
		$query = self::queryBuilder();
		
		if (array_key_exists('firstname', $params))
		{
			$query->where('firstname', $params['firstname']); 
		}

		if (array_key_exists('lastname', $params))
		{
			$query->where('lastname', $params['lastname']); 
		}
		
		return $query->get();
	}
	
}

有关工作示例,请参阅 tests/resources/models/Captain。

在尝试使用数据库之前,请初始化数据库。

use werx\Core\Database as DB;

/*
DSN can be pear-style DSN string: mysql://username:password@host/database OR an array of connection params

$defaults = [
	'driver'	=> 'mysql',
	'host'		=> 'localhost',
	'database'	=> 'mysql',
	'username'	=> 'root',
	'password'	=> null,
	'charset'	=> 'utf8',
	'collation'	=> 'utf8_unicode_ci',
	'prefix'	=> null
];
*/

DB::init($dsn);

一旦初始化了数据库,您就可以从任何地方调用您的 ORM 模型。

// Get all widgets:
$widgets = \Example\Project\Models\Widget::all()->toArray();

foreach ($widgets as $widget) {
	var_dump($widget['type']);
	var_dump($widget['size']);
	var_dump($widget['color']);
}

有关 ORM 的更多信息,请参阅Laravel Eloquent 文档

您还可以访问流畅查询构建器。

use Illuminate\Database\Capsule\Manager as QueryBuilder;

$result = QueryBuilder::table('captains')->where('lastname', 'Kirk')->get();

有关流畅查询构建器的更多信息,请参阅Laravel 数据库文档

多数据库连接支持

要使用多个数据库连接初始化 Eloquent,您可以将连接参数数组传递给 DB::init()

# DSN Strings
$dsn = ['default' => 'mysql://username:password@hostname/primarydb', 'otherdb' => 'mysql://username:password@hostname/otherdb'];

DB::init($dsn);
# Connection setting array
$dsn = [
	'default' => [
		'driver'	=> 'mysql',
		'host'		=> 'localhost',
		'database'	=> 'primarydb',
		'username'	=> 'username',
		'password'	=> 'password'
	],
	'otherdb' => [
		'driver'	=> 'mysql',
		'host'		=> 'localhost',
		'database'	=> 'otherdb',
		'username'	=> 'username',
		'password'	=> 'password'
	]
];

DB::init($dsn);		

然后在您的模型中指定要使用的连接。

<?php
use Illuminate\Database\Eloquent\Model;
class Widget extends Model
{
	public $timestamps = false;
	public $connection = 'otherdb';
}