Put Ion Namespace back in the codebase directly
This commit is contained in:
parent
d9e81a7cf1
commit
e5ef054f5b
@ -4,6 +4,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"files": [
|
"files": [
|
||||||
|
"src/Ion/functions.php",
|
||||||
"src/AnimeClient/constants.php",
|
"src/AnimeClient/constants.php",
|
||||||
"src/AnimeClient/AnimeClient.php"
|
"src/AnimeClient/AnimeClient.php"
|
||||||
],
|
],
|
||||||
@ -13,7 +14,8 @@
|
|||||||
},
|
},
|
||||||
"autoload-dev": {
|
"autoload-dev": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Aviat\\AnimeClient\\Tests\\": "tests/",
|
"Aviat\\AnimeClient\\Tests\\": "tests/AnimeClient",
|
||||||
|
"Aviat\\Ion\\Tests\\": "tests/Ion",
|
||||||
"CodeIgniter\\": "build/CodeIgniter/"
|
"CodeIgniter\\": "build/CodeIgniter/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -23,12 +25,15 @@
|
|||||||
"aura/router": "^3.0",
|
"aura/router": "^3.0",
|
||||||
"aura/session": "^2.0",
|
"aura/session": "^2.0",
|
||||||
"aviat/banker": "^2.0.0",
|
"aviat/banker": "^2.0.0",
|
||||||
"aviat/ion": "^3.0.0",
|
"aviat/query": "^2.5.1",
|
||||||
|
"danielstjules/stringy": "^3.1.0",
|
||||||
|
"ext-dom": "*",
|
||||||
"ext-iconv": "*",
|
"ext-iconv": "*",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-gd":"*",
|
"ext-gd":"*",
|
||||||
"ext-pdo": "*",
|
"ext-pdo": "*",
|
||||||
"laminas/laminas-diactoros": "^2.0.0",
|
"laminas/laminas-diactoros": "^2.0.0",
|
||||||
|
"laminas/laminas-httphandlerrunner": "^1.0",
|
||||||
"maximebf/consolekit": "^1.0",
|
"maximebf/consolekit": "^1.0",
|
||||||
"monolog/monolog": "^2.0.1",
|
"monolog/monolog": "^2.0.1",
|
||||||
"php": "^7.3",
|
"php": "^7.3",
|
||||||
|
38
src/Ion/ArrayWrapper.php
Normal file
38
src/Ion/ArrayWrapper.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion;
|
||||||
|
|
||||||
|
use Aviat\Ion\Type\ArrayType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper to shortcut creating ArrayType objects
|
||||||
|
*/
|
||||||
|
trait ArrayWrapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method for wrapping an array
|
||||||
|
* with the array type class
|
||||||
|
*
|
||||||
|
* @param array $arr
|
||||||
|
* @return ArrayType
|
||||||
|
*/
|
||||||
|
public function arr(array $arr): ArrayType
|
||||||
|
{
|
||||||
|
return new ArrayType($arr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End of ArrayWrapper.php
|
120
src/Ion/Config.php
Normal file
120
src/Ion/Config.php
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion;
|
||||||
|
|
||||||
|
use Aviat\Ion\Exception\ConfigException;
|
||||||
|
use Aviat\Ion\Type\ArrayType;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for configuration values
|
||||||
|
*/
|
||||||
|
class Config implements ConfigInterface {
|
||||||
|
|
||||||
|
use ArrayWrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Config object
|
||||||
|
*
|
||||||
|
* @var ArrayType
|
||||||
|
*/
|
||||||
|
protected $map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param array $configArray
|
||||||
|
*/
|
||||||
|
public function __construct(array $configArray = [])
|
||||||
|
{
|
||||||
|
$this->map = $this->arr($configArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the config item exist?
|
||||||
|
*
|
||||||
|
* @param string|int|array $key
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function has($key): bool
|
||||||
|
{
|
||||||
|
return $this->map->hasKey($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a config value
|
||||||
|
*
|
||||||
|
* @param array|string|null $key
|
||||||
|
* @return mixed
|
||||||
|
* @throws ConfigException
|
||||||
|
*/
|
||||||
|
public function get($key = NULL)
|
||||||
|
{
|
||||||
|
if (\is_array($key))
|
||||||
|
{
|
||||||
|
return $this->map->getDeepKey($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->map->get($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a config value
|
||||||
|
*
|
||||||
|
* @param string|array $key
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function delete($key): void
|
||||||
|
{
|
||||||
|
if (\is_array($key))
|
||||||
|
{
|
||||||
|
$this->map->setDeepKey($key, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$pos =& $this->map->get($key);
|
||||||
|
$pos = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a config value
|
||||||
|
*
|
||||||
|
* @param integer|string|array $key
|
||||||
|
* @param mixed $value
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
* @return ConfigInterface
|
||||||
|
*/
|
||||||
|
public function set($key, $value): ConfigInterface
|
||||||
|
{
|
||||||
|
if (\is_array($key))
|
||||||
|
{
|
||||||
|
$this->map->setDeepKey($key, $value);
|
||||||
|
}
|
||||||
|
else if (is_scalar($key) && ! empty($key))
|
||||||
|
{
|
||||||
|
$this->map->set($key, $value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidArgumentException('Key must be integer, string, or array, and cannot be empty');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End of config.php
|
56
src/Ion/ConfigInterface.php
Normal file
56
src/Ion/ConfigInterface.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard interface for retrieving/setting configuration values
|
||||||
|
*/
|
||||||
|
interface ConfigInterface {
|
||||||
|
/**
|
||||||
|
* Does the config item exist?
|
||||||
|
*
|
||||||
|
* @param string|int|array $key
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function has($key): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a config value
|
||||||
|
*
|
||||||
|
* @param array|string|null $key
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function get($key = NULL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a config value
|
||||||
|
*
|
||||||
|
* @param integer|string|array $key
|
||||||
|
* @param mixed $value
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
* @return ConfigInterface
|
||||||
|
*/
|
||||||
|
public function set($key, $value): self;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a config value
|
||||||
|
*
|
||||||
|
* @param string|array $key
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function delete($key): void;
|
||||||
|
}
|
228
src/Ion/Di/Container.php
Normal file
228
src/Ion/Di/Container.php
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Di;
|
||||||
|
|
||||||
|
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dependency container
|
||||||
|
*/
|
||||||
|
class Container implements ContainerInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of container Generator functions
|
||||||
|
*
|
||||||
|
* @var Callable[]
|
||||||
|
*/
|
||||||
|
protected $container = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of object instances
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $instances = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of logger instances
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $loggers = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param array $values (optional)
|
||||||
|
*/
|
||||||
|
public function __construct(array $values = [])
|
||||||
|
{
|
||||||
|
$this->container = $values;
|
||||||
|
$this->loggers = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds an entry of the container by its identifier and returns it.
|
||||||
|
*
|
||||||
|
* @param string $id - Identifier of the entry to look for.
|
||||||
|
*
|
||||||
|
* @throws NotFoundException - No entry was found for this identifier.
|
||||||
|
* @throws ContainerException - Error while retrieving the entry.
|
||||||
|
*
|
||||||
|
* @return mixed Entry.
|
||||||
|
*/
|
||||||
|
public function get($id)
|
||||||
|
{
|
||||||
|
if ( ! \is_string($id))
|
||||||
|
{
|
||||||
|
throw new ContainerException('Id must be a string');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->has($id))
|
||||||
|
{
|
||||||
|
// Return an object instance, if it already exists
|
||||||
|
if (array_key_exists($id, $this->instances))
|
||||||
|
{
|
||||||
|
return $this->instances[$id];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there isn't already an instance, create one
|
||||||
|
$obj = $this->getNew($id);
|
||||||
|
$this->instances[$id] = $obj;
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotFoundException("Item '{$id}' does not exist in container.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a new instance of the specified item
|
||||||
|
*
|
||||||
|
* @param string $id - Identifier of the entry to look for.
|
||||||
|
* @param array $args - Optional arguments for the factory callable
|
||||||
|
* @throws NotFoundException - No entry was found for this identifier.
|
||||||
|
* @throws ContainerException - Error while retrieving the entry.
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getNew($id, array $args = NULL)
|
||||||
|
{
|
||||||
|
if ( ! \is_string($id))
|
||||||
|
{
|
||||||
|
throw new ContainerException('Id must be a string');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->has($id))
|
||||||
|
{
|
||||||
|
// By default, call a factory with the Container
|
||||||
|
$args = \is_array($args) ? $args : [$this];
|
||||||
|
$obj = \call_user_func_array($this->container[$id], $args);
|
||||||
|
|
||||||
|
// Check for container interface, and apply the container to the object
|
||||||
|
// if applicable
|
||||||
|
return $this->applyContainer($obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotFoundException("Item '{$id}' does not exist in container.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a factory to the container
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @param Callable $value - a factory callable for the item
|
||||||
|
* @return ContainerInterface
|
||||||
|
*/
|
||||||
|
public function set(string $id, Callable $value): ContainerInterface
|
||||||
|
{
|
||||||
|
$this->container[$id] = $value;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a specific instance in the container for an existing factory
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @param mixed $value
|
||||||
|
* @throws NotFoundException - No entry was found for this identifier.
|
||||||
|
* @return ContainerInterface
|
||||||
|
*/
|
||||||
|
public function setInstance(string $id, $value): ContainerInterface
|
||||||
|
{
|
||||||
|
if ( ! $this->has($id))
|
||||||
|
{
|
||||||
|
throw new NotFoundException("Factory '{$id}' does not exist in container. Set that first.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->instances[$id] = $value;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the container can return an entry for the given identifier.
|
||||||
|
* Returns false otherwise.
|
||||||
|
*
|
||||||
|
* @param string $id Identifier of the entry to look for.
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function has($id): bool
|
||||||
|
{
|
||||||
|
return array_key_exists($id, $this->container);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether a logger channel is registered
|
||||||
|
*
|
||||||
|
* @param string $id The logger channel
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function hasLogger(string $id = 'default'): bool
|
||||||
|
{
|
||||||
|
return array_key_exists($id, $this->loggers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a logger to the Container
|
||||||
|
*
|
||||||
|
* @param LoggerInterface $logger
|
||||||
|
* @param string $id The logger 'channel'
|
||||||
|
* @return ContainerInterface
|
||||||
|
*/
|
||||||
|
public function setLogger(LoggerInterface $logger, string $id = 'default'): ContainerInterface
|
||||||
|
{
|
||||||
|
$this->loggers[$id] = $logger;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a logger for the selected channel
|
||||||
|
*
|
||||||
|
* @param string $id The logger to retrieve
|
||||||
|
* @return LoggerInterface|null
|
||||||
|
*/
|
||||||
|
public function getLogger(string $id = 'default'): ?LoggerInterface
|
||||||
|
{
|
||||||
|
return $this->hasLogger($id)
|
||||||
|
? $this->loggers[$id]
|
||||||
|
: NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if object implements ContainerAwareInterface
|
||||||
|
* or uses ContainerAware trait, and if so, apply the container
|
||||||
|
* to that object
|
||||||
|
*
|
||||||
|
* @param mixed $obj
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
private function applyContainer($obj)
|
||||||
|
{
|
||||||
|
$trait_name = ContainerAware::class;
|
||||||
|
$interface_name = ContainerAwareInterface::class;
|
||||||
|
|
||||||
|
$uses_trait = \in_array($trait_name, class_uses($obj), TRUE);
|
||||||
|
$implements_interface = \in_array($interface_name, class_implements($obj), TRUE);
|
||||||
|
|
||||||
|
if ($uses_trait || $implements_interface)
|
||||||
|
{
|
||||||
|
$obj->setContainer($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End of Container.php
|
53
src/Ion/Di/ContainerAware.php
Normal file
53
src/Ion/Di/ContainerAware.php
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Di;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trait implementation of ContainerAwareInterface
|
||||||
|
*/
|
||||||
|
trait ContainerAware {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Di Container
|
||||||
|
*
|
||||||
|
* @var ContainerInterface
|
||||||
|
*/
|
||||||
|
protected $container;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the container for the current object
|
||||||
|
*
|
||||||
|
* @param ContainerInterface $container
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setContainer(ContainerInterface $container): self
|
||||||
|
{
|
||||||
|
$this->container = $container;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the container object
|
||||||
|
*
|
||||||
|
* @return ContainerInterface
|
||||||
|
*/
|
||||||
|
public function getContainer(): ContainerInterface
|
||||||
|
{
|
||||||
|
return $this->container;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End of ContainerAware.php
|
40
src/Ion/Di/ContainerAwareInterface.php
Normal file
40
src/Ion/Di/ContainerAwareInterface.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Di;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for a class that is aware of the Di Container
|
||||||
|
*/
|
||||||
|
interface ContainerAwareInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the container for the current object
|
||||||
|
*
|
||||||
|
* @param ContainerInterface $container
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setContainer(ContainerInterface $container);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the container object
|
||||||
|
*
|
||||||
|
* @return ContainerInterface
|
||||||
|
*/
|
||||||
|
public function getContainer(): ContainerInterface;
|
||||||
|
|
||||||
|
}
|
||||||
|
// End of ContainerAwareInterface.php
|
100
src/Ion/Di/ContainerInterface.php
Normal file
100
src/Ion/Di/ContainerInterface.php
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Di;
|
||||||
|
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for the Dependency Injection Container
|
||||||
|
*
|
||||||
|
* Based on container-interop interface, but return types and
|
||||||
|
* scalar type hints make the interface incompatible to the PHP parser
|
||||||
|
*
|
||||||
|
* @see https://github.com/container-interop/container-interop
|
||||||
|
*/
|
||||||
|
interface ContainerInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds an entry of the container by its identifier and returns it.
|
||||||
|
*
|
||||||
|
* @param string $id Identifier of the entry to look for.
|
||||||
|
* @throws Exception\NotFoundException No entry was found for this identifier.
|
||||||
|
* @throws Exception\ContainerException Error while retrieving the entry.
|
||||||
|
* @return mixed Entry.
|
||||||
|
*/
|
||||||
|
public function get($id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the container can return an entry for the given identifier.
|
||||||
|
* Returns false otherwise.
|
||||||
|
*
|
||||||
|
* @param string $id Identifier of the entry to look for.
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function has($id): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a factory to the container
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @param Callable $value - a factory callable for the item
|
||||||
|
* @return ContainerInterface
|
||||||
|
*/
|
||||||
|
public function set(string $id, Callable $value): ContainerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a specific instance in the container for an existing factory
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @param mixed $value
|
||||||
|
* @return ContainerInterface
|
||||||
|
*/
|
||||||
|
public function setInstance(string $id, $value): ContainerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a new instance of the specified item
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getNew($id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether a logger channel is registered
|
||||||
|
*
|
||||||
|
* @param string $id The logger channel
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function hasLogger(string $id = 'default'): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a logger to the Container
|
||||||
|
*
|
||||||
|
* @param LoggerInterface $logger
|
||||||
|
* @param string $id The logger 'channel'
|
||||||
|
* @return ContainerInterface
|
||||||
|
*/
|
||||||
|
public function setLogger(LoggerInterface $logger, string $id = 'default'): ContainerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a logger for the selected channel
|
||||||
|
*
|
||||||
|
* @param string $id The logger to retrieve
|
||||||
|
* @return LoggerInterface|null
|
||||||
|
*/
|
||||||
|
public function getLogger(string $id = 'default'): ?LoggerInterface;
|
||||||
|
}
|
28
src/Ion/Di/Exception/ContainerException.php
Normal file
28
src/Ion/Di/Exception/ContainerException.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Di\Exception;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Interop\Container\Exception\ContainerException as InteropContainerException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic exception for Di Container
|
||||||
|
*/
|
||||||
|
class ContainerException extends Exception implements InteropContainerException {
|
||||||
|
|
||||||
|
}
|
||||||
|
// End of ContainerException.php
|
28
src/Ion/Di/Exception/NotFoundException.php
Normal file
28
src/Ion/Di/Exception/NotFoundException.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Di\Exception;
|
||||||
|
|
||||||
|
use Interop\Container\Exception\NotFoundException as InteropNotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for Di Container when trying to access a
|
||||||
|
* key that doesn't exist in the container
|
||||||
|
*/
|
||||||
|
class NotFoundException extends ContainerException implements InteropNotFoundException {
|
||||||
|
|
||||||
|
}
|
||||||
|
// End of NotFoundException.php
|
59
src/Ion/Enum.php
Normal file
59
src/Ion/Enum.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion;
|
||||||
|
|
||||||
|
use ReflectionClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class emulating an enumeration type
|
||||||
|
*/
|
||||||
|
abstract class Enum {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the list of constant values for the Enum
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @throws \ReflectionException
|
||||||
|
*/
|
||||||
|
public static function getConstList(): array
|
||||||
|
{
|
||||||
|
static $self;
|
||||||
|
|
||||||
|
if ($self === NULL)
|
||||||
|
{
|
||||||
|
$class = static::class;
|
||||||
|
$self = new $class;
|
||||||
|
}
|
||||||
|
|
||||||
|
$reflect = new ReflectionClass($self);
|
||||||
|
return $reflect->getConstants();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that a constant value is valid
|
||||||
|
*
|
||||||
|
* @param mixed $key
|
||||||
|
* @return boolean
|
||||||
|
* @throws \ReflectionException
|
||||||
|
*/
|
||||||
|
public static function isValid($key): bool
|
||||||
|
{
|
||||||
|
$values = array_values(static::getConstList());
|
||||||
|
return \in_array($key, $values, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End of Enum.php
|
26
src/Ion/Exception/ConfigException.php
Normal file
26
src/Ion/Exception/ConfigException.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Exception;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for bad configuration
|
||||||
|
*/
|
||||||
|
class ConfigException extends InvalidArgumentException {
|
||||||
|
|
||||||
|
}
|
38
src/Ion/Exception/DoubleRenderException.php
Normal file
38
src/Ion/Exception/DoubleRenderException.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Exception;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use LogicException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception called when a view is attempted to be sent twice
|
||||||
|
*/
|
||||||
|
class DoubleRenderException extends LogicException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DoubleRenderException constructor.
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @param int $code
|
||||||
|
* @param Exception|null $previous
|
||||||
|
*/
|
||||||
|
public function __construct(string $message = 'A view can only be rendered once, because headers can only be sent once.', int $code = 0, Exception $previous = NULL)
|
||||||
|
{
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
}
|
||||||
|
}
|
155
src/Ion/Friend.php
Normal file
155
src/Ion/Friend.php
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion;
|
||||||
|
|
||||||
|
use BadMethodCallException;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use ReflectionClass;
|
||||||
|
use ReflectionMethod;
|
||||||
|
use ReflectionProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Friend class for testing
|
||||||
|
*/
|
||||||
|
class Friend {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object to create a friend of
|
||||||
|
* @var mixed
|
||||||
|
*/
|
||||||
|
private $_friend_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reflection class of the object
|
||||||
|
* @var ReflectionClass
|
||||||
|
*/
|
||||||
|
private $_reflect_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a friend object
|
||||||
|
*
|
||||||
|
* @param mixed $obj
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
* @throws \ReflectionException
|
||||||
|
*/
|
||||||
|
public function __construct($obj)
|
||||||
|
{
|
||||||
|
if ( ! \is_object($obj))
|
||||||
|
{
|
||||||
|
throw new InvalidArgumentException('Friend must be an object');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->_friend_ = $obj;
|
||||||
|
$this->_reflect_ = new ReflectionClass($obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a friend's property
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function __get(string $key)
|
||||||
|
{
|
||||||
|
if ($this->__isset($key))
|
||||||
|
{
|
||||||
|
$property = $this->_get_property($key);
|
||||||
|
|
||||||
|
if ($property !== NULL)
|
||||||
|
{
|
||||||
|
return $property->getValue($this->_friend_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See if a property exists on the friend
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function __isset(string $name): bool
|
||||||
|
{
|
||||||
|
return $this->_reflect_->hasProperty($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a friend's property
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @param mixed $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __set(string $key, $value)
|
||||||
|
{
|
||||||
|
if ($this->__isset($key))
|
||||||
|
{
|
||||||
|
$property = $this->_get_property($key);
|
||||||
|
|
||||||
|
if ($property !== NULL)
|
||||||
|
{
|
||||||
|
$property->setValue($this->_friend_, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls a protected or private method on the friend
|
||||||
|
*
|
||||||
|
* @param string $method
|
||||||
|
* @param array $args
|
||||||
|
* @return mixed
|
||||||
|
* @throws BadMethodCallException
|
||||||
|
* @throws \ReflectionException
|
||||||
|
*/
|
||||||
|
public function __call(string $method, array $args)
|
||||||
|
{
|
||||||
|
if ( ! $this->_reflect_->hasMethod($method))
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException("Method '{$method}' does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
$friendMethod = new ReflectionMethod($this->_friend_, $method);
|
||||||
|
$friendMethod->setAccessible(TRUE);
|
||||||
|
return $friendMethod->invokeArgs($this->_friend_, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates over parent classes to get a ReflectionProperty
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @return ReflectionProperty|null
|
||||||
|
*/
|
||||||
|
private function _get_property(string $name): ?ReflectionProperty
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$property = $this->_reflect_->getProperty($name);
|
||||||
|
$property->setAccessible(TRUE);
|
||||||
|
return $property;
|
||||||
|
}
|
||||||
|
// Return NULL on any exception, so no further logic needed
|
||||||
|
// in the catch block
|
||||||
|
catch (\Exception $e)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End of Friend.php
|
139
src/Ion/Json.php
Normal file
139
src/Ion/Json.php
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion;
|
||||||
|
|
||||||
|
use Aviat\Ion\Type\StringType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for json convenience methods
|
||||||
|
*/
|
||||||
|
class Json {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode data in json format
|
||||||
|
*
|
||||||
|
* @param mixed $data
|
||||||
|
* @param int $options
|
||||||
|
* @param int $depth
|
||||||
|
* @throws JsonException
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function encode($data, $options = 0, $depth = 512): string
|
||||||
|
{
|
||||||
|
$json = json_encode($data, $options, $depth);
|
||||||
|
self::check_json_error();
|
||||||
|
return $json;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode data in json format and save to a file
|
||||||
|
*
|
||||||
|
* @param string $filename
|
||||||
|
* @param mixed $data
|
||||||
|
* @param int $jsonOptions - Options to pass to json_encode
|
||||||
|
* @param int $fileOptions - Options to pass to file_get_contents
|
||||||
|
* @throws JsonException
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public static function encodeFile(string $filename, $data, int $jsonOptions = 0, int $fileOptions = 0): int
|
||||||
|
{
|
||||||
|
$json = self::encode($data, $jsonOptions);
|
||||||
|
return file_put_contents($filename, $json, $fileOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode data from json
|
||||||
|
*
|
||||||
|
* @param string|null $json
|
||||||
|
* @param bool $assoc
|
||||||
|
* @param int $depth
|
||||||
|
* @param int $options
|
||||||
|
* @throws JsonException
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public static function decode($json, bool $assoc = TRUE, int $depth = 512, int $options = 0)
|
||||||
|
{
|
||||||
|
// Don't try to decode null
|
||||||
|
if ($json === NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = json_decode($json, $assoc, $depth, $options);
|
||||||
|
|
||||||
|
self::check_json_error();
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode json data loaded from the passed filename
|
||||||
|
*
|
||||||
|
* @param string $filename
|
||||||
|
* @param bool $assoc
|
||||||
|
* @param int $depth
|
||||||
|
* @param int $options
|
||||||
|
* @throws JsonException
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public static function decodeFile(string $filename, bool $assoc = TRUE, int $depth = 512, int $options = 0)
|
||||||
|
{
|
||||||
|
$json = file_get_contents($filename);
|
||||||
|
return self::decode($json, $assoc, $depth, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether a string is valid json
|
||||||
|
*
|
||||||
|
* @param string $string
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function isJson(string $string): bool
|
||||||
|
{
|
||||||
|
return StringType::create($string)->isJson();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call the json error functions to check for errors encoding/decoding
|
||||||
|
*
|
||||||
|
* @throws JsonException
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected static function check_json_error(): void
|
||||||
|
{
|
||||||
|
$constant_map = [
|
||||||
|
JSON_ERROR_NONE => 'JSON_ERROR_NONE',
|
||||||
|
JSON_ERROR_DEPTH => 'JSON_ERROR_DEPTH',
|
||||||
|
JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH',
|
||||||
|
JSON_ERROR_CTRL_CHAR => 'JSON_ERROR_CTRL_CHAR',
|
||||||
|
JSON_ERROR_SYNTAX => 'JSON_ERROR_SYNTAX',
|
||||||
|
JSON_ERROR_UTF8 => 'JSON_ERROR_UTF8',
|
||||||
|
JSON_ERROR_RECURSION => 'JSON_ERROR_RECURSION',
|
||||||
|
JSON_ERROR_INF_OR_NAN => 'JSON_ERROR_INF_OR_NAN',
|
||||||
|
JSON_ERROR_UNSUPPORTED_TYPE => 'JSON_ERROR_UNSUPPORTED_TYPE'
|
||||||
|
];
|
||||||
|
|
||||||
|
$error = json_last_error();
|
||||||
|
$message = json_last_error_msg();
|
||||||
|
|
||||||
|
if (JSON_ERROR_NONE !== $error)
|
||||||
|
{
|
||||||
|
throw new JsonException("{$constant_map[$error]} - {$message}", $error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End of JSON.php
|
27
src/Ion/JsonException.php
Normal file
27
src/Ion/JsonException.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exceptions thrown by the Json class
|
||||||
|
*/
|
||||||
|
class JsonException extends InvalidArgumentException {
|
||||||
|
|
||||||
|
}
|
||||||
|
// End of JsonException.php
|
25
src/Ion/Model.php
Normal file
25
src/Ion/Model.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common base for all Models
|
||||||
|
*/
|
||||||
|
class Model {
|
||||||
|
use StringWrapper;
|
||||||
|
}
|
||||||
|
// End of Model.php
|
55
src/Ion/Model/DB.php
Normal file
55
src/Ion/Model/DB.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Model;
|
||||||
|
|
||||||
|
use Aviat\Ion\ConfigInterface;
|
||||||
|
use Aviat\Ion\Model as BaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base model for database interaction
|
||||||
|
*/
|
||||||
|
class DB extends BaseModel {
|
||||||
|
/**
|
||||||
|
* The query builder object
|
||||||
|
* @var object $db
|
||||||
|
*/
|
||||||
|
protected $db;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The config manager
|
||||||
|
* @var ConfigInterface
|
||||||
|
*/
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The database connection information array
|
||||||
|
* @var array $db_config
|
||||||
|
*/
|
||||||
|
protected $db_config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param ConfigInterface $config
|
||||||
|
*/
|
||||||
|
public function __construct(ConfigInterface $config)
|
||||||
|
{
|
||||||
|
$this->config = $config;
|
||||||
|
$this->db_config = (array)$config->get('database');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End of DB.php
|
38
src/Ion/StringWrapper.php
Normal file
38
src/Ion/StringWrapper.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion;
|
||||||
|
|
||||||
|
use Aviat\Ion\Type\StringType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trait to add convenience method for creating StringType objects
|
||||||
|
*/
|
||||||
|
trait StringWrapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap the String in the Stringy class
|
||||||
|
*
|
||||||
|
* @param string $str
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
* @return StringType
|
||||||
|
*/
|
||||||
|
public function string($str): StringType
|
||||||
|
{
|
||||||
|
return StringType::create($str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End of StringWrapper.php
|
69
src/Ion/Transformer/AbstractTransformer.php
Normal file
69
src/Ion/Transformer/AbstractTransformer.php
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Transformer;
|
||||||
|
|
||||||
|
use Aviat\Ion\StringWrapper;
|
||||||
|
|
||||||
|
use BadMethodCallException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for data transformation
|
||||||
|
*/
|
||||||
|
abstract class AbstractTransformer implements TransformerInterface {
|
||||||
|
|
||||||
|
use StringWrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutate the data structure
|
||||||
|
*
|
||||||
|
* @param array|object $item
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
abstract public function transform($item);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform a set of structures
|
||||||
|
*
|
||||||
|
* @param iterable $collection
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function transformCollection(iterable $collection): array
|
||||||
|
{
|
||||||
|
$list = (array)$collection;
|
||||||
|
return array_map([$this, 'transform'], $list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Untransform a set of structures
|
||||||
|
*
|
||||||
|
* Requires an 'untransform' method in the extending class
|
||||||
|
*
|
||||||
|
* @param iterable $collection
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function untransformCollection(iterable $collection): array
|
||||||
|
{
|
||||||
|
if ( ! method_exists($this, 'untransform'))
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('untransform() method does not exist.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$list = (array)$collection;
|
||||||
|
return array_map([$this, 'untransform'], $list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End of AbstractTransformer.php
|
31
src/Ion/Transformer/TransformerInterface.php
Normal file
31
src/Ion/Transformer/TransformerInterface.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Transformer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for data transformation classes
|
||||||
|
*/
|
||||||
|
interface TransformerInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutate the data structure
|
||||||
|
*
|
||||||
|
* @param array|object $item
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function transform($item);
|
||||||
|
}
|
286
src/Ion/Type/ArrayType.php
Normal file
286
src/Ion/Type/ArrayType.php
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Type;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper class for native array methods for convenience
|
||||||
|
*
|
||||||
|
* @method array chunk(int $size, bool $preserve_keys = FALSE)
|
||||||
|
* @method array pluck(mixed $column_key, mixed $index_key = NULL)
|
||||||
|
* @method array filter(callable $callback = NULL, int $flag = 0)
|
||||||
|
*/
|
||||||
|
class ArrayType {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current array
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $arr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map generated methods to their native implementations
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $nativeMethods = [
|
||||||
|
'chunk' => 'array_chunk',
|
||||||
|
'diff' => 'array_diff',
|
||||||
|
'filter' => 'array_filter',
|
||||||
|
'flip' => 'array_flip',
|
||||||
|
'intersect' => 'array_intersect',
|
||||||
|
'key_diff' => 'array_diff_key',
|
||||||
|
'keys' => 'array_keys',
|
||||||
|
'merge' => 'array_merge',
|
||||||
|
'pad' => 'array_pad',
|
||||||
|
'pluck' => 'array_column',
|
||||||
|
'product' => 'array_product',
|
||||||
|
'random' => 'array_rand',
|
||||||
|
'reduce' => 'array_reduce',
|
||||||
|
'reverse' => 'array_reverse',
|
||||||
|
'sum' => 'array_sum',
|
||||||
|
'unique' => 'array_unique',
|
||||||
|
'values' => 'array_values',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Native methods that modify the passed in array
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $nativeInPlaceMethods = [
|
||||||
|
'shuffle' => 'shuffle',
|
||||||
|
'shift' => 'array_shift',
|
||||||
|
'unshift' => 'array_unshift',
|
||||||
|
'push' => 'array_push',
|
||||||
|
'pop' => 'array_pop',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an ArrayType wrapper class
|
||||||
|
*
|
||||||
|
* @param array $arr
|
||||||
|
*/
|
||||||
|
public function __construct(array &$arr)
|
||||||
|
{
|
||||||
|
$this->arr =& $arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call one of the dynamically created methods
|
||||||
|
*
|
||||||
|
* @param string $method
|
||||||
|
* @param array $args
|
||||||
|
* @return mixed
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function __call(string $method, array $args)
|
||||||
|
{
|
||||||
|
// Simple mapping for the majority of methods
|
||||||
|
if (array_key_exists($method, $this->nativeMethods))
|
||||||
|
{
|
||||||
|
$func = $this->nativeMethods[$method];
|
||||||
|
// Set the current array as the first argument of the method
|
||||||
|
return $func($this->arr, ...$args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mapping for in-place methods
|
||||||
|
if (array_key_exists($method, $this->nativeInPlaceMethods))
|
||||||
|
{
|
||||||
|
$func = $this->nativeInPlaceMethods[$method];
|
||||||
|
$func($this->arr);
|
||||||
|
return $this->arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidArgumentException("Method '{$method}' does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the passed key exist in the current array?
|
||||||
|
*
|
||||||
|
* @param int|string|array $key
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasKey($key): bool
|
||||||
|
{
|
||||||
|
if (\is_array($key))
|
||||||
|
{
|
||||||
|
$pos =& $this->arr;
|
||||||
|
|
||||||
|
foreach($key as $level)
|
||||||
|
{
|
||||||
|
if ( ! array_key_exists($level, $pos))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pos =& $pos[$level];
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_key_exists($key, $this->arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill an array with the specified value
|
||||||
|
*
|
||||||
|
* @param int $start_index
|
||||||
|
* @param int $num
|
||||||
|
* @param mixed $value
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function fill(int $start_index, int $num, $value): array
|
||||||
|
{
|
||||||
|
return array_fill($start_index, $num, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call a callback on each item of the array
|
||||||
|
*
|
||||||
|
* @param callable $callback
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function map(callable $callback): array
|
||||||
|
{
|
||||||
|
return array_map($callback, $this->arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find an array key by its associated value
|
||||||
|
*
|
||||||
|
* @param mixed $value
|
||||||
|
* @param bool $strict
|
||||||
|
* @return false|integer|string
|
||||||
|
*/
|
||||||
|
public function search($value, bool $strict = TRUE)
|
||||||
|
{
|
||||||
|
return array_search($value, $this->arr, $strict);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the array has the passed value
|
||||||
|
*
|
||||||
|
* @param mixed $value
|
||||||
|
* @param bool $strict
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function has($value, bool $strict = TRUE): bool
|
||||||
|
{
|
||||||
|
return \in_array($value, $this->arr, $strict);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the array, or a key
|
||||||
|
*
|
||||||
|
* @param string|integer|null $key
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function &get($key = NULL)
|
||||||
|
{
|
||||||
|
$value = NULL;
|
||||||
|
if ($key === NULL)
|
||||||
|
{
|
||||||
|
$value =& $this->arr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($this->hasKey($key))
|
||||||
|
{
|
||||||
|
$value =& $this->arr[$key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a key on the array
|
||||||
|
*
|
||||||
|
* @param mixed $key
|
||||||
|
* @param mixed $value
|
||||||
|
* @return ArrayType
|
||||||
|
*/
|
||||||
|
public function set($key, $value): ArrayType
|
||||||
|
{
|
||||||
|
$this->arr[$key] = $value;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a reference to the value of an arbitrary key on the array
|
||||||
|
*
|
||||||
|
* @example $arr = new ArrayType([0 => ['data' => ['foo' => 'bar']]]);
|
||||||
|
* $val = $arr->getDeepKey([0, 'data', 'foo']);
|
||||||
|
* // returns 'bar'
|
||||||
|
* @param array $key An array of keys of the array
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function &getDeepKey(array $key)
|
||||||
|
{
|
||||||
|
$pos =& $this->arr;
|
||||||
|
|
||||||
|
foreach ($key as $level)
|
||||||
|
{
|
||||||
|
if (empty($pos) || ! is_array($pos))
|
||||||
|
{
|
||||||
|
// Directly returning a NULL value here will
|
||||||
|
// result in a reference error. This isn't
|
||||||
|
// excess code, just what's required for this
|
||||||
|
// unique situation.
|
||||||
|
$pos = NULL;
|
||||||
|
return $pos;
|
||||||
|
}
|
||||||
|
$pos =& $pos[$level];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of an arbitrarily deep key in the array
|
||||||
|
* and returns the modified array
|
||||||
|
*
|
||||||
|
* @param array $key
|
||||||
|
* @param mixed $value
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function setDeepKey(array $key, $value): array
|
||||||
|
{
|
||||||
|
$pos =& $this->arr;
|
||||||
|
|
||||||
|
// Iterate through the levels of the array,
|
||||||
|
// create the levels if they don't exist
|
||||||
|
foreach ($key as $level)
|
||||||
|
{
|
||||||
|
if ( ! \is_array($pos) && empty($pos))
|
||||||
|
{
|
||||||
|
$pos = [];
|
||||||
|
$pos[$level] = [];
|
||||||
|
}
|
||||||
|
$pos =& $pos[$level];
|
||||||
|
}
|
||||||
|
|
||||||
|
$pos = $value;
|
||||||
|
|
||||||
|
return $this->arr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End of ArrayType.php
|
42
src/Ion/Type/StringType.php
Normal file
42
src/Ion/Type/StringType.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Type;
|
||||||
|
|
||||||
|
use Stringy\Stringy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper around Stringy
|
||||||
|
*/
|
||||||
|
class StringType extends Stringy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See if two strings match, despite being delimited differently,
|
||||||
|
* such as camelCase, PascalCase, kebab-case, or snake_case.
|
||||||
|
*
|
||||||
|
* @param string $strToMatch
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function fuzzyCaseMatch(string $strToMatch): bool
|
||||||
|
{
|
||||||
|
$firstStr = (string)self::create($this->str)->dasherize();
|
||||||
|
$secondStr = (string)self::create($strToMatch)->dasherize();
|
||||||
|
|
||||||
|
return $firstStr === $secondStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End of StringType.php
|
143
src/Ion/View.php
Normal file
143
src/Ion/View.php
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion;
|
||||||
|
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
|
use Aviat\Ion\Di\ContainerInterface;
|
||||||
|
use Aviat\Ion\Exception\DoubleRenderException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base view response class
|
||||||
|
*/
|
||||||
|
abstract class View
|
||||||
|
// partially
|
||||||
|
implements ViewInterface {
|
||||||
|
|
||||||
|
use Di\ContainerAware;
|
||||||
|
use StringWrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP response Object
|
||||||
|
*
|
||||||
|
* @var ResponseInterface
|
||||||
|
*/
|
||||||
|
public $response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the view has sent output via
|
||||||
|
* __toString or send method
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
protected $hasRendered = FALSE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param ContainerInterface $container
|
||||||
|
* @throws Di\Exception\ContainerException
|
||||||
|
* @throws Di\Exception\NotFoundException
|
||||||
|
*/
|
||||||
|
public function __construct(ContainerInterface $container)
|
||||||
|
{
|
||||||
|
$this->setContainer($container);
|
||||||
|
$this->response = $container->get('response');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send output to client
|
||||||
|
*/
|
||||||
|
public function __destruct()
|
||||||
|
{
|
||||||
|
if ( ! $this->hasRendered)
|
||||||
|
{
|
||||||
|
$this->send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return rendered output as string. Renders the view,
|
||||||
|
* and any attempts to call again will result in a DoubleRenderException
|
||||||
|
*
|
||||||
|
* @throws DoubleRenderException
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
if ($this->hasRendered)
|
||||||
|
{
|
||||||
|
throw new DoubleRenderException();
|
||||||
|
}
|
||||||
|
$this->hasRendered = TRUE;
|
||||||
|
return $this->getOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an http header
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param string|string[] $value
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
* @return ViewInterface
|
||||||
|
*/
|
||||||
|
public function addHeader(string $name, $value): ViewInterface
|
||||||
|
{
|
||||||
|
$this->response = $this->response->withHeader($name, $value);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the output string
|
||||||
|
*
|
||||||
|
* @param mixed $string
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
* @throws \RuntimeException
|
||||||
|
* @return ViewInterface
|
||||||
|
*/
|
||||||
|
public function setOutput($string): ViewInterface
|
||||||
|
{
|
||||||
|
$this->response->getBody()->write($string);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append additional output.
|
||||||
|
*
|
||||||
|
* @param string $string
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
* @throws \RuntimeException
|
||||||
|
* @return ViewInterface
|
||||||
|
*/
|
||||||
|
public function appendOutput(string $string): ViewInterface
|
||||||
|
{
|
||||||
|
return $this->setOutput($string);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current output as a string. Does not
|
||||||
|
* render view or send headers.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getOutput(): string
|
||||||
|
{
|
||||||
|
return (string)$this->response->getBody();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End of View.php
|
81
src/Ion/View/HtmlView.php
Normal file
81
src/Ion/View/HtmlView.php
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\View;
|
||||||
|
|
||||||
|
use Aura\Html\HelperLocator;
|
||||||
|
use Aviat\Ion\Di\ContainerInterface;
|
||||||
|
use Aviat\Ion\Di\Exception\ContainerException;
|
||||||
|
use Aviat\Ion\Di\Exception\NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View class for outputting HTML
|
||||||
|
*/
|
||||||
|
class HtmlView extends HttpView {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTML generator/escaper helper
|
||||||
|
*
|
||||||
|
* @var HelperLocator
|
||||||
|
*/
|
||||||
|
protected $helper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response mime type
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $contentType = 'text/html';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the Html View
|
||||||
|
*
|
||||||
|
* @param ContainerInterface $container
|
||||||
|
* @throws ContainerException
|
||||||
|
* @throws NotFoundException
|
||||||
|
*/
|
||||||
|
public function __construct(ContainerInterface $container)
|
||||||
|
{
|
||||||
|
parent::__construct($container);
|
||||||
|
$this->helper = $container->get('html-helper');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render a basic html Template
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @param array $data
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function renderTemplate(string $path, array $data): string
|
||||||
|
{
|
||||||
|
$data['helper'] = $this->helper;
|
||||||
|
$data['escape'] = $this->helper->escape();
|
||||||
|
$data['container'] = $this->container;
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
extract($data, \EXTR_OVERWRITE);
|
||||||
|
include_once $path;
|
||||||
|
$buffer = ob_get_clean();
|
||||||
|
|
||||||
|
|
||||||
|
// Very basic html minify, that won't affect content between html tags
|
||||||
|
$buffer = preg_replace('/>\s+</', '> <', $buffer);
|
||||||
|
|
||||||
|
return $buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End of HtmlView.php
|
102
src/Ion/View/HttpView.php
Normal file
102
src/Ion/View/HttpView.php
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\View;
|
||||||
|
|
||||||
|
use Zend\Diactoros\Response;
|
||||||
|
use Zend\HttpHandlerRunner\Emitter\SapiEmitter;
|
||||||
|
|
||||||
|
use Aviat\Ion\Exception\DoubleRenderException;
|
||||||
|
use Aviat\Ion\View as BaseView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base view class for Http output
|
||||||
|
*/
|
||||||
|
class HttpView extends BaseView {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response mime type
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $contentType = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do a redirect
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @param int $code
|
||||||
|
* @param array $headers
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function redirect(string $url, int $code = 302, array $headers = []): void
|
||||||
|
{
|
||||||
|
$this->response = new Response\RedirectResponse($url, $code, $headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the status code of the request
|
||||||
|
*
|
||||||
|
* @param int $code
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
* @return HttpView
|
||||||
|
*/
|
||||||
|
public function setStatusCode(int $code): HttpView
|
||||||
|
{
|
||||||
|
$this->response = $this->response->withStatus($code)
|
||||||
|
->withProtocolVersion('1.1');
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send output to client. As it renders the view,
|
||||||
|
* any attempt to call again will result in a DoubleRenderException.
|
||||||
|
*
|
||||||
|
* @throws DoubleRenderException
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function send(): void
|
||||||
|
{
|
||||||
|
$this->output();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the appropriate response
|
||||||
|
*
|
||||||
|
* @throws DoubleRenderException
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function output(): void
|
||||||
|
{
|
||||||
|
if ($this->hasRendered)
|
||||||
|
{
|
||||||
|
throw new DoubleRenderException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response = $this->response
|
||||||
|
->withHeader('Content-type', "{$this->contentType};charset=utf-8")
|
||||||
|
->withHeader('X-Content-Type-Options', 'nosniff')
|
||||||
|
->withHeader('X-XSS-Protection', '1;mode=block')
|
||||||
|
->withHeader('X-Frame-Options', 'SAMEORIGIN');
|
||||||
|
|
||||||
|
(new SapiEmitter())->emit($this->response);
|
||||||
|
|
||||||
|
$this->hasRendered = TRUE;
|
||||||
|
}
|
||||||
|
}
|
54
src/Ion/View/JsonView.php
Normal file
54
src/Ion/View/JsonView.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\View;
|
||||||
|
|
||||||
|
use Aviat\Ion\Json;
|
||||||
|
use Aviat\Ion\JsonException;
|
||||||
|
use Aviat\Ion\ViewInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View class to serialize Json
|
||||||
|
*/
|
||||||
|
class JsonView extends HttpView {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response mime type
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $contentType = 'application/json';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the output string
|
||||||
|
*
|
||||||
|
* @param mixed $string
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
* @throws \RuntimeException
|
||||||
|
* @throws JsonException
|
||||||
|
* @return ViewInterface
|
||||||
|
*/
|
||||||
|
public function setOutput($string): ViewInterface
|
||||||
|
{
|
||||||
|
if ( ! \is_string($string))
|
||||||
|
{
|
||||||
|
$string = Json::encode($string);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::setOutput($string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End of JsonView.php
|
75
src/Ion/ViewInterface.php
Normal file
75
src/Ion/ViewInterface.php
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion;
|
||||||
|
|
||||||
|
use Aviat\Ion\Exception\DoubleRenderException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View Interface abstracting a Response
|
||||||
|
*/
|
||||||
|
interface ViewInterface {
|
||||||
|
/**
|
||||||
|
* Return rendered output as string. Renders the view,
|
||||||
|
* and any attempts to call again will result in a DoubleRenderException
|
||||||
|
*
|
||||||
|
* @throws DoubleRenderException
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the output string
|
||||||
|
*
|
||||||
|
* @param mixed $string
|
||||||
|
* @return ViewInterface
|
||||||
|
*/
|
||||||
|
public function setOutput($string): self;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append additional output.
|
||||||
|
*
|
||||||
|
* @param string $string
|
||||||
|
* @return ViewInterface
|
||||||
|
*/
|
||||||
|
public function appendOutput(string $string): self;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an http header
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param string|string[] $value
|
||||||
|
* @return ViewInterface
|
||||||
|
*/
|
||||||
|
public function addHeader(string $name, $value): self;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current output as a string. Does not
|
||||||
|
* render view or send headers.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getOutput(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send output to client. As it renders the view,
|
||||||
|
* any attempt to call again will result in a DoubleRenderException.
|
||||||
|
*
|
||||||
|
* @throws DoubleRenderException
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function send(): void;
|
||||||
|
}
|
279
src/Ion/XML.php
Normal file
279
src/Ion/XML.php
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion;
|
||||||
|
|
||||||
|
use DOMDocument, DOMNode, DOMNodeList, InvalidArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XML <=> PHP Array codec
|
||||||
|
*/
|
||||||
|
final class XML {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XML representation of the data
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $xml;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHP array version of the data
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XML constructor
|
||||||
|
*
|
||||||
|
* @param string $xml
|
||||||
|
* @param array $data
|
||||||
|
*/
|
||||||
|
public function __construct(string $xml = '', array $data = [])
|
||||||
|
{
|
||||||
|
$this->setXML($xml)->setData($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the data to an xml string
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
return static::toXML($this->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the data parsed from the XML
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getData(): array
|
||||||
|
{
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the data to create xml from
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setData(array $data): self
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the xml created from the data
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getXML(): string
|
||||||
|
{
|
||||||
|
return $this->xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the xml to parse the data from
|
||||||
|
*
|
||||||
|
* @param string $xml
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setXML(string $xml): self
|
||||||
|
{
|
||||||
|
$this->xml = $xml;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse an xml document string to a php array
|
||||||
|
*
|
||||||
|
* @param string $xml
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function toArray(string $xml): array
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
$xml = static::stripXMLWhitespace($xml);
|
||||||
|
|
||||||
|
$dom = new DOMDocument();
|
||||||
|
$hasLoaded = @$dom->loadXML($xml);
|
||||||
|
|
||||||
|
if ( ! $hasLoaded)
|
||||||
|
{
|
||||||
|
throw new InvalidArgumentException('Failed to load XML');
|
||||||
|
}
|
||||||
|
|
||||||
|
$root = $dom->documentElement;
|
||||||
|
|
||||||
|
$data[$root->tagName] = [];
|
||||||
|
|
||||||
|
if ($root->hasChildNodes())
|
||||||
|
{
|
||||||
|
static::childNodesToArray($data[$root->tagName], $root->childNodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform the array into XML
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function toXML(array $data): string
|
||||||
|
{
|
||||||
|
$dom = new DOMDocument();
|
||||||
|
$dom->encoding = 'UTF-8';
|
||||||
|
|
||||||
|
static::arrayPropertiesToXmlNodes($dom, $dom, $data);
|
||||||
|
|
||||||
|
return $dom->saveXML();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the xml document string to a php array
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function parse(): array
|
||||||
|
{
|
||||||
|
$xml = $this->getXML();
|
||||||
|
$data = static::toArray($xml);
|
||||||
|
return $this->setData($data)->getData();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform the array into XML
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function createXML(): string
|
||||||
|
{
|
||||||
|
return static::toXML($this->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strip whitespace from raw xml to remove irrelevant text nodes
|
||||||
|
*
|
||||||
|
* @param string $xml
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private static function stripXMLWhitespace(string $xml): string
|
||||||
|
{
|
||||||
|
// Get rid of unimportant text nodes by removing
|
||||||
|
// whitespace characters from between xml tags,
|
||||||
|
// except for the xml declaration tag, Which looks
|
||||||
|
// something like:
|
||||||
|
/* <?xml version="1.0" encoding="UTF-8"?> */
|
||||||
|
return preg_replace('/([^?])>\s+</', '$1><', $xml);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively create array structure based on xml structure
|
||||||
|
*
|
||||||
|
* @param array $root A reference to the current array location
|
||||||
|
* @param DOMNodeList $nodeList The current NodeList object
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function childNodesToArray(array &$root, DOMNodelist $nodeList): void
|
||||||
|
{
|
||||||
|
$length = $nodeList->length;
|
||||||
|
for ($i = 0; $i < $length; $i++)
|
||||||
|
{
|
||||||
|
$el = $nodeList->item($i);
|
||||||
|
$current =& $root[$el->nodeName];
|
||||||
|
|
||||||
|
// It's a top level element!
|
||||||
|
if (( ! $el->hasChildNodes()) || ($el->childNodes->item(0) instanceof \DomText))
|
||||||
|
{
|
||||||
|
$current = $el->textContent;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// An empty value at the current root
|
||||||
|
if ($current === NULL)
|
||||||
|
{
|
||||||
|
$current = [];
|
||||||
|
static::childNodesToArray($current, $el->childNodes);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$keys = array_keys($current);
|
||||||
|
|
||||||
|
// Wrap the array in a containing array
|
||||||
|
// if there are only string keys
|
||||||
|
if ( ! is_numeric($keys[0]))
|
||||||
|
{
|
||||||
|
// But if there is only one key, don't wrap it in
|
||||||
|
// an array, just recurse to parse the child nodes
|
||||||
|
if (count($current) === 1)
|
||||||
|
{
|
||||||
|
static::childNodesToArray($current, $el->childNodes);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$current = [$current];
|
||||||
|
}
|
||||||
|
|
||||||
|
$current[] = [];
|
||||||
|
$index = count($current) - 1;
|
||||||
|
|
||||||
|
static::childNodesToArray($current[$index], $el->childNodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively create xml nodes from array properties
|
||||||
|
*
|
||||||
|
* @param DOMDocument $dom The current DOM object
|
||||||
|
* @param DOMNode $parent The parent element to append children to
|
||||||
|
* @param array $data The data for the current node
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function arrayPropertiesToXmlNodes(DOMDocument $dom, DOMNode $parent, array $data): void
|
||||||
|
{
|
||||||
|
foreach ($data as $key => $props)
|
||||||
|
{
|
||||||
|
// 'Flatten' the array as you create the xml
|
||||||
|
if (is_numeric($key))
|
||||||
|
{
|
||||||
|
foreach ($props as $k => $p)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$node = $dom->createElement($key);
|
||||||
|
|
||||||
|
if (\is_array($props))
|
||||||
|
{
|
||||||
|
static::arrayPropertiesToXmlNodes($dom, $node, $props);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
$tNode = $dom->createTextNode((string)$props);
|
||||||
|
$node->appendChild($tNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
$parent->appendChild($node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
src/Ion/functions.php
Normal file
29
src/Ion/functions.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Joins paths together. Variadic to take an
|
||||||
|
* arbitrary number of arguments
|
||||||
|
*
|
||||||
|
* @param string ...$args
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function _dir(string ...$args): string
|
||||||
|
{
|
||||||
|
return implode(DIRECTORY_SEPARATOR, $args);
|
||||||
|
}
|
28
tests/Ion/BaseModelTest.php
Normal file
28
tests/Ion/BaseModelTest.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests;
|
||||||
|
|
||||||
|
use Aviat\Ion\Model as BaseModel;
|
||||||
|
|
||||||
|
class BaseModelTest extends Ion_TestCase {
|
||||||
|
|
||||||
|
public function testBaseModelSanity()
|
||||||
|
{
|
||||||
|
$baseModel = new BaseModel();
|
||||||
|
$this->assertTrue(is_object($baseModel));
|
||||||
|
}
|
||||||
|
}
|
151
tests/Ion/ConfigTest.php
Normal file
151
tests/Ion/ConfigTest.php
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests;
|
||||||
|
|
||||||
|
use Aviat\Ion\Config;
|
||||||
|
|
||||||
|
class ConfigTest extends Ion_TestCase {
|
||||||
|
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
$this->config = new Config([
|
||||||
|
'foo' => 'bar',
|
||||||
|
'asset_path' => '/assets',
|
||||||
|
'bar' => 'baz',
|
||||||
|
'a' => [
|
||||||
|
'b' => [
|
||||||
|
'c' => TRUE,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConfigHas(): void
|
||||||
|
{
|
||||||
|
$this->assertTrue($this->config->has('foo'));
|
||||||
|
$this->assertTrue($this->config->has(['a', 'b', 'c']));
|
||||||
|
|
||||||
|
$this->assertFalse($this->config->has('baz'));
|
||||||
|
$this->assertFalse($this->config->has(['c', 'b', 'a']));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConfigGet(): void
|
||||||
|
{
|
||||||
|
$this->assertEquals('bar', $this->config->get('foo'));
|
||||||
|
$this->assertEquals('baz', $this->config->get('bar'));
|
||||||
|
$this->assertNull($this->config->get('baz'));
|
||||||
|
$this->assertNull($this->config->get(['apple', 'sauce', 'is']));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConfigSet(): void
|
||||||
|
{
|
||||||
|
$ret = $this->config->set('foo', 'foobar');
|
||||||
|
$this->assertInstanceOf(Config::class, $ret);
|
||||||
|
$this->assertEquals('foobar', $this->config->get('foo'));
|
||||||
|
|
||||||
|
$this->config->set(['apple', 'sauce', 'is'], 'great');
|
||||||
|
$apple = $this->config->get('apple');
|
||||||
|
$this->assertEquals('great', $apple['sauce']['is'], 'Config value not set correctly');
|
||||||
|
|
||||||
|
$this->assertEquals('great', $this->config->get(['apple', 'sauce', 'is']), "Array argument get for config failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConfigBadSet(): void
|
||||||
|
{
|
||||||
|
$this->expectException('InvalidArgumentException');
|
||||||
|
$this->config->set(NULL, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataConfigDelete(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'top level delete' => [
|
||||||
|
'key' => 'apple',
|
||||||
|
'assertKeys' => [
|
||||||
|
[
|
||||||
|
'path' => ['apple', 'sauce', 'is'],
|
||||||
|
'expected' => NULL
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => ['apple', 'sauce'],
|
||||||
|
'expected' => NULL
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => 'apple',
|
||||||
|
'expected' => NULL
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'mid level delete' => [
|
||||||
|
'key' => ['apple', 'sauce'],
|
||||||
|
'assertKeys' => [
|
||||||
|
[
|
||||||
|
'path' => ['apple', 'sauce', 'is'],
|
||||||
|
'expected' => NULL
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => ['apple', 'sauce'],
|
||||||
|
'expected' => NULL
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => 'apple',
|
||||||
|
'expected' => [
|
||||||
|
'sauce' => NULL
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'deep delete' => [
|
||||||
|
'key' => ['apple', 'sauce', 'is'],
|
||||||
|
'assertKeys' => [
|
||||||
|
[
|
||||||
|
'path' => ['apple', 'sauce', 'is'],
|
||||||
|
'expected' => NULL
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => ['apple', 'sauce'],
|
||||||
|
'expected' => [
|
||||||
|
'is' => NULL
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataConfigDelete
|
||||||
|
*/
|
||||||
|
public function testConfigDelete($key, array $assertKeys): void
|
||||||
|
{
|
||||||
|
$config = new Config([]);
|
||||||
|
$config->set(['apple', 'sauce', 'is'], 'great');
|
||||||
|
$config->delete($key);
|
||||||
|
|
||||||
|
foreach($assertKeys as $pair)
|
||||||
|
{
|
||||||
|
$this->assertEquals($pair['expected'], $config->get($pair['path']));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetNonExistentConfigItem(): void
|
||||||
|
{
|
||||||
|
$this->assertNull($this->config->get('foobar'));
|
||||||
|
}
|
||||||
|
}
|
55
tests/Ion/Di/ContainerAwareTest.php
Normal file
55
tests/Ion/Di/ContainerAwareTest.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests\Di;
|
||||||
|
|
||||||
|
use Aviat\Ion\Di\{Container, ContainerAware, ContainerInterface};
|
||||||
|
use Aviat\Ion\Tests\Ion_TestCase;
|
||||||
|
|
||||||
|
class Aware {
|
||||||
|
use ContainerAware;
|
||||||
|
|
||||||
|
public function __construct(ContainerInterface $container)
|
||||||
|
{
|
||||||
|
$this->container = $container;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ContainerAwareTest extends Ion_TestCase {
|
||||||
|
|
||||||
|
protected $aware;
|
||||||
|
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
$this->container = new Container();
|
||||||
|
$this->aware = new Aware($this->container);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testContainerAwareTrait(): void
|
||||||
|
{
|
||||||
|
// The container was set in setup
|
||||||
|
// check that the get method returns the same
|
||||||
|
$this->assertSame($this->container, $this->aware->getContainer());
|
||||||
|
|
||||||
|
$container2 = new Container([
|
||||||
|
'foo' => 'bar',
|
||||||
|
'baz' => 'foobar'
|
||||||
|
]);
|
||||||
|
$this->aware->setContainer($container2);
|
||||||
|
$this->assertSame($container2, $this->aware->getContainer());
|
||||||
|
}
|
||||||
|
}
|
205
tests/Ion/Di/ContainerTest.php
Normal file
205
tests/Ion/Di/ContainerTest.php
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests\Di;
|
||||||
|
|
||||||
|
use Aviat\Ion\Di\{Container, ContainerAware};
|
||||||
|
use Aviat\Ion\Di\Exception\ContainerException;
|
||||||
|
use Aviat\Ion\Tests\Ion_TestCase;
|
||||||
|
use Monolog\Logger;
|
||||||
|
use Monolog\Handler\{TestHandler, NullHandler};
|
||||||
|
use Aviat\Ion\Di\ContainerInterface;
|
||||||
|
use Aviat\Ion\Di\Exception\NotFoundException;
|
||||||
|
|
||||||
|
class FooTest {
|
||||||
|
|
||||||
|
public $item;
|
||||||
|
|
||||||
|
public function __construct($item) {
|
||||||
|
$this->item = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FooTest2 {
|
||||||
|
use ContainerAware;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ContainerTest extends Ion_TestCase {
|
||||||
|
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
$this->container = new Container();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataGetWithException(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'Bad index type: number' => [
|
||||||
|
'id' => 42,
|
||||||
|
'exception' => ContainerException::class,
|
||||||
|
'message' => 'Id must be a string'
|
||||||
|
],
|
||||||
|
'Bad index type: array' => [
|
||||||
|
'id' => [],
|
||||||
|
'exception' => ContainerException::class,
|
||||||
|
'message' => 'Id must be a string'
|
||||||
|
],
|
||||||
|
'Non-existent id' => [
|
||||||
|
'id' => 'foo',
|
||||||
|
'exception' => NotFoundException::class,
|
||||||
|
'message' => "Item 'foo' does not exist in container."
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataGetWithException
|
||||||
|
*/
|
||||||
|
public function testGetWithException($id, $exception, $message): void
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$this->container->get($id);
|
||||||
|
}
|
||||||
|
catch(ContainerException $e)
|
||||||
|
{
|
||||||
|
$this->assertInstanceOf($exception, $e);
|
||||||
|
$this->assertEquals($message, $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataGetWithException
|
||||||
|
*/
|
||||||
|
public function testGetNewWithException($id, $exception, $message): void
|
||||||
|
{
|
||||||
|
$this->expectException($exception);
|
||||||
|
$this->expectExceptionMessage($message);
|
||||||
|
$this->container->getNew($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataSetInstanceWithException(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'Non-existent id' => [
|
||||||
|
'id' => 'foo',
|
||||||
|
'exception' => NotFoundException::class,
|
||||||
|
'message' => "Factory 'foo' does not exist in container. Set that first.",
|
||||||
|
],
|
||||||
|
'Non-existent id 2' => [
|
||||||
|
'id' => 'foobarbaz',
|
||||||
|
'exception' => NotFoundException::class,
|
||||||
|
'message' => "Factory 'foobarbaz' does not exist in container. Set that first.",
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataSetInstanceWithException
|
||||||
|
*/
|
||||||
|
public function testSetInstanceWithException($id, $exception, $message): void
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$this->container->setInstance($id, NULL);
|
||||||
|
}
|
||||||
|
catch(ContainerException $e)
|
||||||
|
{
|
||||||
|
$this->assertInstanceOf($exception, $e);
|
||||||
|
$this->assertEquals($message, $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetNew(): void
|
||||||
|
{
|
||||||
|
$this->container->set('footest', static function($item) {
|
||||||
|
return new FooTest($item);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check that the item is the container, if called without arguments
|
||||||
|
$footest1 = $this->container->getNew('footest');
|
||||||
|
$this->assertInstanceOf(ContainerInterface::class, $footest1->item);
|
||||||
|
|
||||||
|
$footest2 = $this->container->getNew('footest', ['Test String']);
|
||||||
|
$this->assertEquals('Test String', $footest2->item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetContainerInInstance(): void
|
||||||
|
{
|
||||||
|
$this->container->set('footest2', function() {
|
||||||
|
return new FooTest2();
|
||||||
|
});
|
||||||
|
|
||||||
|
$footest2 = $this->container->get('footest2');
|
||||||
|
$this->assertEquals($this->container, $footest2->getContainer());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetNewReturnCallable(): void
|
||||||
|
{
|
||||||
|
$this->container->set('footest', static function($item) {
|
||||||
|
return static function() use ($item) {
|
||||||
|
return $item;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check that the item is the container, if called without arguments
|
||||||
|
$footest1 = $this->container->getNew('footest');
|
||||||
|
$this->assertInstanceOf(ContainerInterface::class, $footest1());
|
||||||
|
|
||||||
|
$footest2 = $this->container->getNew('footest', ['Test String']);
|
||||||
|
$this->assertEquals('Test String', $footest2());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetSet(): void
|
||||||
|
{
|
||||||
|
$container = $this->container->set('foo', static function() {
|
||||||
|
return static function() {};
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->assertInstanceOf(Container::class, $container);
|
||||||
|
$this->assertInstanceOf(ContainerInterface::class, $container);
|
||||||
|
|
||||||
|
// The factory returns a callable
|
||||||
|
$this->assertTrue(is_callable($container->get('foo')));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLoggerMethods(): void
|
||||||
|
{
|
||||||
|
// Does the container have the default logger?
|
||||||
|
$this->assertFalse($this->container->hasLogger());
|
||||||
|
$this->assertFalse($this->container->hasLogger('default'));
|
||||||
|
|
||||||
|
$logger1 = new Logger('default');
|
||||||
|
$logger2 = new Logger('testing');
|
||||||
|
$logger1->pushHandler(new NullHandler());
|
||||||
|
$logger2->pushHandler(new TestHandler());
|
||||||
|
|
||||||
|
// Set the logger channels
|
||||||
|
$container = $this->container->setLogger($logger1);
|
||||||
|
$container2 = $this->container->setLogger($logger2, 'test');
|
||||||
|
|
||||||
|
$this->assertInstanceOf(ContainerInterface::class, $container);
|
||||||
|
$this->assertInstanceOf(Container::class, $container2);
|
||||||
|
|
||||||
|
$this->assertEquals($logger1, $this->container->getLogger('default'));
|
||||||
|
$this->assertEquals($logger2, $this->container->getLogger('test'));
|
||||||
|
$this->assertNull($this->container->getLogger('foo'));
|
||||||
|
|
||||||
|
$this->assertTrue($this->container->hasLogger());
|
||||||
|
$this->assertTrue($this->container->hasLogger('default'));
|
||||||
|
$this->assertTrue($this->container->hasLogger('test'));
|
||||||
|
}
|
||||||
|
}
|
83
tests/Ion/EnumTest.php
Normal file
83
tests/Ion/EnumTest.php
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests;
|
||||||
|
|
||||||
|
use Aviat\Ion\Enum;
|
||||||
|
|
||||||
|
class EnumTest extends Ion_TestCase {
|
||||||
|
|
||||||
|
protected $expectedConstList = [
|
||||||
|
'FOO' => 'bar',
|
||||||
|
'BAR' => 'foo',
|
||||||
|
'FOOBAR' => 'baz'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function setUp(): void {
|
||||||
|
parent::setUp();
|
||||||
|
$this->enum = new TestEnum();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testStaticGetConstList()
|
||||||
|
{
|
||||||
|
$actual = TestEnum::getConstList();
|
||||||
|
$this->assertEquals($this->expectedConstList, $actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetConstList()
|
||||||
|
{
|
||||||
|
$actual = $this->enum->getConstList();
|
||||||
|
$this->assertEquals($this->expectedConstList, $actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataIsValid()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'Valid' => [
|
||||||
|
'value' => 'baz',
|
||||||
|
'expected' => TRUE,
|
||||||
|
'static' => FALSE
|
||||||
|
],
|
||||||
|
'ValidStatic' => [
|
||||||
|
'value' => 'baz',
|
||||||
|
'expected' => TRUE,
|
||||||
|
'static' => TRUE
|
||||||
|
],
|
||||||
|
'Invalid' => [
|
||||||
|
'value' => 'foobar',
|
||||||
|
'expected' => FALSE,
|
||||||
|
'static' => FALSE
|
||||||
|
],
|
||||||
|
'InvalidStatic' => [
|
||||||
|
'value' => 'foobar',
|
||||||
|
'expected' => FALSE,
|
||||||
|
'static' => TRUE
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataIsValid
|
||||||
|
*/
|
||||||
|
public function testIsValid($value, $expected, $static)
|
||||||
|
{
|
||||||
|
$actual = ($static)
|
||||||
|
? TestEnum::isValid($value)
|
||||||
|
: $this->enum->isValid($value);
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $actual);
|
||||||
|
}
|
||||||
|
}
|
31
tests/Ion/Exception/DoubleRenderExceptionTest.php
Normal file
31
tests/Ion/Exception/DoubleRenderExceptionTest.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests\Exception;
|
||||||
|
|
||||||
|
use Aviat\Ion\Exception\DoubleRenderException;
|
||||||
|
use Aviat\Ion\Tests\Ion_TestCase;
|
||||||
|
|
||||||
|
class DoubleRenderExceptionTest extends Ion_TestCase {
|
||||||
|
|
||||||
|
public function testDefaultMessage()
|
||||||
|
{
|
||||||
|
$this->expectException(DoubleRenderException::class);
|
||||||
|
$this->expectExceptionMessage('A view can only be rendered once, because headers can only be sent once.');
|
||||||
|
|
||||||
|
throw new DoubleRenderException();
|
||||||
|
}
|
||||||
|
}
|
75
tests/Ion/FriendTest.php
Normal file
75
tests/Ion/FriendTest.php
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests;
|
||||||
|
|
||||||
|
use Aviat\Ion\Friend;
|
||||||
|
use Aviat\Ion\Tests\FriendTestClass;
|
||||||
|
|
||||||
|
class FriendTest extends Ion_TestCase {
|
||||||
|
|
||||||
|
public function setUp(): void {
|
||||||
|
parent::setUp();
|
||||||
|
$obj = new FriendTestClass();
|
||||||
|
$this->friend = new Friend($obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPrivateMethod()
|
||||||
|
{
|
||||||
|
$actual = $this->friend->getPrivate();
|
||||||
|
$this->assertEquals(23, $actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProtectedMethod()
|
||||||
|
{
|
||||||
|
$actual = $this->friend->getProtected();
|
||||||
|
$this->assertEquals(4, $actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGet()
|
||||||
|
{
|
||||||
|
$this->assertEquals(356, $this->friend->protected);
|
||||||
|
$this->assertNull($this->friend->foo); // Return NULL for non-existent properties
|
||||||
|
$this->assertEquals(47, $this->friend->parentProtected);
|
||||||
|
$this->assertEquals(84, $this->friend->grandParentProtected);
|
||||||
|
$this->assertNull($this->friend->parentPrivate); // Can't get a parent's privates
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSet()
|
||||||
|
{
|
||||||
|
$this->friend->private = 123;
|
||||||
|
$this->assertEquals(123, $this->friend->private);
|
||||||
|
|
||||||
|
$this->friend->foo = 32;
|
||||||
|
$this->assertNull($this->friend->foo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBadInvokation()
|
||||||
|
{
|
||||||
|
$this->expectException('InvalidArgumentException');
|
||||||
|
$this->expectExceptionMessage('Friend must be an object');
|
||||||
|
|
||||||
|
$friend = new Friend('foo');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBadMethod()
|
||||||
|
{
|
||||||
|
$this->expectException('BadMethodCallException');
|
||||||
|
$this->expectExceptionMessage("Method 'foo' does not exist");
|
||||||
|
|
||||||
|
$this->friend->foo();
|
||||||
|
}
|
||||||
|
}
|
133
tests/Ion/Ion_TestCase.php
Normal file
133
tests/Ion/Ion_TestCase.php
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests;
|
||||||
|
|
||||||
|
use function Aviat\Ion\_dir;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Zend\Diactoros\ServerRequestFactory;
|
||||||
|
|
||||||
|
define('ROOT_DIR', realpath(__DIR__ . '/../') . '/');
|
||||||
|
define('SRC_DIR', ROOT_DIR . 'src/');
|
||||||
|
define('TEST_DATA_DIR', __DIR__ . '/test_data');
|
||||||
|
define('TEST_VIEW_DIR', __DIR__ . '/test_views');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for TestCases
|
||||||
|
*/
|
||||||
|
class Ion_TestCase extends TestCase {
|
||||||
|
// Test directory constants
|
||||||
|
public const ROOT_DIR = ROOT_DIR;
|
||||||
|
public const SRC_DIR = SRC_DIR;
|
||||||
|
public const TEST_DATA_DIR = TEST_DATA_DIR;
|
||||||
|
public const TEST_VIEW_DIR = TEST_VIEW_DIR;
|
||||||
|
|
||||||
|
protected $container;
|
||||||
|
protected static $staticContainer;
|
||||||
|
protected static $session_handler;
|
||||||
|
|
||||||
|
/*public static function setUpBeforeClass()
|
||||||
|
{
|
||||||
|
// Use mock session handler
|
||||||
|
$session_handler = new TestSessionHandler();
|
||||||
|
session_set_save_handler($session_handler, TRUE);
|
||||||
|
self::$session_handler = $session_handler;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$ROOT_DIR = realpath(_dir(__DIR__, '/../'));
|
||||||
|
$APP_DIR = _dir($ROOT_DIR, 'app');
|
||||||
|
|
||||||
|
$config_array = [
|
||||||
|
'asset_path' => '//localhost/assets/',
|
||||||
|
'img_cache_path' => _dir(ROOT_DIR, 'public/images'),
|
||||||
|
'database' => [
|
||||||
|
'collection' => [
|
||||||
|
'type' => 'sqlite',
|
||||||
|
'host' => '',
|
||||||
|
'user' => '',
|
||||||
|
'pass' => '',
|
||||||
|
'port' => '',
|
||||||
|
'name' => 'default',
|
||||||
|
'database' => '',
|
||||||
|
'file' => ':memory:',
|
||||||
|
],
|
||||||
|
'cache' => [
|
||||||
|
'type' => 'sqlite',
|
||||||
|
'host' => '',
|
||||||
|
'user' => '',
|
||||||
|
'pass' => '',
|
||||||
|
'port' => '',
|
||||||
|
'name' => 'default',
|
||||||
|
'database' => '',
|
||||||
|
'file' => ':memory:',
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'routes' => [
|
||||||
|
'route_config' => [
|
||||||
|
'asset_path' => '/assets'
|
||||||
|
],
|
||||||
|
'routes' => [
|
||||||
|
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'redis' => [
|
||||||
|
'host' => (array_key_exists('REDIS_HOST', $_ENV)) ? $_ENV['REDIS_HOST'] : 'localhost',
|
||||||
|
'database' => 13
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
// Set up DI container
|
||||||
|
$di = require('di.php');
|
||||||
|
$container = $di($config_array);
|
||||||
|
$container->set('session-handler', static function() {
|
||||||
|
// Use mock session handler
|
||||||
|
$session_handler = new TestSessionHandler();
|
||||||
|
session_set_save_handler($session_handler, TRUE);
|
||||||
|
return $session_handler;
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->container = $container;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set arbitrary superglobal values for testing purposes
|
||||||
|
*
|
||||||
|
* @param array $supers
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setSuperGlobals(array $supers = []): void
|
||||||
|
{
|
||||||
|
$default = [
|
||||||
|
'_SERVER' => $_SERVER,
|
||||||
|
'_GET' => $_GET,
|
||||||
|
'_POST' => $_POST,
|
||||||
|
'_COOKIE' => $_COOKIE,
|
||||||
|
'_FILES' => $_FILES
|
||||||
|
];
|
||||||
|
|
||||||
|
$request = call_user_func_array(
|
||||||
|
[ServerRequestFactory::class, 'fromGlobals'],
|
||||||
|
array_merge($default, $supers)
|
||||||
|
);
|
||||||
|
$this->container->setInstance('request', $request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End of Ion_TestCase.php
|
89
tests/Ion/JsonTest.php
Normal file
89
tests/Ion/JsonTest.php
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests;
|
||||||
|
|
||||||
|
use function Aviat\Ion\_dir;
|
||||||
|
|
||||||
|
use Aviat\Ion\{Json, JsonException};
|
||||||
|
|
||||||
|
class JsonTest extends Ion_TestCase {
|
||||||
|
|
||||||
|
public function testEncode()
|
||||||
|
{
|
||||||
|
$data = (object) [
|
||||||
|
'foo' => [1, 2, 3, 4]
|
||||||
|
];
|
||||||
|
$expected = '{"foo":[1,2,3,4]}';
|
||||||
|
$this->assertEquals($expected, Json::encode($data));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataEncodeDecode()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'set1' => [
|
||||||
|
'data' => [
|
||||||
|
'apple' => [
|
||||||
|
'sauce' => ['foo','bar','baz']
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'expected_size' => 39,
|
||||||
|
'expected_json' => '{"apple":{"sauce":["foo","bar","baz"]}}'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataEncodeDecode
|
||||||
|
*/
|
||||||
|
public function testEncodeDecodeFile($data, $expected_size, $expected_json)
|
||||||
|
{
|
||||||
|
$target_file = _dir(self::TEST_DATA_DIR, 'json_write.json');
|
||||||
|
|
||||||
|
$actual_size = Json::encodeFile($target_file, $data);
|
||||||
|
$actual_json = file_get_contents($target_file);
|
||||||
|
|
||||||
|
$this->assertTrue(Json::isJson($actual_json));
|
||||||
|
$this->assertEquals($expected_size, $actual_size);
|
||||||
|
$this->assertEquals($expected_json, $actual_json);
|
||||||
|
|
||||||
|
$this->assertEquals($data, Json::decodeFile($target_file));
|
||||||
|
|
||||||
|
unlink($target_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDecode()
|
||||||
|
{
|
||||||
|
$json = '{"foo":[1,2,3,4]}';
|
||||||
|
$expected = [
|
||||||
|
'foo' => [1, 2, 3, 4]
|
||||||
|
];
|
||||||
|
$this->assertEquals($expected, Json::decode($json));
|
||||||
|
$this->assertEquals((object)$expected, Json::decode($json, false));
|
||||||
|
|
||||||
|
$badJson = '{foo:{1|2}}';
|
||||||
|
$this->expectException('Aviat\Ion\JsonException');
|
||||||
|
$this->expectExceptionMessage('JSON_ERROR_SYNTAX - Syntax error');
|
||||||
|
$this->expectExceptionCode(JSON_ERROR_SYNTAX);
|
||||||
|
|
||||||
|
Json::decode($badJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDecodeNull()
|
||||||
|
{
|
||||||
|
$this->assertNull(Json::decode(NULL));
|
||||||
|
}
|
||||||
|
}
|
29
tests/Ion/Model/BaseDBModelTest.php
Normal file
29
tests/Ion/Model/BaseDBModelTest.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests\Model;
|
||||||
|
|
||||||
|
use Aviat\Ion\Model\DB as BaseDBModel;
|
||||||
|
use Aviat\Ion\Tests\Ion_TestCase;
|
||||||
|
|
||||||
|
class BaseDBModelTest extends Ion_TestCase {
|
||||||
|
|
||||||
|
public function testBaseDBModelSanity()
|
||||||
|
{
|
||||||
|
$baseDBModel = new BaseDBModel($this->container->get('config'));
|
||||||
|
$this->assertTrue(is_object($baseDBModel));
|
||||||
|
}
|
||||||
|
}
|
39
tests/Ion/StringWrapperTest.php
Normal file
39
tests/Ion/StringWrapperTest.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests;
|
||||||
|
|
||||||
|
use Aviat\Ion\StringWrapper;
|
||||||
|
use Aviat\Ion\Type\StringType;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class StringWrapperTest extends TestCase {
|
||||||
|
|
||||||
|
protected $wrapper;
|
||||||
|
|
||||||
|
public function setUp(): void {
|
||||||
|
$this->wrapper = new class {
|
||||||
|
use StringWrapper;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testString()
|
||||||
|
{
|
||||||
|
$str = $this->wrapper->string('foo');
|
||||||
|
$this->assertInstanceOf(StringType::class, $str);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
71
tests/Ion/TestSessionHandler.php
Normal file
71
tests/Ion/TestSessionHandler.php
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests;
|
||||||
|
|
||||||
|
use SessionHandlerInterface;
|
||||||
|
|
||||||
|
class TestSessionHandler implements SessionHandlerInterface {
|
||||||
|
|
||||||
|
public $data = [];
|
||||||
|
public $save_path = './test_data/sessions';
|
||||||
|
|
||||||
|
public function close()
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
$file = "$this->save_path/$id";
|
||||||
|
if (file_exists($file))
|
||||||
|
{
|
||||||
|
@unlink($file);
|
||||||
|
}
|
||||||
|
$this->data[$id] = [];
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function gc($maxLifetime)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function open($save_path, $name)
|
||||||
|
{
|
||||||
|
/*if ( ! array_key_exists($save_path, $this->data))
|
||||||
|
{
|
||||||
|
$this->save_path = $save_path;
|
||||||
|
$this->data = [];
|
||||||
|
}*/
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function read($id)
|
||||||
|
{
|
||||||
|
return json_decode(@file_get_contents("$this->save_path/$id"), TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write($id, $data)
|
||||||
|
{
|
||||||
|
$file = "$this->save_path/$id";
|
||||||
|
file_put_contents($file, json_encode($data));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// End of TestSessionHandler.php
|
157
tests/Ion/Transformer/AbstractTransformerTest.php
Normal file
157
tests/Ion/Transformer/AbstractTransformerTest.php
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests\Transformer;
|
||||||
|
|
||||||
|
use Aviat\Ion\Tests\Ion_TestCase;
|
||||||
|
use Aviat\Ion\Tests\{TestTransformer, TestTransformerUntransform};
|
||||||
|
|
||||||
|
class AbstractTransformerTest extends Ion_TestCase {
|
||||||
|
|
||||||
|
protected $transformer;
|
||||||
|
protected $untransformer;
|
||||||
|
|
||||||
|
|
||||||
|
public function setUp(): void {
|
||||||
|
$this->transformer = new TestTransformer();
|
||||||
|
$this->untransformer = new TestTransformerUntransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataTransformCollection()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'object' => [
|
||||||
|
'original' => [
|
||||||
|
(object)[
|
||||||
|
['name' => 'Comedy'],
|
||||||
|
['name' => 'Romance'],
|
||||||
|
['name' => 'School'],
|
||||||
|
['name' => 'Harem']
|
||||||
|
],
|
||||||
|
(object)[
|
||||||
|
['name' => 'Action'],
|
||||||
|
['name' => 'Comedy'],
|
||||||
|
['name' => 'Magic'],
|
||||||
|
['name' => 'Fantasy'],
|
||||||
|
['name' => 'Mahou Shoujo']
|
||||||
|
],
|
||||||
|
(object)[
|
||||||
|
['name' => 'Comedy'],
|
||||||
|
['name' => 'Sci-Fi']
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'expected' => [
|
||||||
|
['Comedy', 'Romance', 'School', 'Harem'],
|
||||||
|
['Action', 'Comedy', 'Magic', 'Fantasy', 'Mahou Shoujo'],
|
||||||
|
['Comedy', 'Sci-Fi']
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'array' => [
|
||||||
|
'original' => [
|
||||||
|
[
|
||||||
|
['name' => 'Comedy'],
|
||||||
|
['name' => 'Romance'],
|
||||||
|
['name' => 'School'],
|
||||||
|
['name' => 'Harem']
|
||||||
|
],
|
||||||
|
[
|
||||||
|
['name' => 'Action'],
|
||||||
|
['name' => 'Comedy'],
|
||||||
|
['name' => 'Magic'],
|
||||||
|
['name' => 'Fantasy'],
|
||||||
|
['name' => 'Mahou Shoujo']
|
||||||
|
],
|
||||||
|
[
|
||||||
|
['name' => 'Comedy'],
|
||||||
|
['name' => 'Sci-Fi']
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'expected' => [
|
||||||
|
['Comedy', 'Romance', 'School', 'Harem'],
|
||||||
|
['Action', 'Comedy', 'Magic', 'Fantasy', 'Mahou Shoujo'],
|
||||||
|
['Comedy', 'Sci-Fi']
|
||||||
|
]
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataUnTransformCollection()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'object' => [
|
||||||
|
'original' => [
|
||||||
|
(object)['Comedy', 'Romance', 'School', 'Harem'],
|
||||||
|
(object)['Action', 'Comedy', 'Magic', 'Fantasy', 'Mahou Shoujo'],
|
||||||
|
(object)['Comedy', 'Sci-Fi']
|
||||||
|
],
|
||||||
|
'expected' => [
|
||||||
|
['Comedy', 'Romance', 'School', 'Harem'],
|
||||||
|
['Action', 'Comedy', 'Magic', 'Fantasy', 'Mahou Shoujo'],
|
||||||
|
['Comedy', 'Sci-Fi']
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'array' => [
|
||||||
|
'original' => [
|
||||||
|
['Comedy', 'Romance', 'School', 'Harem'],
|
||||||
|
['Action', 'Comedy', 'Magic', 'Fantasy', 'Mahou Shoujo'],
|
||||||
|
['Comedy', 'Sci-Fi']
|
||||||
|
],
|
||||||
|
'expected' => [
|
||||||
|
['Comedy', 'Romance', 'School', 'Harem'],
|
||||||
|
['Action', 'Comedy', 'Magic', 'Fantasy', 'Mahou Shoujo'],
|
||||||
|
['Comedy', 'Sci-Fi']
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTransform()
|
||||||
|
{
|
||||||
|
$data = $this->dataTransformCollection();
|
||||||
|
$original = $data['object']['original'][0];
|
||||||
|
$expected = $data['object']['expected'][0];
|
||||||
|
|
||||||
|
$actual = $this->transformer->transform($original);
|
||||||
|
$this->assertEquals($expected, $actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataTransformCollection
|
||||||
|
*/
|
||||||
|
public function testTransformCollection($original, $expected)
|
||||||
|
{
|
||||||
|
$actual = $this->transformer->transformCollection($original);
|
||||||
|
$this->assertEquals($expected, $actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataUnTransformCollection
|
||||||
|
*/
|
||||||
|
public function testUntransformCollection($original, $expected)
|
||||||
|
{
|
||||||
|
$actual = $this->untransformer->untransformCollection($original);
|
||||||
|
$this->assertEquals($expected, $actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataUnTransformCollection
|
||||||
|
*/
|
||||||
|
public function testUntransformCollectionWithException($original, $expected)
|
||||||
|
{
|
||||||
|
$this->expectException(\BadMethodCallException::class);
|
||||||
|
$this->transformer->untransformCollection($original);
|
||||||
|
}
|
||||||
|
}
|
215
tests/Ion/Type/ArrayTypeTest.php
Normal file
215
tests/Ion/Type/ArrayTypeTest.php
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests\Type;
|
||||||
|
|
||||||
|
use Aviat\Ion\ArrayWrapper;
|
||||||
|
use Aviat\Ion\Tests\Ion_TestCase;
|
||||||
|
|
||||||
|
class ArrayTypeTest extends Ion_TestCase {
|
||||||
|
use ArrayWrapper;
|
||||||
|
|
||||||
|
public function setUp(): void {
|
||||||
|
parent::setUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataCall()
|
||||||
|
{
|
||||||
|
$method_map = [
|
||||||
|
'chunk' => 'array_chunk',
|
||||||
|
'pluck' => 'array_column',
|
||||||
|
'assoc_diff' => 'array_diff_assoc',
|
||||||
|
'key_diff' => 'array_diff_key',
|
||||||
|
'diff' => 'array_diff',
|
||||||
|
'filter' => 'array_filter',
|
||||||
|
'flip' => 'array_flip',
|
||||||
|
'intersect' => 'array_intersect',
|
||||||
|
'keys' => 'array_keys',
|
||||||
|
'merge' => 'array_merge',
|
||||||
|
'pad' => 'array_pad',
|
||||||
|
'random' => 'array_rand',
|
||||||
|
'reduce' => 'array_reduce',
|
||||||
|
];
|
||||||
|
|
||||||
|
return [
|
||||||
|
'array_merge' => [
|
||||||
|
'method' => 'merge',
|
||||||
|
'array' => [1, 3, 5, 7],
|
||||||
|
'args' => [[2, 4, 6, 8]],
|
||||||
|
'expected' => [1, 3, 5, 7, 2, 4, 6, 8]
|
||||||
|
],
|
||||||
|
'array_product' => [
|
||||||
|
'method' => 'product',
|
||||||
|
'array' => [1, 2, 3],
|
||||||
|
'args' => [],
|
||||||
|
'expected' => 6
|
||||||
|
],
|
||||||
|
'array_reverse' => [
|
||||||
|
'method' => 'reverse',
|
||||||
|
'array' => [1, 2, 3, 4, 5],
|
||||||
|
'args' => [],
|
||||||
|
'expected' => [5, 4, 3, 2, 1]
|
||||||
|
],
|
||||||
|
'array_sum' => [
|
||||||
|
'method' => 'sum',
|
||||||
|
'array' => [1, 2, 3, 4, 5, 6],
|
||||||
|
'args' => [],
|
||||||
|
'expected' => 21
|
||||||
|
],
|
||||||
|
'array_unique' => [
|
||||||
|
'method' => 'unique',
|
||||||
|
'array' => [1, 1, 3, 2, 2, 2, 3, 3, 5],
|
||||||
|
'args' => [SORT_REGULAR],
|
||||||
|
'expected' => [0 => 1, 2 => 3, 3 => 2, 8 => 5]
|
||||||
|
],
|
||||||
|
'array_values' => [
|
||||||
|
'method' => 'values',
|
||||||
|
'array' => ['foo' => 'bar', 'baz' => 'foobar'],
|
||||||
|
'args' => [],
|
||||||
|
'expected' => ['bar', 'foobar']
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the array methods defined for the __Call method
|
||||||
|
*
|
||||||
|
* @dataProvider dataCall
|
||||||
|
*/
|
||||||
|
public function testCall($method, $array, $args, $expected)
|
||||||
|
{
|
||||||
|
$obj = $this->arr($array);
|
||||||
|
$actual = $obj->__call($method, $args);
|
||||||
|
$this->assertEquals($expected, $actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSet()
|
||||||
|
{
|
||||||
|
$obj = $this->arr([]);
|
||||||
|
$arraytype = $obj->set('foo', 'bar');
|
||||||
|
|
||||||
|
$this->assertInstanceOf('Aviat\Ion\Type\ArrayType', $arraytype);
|
||||||
|
$this->assertEquals('bar', $obj->get('foo'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGet()
|
||||||
|
{
|
||||||
|
$array = [1, 2, 3, 4, 5];
|
||||||
|
$obj = $this->arr($array);
|
||||||
|
$this->assertEquals($array, $obj->get());
|
||||||
|
$this->assertEquals(1, $obj->get(0));
|
||||||
|
$this->assertEquals(5, $obj->get(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetDeepKey()
|
||||||
|
{
|
||||||
|
$arr = [
|
||||||
|
'foo' => 'bar',
|
||||||
|
'baz' => [
|
||||||
|
'bar' => 'foobar'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
$obj = $this->arr($arr);
|
||||||
|
$this->assertEquals('foobar', $obj->getDeepKey(['baz', 'bar']));
|
||||||
|
$this->assertNull($obj->getDeepKey(['foo', 'bar', 'baz']));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMap()
|
||||||
|
{
|
||||||
|
$obj = $this->arr([1, 2, 3]);
|
||||||
|
$actual = $obj->map(function($item) {
|
||||||
|
return $item * 2;
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->assertEquals([2, 4, 6], $actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBadCall()
|
||||||
|
{
|
||||||
|
$obj = $this->arr([]);
|
||||||
|
|
||||||
|
$this->expectException('InvalidArgumentException');
|
||||||
|
$this->expectExceptionMessage("Method 'foo' does not exist");
|
||||||
|
|
||||||
|
$obj->foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testShuffle()
|
||||||
|
{
|
||||||
|
$original = [1, 2, 3, 4];
|
||||||
|
$test = [1, 2, 3, 4];
|
||||||
|
$obj = $this->arr($test);
|
||||||
|
$actual = $obj->shuffle();
|
||||||
|
|
||||||
|
//$this->assertNotEquals($actual, $original);
|
||||||
|
$this->assertTrue(is_array($actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHasKey()
|
||||||
|
{
|
||||||
|
$obj = $this->arr([
|
||||||
|
'a' => 'b',
|
||||||
|
'z' => 'y'
|
||||||
|
]);
|
||||||
|
$this->assertTrue($obj->hasKey('a'));
|
||||||
|
$this->assertFalse($obj->hasKey('b'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHasKeyArray()
|
||||||
|
{
|
||||||
|
$obj = $this->arr([
|
||||||
|
'foo' => [
|
||||||
|
'bar' => [
|
||||||
|
'baz' => [
|
||||||
|
'foobar' => NULL,
|
||||||
|
'one' => 1,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertTrue($obj->hasKey(['foo']));
|
||||||
|
$this->assertTrue($obj->hasKey(['foo', 'bar']));
|
||||||
|
$this->assertTrue($obj->hasKey(['foo', 'bar', 'baz']));
|
||||||
|
$this->assertTrue($obj->hasKey(['foo', 'bar', 'baz', 'one']));
|
||||||
|
$this->assertTrue($obj->hasKey(['foo', 'bar', 'baz', 'foobar']));
|
||||||
|
|
||||||
|
$this->assertFalse($obj->hasKey(['foo', 'baz']));
|
||||||
|
$this->assertFalse($obj->hasKey(['bar', 'baz']));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHas()
|
||||||
|
{
|
||||||
|
$obj = $this->arr([1, 2, 6, 8, 11]);
|
||||||
|
$this->assertTrue($obj->has(8));
|
||||||
|
$this->assertFalse($obj->has(8745));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSearch()
|
||||||
|
{
|
||||||
|
$obj = $this->arr([1, 2, 5, 7, 47]);
|
||||||
|
$actual = $obj->search(47);
|
||||||
|
$this->assertEquals(4, $actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFill()
|
||||||
|
{
|
||||||
|
$obj = $this->arr([]);
|
||||||
|
$expected = ['?', '?', '?'];
|
||||||
|
$actual = $obj->fill(0, 3, '?');
|
||||||
|
$this->assertEquals($actual, $expected);
|
||||||
|
}
|
||||||
|
}
|
66
tests/Ion/Type/StringTypeTest.php
Normal file
66
tests/Ion/Type/StringTypeTest.php
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests\Type;
|
||||||
|
|
||||||
|
use Aviat\Ion\StringWrapper;
|
||||||
|
use Aviat\Ion\Tests\Ion_TestCase;
|
||||||
|
|
||||||
|
class StringTypeTest extends Ion_TestCase {
|
||||||
|
use StringWrapper;
|
||||||
|
|
||||||
|
|
||||||
|
public function dataFuzzyCaseMatch()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'space separated' => [
|
||||||
|
'str1' => 'foo bar baz',
|
||||||
|
'str2' => 'foo-bar-baz',
|
||||||
|
'expected' => true
|
||||||
|
],
|
||||||
|
'camelCase' => [
|
||||||
|
'str1' => 'fooBarBaz',
|
||||||
|
'str2' => 'foo-bar-baz',
|
||||||
|
'expected' => true
|
||||||
|
],
|
||||||
|
'PascalCase' => [
|
||||||
|
'str1' => 'FooBarBaz',
|
||||||
|
'str2' => 'foo-bar-baz',
|
||||||
|
'expected' => true
|
||||||
|
],
|
||||||
|
'snake_case' => [
|
||||||
|
'str1' => 'foo_bar_baz',
|
||||||
|
'str2' => 'foo-bar-baz',
|
||||||
|
'expected' => true
|
||||||
|
],
|
||||||
|
'mEsSYcAse' => [
|
||||||
|
'str1' => 'fOObArBAZ',
|
||||||
|
'str2' => 'foo-bar-baz',
|
||||||
|
'expected' => false
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataFuzzyCaseMatch
|
||||||
|
*/
|
||||||
|
public function testFuzzyCaseMatch($str1, $str2, $expected)
|
||||||
|
{
|
||||||
|
$actual = $this->string($str1)->fuzzyCaseMatch($str2);
|
||||||
|
$this->assertEquals($expected, $actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
42
tests/Ion/View/HtmlViewTest.php
Normal file
42
tests/Ion/View/HtmlViewTest.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests\View;
|
||||||
|
|
||||||
|
use function Aviat\Ion\_dir;
|
||||||
|
|
||||||
|
use Aviat\Ion\Tests\TestHtmlView;
|
||||||
|
|
||||||
|
class HtmlViewTest extends HttpViewTest {
|
||||||
|
|
||||||
|
protected $template_path;
|
||||||
|
|
||||||
|
public function setUp(): void {
|
||||||
|
parent::setUp();
|
||||||
|
$this->view = new TestHtmlView($this->container);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRenderTemplate()
|
||||||
|
{
|
||||||
|
$path = _dir(self::TEST_VIEW_DIR, 'test_view.php');
|
||||||
|
$expected = '<tag>foo</tag>';
|
||||||
|
$actual = $this->view->renderTemplate($path, [
|
||||||
|
'var' => 'foo'
|
||||||
|
]);
|
||||||
|
$this->assertEquals($expected, $actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
95
tests/Ion/View/HttpViewTest.php
Normal file
95
tests/Ion/View/HttpViewTest.php
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests\View;
|
||||||
|
|
||||||
|
use Aviat\Ion\Friend;
|
||||||
|
use Aviat\Ion\Exception\DoubleRenderException;
|
||||||
|
use Aviat\Ion\Tests\Ion_TestCase;
|
||||||
|
use Aviat\Ion\Tests\TestHttpView;
|
||||||
|
|
||||||
|
class HttpViewTest extends Ion_TestCase {
|
||||||
|
|
||||||
|
protected $view;
|
||||||
|
protected $friend;
|
||||||
|
|
||||||
|
public function setUp(): void {
|
||||||
|
parent::setUp();
|
||||||
|
$this->view = new TestHttpView($this->container);
|
||||||
|
$this->friend = new Friend($this->view);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetOutput()
|
||||||
|
{
|
||||||
|
$this->friend->setOutput('foo');
|
||||||
|
$this->assertEquals('foo', $this->friend->getOutput());
|
||||||
|
$this->assertFalse($this->friend->hasRendered);
|
||||||
|
|
||||||
|
$this->assertEquals($this->friend->getOutput(), $this->friend->__toString());
|
||||||
|
$this->assertTrue($this->friend->hasRendered);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetOutput()
|
||||||
|
{
|
||||||
|
$same = $this->view->setOutput('<h1></h1>');
|
||||||
|
$this->assertEquals($same, $this->view);
|
||||||
|
$this->assertEquals('<h1></h1>', $this->view->getOutput());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAppendOutput()
|
||||||
|
{
|
||||||
|
$this->view->setOutput('<h1>');
|
||||||
|
$this->view->appendOutput('</h1>');
|
||||||
|
$this->assertEquals('<h1></h1>', $this->view->getOutput());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetStatusCode()
|
||||||
|
{
|
||||||
|
$view = $this->view->setStatusCode(404);
|
||||||
|
$this->assertEquals(404, $view->response->getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAddHeader()
|
||||||
|
{
|
||||||
|
$view = $this->view->addHeader('foo', 'bar');
|
||||||
|
$this->assertTrue($view->response->hasHeader('foo'));
|
||||||
|
$this->assertEquals(['bar'], $view->response->getHeader('foo'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSendDoubleRenderException()
|
||||||
|
{
|
||||||
|
$this->expectException(DoubleRenderException::class);
|
||||||
|
$this->expectExceptionMessage('A view can only be rendered once, because headers can only be sent once.');
|
||||||
|
|
||||||
|
// First render
|
||||||
|
$this->view->__toString();
|
||||||
|
|
||||||
|
// Second render
|
||||||
|
$this->view->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test__toStringDoubleRenderException()
|
||||||
|
{
|
||||||
|
$this->expectException(DoubleRenderException::class);
|
||||||
|
$this->expectExceptionMessage('A view can only be rendered once, because headers can only be sent once.');
|
||||||
|
|
||||||
|
// First render
|
||||||
|
$this->view->send();
|
||||||
|
|
||||||
|
// Second render
|
||||||
|
$this->view->__toString();
|
||||||
|
}
|
||||||
|
}
|
57
tests/Ion/View/JsonViewTest.php
Normal file
57
tests/Ion/View/JsonViewTest.php
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests\View;
|
||||||
|
|
||||||
|
use Aviat\Ion\Friend;
|
||||||
|
use Aviat\Ion\Tests\TestJsonView;
|
||||||
|
|
||||||
|
class JsonViewTest extends HttpViewTest {
|
||||||
|
|
||||||
|
public function setUp(): void {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->view = new TestJsonView($this->container);
|
||||||
|
$this->friend = new Friend($this->view);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetOutputJSON()
|
||||||
|
{
|
||||||
|
// Extend view class to remove destructor which does output
|
||||||
|
$view = new TestJsonView($this->container);
|
||||||
|
|
||||||
|
// Json encode non-string
|
||||||
|
$content = ['foo' => 'bar'];
|
||||||
|
$expected = json_encode($content);
|
||||||
|
$view->setOutput($content);
|
||||||
|
$this->assertEquals($expected, $this->view->getOutput());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetOutput()
|
||||||
|
{
|
||||||
|
// Directly set string
|
||||||
|
$view = new TestJsonView($this->container);
|
||||||
|
$content = '{}';
|
||||||
|
$expected = '{}';
|
||||||
|
$view->setOutput($content);
|
||||||
|
$this->assertEquals($expected, $view->getOutput());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOutput()
|
||||||
|
{
|
||||||
|
$this->assertEquals('application/json', $this->friend->contentType);
|
||||||
|
}
|
||||||
|
}
|
88
tests/Ion/XMLTest.php
Normal file
88
tests/Ion/XMLTest.php
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests;
|
||||||
|
|
||||||
|
use Aviat\Ion\XML;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class XMLTest extends TestCase {
|
||||||
|
|
||||||
|
protected $xml;
|
||||||
|
protected $expectedXml;
|
||||||
|
protected $object;
|
||||||
|
protected $array;
|
||||||
|
|
||||||
|
public function setUp(): void {
|
||||||
|
$this->xml = file_get_contents(__DIR__ . '/test_data/XML/xmlTestFile.xml');
|
||||||
|
$this->expectedXml = file_get_contents(__DIR__ . '/test_data/XML/minifiedXmlTestFile.xml');
|
||||||
|
|
||||||
|
$this->array = [
|
||||||
|
'entry' => [
|
||||||
|
'foo' => [
|
||||||
|
'bar' => [
|
||||||
|
'baz' => 42
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'episode' => '11',
|
||||||
|
'status' => 'watching',
|
||||||
|
'score' => '7',
|
||||||
|
'storage_type' => '1',
|
||||||
|
'storage_value' => '2.5',
|
||||||
|
'times_rewatched' => '1',
|
||||||
|
'rewatch_value' => '3',
|
||||||
|
'date_start' => '01152015',
|
||||||
|
'date_finish' => '10232016',
|
||||||
|
'priority' => '2',
|
||||||
|
'enable_discussion' => '0',
|
||||||
|
'enable_rewatching' => '1',
|
||||||
|
'comments' => 'Should you say something?',
|
||||||
|
'tags' => 'test tag, 2nd tag'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->object = new XML();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testToArray()
|
||||||
|
{
|
||||||
|
$this->assertEquals($this->array, XML::toArray($this->xml));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testParse()
|
||||||
|
{
|
||||||
|
$this->object->setXML($this->xml);
|
||||||
|
$this->assertEquals($this->array, $this->object->parse());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testToXML()
|
||||||
|
{
|
||||||
|
$this->assertEquals($this->expectedXml, XML::toXML($this->array));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateXML()
|
||||||
|
{
|
||||||
|
$this->object->setData($this->array);
|
||||||
|
$this->assertEquals($this->expectedXml, $this->object->createXML());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testToString()
|
||||||
|
{
|
||||||
|
$this->object->setData($this->array);
|
||||||
|
$this->assertEquals($this->expectedXml, $this->object->__toString());
|
||||||
|
$this->assertEquals($this->expectedXml, (string)$this->object);
|
||||||
|
}
|
||||||
|
}
|
41
tests/Ion/bootstrap.php
Normal file
41
tests/Ion/bootstrap.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Global setup for unit tests
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Work around the silly timezone error
|
||||||
|
$timezone = ini_get('date.timezone');
|
||||||
|
if ($timezone === '' || $timezone === FALSE)
|
||||||
|
{
|
||||||
|
ini_set('date.timezone', 'GMT');
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Autoloading
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Composer autoload
|
||||||
|
require realpath(__DIR__ . '/../vendor/autoload.php');
|
||||||
|
require 'Ion_TestCase.php';
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Ini Settings
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
ini_set('session.use_cookies', 0);
|
||||||
|
ini_set('session.use_only_cookies',0);
|
||||||
|
ini_set('session.use_trans_sid',1);
|
||||||
|
// Start session here to surpress error about headers not sent
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Load base test case and mocks
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Pre-define some superglobals
|
||||||
|
$_SESSION = [];
|
||||||
|
$_COOKIE = [];
|
||||||
|
|
||||||
|
// Request base test case and mocks
|
||||||
|
require 'TestSessionHandler.php';
|
||||||
|
require 'mocks.php';
|
||||||
|
|
||||||
|
// End of bootstrap.php
|
48
tests/Ion/di.php
Normal file
48
tests/Ion/di.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
use Aura\Html\HelperLocatorFactory;
|
||||||
|
use Aura\Session\SessionFactory;
|
||||||
|
use Zend\Diactoros\ServerRequestFactory;
|
||||||
|
use Zend\Diactoros\Response;
|
||||||
|
|
||||||
|
use Aviat\Ion\Config;
|
||||||
|
use Aviat\Ion\Di\Container;
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Setup DI container
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
return static function(array $config_array = []) {
|
||||||
|
$container = new Container();
|
||||||
|
|
||||||
|
$container->set('config', static function() {
|
||||||
|
return new Config([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
$container->setInstance('config', new Config($config_array));
|
||||||
|
|
||||||
|
$container->set('request', static function() {
|
||||||
|
return ServerRequestFactory::fromGlobals(
|
||||||
|
$_SERVER,
|
||||||
|
$_GET,
|
||||||
|
$_POST,
|
||||||
|
$_COOKIE,
|
||||||
|
$_FILES
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
$container->set('response', static function() {
|
||||||
|
return new Response();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create session Object
|
||||||
|
$container->set('session', static function() {
|
||||||
|
return (new SessionFactory())->newInstance($_COOKIE);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create Html helper Object
|
||||||
|
$container->set('html-helper', static function() {
|
||||||
|
return (new HelperLocatorFactory)->newInstance();
|
||||||
|
});
|
||||||
|
|
||||||
|
return $container;
|
||||||
|
};
|
33
tests/Ion/functionsTest.php
Normal file
33
tests/Ion/functionsTest.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests;
|
||||||
|
|
||||||
|
use function Aviat\Ion\_dir;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class functionsTest extends TestCase {
|
||||||
|
|
||||||
|
|
||||||
|
public function test_dir()
|
||||||
|
{
|
||||||
|
$args = ['foo', 'bar', 'baz'];
|
||||||
|
$expected = implode(\DIRECTORY_SEPARATOR, $args);
|
||||||
|
|
||||||
|
$this->assertEquals(_dir(...$args), $expected);
|
||||||
|
}
|
||||||
|
}
|
191
tests/Ion/mocks.php
Normal file
191
tests/Ion/mocks.php
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Ion
|
||||||
|
*
|
||||||
|
* Building blocks for web development
|
||||||
|
*
|
||||||
|
* PHP version 7.2
|
||||||
|
*
|
||||||
|
* @package Ion
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2019 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 3.0.0
|
||||||
|
* @link https://git.timshomepage.net/aviat/ion
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\Ion\Tests;
|
||||||
|
|
||||||
|
use Aviat\Ion\Enum;
|
||||||
|
use Aviat\Ion\Exception\DoubleRenderException;
|
||||||
|
use Aviat\Ion\Friend;
|
||||||
|
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||||
|
use Aviat\Ion\View;
|
||||||
|
use Aviat\Ion\View\{HtmlView, HttpView, JsonView};
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Mock the default error handler
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class MockErrorHandler {
|
||||||
|
public function addDataTable($name, array $values=[]) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Ion Mocks
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class TestEnum extends Enum {
|
||||||
|
const FOO = 'bar';
|
||||||
|
const BAR = 'foo';
|
||||||
|
const FOOBAR = 'baz';
|
||||||
|
}
|
||||||
|
|
||||||
|
class FriendGrandParentTestClass {
|
||||||
|
protected $grandParentProtected = 84;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FriendParentTestClass extends FriendGrandParentTestClass {
|
||||||
|
protected $parentProtected = 47;
|
||||||
|
private $parentPrivate = 654;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FriendTestClass extends FriendParentTestClass {
|
||||||
|
protected $protected = 356;
|
||||||
|
private $private = 486;
|
||||||
|
|
||||||
|
protected function getProtected()
|
||||||
|
{
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getPrivate()
|
||||||
|
{
|
||||||
|
return 23;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestTransformer extends AbstractTransformer {
|
||||||
|
|
||||||
|
public function transform($item)
|
||||||
|
{
|
||||||
|
$out = [];
|
||||||
|
$genre_list = (array) $item;
|
||||||
|
|
||||||
|
foreach($genre_list as $genre)
|
||||||
|
{
|
||||||
|
$out[] = $genre['name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestTransformerUntransform extends TestTransformer {
|
||||||
|
public function untransform($item)
|
||||||
|
{
|
||||||
|
return (array)$item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait MockViewOutputTrait {
|
||||||
|
/*protected function output() {
|
||||||
|
$reflect = new ReflectionClass($this);
|
||||||
|
$properties = $reflect->getProperties();
|
||||||
|
$props = [];
|
||||||
|
|
||||||
|
foreach($properties as $reflectProp)
|
||||||
|
{
|
||||||
|
$reflectProp->setAccessible(TRUE);
|
||||||
|
$props[$reflectProp->getName()] = $reflectProp->getValue($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
$view = new TestView($this->container);
|
||||||
|
$friend = new Friend($view);
|
||||||
|
foreach($props as $name => $val)
|
||||||
|
{
|
||||||
|
$friend->__set($name, $val);
|
||||||
|
}
|
||||||
|
|
||||||
|
//$friend->output();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public function send(): void
|
||||||
|
{
|
||||||
|
if ($this->hasRendered)
|
||||||
|
{
|
||||||
|
throw new DoubleRenderException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->hasRendered = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestView extends View {
|
||||||
|
public function send(): void
|
||||||
|
{
|
||||||
|
if ($this->hasRendered)
|
||||||
|
{
|
||||||
|
throw new DoubleRenderException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->hasRendered = TRUE;
|
||||||
|
}
|
||||||
|
public function output() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestHtmlView extends HtmlView {
|
||||||
|
protected function output(): void
|
||||||
|
{
|
||||||
|
if ($this->hasRendered)
|
||||||
|
{
|
||||||
|
throw new DoubleRenderException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->hasRendered = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestHttpView extends HttpView {
|
||||||
|
protected function output(): void
|
||||||
|
{
|
||||||
|
if ($this->hasRendered)
|
||||||
|
{
|
||||||
|
throw new DoubleRenderException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->hasRendered = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestJsonView extends JsonView {
|
||||||
|
public function __destruct() {}
|
||||||
|
|
||||||
|
protected function output(): void
|
||||||
|
{
|
||||||
|
if ($this->hasRendered)
|
||||||
|
{
|
||||||
|
throw new DoubleRenderException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->hasRendered = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// AnimeClient Mocks
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
trait MockInjectionTrait {
|
||||||
|
public function __get($key)
|
||||||
|
{
|
||||||
|
return $this->$key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __set($key, $value)
|
||||||
|
{
|
||||||
|
$this->$key = $value;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End of mocks.php
|
2
tests/Ion/test_data/XML/minifiedXmlTestFile.xml
Normal file
2
tests/Ion/test_data/XML/minifiedXmlTestFile.xml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<entry><foo><bar><baz>42</baz></bar></foo><episode>11</episode><status>watching</status><score>7</score><storage_type>1</storage_type><storage_value>2.5</storage_value><times_rewatched>1</times_rewatched><rewatch_value>3</rewatch_value><date_start>01152015</date_start><date_finish>10232016</date_finish><priority>2</priority><enable_discussion>0</enable_discussion><enable_rewatching>1</enable_rewatching><comments>Should you say something?</comments><tags>test tag, 2nd tag</tags></entry>
|
22
tests/Ion/test_data/XML/xmlTestFile.xml
Normal file
22
tests/Ion/test_data/XML/xmlTestFile.xml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<entry>
|
||||||
|
<foo>
|
||||||
|
<bar>
|
||||||
|
<baz>42</baz>
|
||||||
|
</bar>
|
||||||
|
</foo>
|
||||||
|
<episode>11</episode>
|
||||||
|
<status>watching</status>
|
||||||
|
<score>7</score>
|
||||||
|
<storage_type>1</storage_type>
|
||||||
|
<storage_value>2.5</storage_value>
|
||||||
|
<times_rewatched>1</times_rewatched>
|
||||||
|
<rewatch_value>3</rewatch_value>
|
||||||
|
<date_start>01152015</date_start>
|
||||||
|
<date_finish>10232016</date_finish>
|
||||||
|
<priority>2</priority>
|
||||||
|
<enable_discussion>0</enable_discussion>
|
||||||
|
<enable_rewatching>1</enable_rewatching>
|
||||||
|
<comments>Should you say something?</comments>
|
||||||
|
<tags>test tag, 2nd tag</tags>
|
||||||
|
</entry>
|
1
tests/Ion/test_data/invalid_json.json
Normal file
1
tests/Ion/test_data/invalid_json.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[}]
|
5
tests/Ion/test_data/valid_json.json
Normal file
5
tests/Ion/test_data/valid_json.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[{
|
||||||
|
"foo": {
|
||||||
|
"bar": [1,2,3]
|
||||||
|
}
|
||||||
|
}]
|
1
tests/Ion/test_views/test_view.php
Normal file
1
tests/Ion/test_views/test_view.php
Normal file
@ -0,0 +1 @@
|
|||||||
|
<tag><?= $var ?></tag>
|
Loading…
Reference in New Issue
Block a user