Development

- Optimised Input and Input-related features.
- Removed InputCollection class.
- Changed more foreach to for.
- Updated documentation.
This commit is contained in:
Simon Sessingø
2016-11-24 22:44:58 +01:00
parent b2f23c6c7d
commit abe427ff59
11 changed files with 263 additions and 188 deletions
+69 -14
View File
@@ -341,9 +341,11 @@ By default all controller and resource routes will use a simplified version of t
SimpleRouter::get('/product-view/{id}', 'ProductsController@show', ['as' => 'product']);
url('product', ['id' => 22], ['category' => 'shoes']);
url('product', null, ['category' => 'shoes']);
# output
# /product-view/22/?category=shoes
# /product-view/?category=shoes
```
**Getting the url using the name (controller route)**
@@ -353,10 +355,12 @@ SimpleRouter::controller('/images', 'ImagesController', ['as' => 'picture']);
url('picture@getView', null, ['category' => 'shoes']);
url('picture', 'getView', ['category' => 'shoes']);
url('picture', 'view');
# output
# /images/view/?category=shows
# /images/view/?category=shows
# /images/view/
```
**Getting the url using class**
@@ -370,7 +374,7 @@ url('ImagesController@getImage', null, ['id' => 22]);
# output
# /product-view/22/?category=shoes
# /images/image/?category=shows
# /images/image/?id=22
```
**Using custom names for methods on a controller/resource route**
@@ -405,6 +409,11 @@ url('phones.edit');
**Return the current url**
```php
url();
url(null, null, ['q' => 'cars']);
# output
# /CURRENT-URL/
# /CURRENT-URL/?q=cars
```
## Custom CSRF verifier
@@ -466,7 +475,6 @@ class CustomRouterRules implement IRouterBootManager {
}
}
```
The above should be pretty self-explanatory and can easily be changed to loop through urls store in the database, file or cache.
@@ -526,7 +534,6 @@ class CustomMiddleware implements Middleware {
}
}
```
#### Changing callback
@@ -558,32 +565,78 @@ class CustomMiddleware implements Middleware {
## Using the Input class to manage parameters
We've added the `Input` class to easy access parameters from your Controller-classes.
We've added the `Input` class to easy access and manage parameters from your Controller-classes.
**Return single parameter value (matches both GET, POST, FILE):**
If items is grouped in the html, it will return an array of items.
**Note:** `get` will automatically trim the value and ensure that it's not empty. If it's empty the `$defaultValue` will be returned.
```php
$value = input()->get('name');
$value = input()->get($index, $defaultValue);
```
**Return parameter object (matches both GET, POST, FILE):**
Will return an instance of `InputItem` or `InputFile` depending on the type.
You can use this in your html as it will render the value of the item.
However if you want to compare value in your if statements, you have to use
the `getValue` or use the `input()->get()` instead.
If items is grouped in the html, it will return an array of items.
**Note:** `getObject` will only return `$defaultValue` if the item doesn't exist. If you want `$defaultValue` to be returned if the item is empty, please use `input()->get()` instead.
```php
$object = input()->getObject('name');
$object = input()->getObject($index);
```
**Return specific GET parameter (where name is the name of your parameter):**
```php
$object = input()->get->name;
$object = input()->post->name;
$object = input()->file->name;
# -- match any (default) --
/*
* This is the recommended way to go for normal usage
* as it will strip empty values, ensuring that
* $defaultValue is returned if the value is empty.
*/
$id = input()->get($index, $defaultValue);
# -- match specific --
$object = input()->get($index, $defaultValue, 'get');
$object = input()->get($index, $defaultValue, 'post');
$object = input()->get($index, $defaultValue, 'file');
# -- or --
$object = input()->get->get($key, $defaultValue);
$object = input()->post->get($key, $defaultValue);
$object = input()->file->get($key, $defaultValue);
$object = input()->findGet($index, $defaultValue);
$object = input()->findPost($index, $defaultValue);
$object = input()->findFile($index, $defaultValue);
# -- examples --
/**
* In this small example we loop through a collection of files
* added on the page like this
* <input type="file" name="images[]" />
*/
/* @var $image \Pecee\Http\Input\InputFile */
foreach(input()->get('images', []) as $image)
{
if($image->getMime() === 'image/jpeg') {
$destinationFilname = sprintf('%s.%s', uniqid(), $image->getExtension());
$image->move('/uploads/' . $destinationFilename);
}
}
```
**Return all parameters:**
@@ -599,11 +652,11 @@ $values = input()->all([
]);
```
All object inherits from `InputItem` class and will always contain these methods:
All object implements the `IInputItem` interface and will always contain these methods:
- `getValue()` - returns the value of the input.
- `getIndex()` - returns the index/key of the input.
- `getName()` - returns a human friendly name for the input (company_name will be Company Name etc).
- `getValue()` - returns the value of the input.
`InputFile` has the same methods as above along with some other file-specific methods like:
- `getTmpName()` - get file temporary name.
@@ -612,6 +665,8 @@ All object inherits from `InputItem` class and will always contain these methods
- `getContents()` - get file content.
- `getType()` - get mime-type for file.
- `getError()` - get file upload error.
- `hasError()` - returns `bool` if an error occurred while uploading (if getError is not 0).
- `toArray()` - returns raw array
Below example requires you to have the helper functions added. Please refer to the helper functions section in the documentation.
+15
View File
@@ -0,0 +1,15 @@
<?php
namespace Pecee\Http\Input;
interface IInputItem
{
public function getIndex();
public function getName();
public function getValue();
public function __toString();
}
+79 -49
View File
@@ -6,19 +6,19 @@ use Pecee\Http\Request;
class Input
{
/**
* @var \Pecee\Http\Input\InputCollection
* @var array
*/
public $get;
public $get = [];
/**
* @var \Pecee\Http\Input\InputCollection
* @var array
*/
public $post;
public $post = [];
/**
* @var \Pecee\Http\Input\InputCollection
* @var array
*/
public $file;
public $file = [];
/**
* @var Request
@@ -36,10 +36,6 @@ class Input
{
$this->request = $request;
$this->post = new InputCollection();
$this->get = new InputCollection();
$this->file = new InputCollection();
if ($request->getMethod() !== 'get') {
$requestContentType = $request->getHeader('http-content-type');
@@ -60,6 +56,7 @@ class Input
if ($this->invalidContentType === false) {
$this->parseInputs();
}
}
protected function parseInputs()
@@ -76,7 +73,21 @@ class Input
$key = $keys[$i];
$value = $_GET[$key];
$this->get->{$key} = new InputItem($key, $value);
// Handle array input
if (is_array($value) === false) {
$this->get[$key] = new InputItem($key, $value);
continue;
}
$subMax = count($value) - 1;
$keys = array_keys($value);
$output = [];
for ($i = $subMax; $i >= 0; $i--) {
$output[$keys[$i]] = new InputItem($key, $value[$keys[$i]]);
}
$this->get[$key] = $output;
}
}
@@ -99,7 +110,21 @@ class Input
$key = $keys[$i];
$value = $postVars[$key];
$this->post->{strtolower($key)} = new InputItem($key, $value);
// Handle array input
if (is_array($value) === false) {
$this->post[$key] = new InputItem($key, $value);
continue;
}
$subMax = count($value) - 1;
$keys = array_keys($value);
$output = [];
for ($i = $subMax; $i >= 0; $i--) {
$output[$keys[$i]] = new InputItem($key, $value[$keys[$i]]);
}
$this->post[$key] = $output;
}
}
@@ -119,56 +144,66 @@ class Input
// Handle array input
if (is_array($value['name']) === false) {
$values['index'] = $key;
$this->file->{strtolower($key)} = InputFile::createFromArray($values);
$this->file[$key] = InputFile::createFromArray(array_merge($value, $values));
continue;
}
$output = new InputCollection();
$subMax = count($value['name']) - 1;
$keys = array_keys($value['name']);
$output = [];
foreach ($value['name'] as $k => $val) {
for ($i = $subMax; $i >= 0; $i--) {
$output->{$k} = InputFile::createFromArray([
$output[$keys[$i]] = InputFile::createFromArray([
'index' => $key,
'error' => $value['error'][$k],
'tmp_name' => $value['tmp_name'][$k],
'type' => $value['type'][$k],
'size' => $value['size'][$k],
'name' => $value['name'][$k],
'error' => $value['error'][$keys[$i]],
'tmp_name' => $value['tmp_name'][$keys[$i]],
'type' => $value['type'][$keys[$i]],
'size' => $value['size'][$keys[$i]],
'name' => $value['name'][$keys[$i]],
]);
}
$this->file->{strtolower($key)} = $output;
$this->file[$key] = $output;
}
}
}
public function getObject($index, $default = null)
public function findPost($index, $default = null)
{
$key = (strpos($index, '[') > -1) ? substr($index, strpos($index, '[') + 1, strpos($index, ']') - strlen($index)) : null;
$index = (strpos($index, '[') > -1) ? substr($index, 0, strpos($index, '[')) : $index;
return isset($this->post[$index]) ? $this->post[$index] : $default;
}
$element = $this->get->findFirst($index);
public function findFile($index, $default = null)
{
return isset($this->file[$index]) ? $this->file[$index] : $default;
}
if ($element !== null) {
return ($key !== null) ? $element[$key] : $element;
public function findGet($index, $default = null)
{
return isset($this->get[$index]) ? $this->get[$index] : $default;
}
public function getObject($index, $default = null, $method = null)
{
$element = null;
if ($method === null || strtolower($method) === 'get') {
$element = $this->findGet($index);
}
if ($this->request->getMethod() !== 'get') {
$element = $this->post->findFirst($index);
if ($element !== null) {
return ($key !== null) ? $element[$key] : $element;
}
$element = $this->file->findFirst($index);
if ($element !== null) {
return ($key !== null) ? $element[$key] : $element;
}
if ($element === null && $method === null || strtolower($method) === 'post') {
$element = $this->findPost($index);
}
return $default;
if ($element === null && $method === null || strtolower($method) === 'file') {
$element = $this->findFile($index);
}
return ($element === null) ? $default : $element;
}
/**
@@ -180,18 +215,13 @@ class Input
*/
public function get($index, $default = null)
{
$item = $this->getObject($index);
$input = $this->getObject($index, $default);
if ($item !== null) {
if ($item instanceof InputCollection || $item instanceof InputFile) {
return $item;
}
return (!is_array($item->getValue()) && trim($item->getValue()) === '') ? $default : $item;
if ($input instanceof InputItem) {
return (trim($input->getValue()) === '') ? $default : $input->getValue();
}
return $default;
return $input;
}
public function exists($index)
-91
View File
@@ -1,91 +0,0 @@
<?php
namespace Pecee\Http\Input;
class InputCollection implements \IteratorAggregate
{
protected $data = [];
/**
* Search for input element matching index.
*
* @param string $index
* @param string|null $default
* @return InputItem|mixed
*/
public function findFirst($index, $default = null)
{
if (count($this->data) > 0) {
if (isset($this->data[$index])) {
return $this->data[$index];
}
foreach ($this->data as $key => $input) {
if (strtolower($index) === strtolower($key)) {
return $input;
}
}
}
return $default;
}
/**
* Get input element value matching index
*
* @param string $index
* @param string|null $default
* @return string|null
*/
public function get($index, $default = null)
{
$input = $this->findFirst($index);
if ($input !== null && trim($input->getValue()) !== '') {
return $input->getValue();
}
return $default;
}
/**
* @param string $index
* @throws \InvalidArgumentException
* @return InputItem
*/
public function __get($index)
{
$item = $this->findFirst($index);
// Ensure that item are always available
if ($item === null) {
$this->data[$index] = new InputItem($index, null);
return $this->data[$index];
}
return $item;
}
public function __set($index, $value)
{
$this->data[$index] = $value;
}
public function getData()
{
return $this->data;
}
/**
* Retrieve an external iterator
* @link http://php.net/manual/en/iteratoraggregate.getiterator.php
* @return \Traversable An instance of an object implementing <b>Iterator</b> or
* <b>Traversable</b>
* @since 5.0.0
*/
public function getIterator()
{
return new \ArrayIterator($this->data);
}
}
+56 -13
View File
@@ -1,13 +1,39 @@
<?php
namespace Pecee\Http\Input;
class InputFile extends InputItem
class InputFile implements IInputItem
{
public $index;
public $name;
public $size;
public $type;
public $error;
public $tmpName;
public function __construct($index)
{
$this->index = $index;
// Make the name human friendly, by replace _ with space
$this->name = ucfirst(str_replace('_', ' ', $this->index));
}
/**
* @return string
*/
public function getIndex()
{
return $this->index;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return string
*/
@@ -60,6 +86,13 @@ class InputFile extends InputItem
return file_get_contents($this->tmpName);
}
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Set file temp. name
* @param string $name
@@ -68,6 +101,7 @@ class InputFile extends InputItem
public function setTmpName($name)
{
$this->tmpName = $name;
return $this;
}
@@ -79,6 +113,7 @@ class InputFile extends InputItem
public function setSize($size)
{
$this->size = $size;
return $this;
}
@@ -90,6 +125,7 @@ class InputFile extends InputItem
public function setType($type)
{
$this->type = $type;
return $this;
}
@@ -101,6 +137,7 @@ class InputFile extends InputItem
public function setError($error)
{
$this->error = (int)$error;
return $this;
}
@@ -109,7 +146,8 @@ class InputFile extends InputItem
return $this->getTmpName();
}
public function hasError() {
public function hasError()
{
return ($this->getError() !== 0);
}
@@ -120,28 +158,33 @@ class InputFile extends InputItem
*/
public static function createFromArray(array $values)
{
if(!isset($values['index'])) {
if (!isset($values['index'])) {
throw new \InvalidArgumentException('Index key is required');
}
$input = new static($values['index']);
$input->setError((isset($values['error']) ? $values['error'] : null));
$input->setName((isset($values['name']) ? $values['name'] : null));
$input->setSize((isset($values['size']) ? $values['size'] : null));
$input->setType((isset($values['type']) ? $values['type'] : null));
$input->setTmpName((isset($values['tmp_name']) ? $values['tmp_name'] : null));
$input->setError(isset($values['error']) ? $values['error'] : null);
$input->setName(isset($values['name']) ? $values['name'] : null);
$input->setSize(isset($values['size']) ? $values['size'] : null);
$input->setType(isset($values['type']) ? $values['type'] : null);
$input->setTmpName(isset($values['tmp_name']) ? $values['tmp_name'] : null);
return $input;
}
public function toArray() {
public function toArray()
{
return [
'tmp_name' => $this->tmpName,
'type' => $this->type,
'size' => $this->size,
'name' => $this->name,
'error' => $this->error,
'type' => $this->type,
'size' => $this->size,
'name' => $this->name,
'error' => $this->error,
];
}
public function __toString()
{
return $this->getValue();
}
}
+9 -9
View File
@@ -1,7 +1,7 @@
<?php
namespace Pecee\Http\Input;
class InputItem
class InputItem implements IInputItem
{
public $index;
public $name;
@@ -16,6 +16,14 @@ class InputItem
$this->name = ucfirst(str_replace('_', ' ', $this->index));
}
/**
* @return string
*/
public function getIndex()
{
return $this->index;
}
/**
* @return string
*/
@@ -32,14 +40,6 @@ class InputItem
return $this->value;
}
/**
* @return string
*/
public function getIndex()
{
return $this->index;
}
/**
* Set input name
* @param string $name
@@ -34,7 +34,11 @@ class BaseCsrfVerifier implements IMiddleware
return false;
}
foreach ($this->except as $url) {
$max = count($this->except) - 1;
for ($i = $max; $i >= 0; $i--) {
$url = $this->except[$i];
$url = rtrim($url, '/');
if ($url[strlen($url) - 1] === '*') {
$url = rtrim($url, '*');
@@ -43,7 +47,7 @@ class BaseCsrfVerifier implements IMiddleware
$skip = ($url === rtrim($request->getUri(), '/'));
}
if ($skip) {
if ($skip === true) {
return true;
}
}
@@ -56,14 +60,14 @@ class BaseCsrfVerifier implements IMiddleware
if ($request->getMethod() !== 'get' && !$this->skip($request)) {
$token = $request->getInput()->post->get(static::POST_KEY);
$token = $request->getInput()->get(static::POST_KEY, null, 'post');
// If the token is not posted, check headers for valid x-csrf-token
if ($token === null) {
$token = $request->getHeader(static::HEADER_KEY);
}
if (!$this->csrfToken->validate($token)) {
if ($this->csrfToken->validate($token) === false) {
throw new TokenMismatchException('Invalid csrf-token.');
}
+9 -3
View File
@@ -25,9 +25,15 @@ class Request
{
$this->headers = [];
foreach ($_SERVER as $name => $value) {
$this->headers[strtolower($name)] = $value;
$this->headers[strtolower(str_replace('_', '-', $name))] = $value;
$max = count($_SERVER) - 1;
$keys = array_keys($_SERVER);
for($i = $max; $i >= 0; $i--) {
$key = $keys[$i];
$value = $_SERVER[$key];
$this->headers[strtolower($key)] = $value;
$this->headers[strtolower(str_replace('_', '-', $key))] = $value;
}
}
@@ -59,7 +59,12 @@ class RouteController extends LoadableRoute implements IControllerRoute
/* Remove requestType from method-name, if it exists */
if ($method !== null) {
foreach (static::$requestTypes as $requestType) {
$max = count(static::$requestTypes);
for ($i = 0; $i < $max; $i++) {
$requestType = static::$requestTypes[$i];
if (stripos($method, $requestType) === 0) {
$method = substr($method, strlen($requestType));
break;
+5 -1
View File
@@ -19,8 +19,12 @@ class RouteGroup extends Route implements IGroupRoute
public function matchDomain(Request $request)
{
if (count($this->domains) > 0) {
foreach ($this->domains as $domain) {
$max = count($this->domains);
for ($i = 0; $i < $max; $i++) {
$domain = $this->domains[$i];
$parameters = $this->parseParameters($domain, $request->getHost(), '.*');
if ($parameters !== null) {
+7 -3
View File
@@ -140,8 +140,12 @@ class Router
protected function processRoutes(array $routes, IGroupRoute $group = null, IRoute $parent = null)
{
// Loop through each route-request
$max = count($routes) - 1;
/* @var $route IRoute */
foreach ($routes as $route) {
for ($i = $max; $i >= 0; $i--) {
$route = $routes[$i];
if ($route instanceof IGroupRoute) {
@@ -238,10 +242,10 @@ class Router
$this->originalUrl = $this->request->getUri();
}
$max = count($this->processedRoutes);
$max = count($this->processedRoutes) - 1;
/* @var $route IRoute */
for ($i = 0; $i < $max; $i++) {
for ($i = $max; $i >= 0; $i--) {
$route = $this->processedRoutes[$i];