diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..319a2b6 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,12 @@ +* text=auto + +*.md diff=markdown +*.php diff=php + +/.github export-ignore +/tests export-ignore +.editorconfig export-ignore +.gitattributes export-ignore +.gitignore export-ignore +.php-cs-fixer.php export-ignore +phpunit.xml.dist export-ignore diff --git a/.gitignore b/.gitignore index 9c7c8b9..5e260f9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,10 @@ /vendor composer.phar -composer.lock .DS_Store Thumbs.db /.idea /.vscode /.git -.php-cs-fixer.cache \ No newline at end of file +.php-cs-fixer.cache +*.lock +*.cache \ No newline at end of file diff --git a/composer.json b/composer.json index 02b5321..f13e495 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,8 @@ "predis/predis": "^1.1", "ext-curl": "*", "monolog/monolog": "^2.3", - "ext-pdo": "*" + "ext-pdo": "*", + "psr/http-message": "^1.0" }, "require-dev": { "phpunit/phpunit": "^6.2 | ^7 | ^8 | ^9", diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 89d7396..b80e9a1 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,21 +1,16 @@ - + + + + src/ + + ./tests - - - src/ - - diff --git a/src/blankphp/Application.php b/src/blankphp/Application.php index dee6042..4696948 100644 --- a/src/blankphp/Application.php +++ b/src/blankphp/Application.php @@ -19,9 +19,11 @@ use BlankPhp\Database\Grammar\MysqlGrammar; use BlankPhp\Kernel\ConsoleKernel; use BlankPhp\Log\Log; +use BlankPhp\Request\Parse; use BlankPhp\Request\Request; use BlankPhp\Response\Response; use BlankPhp\Route\Route; +use BlankPhp\Route\RouteCollection; use BlankPhp\Route\Router; use BlankPhp\Scheme\Scheme; use BlankPhp\Session\Session; @@ -33,8 +35,7 @@ class Application extends Container private $version = '0.2.3-dev'; /** - * @var - * 存储单例 + * @var Application */ protected static $instance; @@ -45,6 +46,7 @@ public static function init() protected function __construct() { + parent::__construct(); $this->registerDirName(); $this->registerBaseService(); $this->registerBase(); @@ -59,7 +61,7 @@ public static function getInstance() { //Unsafe usage of new static() if (empty(static::$instance)) { - new self(); + new static(); } return static::$instance; @@ -80,7 +82,9 @@ public function registerBaseService() foreach ([ 'console' => ConsoleKernel::class, 'request' => [\BlankPhp\Contract\Request::class, Request::class], + 'request.parse' => [Parse::class], 'route' => [\BlankPhp\Contract\Route::class, Route::class], + 'route.collection' => [RouteCollection::class], 'router' => [Router::class], 'app' => [\BlankPhp\Contract\Container::class, __CLASS__], 'db' => Database::class, diff --git a/src/blankphp/Base/Traits/ContainerBindMake.php b/src/blankphp/Base/Traits/ContainerBindMake.php new file mode 100644 index 0000000..1569ec4 --- /dev/null +++ b/src/blankphp/Base/Traits/ContainerBindMake.php @@ -0,0 +1,28 @@ + + * + * This source file is subject to the MIT license that is bundled. + */ + +namespace BlankPhp\Base\Traits; + +trait ContainerBindMake +{ + private $bindThisObj = []; + + public function useThis($instance) + { + $this->bindThisObj[] = $instance; + } + + public function cleanThem() + { + foreach ($this->bindThisObj as $item) { + app()->cleanInstance($item); + } + } +} diff --git a/src/blankphp/Cache/Cache.php b/src/blankphp/Cache/Cache.php index 63d5b69..3737c63 100644 --- a/src/blankphp/Cache/Cache.php +++ b/src/blankphp/Cache/Cache.php @@ -108,7 +108,7 @@ public function set($key, $value, $ttl = null) /** * @param $key - * @param null $default + * @param $default * * @return mixed */ @@ -118,8 +118,6 @@ public function get($key, $default = null) } /** - * @param $key - * * @return mixed */ public function remember(string $key, \Closure $closure) diff --git a/src/blankphp/Collection/Collection.php b/src/blankphp/Collection/Collection.php index 525caff..b14d146 100644 --- a/src/blankphp/Collection/Collection.php +++ b/src/blankphp/Collection/Collection.php @@ -30,7 +30,12 @@ public function item($obj) return $this->item[] = empty($obj) ? null : $obj; } - public function merg($value): void + public function items(): array + { + return $this->item; + } + + public function merge($value): void { $this->item = array_merge($this->item, $value); } @@ -102,7 +107,7 @@ public function __call($name, $arguments) { } - public function __toArray() + public function __toArray(): array { $data = []; foreach ($this->item as $item) { diff --git a/src/blankphp/Container.php b/src/blankphp/Container.php index e2dfeac..5ae7824 100644 --- a/src/blankphp/Container.php +++ b/src/blankphp/Container.php @@ -10,6 +10,7 @@ namespace BlankPhp; +use BlankPhp\Container\InteractiveBind; use BlankPhp\Contract\Container as ContainerContract; use BlankPhp\Contract\Event; use BlankPhp\Exception\ParameterLoopException; @@ -45,9 +46,9 @@ class Container implements \ArrayAccess, ContainerContract, Event /** * 别名. * - * @var array + * @var InteractiveBind */ - protected $alice = []; + protected $alice = null; /** * @var array @@ -62,6 +63,11 @@ class Container implements \ArrayAccess, ContainerContract, Event */ protected $parameterStatus = []; + protected function __construct() + { + $this->alice = new InteractiveBind(); + } + protected function getShareObj($abstract) { return $this->classes[$abstract] ?? null; @@ -73,13 +79,12 @@ protected function getShareObj($abstract) */ public function make($abstract, $parameters = []) { - // 判断共享对象中是否有 - if ($res = $this->getShareObj($abstract)) { - return $res; - } if ($res = $this->getInstances($abstract)) { return $res; } + if ($class = $this->alice->getValue($abstract)) { + $abstract = $class; + } // 是否为绑定 if ($class = $this->getBinds($abstract)) { $abstract = $class; @@ -95,22 +100,21 @@ private function getInstances($abstract) private function getBinds($binds) { - return $this->binds[$binds]['concert'] ?? null; + return $this->binds[$binds] ?? null; } public function has($abstract) { - return isset($this->instances[$abstract]) || isset($this->alice[$abstract]) || isset($this->binds[$abstract]) || isset($this->classes[$abstract]); + return isset($this->instances[$abstract]) || $this->alice->verifyValue($abstract) || isset($this->binds[$abstract]); } /** * @param $instance * @param $abstract - * @param $share * * @return mixed|void */ - public function bind($abstract, $instance, $share = false) + public function bind($abstract, $instance) { //清理老数据 if (null === $instance) { @@ -122,48 +126,34 @@ public function bind($abstract, $instance, $share = false) $concert = $instance; } } - $this->binds[$abstract] = compact('concert', 'share'); - $this->bindAlice(is_array($instance) ? $instance : [$instance], $abstract); + $this->binds[$abstract] = $concert; + $this->bindAlice($abstract, $instance); } /** * @param $abstract + * @param $instance * * @return void */ - public function bindAlice(array $classes, $abstract) + public function bindAlice($abstract, $instance) { - $this->alice[$abstract] = array_merge($classes, $this->alice[$abstract] ?? []); - } - - /** - * @param $abstract - * - * @return mixed|null - */ - public function getAlice($abstract) - { - return $this->alice[$abstract] ?? []; + $this->alice->binds($abstract, $instance); } /** * @param $abstract * @param $instance - * @param $share * * @return mixed|void * 实例注册 */ - public function instance($abstract, $instance, $share = false) + public function instance($abstract, $instance) { - // 是否有别名 - if ($share) { - $this->classes[$abstract] = $instance; - } - $this->instances[$abstract] = $instance; - foreach ($this->getAlice($abstract) as $item) { + foreach ($this->alice->getByKey($abstract) as $item) { $this->instances[$item] = $instance; } + $this->instances[$abstract] = $instance; unset($this->binds[$abstract]); return $instance; @@ -224,19 +214,18 @@ public function build($concrete, int $count = 0) } } - /** - * @param ReflectionParameter[] $params + /*** + * @param array $params * @param $count - * - * @throws \ReflectionException + * @return array * @throws ParameterLoopException + * @throws \ReflectionException */ public function resolveDepends(array $params, $count): array { // 判断参数类型 ++$count; /** - * @var string $key * @var ReflectionParameter $param */ foreach ($params as $param) { @@ -253,8 +242,7 @@ public function resolveDepends(array $params, $count): array } if ($this->has($paramClassName)) { $args = $this->make($paramClassName); - } // 共享内存获取 - else { + } else { $args = $this->build($paramClassName, $count); } } diff --git a/src/blankphp/Container/InteractiveBind.php b/src/blankphp/Container/InteractiveBind.php new file mode 100644 index 0000000..0e72a05 --- /dev/null +++ b/src/blankphp/Container/InteractiveBind.php @@ -0,0 +1,52 @@ + + * + * This source file is subject to the MIT license that is bundled. + */ + +namespace BlankPhp\Container; + +class InteractiveBind +{ + private $keys; + private $values; + + public function binds($key, $values) + { + if (!is_array($values)) { + $values = [$values]; + } + $this->keys[$key] = $values; + foreach ($values as $item) { + $this->values[$item] = $key; + } + } + + public function verifyKey() + { + } + + public function verifyValue($key): bool + { + return isset($this->values[$key]); + } + + public function get($key) + { + return $this->keys[$key] ?? $this->values[$key] ?? null; + } + + public function getByKey($key, $default = []) + { + return $this->keys[$key] ?? $default; + } + + public function getValue($key, $default = null) + { + return $this->values[$key] ?? $default; + } +} diff --git a/src/blankphp/Contract/Container.php b/src/blankphp/Contract/Container.php index 330560a..bf13187 100644 --- a/src/blankphp/Contract/Container.php +++ b/src/blankphp/Contract/Container.php @@ -26,11 +26,10 @@ public function has($abstract); * * @param $abstract * @param $instance - * @param $share * * @return mixed */ - public function bind($abstract, $instance, $share = false); + public function bind($abstract, $instance); /** * @param $abstract @@ -39,7 +38,7 @@ public function bind($abstract, $instance, $share = false); * * @return mixed */ - public function instance($abstract, $instance, $share = false); + public function instance($abstract, $instance); /** * @param array $parameters diff --git a/src/blankphp/Contract/Request.php b/src/blankphp/Contract/Request.php index bc731c0..95deb3e 100644 --- a/src/blankphp/Contract/Request.php +++ b/src/blankphp/Contract/Request.php @@ -25,6 +25,4 @@ public function getUserAgent(); public function userIp(); public function getLanguage(); - - public function stripSlashesDeep($value); } diff --git a/src/blankphp/Request/FormRequest.php b/src/blankphp/Request/FormRequest.php index ab6da93..84c1a66 100644 --- a/src/blankphp/Request/FormRequest.php +++ b/src/blankphp/Request/FormRequest.php @@ -10,6 +10,19 @@ namespace BlankPhp\Request; -class FormRequest extends Request +class FormRequest { + private $request; + + public function __construct(\BlankPhp\Contract\Request $request) + { + $this->request = $request; + } + + public function __call(string $name, array $arguments) + { + // call request + // TODO: Implement __call() method. + return $this->request->{$name}(...$arguments); + } } diff --git a/src/blankphp/Request/Parse.php b/src/blankphp/Request/Parse.php new file mode 100644 index 0000000..6d87e0d --- /dev/null +++ b/src/blankphp/Request/Parse.php @@ -0,0 +1,182 @@ + + * + * This source file is subject to the MIT license that is bundled. + */ + +namespace BlankPhp\Request; + +use BlankPhp\Request\Secure\SlashString; +use BlankQwq\Helpers\Arr; + +/** + * @method parseFiles($files) + * @method parseCookie($cookies) + * @method parseArr($get) + * @method input() + */ +class Parse +{ + private $infoDic = [ + 'HTTP_USER_AGENT' => 'userAgent', 'REMOTE_ADDR' => '', 'HTTP_ACCEPT_LANGUAGE' => 'lang', + ]; + + private $secure = [ + 'parseArr' => SlashString::class, + 'parseCookie' => SlashString::class, + ]; + + /** + * @param $header + * @param $server + * @param $get + * @param $post + * @param $cookies + * @param $files + */ + public function factory($header, $server, $get, $post, $cookies, $files): array + { + $res = []; + $flag = 0; + if (is_null($header) && is_null($server)) { + $this->parseHeaderByServer($res, $_SERVER); + $flag = 1; + } else { + $this->parseHeaderByServer($res, $header); + } + if (is_null($server)) { + $this->parseServer($res, $_SERVER); + } else { + $this->parseServer($res, $server); + } + + if (is_null($post)) { + $res['post'] = $this->parseArr($_POST); + } else { + $res['post'] = $this->parseArr($post); + } + + $res['post'] = Arr::merge($res['post'], $this->input()); + + if (is_null($get)) { + $res['get'] = $this->parseArr($_GET); + } else { + $res['get'] = $this->parseArr($get); + } + + if (is_null($cookies)) { + $res['cookie'] = $this->parseCookie($_COOKIE); + } else { + $res['cookie'] = $this->parseCookie($cookies); + } + if (is_null($files)) { + $res['files'] = $this->parseFiles($_FILES); + } else { + $res['files'] = $this->parseFiles($files); + } + + return $res; + } + + private function _parseFiles($files) + { + return $files; + } + + private function _parseCookie($cookie) + { + return $cookie; + } + + private function _parseArr($arr) + { + return $arr; + } + + private function parseHeaderByServer(&$res, $server) + { + $this->parseHeader($res, $server); + } + + private function parseHeader(&$res, $server) + { + $res['header'] = $server; + } + + private function parseServer(&$res, $data) + { + $res['uri'] = $this->getUri($data); + $res['method'] = $this->getMethod($data); + + foreach ($this->infoDic as $k => $v) { + $res[$v] = $data[$k] ?? null; + } + } + + private function getUri($server) + { + $url = $server['REQUEST_URI']; + // 清除?之后的内容,计算?出现的位置position(定位) + $position = strpos($url, '?'); + //是否截取其中的代码 + $url = false === $position ? $url : substr($url, 0, $position); + $url = ltrim($url, '/'); + $urlArray = explode('/', $url); + $urlArray = array_filter($urlArray); + //获取路径 + $file = explode('/', str_replace(DS, '/', PUBLIC_PATH.'index.php')); + $urlArray = array_diff($urlArray, $file); + //去除两边的东西 + if ($urlArray) { + $uri = '/'.implode('/', $urlArray); + } else { + $uri = '/'; + } + + return $uri; + } + + private function getMethod($server) + { + return $server['REQUEST_METHOD']; + } + + private function _input() + { + $res = []; + $input = file_get_contents('php://input'); + if (strstr($input, '{')) { + $res = json_decode($input, true); + } else { + parse_str($input, $res); + } + + return $res; + } + + /** + * @return mixed + */ + public function __call(string $name, array $arguments) + { + $method = '_'.$name; + if (method_exists($this, $method)) { + $secure = null; + if (isset($this->secure[$name])) { + $secureData = $this->secure[$name]; + $secure = new $secureData(); + $arguments = $secure->runBefore(...$arguments); + } + $res = $this->{'_'.$name}(...$arguments); + if (!empty($secure)) { + $secure->runAfter(...$arguments); + } + + return $res; + } + } +} diff --git a/src/blankphp/Request/Request.php b/src/blankphp/Request/Request.php index ebd9d5e..91b6c75 100644 --- a/src/blankphp/Request/Request.php +++ b/src/blankphp/Request/Request.php @@ -10,253 +10,141 @@ namespace BlankPhp\Request; +use BlankPhp\Base\Traits\ContainerBindMake; use BlankPhp\Contract\Request as RequestContract; -use BlankPhp\Facade\Cookie; +use BlankQwq\Helpers\Arr; class Request implements RequestContract { - //端口存储以及其他信息的存储!!--》 表单验证功能的实现 + use ContainerBindMake; + public $uri; - //方法 public $method; - //请求数组 - public $request = [ - 'get' => '', - 'post' => '', - 'files' => '', - 'input' => '', - ]; - public $session = []; - public $cookie = []; - //php://input public $input = []; - //用户ip; public $user_ip; - //访问所需的ip public $server_ip; - //http协议 public $http; - //443 public $https; - //用户user - public $userAgent; - //用户ip - public $userIp; - //用户语言 + public $port; + private $server; + private $header; + private $get; + private $post; + private $files; + public $cookie = []; public $language; - //Server - public $server; + public $userIp; + public $userAgent; + public static $instance; + + public static function capture($header = null, $server = null, $get = null, $post = null, $cookies = null, $files = null): Request + { + $obj = new self(); + /** @var Parse $parse */ + $parse = app('request.parse'); + $res = $parse->factory($header, $server, $get, $post, $cookies, $files); + foreach ($res as $k => $v) { + $method = 'set'.ucfirst($k); + if (method_exists($obj, $method)) { + $obj->{$method}($v); + } else { + $obj->{$k} = $v; + } + } - public function __construct() - { - $this->getUri(); - $this->getMethod(); - $this->getRequest(); - $this->getFromServer(); + return self::$instance = $obj; } - public function getFromServer() + private function setServer($server) { - $this->getUserAgent(); - $this->getLanguage(); - $this->getServicePort(); + $this->server = $server; } - public function stripSlashesDeep($value) + private function setGet($get) { - //递归方式解决不安全字符 - $value = is_array($value) ? array_map([$this, 'stripSlashesDeep'], $value) : stripslashes($value); - - return $value; + $this->get = $get; } - public function get($name = '', $default = null) + private function setPost($post) { - $this->{'_'.strtolower($this->method)}(); - if (isset($this->request[strtolower($this->method)][$name])) { - return $this->request[strtolower($this->method)][$name]; - } - $this->getRequest(); - foreach ($this->request as $item) { - if (isset($item[$name])) { - return $item[$name]; - } - } - - return null; + $this->post = $post; } - public function capture() + private function setFiles($files) { - return $this; + $this->files = $files; } - public function getUri() + private function setCookie($cookie) { - if (empty($this->uri)) { - $url = $this->server['REQUEST_URI']; - // 清除?之后的内容,计算?出现的位置position(定位) - $position = strpos($url, '?'); - //是否截取其中的代码 - $url = false === $position ? $url : substr($url, 0, $position); - $url = ltrim($url, '/'); - $urlArray = explode('/', $url); - $urlArray = array_filter($urlArray); - //获取路径 - $file = explode('/', str_replace(DS, '/', PUBLIC_PATH.'index.php')); - $urlArray = array_diff($urlArray, $file); - //去除两边的东西 - if ($urlArray) { - $this->uri = '/'.implode('/', $urlArray); - } else { - $this->uri = '/'; - } - } - - return $this->uri; + $this->cookie = $cookie; } - public function getMethod() + private function __construct() { - $method = $this->server['REQUEST_METHOD']; - if ('POST' === $method) { - $method = isset($this->request['post']['_method']) ? strtoupper($this->request['post']['_method']) : 'POST'; - } - $this->method = $method; + // 其他方法 + } - return $this->method; + public function input($name = '', $default = null) + { + return $this->getByName($name, $this->get, $default); } - public function file($name = '') + private function getByName($name, $arr, $default) { - if (empty($this->request['files'])) { - $this->request['files'] = !is_null($_FILES) ? $_FILES : ''; - unset($_FILES); - } - if (isset($this->request['files'][$name])) { - return $this->request['files'][$name]; - } + return Arr::get($arr, $name, $default); + } - return ''; + public function get($name = '', $default = null) + { + return $this->getByName($name, $this->post, $default); } - public function __get($name) + public function getUri() { - if (!isset($this->$name)) { - return $this->get($name); - } + return $this->uri; + } - return $this->$name; + public function getMethod() + { + return $this->method; } - private function getRequest() + public function file($name = '') { - $this->_get(); - $this->_post(); - $this->_input(); - $this->file(); - $this->_cookie(); + return $this->files[$name] ?: null; } public function getUserAgent() { - if (empty($this->userAgent)) { - $this->userAgent = $_SERVER['HTTP_USER_AGENT']; - } - return $this->userAgent; } public function userIp() { - if (empty($this->user_ip)) { - $this->user_ip = $_SERVER['REMOTE_ADDR']; - } - return $this->user_ip; } public function getLanguage() { - if (empty($this->language)) { - $this->language = $_SERVER['HTTP_ACCEPT_LANGUAGE']; - } - return $this->language; } public function getHttp() { + return $this->http; } public function getServicePort() { + return $this->port; } - private function _cookie($name = '', array $optionm = []) - { - return $this->cookie = Cookie::get($name); - } - - private function _get($name = '', array $optionm = []) - { - if (empty($this->request['get'])) { - //是否进行过滤?递归的效率很成问题 - $this->request['get'] = !is_null($_GET) ? $this->stripSlashesDeep($_GET) : ''; - unset($_GET); - } - if (isset($this->request['get'][$name])) { - return $this->request['get'][$name]; - } - - return ''; - } - - private function _post($name = '', array $optionm = []) - { - if (empty($this->request['post'])) { - $this->request['post'] = !is_null($_POST) ? $this->stripSlashesDeep($_POST) : ''; - unset($_POST); - } - if (isset($this->request['post'][$name])) { - return $this->request['post'][$name]; - } - - return ''; - } - - private function _input($name = '', array $args = []) - { - if (empty($this->request['input'])) { - $this->input = file_get_contents('php://input'); - if (strstr($this->input, '{')) { - $this->request['input'] = json_decode($this->input, true); - } else { - parse_str($this->input, $this->request['input']); - } - } - if (empty($name)) { - return $this->input; - } - if (isset($this->request['input'][$name])) { - return $this->request['input'][$name]; - } - - return ''; - } - - public function flush() - { - //清理 - } - - public function __toArray() + public function __toArray(): array { return [ 'uri' => $this->uri, 'method' => $this->method, - 'request' => $this->request, - 'session' => $this->session, 'input' => $this->input, 'user_ip' => $this->user_ip, 'server_ip' => $this->server_ip, diff --git a/src/blankphp/Request/Secure/BaseSecure.php b/src/blankphp/Request/Secure/BaseSecure.php new file mode 100644 index 0000000..f3098c9 --- /dev/null +++ b/src/blankphp/Request/Secure/BaseSecure.php @@ -0,0 +1,18 @@ + + * + * This source file is subject to the MIT license that is bundled. + */ + +namespace BlankPhp\Request\Secure; + +abstract class BaseSecure +{ + abstract public function runBefore($data); + + abstract public function runAfter($data); +} diff --git a/src/blankphp/Request/Secure/ClearGlobal.php b/src/blankphp/Request/Secure/ClearGlobal.php new file mode 100644 index 0000000..190bef6 --- /dev/null +++ b/src/blankphp/Request/Secure/ClearGlobal.php @@ -0,0 +1,15 @@ + + * + * This source file is subject to the MIT license that is bundled. + */ + +namespace BlankPhp\Request\Secure; + +class ClearGlobal +{ +} diff --git a/src/blankphp/Request/Secure/SlashString.php b/src/blankphp/Request/Secure/SlashString.php new file mode 100644 index 0000000..a45b70b --- /dev/null +++ b/src/blankphp/Request/Secure/SlashString.php @@ -0,0 +1,35 @@ + + * + * This source file is subject to the MIT license that is bundled. + */ + +namespace BlankPhp\Request\Secure; + +class SlashString extends BaseSecure +{ + /** + * @param $value + * + * @return array|string + */ + private function stripSlashesDeep($value) + { + //递归方式解决不安全字符 + return is_array($value) ? array_map([$this, 'stripSlashesDeep'], $value) : stripslashes($value); + } + + public function runBefore($data) + { + return [$this->stripSlashesDeep($data)]; + } + + public function runAfter($data) + { + // TODO: Implement runAfter() method. + } +} diff --git a/src/blankphp/Request/TestRequest.php b/src/blankphp/Request/TestRequest.php deleted file mode 100644 index e1548ba..0000000 --- a/src/blankphp/Request/TestRequest.php +++ /dev/null @@ -1,40 +0,0 @@ - - * - * This source file is subject to the MIT license that is bundled. - */ - -namespace BlankPhp\Request; - -class TestRequest extends Request -{ - protected static $instance; - - public function __construct() - { - } - - public static function create( - $method, - $uri, - $parameters, - $cookies, - $files, - $server, - $content - ): TestRequest { - self::$instance = new self(); - self::$instance->uri = $uri; - self::$instance->method = $method; - self::$instance->request = $parameters; - self::$instance->request['cookie'] = $cookies; - self::$instance->request['files'] = $files; - self::$instance->server = $server; - - return self::$instance; - } -} diff --git a/src/blankphp/Response/Response.php b/src/blankphp/Response/Response.php index a86cede..fb5bd13 100644 --- a/src/blankphp/Response/Response.php +++ b/src/blankphp/Response/Response.php @@ -10,11 +10,13 @@ namespace BlankPhp\Response; -use BlankPhp\Response\Traits\ResponseType; +use BlankPhp\Response\Traits\Type; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\StreamInterface; -class Response +class Response implements ResponseInterface { - use ResponseType; + use Type; /** * @var string @@ -26,15 +28,36 @@ class Response */ protected $headerStack = []; + /** + * @var array + */ + protected $headers = []; + + /** + * @var array + */ + protected $removeHeaderStack = []; + + /** + * @var int + */ + protected $statusCode = 200; + + /** + * @var string + */ + protected $reasonPhrase = ''; + + /** + * @var string + */ + protected $protocolVersion = ''; + public function __construct($result) { $result = is_array($result) ? json_encode($result) : $result; $this->result = (string) $result; - if ($this->isJson($this->result)) { - $this->setType(self::$header['json']); - } else { - $this->setType(self::$header['html']); - } + // type设置 } public function getHeaderStack(): array @@ -43,10 +66,9 @@ public function getHeaderStack(): array } /** - * @param array $headerStack - * @param null $key + * @param null $key */ - public function setHeaderStack($headerStack, $key = null): void + public function setHeaderStack(array $headerStack, $key = null): void { if (empty($key)) { $this->headerStack[] = $headerStack; @@ -58,21 +80,31 @@ public function setHeaderStack($headerStack, $key = null): void public function setHeader(): void { foreach ($this->getHeaderStack() as $item) { - header($item); + $this->header($item); } } - public function header($item): Response + /** + * @param $item + * @param $value + * + * @return $this + */ + public function header($item, $value = null) { - if (is_numeric($item)) { - header(self::$httpStatus[$item]); - } elseif (in_array($item, self::$header, true)) { - header($item); + if (!empty($value)) { + // 是否为header格式? + header($this->parseHeaderLine($item, $value)); + } else { + header($this->getHeaderLine($item)); } return $this; } + /** + * @param $value + */ public function setContent($value): void { if (null === $value) { @@ -97,11 +129,17 @@ public function send(): void ob_end_flush(); } + /** + * @return $this + */ public function prepare(): Response { return $this; } + /** + * @param $string + */ public function isJson($string): bool { return 0 === strpos($string, '{'); @@ -111,4 +149,100 @@ public function returnSend(): string { return $this->result; } + + /** + * @return string + */ + public function getProtocolVersion() + { + return $this->protocolVersion; + } + + /** + * @param $version + * + * @return $this|Response + */ + public function withProtocolVersion($version) + { + $this->protocolVersion = $version; + + return $this; + } + + public function getHeaders(): array + { + return $this->headers; + } + + public function hasHeader($name) + { + return isset($this->headers[$name]); + } + + public function getHeader($name) + { + return $this->headers[$name]; + } + + public function getHeaderLine($name): string + { + return $this->parseHeaderLine($name, $this->getHeader($name)); + } + + private function parseHeaderLine($key, $value): string + { + return sprintf('%s: %s', $key, $value); + } + + public function withHeader($name, $value) + { + return $this->header($name, $value); + } + + public function withAddedHeader($name, $value) + { + $this->headerStack[] = [$name, $value]; + + return $this; + } + + public function withoutHeader($name) + { + $this->removeHeaderStack[] = $name; + + return $this; + } + + public function getBody(): string + { + return $this->result; + } + + public function withBody(StreamInterface $body) + { + } + + public function getStatusCode(): int + { + return $this->statusCode; + } + + protected function setStatusCode($code, $reasonPhrase = '') + { + $this->statusCode = $code; + $this->reasonPhrase = $reasonPhrase; + + return $this; + } + + public function withStatus($code, $reasonPhrase = '') + { + return $this->setStatusCode($code, $reasonPhrase); + } + + public function getReasonPhrase() + { + return $this->reasonPhrase; + } } diff --git a/src/blankphp/Response/ResponseType.php b/src/blankphp/Response/ResponseType.php new file mode 100644 index 0000000..bd39b8f --- /dev/null +++ b/src/blankphp/Response/ResponseType.php @@ -0,0 +1,18 @@ + + * + * This source file is subject to the MIT license that is bundled. + */ + +namespace BlankPhp\Response; + +class ResponseType +{ + public static function getStatus($key) + { + } +} diff --git a/src/blankphp/Response/Traits/ResponseType.php b/src/blankphp/Response/Traits/ResponseType.php deleted file mode 100644 index 0fbff98..0000000 --- a/src/blankphp/Response/Traits/ResponseType.php +++ /dev/null @@ -1,88 +0,0 @@ - - * - * This source file is subject to the MIT license that is bundled. - */ - -namespace BlankPhp\Response\Traits; - -trait ResponseType -{ - public static $header = [ - 'html' => 'Content-Type: text/html; charset=utf-8', - 'json' => 'Content-type: application/json', - 'text' => 'Content-Type: text/plain', - 'image' => 'Content-Type: image/png', - ]; - - protected static $httpStatus = [ - 100 => 'HTTP/1.1 100 Continue', - 101 => 'HTTP/1.1 101 Switching Protocols', - 200 => 'HTTP/1.1 200 OK', - 201 => 'HTTP/1.1 201 Created', - 202 => 'HTTP/1.1 202 Accepted', - 203 => 'HTTP/1.1 203 Non-Authoritative Information', - 204 => 'HTTP/1.1 204 No Content', - 205 => 'HTTP/1.1 205 Reset Content', - 206 => 'HTTP/1.1 206 Partial Content', - 300 => 'HTTP/1.1 300 Multiple Choices', - 301 => 'HTTP/1.1 301 Moved Permanently', - 302 => 'HTTP/1.1 302 Found', - 303 => 'HTTP/1.1 303 See Other', - 304 => 'HTTP/1.1 304 Not Modified', - 305 => 'HTTP/1.1 305 Use Proxy', - 307 => 'HTTP/1.1 307 Temporary Redirect', - 400 => 'HTTP/1.1 400 Bad Request', - 401 => 'HTTP/1.1 401 Unauthorized', - 402 => 'HTTP/1.1 402 Payment Required', - 403 => 'HTTP/1.1 403 Forbidden', - 404 => 'HTTP/1.1 404 Not Found', - 405 => 'HTTP/1.1 405 Method Not Allowed', - 406 => 'HTTP/1.1 406 Not Acceptable', - 407 => 'HTTP/1.1 407 Proxy Authentication Required', - 408 => 'HTTP/1.1 408 Request Time-out', - 409 => 'HTTP/1.1 409 Conflict', - 410 => 'HTTP/1.1 410 Gone', - 411 => 'HTTP/1.1 411 Length Required', - 412 => 'HTTP/1.1 412 Precondition Failed', - 413 => 'HTTP/1.1 413 Request Entity Too Large', - 414 => 'HTTP/1.1 414 Request-URI Too Large', - 415 => 'HTTP/1.1 415 Unsupported Media Type', - 416 => 'HTTP/1.1 416 Requested range not satisfiable', - 417 => 'HTTP/1.1 417 Expectation Failed', - 500 => 'HTTP/1.1 500 Internal Server Error', - 501 => 'HTTP/1.1 501 Not Implemented', - 502 => 'HTTP/1.1 502 Bad Gateway', - 503 => 'HTTP/1.1 503 Service Unavailable', - 504 => 'HTTP/1.1 504 Gateway Time-out', - ]; - - public function setType($value): void - { - $this->setHeaderStack($value, 'type'); - } - - public function json($value = null) - { - $this->setType(self::$header['json']); - $this->setContent($value); - - return $this; - } - - public function file($value = null): void - { - } - - public function image($value = null) - { - $this->setType(self::$header['image']); - $this->setContent($value); - - return $this; - } -} diff --git a/src/blankphp/Response/Traits/Type.php b/src/blankphp/Response/Traits/Type.php new file mode 100644 index 0000000..8bb1703 --- /dev/null +++ b/src/blankphp/Response/Traits/Type.php @@ -0,0 +1,39 @@ + + * + * This source file is subject to the MIT license that is bundled. + */ + +namespace BlankPhp\Response\Traits; + +trait Type +{ + public function setType($value): void + { + $this->setHeaderStack($value, 'type'); + } + + public function json($value = null) + { + $this->setType(self::$header['json']); + $this->setContent($value); + + return $this; + } + + public function file($value = null): void + { + } + + public function image($value = null) + { + $this->setType(self::$header['image']); + $this->setContent($value); + + return $this; + } +} diff --git a/src/blankphp/Response/Type/Stream.php b/src/blankphp/Response/Type/Stream.php new file mode 100644 index 0000000..2271984 --- /dev/null +++ b/src/blankphp/Response/Type/Stream.php @@ -0,0 +1,91 @@ + + * + * This source file is subject to the MIT license that is bundled. + */ + +namespace BlankPhp\Response\Type; + +use Psr\Http\Message\StreamInterface; + +class Stream implements StreamInterface +{ + public function __toString() + { + // TODO: Implement __toString() method. + } + + public function close() + { + // TODO: Implement close() method. + } + + public function detach() + { + // TODO: Implement detach() method. + } + + public function getSize() + { + // TODO: Implement getSize() method. + } + + public function tell() + { + // TODO: Implement tell() method. + } + + public function eof() + { + // TODO: Implement eof() method. + } + + public function isSeekable() + { + // TODO: Implement isSeekable() method. + } + + public function seek($offset, $whence = SEEK_SET) + { + // TODO: Implement seek() method. + } + + public function rewind() + { + // TODO: Implement rewind() method. + } + + public function isWritable() + { + // TODO: Implement isWritable() method. + } + + public function write($string) + { + // TODO: Implement write() method. + } + + public function isReadable() + { + // TODO: Implement isReadable() method. + } + + public function read($length) + { + // TODO: Implement read() method. + } + + public function getContents() + { + // TODO: Implement getContents() method. + } + + public function getMetadata($key = null) + { + // TODO: Implement getMetadata() method. + } +} diff --git a/src/blankphp/Route/Route.php b/src/blankphp/Route/Route.php index 12b2af6..6db26e8 100644 --- a/src/blankphp/Route/Route.php +++ b/src/blankphp/Route/Route.php @@ -24,9 +24,9 @@ class Route */ public static $verbs = ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']; - public function __construct() + public function __construct(RouteCollection $collection) { - $this->routeRules = new RouteCollection(); + $this->routeRules = $collection; } /** diff --git a/src/blankphp/Route/RouteCollection.php b/src/blankphp/Route/RouteCollection.php index ab1e99c..e7b44f8 100644 --- a/src/blankphp/Route/RouteCollection.php +++ b/src/blankphp/Route/RouteCollection.php @@ -14,6 +14,9 @@ class RouteCollection extends Collection { + /** + * @var array + */ private $rules = []; private function insert($url, $method, $rule) @@ -45,6 +48,13 @@ public function pregUri($uri) } } + public function items(): array + { + $this->parseRules(); + + return parent::items(); // TODO: Change the autogenerated stub + } + public function __toArray(): array { $this->parseRules(); diff --git a/src/helpers/Arr.php b/src/helpers/Arr.php index d52aa5c..a5ed0a9 100644 --- a/src/helpers/Arr.php +++ b/src/helpers/Arr.php @@ -1,5 +1,7 @@ has($abstract)) { return $a->make($abstract); } - return $a->getSignal($abstract); + throw new \RuntimeException('can\'t get this'); } } diff --git a/tests/Route/RouteGroupTest.php b/tests/Route/RouteGroupTest.php new file mode 100644 index 0000000..0dd9d06 --- /dev/null +++ b/tests/Route/RouteGroupTest.php @@ -0,0 +1,13 @@ +assertEquals(1, 1); + } +} diff --git a/tests/Route/RouteTest.php b/tests/Route/RouteTest.php index aa0fd52..44674ca 100644 --- a/tests/Route/RouteTest.php +++ b/tests/Route/RouteTest.php @@ -5,6 +5,7 @@ use BlankPhp\Contract\Kernel; use BlankPhp\Facade\Route; use BlankPhp\Response\Response; +use BlankPhp\Route\RouteCollection; use PHPUnit\Framework\TestCase; class RouteTest extends TestCase @@ -26,6 +27,7 @@ class RouteTest extends TestCase "; + public function createApplication() { $app = \BlankPhp\Application::init(); @@ -37,6 +39,7 @@ public function createApplication() return $this->text; })->middleware('test'); $this->app = $app; + return $kernel; } @@ -46,35 +49,41 @@ public function testBasicTest() $this->assertEquals($this->text, $response); } + public function testRouteCollection(){ + $this->createApplication(); + $router = $this->app->make(RouteCollection::class); + $this->assertEquals(array_keys($router->items()),['/','/2']); + } + public function get($uri) { return $this->call('GET', $uri, [], [], []); } + public function post($uri) + { + return $this->call('POST', $uri, [], [], []); + } + + public function call($method, $uri, $parameters = [], $cookies = [], $files = [], $server = [], $content = null) { /** @var Kernel $kernel */ $kernel = $this->createApplication(); - $server['REQUEST_METHOD'] = 'GET'; + $server['REQUEST_METHOD'] = $method; $server['REQUEST_URI'] = '/'; /** @var Response $response */ $response = $kernel->handle( - \BlankPhp\Request\TestRequest::create( - $method, - $uri, - $parameters, - $cookies, - $files, + \BlankPhp\Request\Request::capture( + $header = null, $server, - $content + $get = [], + $post = [], + $cookies = [], + $files = [] ) ); return $response->returnSend(); } - - public function testOk() - { - $this->assertStringStartsWith('1', '111'); - } }

AltStyle によって変換されたページ (->オリジナル) /