First commit -- split from timw4mail/HummingBirdAnimeClient
This commit is contained in:
commit
8c501e08b7
29
.gitignore
vendored
Normal file
29
.gitignore
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
.codelite
|
||||
.phing_targets
|
||||
.sonar/
|
||||
*.phprj
|
||||
*.workspace
|
||||
vendor
|
||||
**/cache/**
|
||||
**/logs/**
|
||||
**/coverage/**
|
||||
**/docs/**
|
||||
**/node_modules/**
|
||||
public/images/*
|
||||
composer.lock
|
||||
*.sqlite
|
||||
*.db
|
||||
*.sqlite3
|
||||
docs/*
|
||||
tests/test_data/sessions/*
|
||||
cache.properties
|
||||
build/**
|
||||
!build/*.txt
|
||||
!build/*.xml
|
||||
!build/*.php
|
||||
app/config/*.toml
|
||||
!app/config/*.toml.example
|
||||
phinx.yml
|
||||
.idea/
|
||||
Caddyfile
|
||||
build/humbuglog.txt
|
37
.gitlab-ci.yml
Normal file
37
.gitlab-ci.yml
Normal file
@ -0,0 +1,37 @@
|
||||
# Composer stores all downloaded packages in the vendor/ directory.
|
||||
# Do not use the following if the vendor/ directory is commited to
|
||||
# your git repository.
|
||||
cache:
|
||||
paths:
|
||||
- vendor/
|
||||
|
||||
services:
|
||||
- redis:latest
|
||||
|
||||
test:5.6:
|
||||
before_script:
|
||||
- bash build/docker_install.sh > /dev/null
|
||||
- curl -sS https://getcomposer.org/installer | php
|
||||
- php composer.phar install --no-dev
|
||||
image: php:5.6
|
||||
script:
|
||||
- phpunit -c build
|
||||
|
||||
test:7:
|
||||
before_script:
|
||||
- bash build/docker_install.sh > /dev/null
|
||||
- curl -sS https://getcomposer.org/installer | php
|
||||
- php composer.phar install --no-dev
|
||||
image: php:7
|
||||
script:
|
||||
- phpunit -c build
|
||||
|
||||
test:hhvm:
|
||||
before_script:
|
||||
- /usr/local/bin/composer self-update
|
||||
- curl -Lo /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar
|
||||
- chmod +x /usr/local/bin/phpunit
|
||||
- composer install --no-dev
|
||||
image: 51systems/docker-gitlab-ci-runner-hhvm
|
||||
script:
|
||||
- phpunit -c build
|
3
README.md
Normal file
3
README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Ion
|
||||
|
||||
Ion is a set of helpful PHP libraries for general web development
|
11
build/animeclient_header_comment.txt
Normal file
11
build/animeclient_header_comment.txt
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Hummingbird Anime Client
|
||||
*
|
||||
* An API client for Hummingbird to manage anime and manga watch lists
|
||||
*
|
||||
* @package HummingbirdAnimeClient
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @link https://github.com/timw4mail/HummingBirdAnimeClient
|
||||
* @license MIT
|
||||
*/
|
10
build/ion_header_comment.txt
Normal file
10
build/ion_header_comment.txt
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
131
build/phpdox.xml
Normal file
131
build/phpdox.xml
Normal file
@ -0,0 +1,131 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!-- This is a skeleton phpDox config file - Check http://phpDox.de for latest version and more info -->
|
||||
<phpdox xmlns="http://xml.phpdox.net/config" silent="false">
|
||||
<!-- @silent: true | false to enable or disable visual output of progress -->
|
||||
|
||||
<!-- Additional bootstrap files to load for additional parsers, enrichers and/or engines -->
|
||||
<!-- Place as many require nodes as you feel like in this container -->
|
||||
<!-- syntax: <require file="/path/to/file.php" /> -->
|
||||
<bootstrap />
|
||||
|
||||
<!-- A phpDox project to process, you can have multiple projects in one config file -->
|
||||
<project name="Hummingbird Anime Client" source="../src" workdir="phpdox/xml">
|
||||
<!-- @name - The name of the project -->
|
||||
<!-- @source - The source directory of the application to process -->
|
||||
<!-- @workdir - The directory to store the xml data files in -->
|
||||
|
||||
<!-- A phpDox config file can define additional variables (properties) per project -->
|
||||
<!-- <property name="some.name" value="the.value" /> -->
|
||||
|
||||
<!-- Values can make use of previously defined properties -->
|
||||
<!-- The following are defined by default:
|
||||
|
||||
${basedir} Directory the loaded config file is in
|
||||
|
||||
${phpDox.home} Directory of the phpDox installation
|
||||
${phpDox.file} The current config file
|
||||
${phpDox.version} phpDox' version number
|
||||
|
||||
${phpDox.project.name} The value of project/@name if set, otherwise 'unnamed'
|
||||
${phpDox.project.source} The value of project/@source if set, otherwise '${basedir}/src'
|
||||
${phpDox.project.workdir} The value of project/@workdir if set, otherwise '${basedir}/build/phpdox/xml'
|
||||
|
||||
${phpDox.php.version} The PHP Version of the interpreter in use
|
||||
|
||||
-->
|
||||
|
||||
<!-- Additional configuration for the collecting process (parsing of php code, generation of xml data) -->
|
||||
<collector publiconly="false" backend="parser" encoding="auto">
|
||||
<!-- @publiconly - Flag to disable/enable processing of non public methods and members -->
|
||||
<!-- @backend - The collector backend to use, currently only shipping with 'parser' -->
|
||||
<!-- @encoding - Charset encoding of source files (overwrite default 'auto' if detection fails) -->
|
||||
|
||||
<!-- <include / exclude filter for filelist generator, mask must follow fnmatch() requirements -->
|
||||
<include mask="*.php" />
|
||||
<exclude mask="" />
|
||||
|
||||
<!-- How to handle inheritance -->
|
||||
<inheritance resolve="true">
|
||||
<!-- @resolve - Flag to enable/disable resolving of inheritance -->
|
||||
|
||||
<!-- You can define multiple (external) dependencies to be included -->
|
||||
<!-- <dependency path="" -->
|
||||
<!-- @path - path to a directory containing an index.xml for a dependency project -->
|
||||
</inheritance>
|
||||
|
||||
</collector>
|
||||
|
||||
<!-- Configuration of generation process -->
|
||||
<generator output="../docs">
|
||||
<!-- @output - (Base-)Directory to store output data in -->
|
||||
|
||||
<!-- A generation process consists of one or more build tasks and of (optional) enrich sources -->
|
||||
|
||||
<enrich base="logs">
|
||||
<!-- @base - (Base-)Directory of datafiles used for enrich process -->
|
||||
|
||||
<!--<source type="...">-->
|
||||
<!-- @type - the handler for the enrichment -->
|
||||
<!-- known types by default are: build, checkstyle, git, phpcs, phploc, phpunit, pmd -->
|
||||
|
||||
<!-- every enrichment source can have additional configuration nodes, most probably need a logfile -->
|
||||
<!-- <file name="path/to/log.xml" /> -->
|
||||
<!--</source> -->
|
||||
|
||||
<!-- add phploc output -->
|
||||
<source type="phploc">
|
||||
<file name="phploc.xml" />
|
||||
</source>
|
||||
|
||||
<!-- git vcs information -->
|
||||
<source type="git">
|
||||
<git binary="/usr/bin/git" />
|
||||
<history enabled="true" limit="15" cache="${phpDox.project.workdir}/gitlog.xml" />
|
||||
</source>
|
||||
|
||||
<!-- PHP Code Sniffer findings -->
|
||||
<!--
|
||||
<source type="phpcs">
|
||||
<file name="logs/phpcs.xml" />
|
||||
</source>
|
||||
-->
|
||||
|
||||
<!-- PHPMessDetector -->
|
||||
<!--
|
||||
<source type="pmd">
|
||||
<file name="pmd.xml" />
|
||||
</source>
|
||||
-->
|
||||
|
||||
<!-- PHPUnit Coverage XML -->
|
||||
<source type="phpunit">
|
||||
<!-- <coverage path="clover.xml" />-->
|
||||
<!-- @path - the directory where the xml code coverage report can be found -->
|
||||
<!--<filter directory="${phpDox.project.source}" />-->
|
||||
<!-- @directory - path of the phpunit config whitelist filter directory -->
|
||||
</source>
|
||||
<!--
|
||||
<source type="phpunit">
|
||||
<filter directory="${phpDox.project.source}" />
|
||||
</source>
|
||||
-->
|
||||
|
||||
</enrich>
|
||||
|
||||
<!-- <build engine="..." enabled="true" output="..." /> -->
|
||||
<!-- @engine - The name of the engine this build task uses, use ./phpDox - -engines to get a list of available engines -->
|
||||
<!-- @enabled - Flag to enable/disable this engine, default: enabled=true -->
|
||||
<!-- @output - (optional) Output directory; if relative (no / as first char) it is interpreted as relative to generator/@output -->
|
||||
|
||||
<!-- An engine and thus build node can have additional configuration child nodes, please check the documentation for the engine to find out more -->
|
||||
|
||||
<!-- default engine "html" -->
|
||||
<build engine="html" enabled="true">
|
||||
<template dir="${phpDox.home}/templates/html" />
|
||||
<file extension="html" />
|
||||
</build>
|
||||
|
||||
</generator>
|
||||
</project>
|
||||
|
||||
</phpdox>
|
33
build/phpunit.xml
Normal file
33
build/phpunit.xml
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit
|
||||
colors="true"
|
||||
stopOnFailure="false"
|
||||
bootstrap="../tests/bootstrap.php"
|
||||
beStrictAboutTestsThatDoNotTestAnything="true"
|
||||
checkForUnintentionallyCoveredCode="true"
|
||||
>
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">../src/Aviat/Ion</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
<testsuites>
|
||||
<testsuite name="Ion">
|
||||
<directory>../tests/Ion</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<logging>
|
||||
<log type="coverage-html" target="coverage"/>
|
||||
<log type="coverage-clover" target="logs/clover.xml"/>
|
||||
<log type="coverage-crap4j" target="logs/crap4j.xml"/>
|
||||
<log type="coverage-xml" target="logs/coverage" />
|
||||
<log type="junit" target="logs/junit.xml" logIncompleteSkipped="false"/>
|
||||
</logging>
|
||||
<php>
|
||||
<server name="HTTP_USER_AGENT" value="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393" />
|
||||
<server name="HTTP_HOST" value="localhost" />
|
||||
<server name="SERVER_NAME" value="localhost" />
|
||||
<server name="REQUEST_URI" value="/" />
|
||||
<server name="REQUEST_METHOD" value="GET" />
|
||||
</php>
|
||||
</phpunit>
|
70
build/update_header_comments.php
Normal file
70
build/update_header_comments.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
$ion_file_patterns = [
|
||||
'src/Aviat/Ion/*.php'
|
||||
];
|
||||
|
||||
if ( ! function_exists('glob_recursive'))
|
||||
{
|
||||
// Does not support flag GLOB_BRACE
|
||||
|
||||
function glob_recursive($pattern, $flags = 0)
|
||||
{
|
||||
$files = glob($pattern, $flags);
|
||||
|
||||
foreach (glob(dirname($pattern) . '/*', GLOB_ONLYDIR | GLOB_NOSORT) as $dir)
|
||||
{
|
||||
$files = array_merge($files, glob_recursive($dir . '/' . basename($pattern), $flags));
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
}
|
||||
|
||||
function get_text_to_replace($tokens)
|
||||
{
|
||||
if ($tokens[0][0] !== T_OPEN_TAG)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// If there is already a docblock, as the second token after the
|
||||
// open tag, get the contents of that token to replace
|
||||
if ($tokens[1][0] === T_DOC_COMMENT)
|
||||
{
|
||||
return "<?php\n" . $tokens[1][1];
|
||||
}
|
||||
else if ($tokens[1][0] !== T_DOC_COMMENT)
|
||||
{
|
||||
return "<?php";
|
||||
}
|
||||
}
|
||||
|
||||
function get_tokens($source)
|
||||
{
|
||||
return token_get_all($source);
|
||||
}
|
||||
|
||||
function replace_files(array $files, $template)
|
||||
{
|
||||
foreach ($files as $file)
|
||||
{
|
||||
$source = file_get_contents($file);
|
||||
$tokens = get_tokens($source);
|
||||
$text_to_replace = get_text_to_replace($tokens);
|
||||
|
||||
$header = file_get_contents(__DIR__ . $template);
|
||||
$new_text = "<?php\n{$header}";
|
||||
|
||||
$new_source = str_replace($text_to_replace, $new_text, $source);
|
||||
file_put_contents($file, $new_source);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($ion_file_patterns as $glob)
|
||||
{
|
||||
$files = glob_recursive($glob);
|
||||
replace_files($files, '/ion_header_comment.txt');
|
||||
}
|
||||
|
||||
echo "Successfully updated headers \n";
|
29
composer.json
Normal file
29
composer.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "aviat/ion",
|
||||
"description": "Basic PHP Framework",
|
||||
"license":"MIT",
|
||||
"require": {
|
||||
"aviat/query": "^2.5",
|
||||
"aura/html": "2.*",
|
||||
"container-interop/container-interop": "1.*",
|
||||
"danielstjules/stringy": "~2.1",
|
||||
"guzzlehttp/guzzle": "6.*",
|
||||
"monolog/monolog": "1.*",
|
||||
"predis/predis": "1.1.*",
|
||||
"psr/http-message": "~1.0",
|
||||
"psr/log": "~1.0",
|
||||
"yosymfony/toml": "0.3.*",
|
||||
"zendframework/zend-diactoros": "1.3.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"pdepend/pdepend": "^2.2",
|
||||
"sebastian/phpcpd": "^2.0",
|
||||
"theseer/phpdox": "0.8.1.1",
|
||||
"phploc/phploc": "^3.0",
|
||||
"phpmd/phpmd": "^2.4",
|
||||
"phpunit/phpunit": "^5.4",
|
||||
"robmorgan/phinx": "^0.6.4",
|
||||
"humbug/humbug": "~1.0@dev",
|
||||
"codegyre/robo": "*"
|
||||
}
|
||||
}
|
12
humbug.json.dist
Normal file
12
humbug.json.dist
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"source": {
|
||||
"directories": [
|
||||
"src"
|
||||
]
|
||||
},
|
||||
"timeout": 10,
|
||||
"logs": {
|
||||
"text": "build\/humbuglog.txt",
|
||||
"json": "build\/humbug.json"
|
||||
}
|
||||
}
|
16
phpdoc.dist.xml
Normal file
16
phpdoc.dist.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<phpdoc>
|
||||
<title>Hummingbird Anime Client</title>
|
||||
<parser>
|
||||
<target>docs</target>
|
||||
</parser>
|
||||
<transformer>
|
||||
<target>docs</target>
|
||||
</transformer>
|
||||
<transformations>
|
||||
<template name="clean" />
|
||||
</transformations>
|
||||
<files>
|
||||
<directory>src/Aviat</directory>
|
||||
</files>
|
||||
</phpdoc>
|
25
phpunit.xml
Normal file
25
phpunit.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit
|
||||
colors="true"
|
||||
stopOnFailure="false"
|
||||
bootstrap="tests/bootstrap.php"
|
||||
beStrictAboutTestsThatDoNotTestAnything="true"
|
||||
>
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">src/Aviat/Ion</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
<testsuites>
|
||||
<testsuite name="Ion">
|
||||
<directory>tests/Ion</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<server name="HTTP_USER_AGENT" value="Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:38.0) Gecko/20100101 Firefox/38.0" />
|
||||
<server name="HTTP_HOST" value="localhost" />
|
||||
<server name="SERVER_NAME" value="localhost" />
|
||||
<server name="REQUEST_URI" value="/" />
|
||||
<server name="REQUEST_METHOD" value="GET" />
|
||||
</php>
|
||||
</phpunit>
|
34
src/Aviat/Ion/ArrayWrapper.php
Normal file
34
src/Aviat/Ion/ArrayWrapper.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
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)
|
||||
{
|
||||
return new ArrayType($arr);
|
||||
}
|
||||
}
|
||||
// End of ArrayWrapper.php
|
48
src/Aviat/Ion/Cache/CacheInterface.php
Normal file
48
src/Aviat/Ion/Cache/CacheInterface.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion\Cache;
|
||||
|
||||
/**
|
||||
* Interface for retrieving values from cache
|
||||
*/
|
||||
interface CacheInterface {
|
||||
|
||||
/**
|
||||
* Retrieve a cached value if it exists, otherwise, get the value
|
||||
* from the passed arguments
|
||||
*
|
||||
* @param object $object - object to retrieve fresh value from
|
||||
* @param string $method - method name to call
|
||||
* @param [array] $args - the arguments to pass to the retrieval method
|
||||
* @return mixed - the cached or fresh data
|
||||
*/
|
||||
public function get($object, $method, array $args=[]);
|
||||
|
||||
/**
|
||||
* Retrieve a fresh value, and update the cache
|
||||
*
|
||||
* @param object $object - object to retrieve fresh value from
|
||||
* @param string $method - method name to call
|
||||
* @param [array] $args - the arguments to pass to the retrieval method
|
||||
* @return mixed - the fresh data
|
||||
*/
|
||||
public function getFresh($object, $method, array $args=[]);
|
||||
|
||||
/**
|
||||
* Clear the entire cache
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function purge();
|
||||
}
|
||||
// End of CacheInterface.php
|
117
src/Aviat/Ion/Cache/CacheManager.php
Normal file
117
src/Aviat/Ion/Cache/CacheManager.php
Normal file
@ -0,0 +1,117 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion\Cache;
|
||||
|
||||
use Aviat\Ion\ConfigInterface;
|
||||
use Aviat\Ion\Cache\Driver\DriverInterface;
|
||||
|
||||
/**
|
||||
* Class proxying cached and fresh values from the selected cache driver
|
||||
*/
|
||||
class CacheManager implements CacheInterface {
|
||||
|
||||
/**
|
||||
* @var DriverInterface
|
||||
*/
|
||||
protected $driver;
|
||||
|
||||
/**
|
||||
* Retrieve the appropriate driver from the container
|
||||
*
|
||||
* @param ConfigInterface $config The configuration management class
|
||||
*/
|
||||
public function __construct(ConfigInterface $config)
|
||||
{
|
||||
$driverConf = $config->get('cache_driver');
|
||||
|
||||
if (empty($driverConf))
|
||||
{
|
||||
$driverConf = 'NullDriver';
|
||||
}
|
||||
|
||||
$driverClass = __NAMESPACE__ . "\\Driver\\{$driverConf}";
|
||||
$driver = new $driverClass($config);
|
||||
|
||||
$this->driver = $driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a cached value if it exists, otherwise, get the value
|
||||
* from the passed arguments
|
||||
*
|
||||
* @param object $object - object to retrieve fresh value from
|
||||
* @param string $method - method name to call
|
||||
* @param [array] $args - the arguments to pass to the retrieval method
|
||||
* @return mixed - the cached or fresh data
|
||||
*/
|
||||
public function get($object, $method, array $args=[])
|
||||
{
|
||||
$hash = $this->generateHashForMethod($object, $method, $args);
|
||||
|
||||
$data = $this->driver->get($hash);
|
||||
|
||||
if (empty($data))
|
||||
{
|
||||
$data = call_user_func_array([$object, $method], $args);
|
||||
$this->driver->set($hash, $data);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a fresh value from the method, and update the cache
|
||||
* @param object $object - object to retrieve fresh value from
|
||||
* @param string $method - method name to call
|
||||
* @param [array] $args - the arguments to pass to the retrieval method
|
||||
* @return mixed - the fresh data
|
||||
*/
|
||||
public function getFresh($object, $method, array $args=[])
|
||||
{
|
||||
$hash = $this->generateHashForMethod($object, $method, $args);
|
||||
$data = call_user_func_array([$object, $method], $args);
|
||||
$this->driver->set($hash, $data);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the entire cache
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function purge()
|
||||
{
|
||||
$this->driver->invalidateAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a hash as a cache key from the current method call
|
||||
*
|
||||
* @param object $object
|
||||
* @param string $method
|
||||
* @param array $args
|
||||
* @return string
|
||||
*/
|
||||
protected function generateHashForMethod($object, $method, array $args)
|
||||
{
|
||||
$classname = get_class($object);
|
||||
$keyObj = [
|
||||
'class' => $classname,
|
||||
'method' => $method,
|
||||
'args' => $args,
|
||||
];
|
||||
$hash = sha1(json_encode($keyObj));
|
||||
return $hash;
|
||||
}
|
||||
}
|
||||
// End of CacheManager.php
|
51
src/Aviat/Ion/Cache/Driver/DriverInterface.php
Normal file
51
src/Aviat/Ion/Cache/Driver/DriverInterface.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion\Cache\Driver;
|
||||
|
||||
/**
|
||||
* Interface for cache drivers
|
||||
*/
|
||||
interface DriverInterface {
|
||||
/**
|
||||
* Retreive a value from the cache backend
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key);
|
||||
|
||||
/**
|
||||
* Set a cached value
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return DriverInterface
|
||||
*/
|
||||
public function set($key, $value);
|
||||
|
||||
/**
|
||||
* Invalidate a cached value
|
||||
*
|
||||
* @param string $key
|
||||
* @return DriverInterface
|
||||
*/
|
||||
public function invalidate($key);
|
||||
|
||||
/**
|
||||
* Clear the contents of the cache
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function invalidateAll();
|
||||
}
|
||||
// End of DriverInterface.php
|
62
src/Aviat/Ion/Cache/Driver/DriverTrait.php
Normal file
62
src/Aviat/Ion/Cache/Driver/DriverTrait.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion\Cache\Driver;
|
||||
|
||||
use Aviat\Ion\Json;
|
||||
use Aviat\Ion\JsonException;
|
||||
|
||||
/**
|
||||
* Abstract base for Cache drivers to share common functionality
|
||||
*/
|
||||
trait DriverTrait {
|
||||
|
||||
/**
|
||||
* Key prefix for key / value cache stores
|
||||
*/
|
||||
protected static $CACHE_KEY_PREFIX = "hbac:cache:";
|
||||
|
||||
/**
|
||||
* Set key prefix for cache drivers that have global keys
|
||||
*
|
||||
* @param string $key - the raw key name
|
||||
* @return string - the prefixed key name
|
||||
*/
|
||||
protected function prefix($key)
|
||||
{
|
||||
return static::$CACHE_KEY_PREFIX . $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts data to cache to a string representation for storage in a cache
|
||||
*
|
||||
* @param mixed $data - data to store in the cache backend
|
||||
* @return string
|
||||
*/
|
||||
protected function serialize($data)
|
||||
{
|
||||
return Json::encode($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert serialized data from cache backend to native types
|
||||
*
|
||||
* @param string $data - data from cache backend
|
||||
* @return mixed
|
||||
* @throws JsonException
|
||||
*/
|
||||
protected function unserialize($data)
|
||||
{
|
||||
return Json::decode($data);
|
||||
}
|
||||
}
|
||||
// End of DriverTrait.php
|
74
src/Aviat/Ion/Cache/Driver/NullDriver.php
Normal file
74
src/Aviat/Ion/Cache/Driver/NullDriver.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion\Cache\Driver;
|
||||
use Aviat\Ion\ConfigInterface;
|
||||
|
||||
/**
|
||||
* The Driver for no real cache
|
||||
*/
|
||||
class NullDriver implements DriverInterface {
|
||||
|
||||
/**
|
||||
* 'Cache' for Null data store
|
||||
*/
|
||||
protected $data = [];
|
||||
|
||||
/**
|
||||
* Retrieve a value from the cache backend
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
return (array_key_exists($key, $this->data))
|
||||
? $this->data[$key]
|
||||
: NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a cached value
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return DriverInterface
|
||||
*/
|
||||
public function set($key, $value)
|
||||
{
|
||||
$this->data[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate a cached value
|
||||
*
|
||||
* @param string $key
|
||||
* @return DriverInterface
|
||||
*/
|
||||
public function invalidate($key)
|
||||
{
|
||||
unset($this->data[$key]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the contents of the cache
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function invalidateAll()
|
||||
{
|
||||
$this->data = [];
|
||||
}
|
||||
}
|
||||
// End of NullDriver.php
|
117
src/Aviat/Ion/Cache/Driver/RedisDriver.php
Normal file
117
src/Aviat/Ion/Cache/Driver/RedisDriver.php
Normal file
@ -0,0 +1,117 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion\Cache\Driver;
|
||||
|
||||
use Aviat\Ion\ConfigInterface;
|
||||
|
||||
use Predis\Client;
|
||||
|
||||
/**
|
||||
* Cache Driver for a Redis backend
|
||||
*/
|
||||
class RedisDriver implements DriverInterface {
|
||||
|
||||
use DriverTrait;
|
||||
|
||||
/**
|
||||
* THe Predis library instance
|
||||
*
|
||||
* @var Client
|
||||
*/
|
||||
protected $redis;
|
||||
|
||||
/**
|
||||
* Create the Redis cache driver
|
||||
*
|
||||
* @param ConfigInterface $config The configuration management class
|
||||
*/
|
||||
public function __construct(ConfigInterface $config)
|
||||
{
|
||||
$redisConfig = $config->get('redis');
|
||||
|
||||
// If you don't have a redis password set, and you attempt to send an
|
||||
// empty string, Redis will think you want to authenticate with a password
|
||||
// that is an empty string. To work around this, empty string passwords
|
||||
// are considered to be a lack of a password
|
||||
if (array_key_exists('password', $redisConfig) && $redisConfig['password'] === '')
|
||||
{
|
||||
unset($redisConfig['password']);
|
||||
}
|
||||
|
||||
$this->redis = new Client($redisConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from redis
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->redis = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a value from the cache backend
|
||||
*
|
||||
* @param string $rawKey
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($rawKey)
|
||||
{
|
||||
$key = $this->prefix($rawKey);
|
||||
$serializedData = $this->redis->get($key);
|
||||
|
||||
return $this->unserialize($serializedData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a cached value
|
||||
*
|
||||
* @param string $rawKey
|
||||
* @param mixed $value
|
||||
* @return DriverInterface
|
||||
*/
|
||||
public function set($rawKey, $value)
|
||||
{
|
||||
$key = $this->prefix($rawKey);
|
||||
$serializedData = $this->serialize($value);
|
||||
|
||||
$this->redis->set($key, $serializedData);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate a cached value
|
||||
*
|
||||
* @param string $rawKey
|
||||
* @return DriverInterface
|
||||
*/
|
||||
public function invalidate($rawKey)
|
||||
{
|
||||
$key = $this->prefix($rawKey);
|
||||
$this->redis->del($key);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the contents of the cache
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function invalidateAll()
|
||||
{
|
||||
$this->redis->flushdb();
|
||||
}
|
||||
}
|
||||
// End of RedisDriver.php
|
119
src/Aviat/Ion/Cache/Driver/SQLDriver.php
Normal file
119
src/Aviat/Ion/Cache/Driver/SQLDriver.php
Normal file
@ -0,0 +1,119 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion\Cache\Driver;
|
||||
|
||||
use Aviat\Ion\ConfigInterface;
|
||||
use Aviat\Ion\Exception\ConfigException;
|
||||
use Aviat\Ion\Model\DB;
|
||||
|
||||
/**
|
||||
* Driver for caching via a traditional SQL database
|
||||
*/
|
||||
class SQLDriver extends DB implements DriverInterface {
|
||||
|
||||
use DriverTrait;
|
||||
|
||||
/**
|
||||
* The query builder object
|
||||
* @var object $db
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* Create the driver object
|
||||
*
|
||||
* @param ConfigInterface $config
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function __construct(ConfigInterface $config)
|
||||
{
|
||||
parent::__construct($config);
|
||||
|
||||
if ( ! array_key_exists('cache', $this->db_config))
|
||||
{
|
||||
throw new ConfigException("Missing '[cache]' section in database config.");
|
||||
}
|
||||
|
||||
$this->db = \Query($this->db_config['cache']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a value from the cache backend
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
$query = $this->db->select('value')
|
||||
->from('cache')
|
||||
->where('key', $key)
|
||||
->get();
|
||||
|
||||
$row = $query->fetch(\PDO::FETCH_ASSOC);
|
||||
|
||||
if (empty($row))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$serializedData = $row['value'];
|
||||
return $this->unserialize($serializedData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a cached value
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return DriverInterface
|
||||
*/
|
||||
public function set($key, $value)
|
||||
{
|
||||
$serializedData = $this->serialize($value);
|
||||
|
||||
$this->db->set([
|
||||
'key' => $key,
|
||||
'value' => $serializedData,
|
||||
]);
|
||||
|
||||
$this->db->insert('cache');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate a cached value
|
||||
*
|
||||
* @param string $key
|
||||
* @return DriverInterface
|
||||
*/
|
||||
public function invalidate($key)
|
||||
{
|
||||
$this->db->where('key', $key)
|
||||
->delete('cache');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the contents of the cache
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function invalidateAll()
|
||||
{
|
||||
$this->db->truncate('cache');
|
||||
}
|
||||
}
|
||||
// End of SQLDriver.php
|
106
src/Aviat/Ion/Config.php
Normal file
106
src/Aviat/Ion/Config.php
Normal file
@ -0,0 +1,106 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion;
|
||||
|
||||
|
||||
use Aviat\Ion\Exception\ConfigException;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Wrapper for configuration values
|
||||
*/
|
||||
class Config implements ConfigInterface {
|
||||
|
||||
use ArrayWrapper;
|
||||
|
||||
/**
|
||||
* Config object
|
||||
*
|
||||
* @var \Aviat\Ion\Type\ArrayType
|
||||
*/
|
||||
protected $map = [];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $config_array
|
||||
*/
|
||||
public function __construct(array $config_array = [])
|
||||
{
|
||||
$this->map = $this->arr($config_array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a config value
|
||||
*
|
||||
* @param array|string $key
|
||||
* @return mixed
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
if (is_array($key))
|
||||
{
|
||||
return $this->map->get_deep_key($key);
|
||||
}
|
||||
|
||||
return $this->map->get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a config value
|
||||
*
|
||||
* @param string|array $key
|
||||
* @return void
|
||||
*/
|
||||
public function delete($key)
|
||||
{
|
||||
if (is_array($key))
|
||||
{
|
||||
$this->map->set_deep_key($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 Config
|
||||
*/
|
||||
public function set($key, $value)
|
||||
{
|
||||
if (is_array($key))
|
||||
{
|
||||
$this->map->set_deep_key($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
|
41
src/Aviat/Ion/ConfigInterface.php
Normal file
41
src/Aviat/Ion/ConfigInterface.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion;
|
||||
|
||||
interface ConfigInterface {
|
||||
/**
|
||||
* Get a config value
|
||||
*
|
||||
* @param array|string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key);
|
||||
|
||||
/**
|
||||
* Set a config value
|
||||
*
|
||||
* @param integer|string|array $key
|
||||
* @param mixed $value
|
||||
* @throws \InvalidArgumentException
|
||||
* @return ConfigInterface
|
||||
*/
|
||||
public function set($key, $value);
|
||||
|
||||
/**
|
||||
* Remove a config value
|
||||
*
|
||||
* @param string|array $key
|
||||
* @return void
|
||||
*/
|
||||
public function delete($key);
|
||||
}
|
171
src/Aviat/Ion/Di/Container.php
Normal file
171
src/Aviat/Ion/Di/Container.php
Normal file
@ -0,0 +1,171 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion\Di;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
use Aviat\Ion\Di\Exception\ContainerException;
|
||||
use Aviat\Ion\Di\Exception\NotFoundException;
|
||||
|
||||
|
||||
/**
|
||||
* Dependency container
|
||||
*/
|
||||
class Container implements ContainerInterface {
|
||||
|
||||
/**
|
||||
* Array with class instances
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $container = [];
|
||||
|
||||
/**
|
||||
* 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))
|
||||
{
|
||||
$item = $this->container[$id];
|
||||
|
||||
if (is_callable($item))
|
||||
{
|
||||
return $this->applyContainer($item($this));
|
||||
}
|
||||
else
|
||||
{
|
||||
return $item;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotFoundException("Item '{$id}' does not exist in container.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a value to the container
|
||||
*
|
||||
* @param string $id
|
||||
* @param mixed $value
|
||||
* @return ContainerInterface
|
||||
*/
|
||||
public function set($id, $value)
|
||||
{
|
||||
$this->container[$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)
|
||||
{
|
||||
return array_key_exists($id, $this->container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a logger channel is registered
|
||||
* @param string $key The logger channel
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasLogger($key = 'default')
|
||||
{
|
||||
return array_key_exists($key, $this->loggers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a logger to the Container
|
||||
*
|
||||
* @param LoggerInterface $logger
|
||||
* @param string $key The logger 'channel'
|
||||
* @return ContainerInterface
|
||||
*/
|
||||
public function setLogger(LoggerInterface $logger, $key = 'default')
|
||||
{
|
||||
$this->loggers[$key] = $logger;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a logger for the selected channel
|
||||
*
|
||||
* @param string $key The logger to retrieve
|
||||
* @return LoggerInterface|null
|
||||
*/
|
||||
public function getLogger($key = 'default')
|
||||
{
|
||||
return ($this->hasLogger($key))
|
||||
? $this->loggers[$key]
|
||||
: 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 = __NAMESPACE__ . '\\ContainerAware';
|
||||
$interface_name = __NAMESPACE__ . '\\ContainerAwareInterface';
|
||||
|
||||
$uses_trait = in_array($trait_name, class_uses($obj));
|
||||
$implements_interface = in_array($interface_name, class_implements($obj));
|
||||
|
||||
if ($uses_trait || $implements_interface)
|
||||
{
|
||||
$obj->setContainer($this);
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
}
|
||||
// End of Container.php
|
49
src/Aviat/Ion/Di/ContainerAware.php
Normal file
49
src/Aviat/Ion/Di/ContainerAware.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
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 $this
|
||||
*/
|
||||
public function setContainer(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the container object
|
||||
*
|
||||
* @return ContainerInterface
|
||||
*/
|
||||
public function getContainer()
|
||||
{
|
||||
return $this->container;
|
||||
}
|
||||
}
|
||||
// End of ContainerAware.php
|
36
src/Aviat/Ion/Di/ContainerAwareInterface.php
Normal file
36
src/Aviat/Ion/Di/ContainerAwareInterface.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
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();
|
||||
|
||||
}
|
||||
// End of ContainerAwareInterface.php
|
54
src/Aviat/Ion/Di/ContainerInterface.php
Normal file
54
src/Aviat/Ion/Di/ContainerInterface.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion\Di;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Interface for the Dependency Injection Container
|
||||
*/
|
||||
interface ContainerInterface extends \Interop\Container\ContainerInterface {
|
||||
|
||||
/**
|
||||
* Add a value to the container
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return ContainerInterface
|
||||
*/
|
||||
public function set($key, $value);
|
||||
|
||||
/**
|
||||
* Determine whether a logger channel is registered
|
||||
* @param string $key The logger channel
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasLogger($key = 'default');
|
||||
|
||||
/**
|
||||
* Add a logger to the Container
|
||||
*
|
||||
* @param LoggerInterface $logger
|
||||
* @param string $key The logger 'channel'
|
||||
* @return Container
|
||||
*/
|
||||
public function setLogger(LoggerInterface $logger, $key = 'default');
|
||||
|
||||
/**
|
||||
* Retrieve a logger for the selected channel
|
||||
*
|
||||
* @param string $key The logger to retreive
|
||||
* @return LoggerInterface|null
|
||||
*/
|
||||
public function getLogger($key = 'default');
|
||||
}
|
21
src/Aviat/Ion/Di/Exception/ContainerException.php
Normal file
21
src/Aviat/Ion/Di/Exception/ContainerException.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion\Di\Exception;
|
||||
|
||||
/**
|
||||
* Generic exception for Di Container
|
||||
*/
|
||||
class ContainerException extends \Exception implements \Interop\Container\Exception\ContainerException {
|
||||
|
||||
}
|
||||
// End of ContainerException.php
|
22
src/Aviat/Ion/Di/Exception/NotFoundException.php
Normal file
22
src/Aviat/Ion/Di/Exception/NotFoundException.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion\Di\Exception;
|
||||
|
||||
/**
|
||||
* Exception for Di Container when trying to access a
|
||||
* key that doesn't exist in the container
|
||||
*/
|
||||
class NotFoundException extends ContainerException implements \Interop\Container\Exception\NotFoundException {
|
||||
|
||||
}
|
||||
// End of NotFoundException.php
|
49
src/Aviat/Ion/Enum.php
Normal file
49
src/Aviat/Ion/Enum.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion;
|
||||
|
||||
use ReflectionClass;
|
||||
|
||||
/**
|
||||
* Class emulating an enumeration type
|
||||
*
|
||||
* @method bool isValid(mixed $key)
|
||||
* @method array getConstList()
|
||||
*/
|
||||
abstract class Enum {
|
||||
|
||||
use StaticInstance;
|
||||
|
||||
/**
|
||||
* Return the list of constant values for the Enum
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getConstList()
|
||||
{
|
||||
$reflect = new ReflectionClass($this);
|
||||
return $reflect->getConstants();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a constant value is valid
|
||||
* @param mixed $key
|
||||
* @return boolean
|
||||
*/
|
||||
protected function isValid($key)
|
||||
{
|
||||
$values = array_values($this->getConstList());
|
||||
return in_array($key, $values);
|
||||
}
|
||||
}
|
||||
// End of Enum.php
|
20
src/Aviat/Ion/Exception/ConfigException.php
Normal file
20
src/Aviat/Ion/Exception/ConfigException.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion\Exception;
|
||||
|
||||
/**
|
||||
* Exception for bad configuration
|
||||
*/
|
||||
class ConfigException extends \InvalidArgumentException {
|
||||
|
||||
}
|
129
src/Aviat/Ion/Friend.php
Normal file
129
src/Aviat/Ion/Friend.php
Normal file
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion;
|
||||
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use ReflectionProperty;
|
||||
use InvalidArgumentException;
|
||||
use BadMethodCallException;
|
||||
|
||||
/**
|
||||
* Friend class for testing
|
||||
*/
|
||||
class Friend {
|
||||
|
||||
/**
|
||||
* Object to create a friend of
|
||||
* @var object
|
||||
*/
|
||||
private $_friend_;
|
||||
|
||||
/**
|
||||
* Reflection class of the object
|
||||
* @var object
|
||||
*/
|
||||
private $_reflect_;
|
||||
|
||||
/**
|
||||
* Create a friend object
|
||||
*
|
||||
* @param object $obj
|
||||
*/
|
||||
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($key)
|
||||
{
|
||||
if ($this->_reflect_->hasProperty($key))
|
||||
{
|
||||
$property = $this->_get_property($key);
|
||||
return $property->getValue($this->_friend_);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a friend's property
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public function __set($key, $value)
|
||||
{
|
||||
if ($this->_reflect_->hasProperty($key))
|
||||
{
|
||||
$property = $this->_get_property($key);
|
||||
$property->setValue($this->_friend_, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a protected or private method on the friend
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $args
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $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
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @param string $name
|
||||
* @return ReflectionProperty|null
|
||||
*/
|
||||
private function _get_property($name)
|
||||
{
|
||||
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
|
130
src/Aviat/Ion/Json.php
Normal file
130
src/Aviat/Ion/Json.php
Normal file
@ -0,0 +1,130 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
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
|
||||
* @return string
|
||||
*/
|
||||
public static function encode($data, $options = 0, $depth = 512)
|
||||
{
|
||||
$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 $json_options - Options to pass to json_encode
|
||||
* @param int $file_options - Options to pass to file_get_contents
|
||||
* @return int
|
||||
*/
|
||||
public static function encodeFile($filename, $data, $json_options = 0, $file_options = 0)
|
||||
{
|
||||
$json = self::encode($data, $json_options);
|
||||
return file_put_contents($filename, $json, $file_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode data from json
|
||||
*
|
||||
* @param string $json
|
||||
* @param bool $assoc
|
||||
* @param int $depth
|
||||
* @param int $options
|
||||
* @return mixed
|
||||
*/
|
||||
public static function decode($json, $assoc = TRUE, $depth = 512, $options = 0)
|
||||
{
|
||||
// Don't try to decode null
|
||||
if (empty($json))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// cast json to string so that streams from guzzle are correctly decoded
|
||||
$data = json_decode((string) $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
|
||||
* @return mixed
|
||||
*/
|
||||
public static function decodeFile($filename, $assoc = TRUE, $depth = 512, $options = 0)
|
||||
{
|
||||
$json = file_get_contents($filename);
|
||||
return self::decode($json, $assoc, $depth, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a string is valid json
|
||||
*
|
||||
* @param string $string
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isJson($string)
|
||||
{
|
||||
return StringType::create($string)->isJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the json error functions to check for errors encoding/decoding
|
||||
*
|
||||
* @throws JsonException
|
||||
*/
|
||||
protected static function check_json_error()
|
||||
{
|
||||
$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
|
18
src/Aviat/Ion/JsonException.php
Normal file
18
src/Aviat/Ion/JsonException.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion;
|
||||
|
||||
class JsonException extends \InvalidArgumentException {
|
||||
|
||||
}
|
||||
// End of JsonException.php
|
21
src/Aviat/Ion/Model.php
Normal file
21
src/Aviat/Ion/Model.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion;
|
||||
|
||||
/**
|
||||
* Common base for all Models
|
||||
*/
|
||||
class Model {
|
||||
use StringWrapper;
|
||||
}
|
||||
// End of Model.php
|
51
src/Aviat/Ion/Model/DB.php
Normal file
51
src/Aviat/Ion/Model/DB.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
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
|
63
src/Aviat/Ion/StaticInstance.php
Normal file
63
src/Aviat/Ion/StaticInstance.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion;
|
||||
|
||||
/**
|
||||
* Trait to allow calling a method statically,
|
||||
* as well as with an instance
|
||||
*/
|
||||
trait StaticInstance {
|
||||
/**
|
||||
* Instance for 'faking' static methods
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
private static $instance = [];
|
||||
|
||||
/**
|
||||
* Call methods protected to allow for
|
||||
* static and instance calling
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @param string $method
|
||||
* @param array $args
|
||||
* @retun mixed
|
||||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
if (method_exists($this, $method))
|
||||
{
|
||||
return call_user_func_array([$this, $method], $args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call non-static methods statically, so that
|
||||
* an instance of the class isn't required
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $args
|
||||
* @return mixed
|
||||
*/
|
||||
public static function __callStatic($method, $args)
|
||||
{
|
||||
$class = get_called_class();
|
||||
if ( ! array_key_exists($class, self::$instance))
|
||||
{
|
||||
self::$instance[$class] = new $class();
|
||||
}
|
||||
|
||||
return call_user_func_array([self::$instance[$class], $method], $args);
|
||||
}
|
||||
}
|
||||
// End of StaticInstance.php
|
33
src/Aviat/Ion/StringWrapper.php
Normal file
33
src/Aviat/Ion/StringWrapper.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
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
|
||||
* @return StringType
|
||||
*/
|
||||
public function string($str)
|
||||
{
|
||||
return StringType::create($str);
|
||||
}
|
||||
}
|
||||
// End of StringWrapper.php
|
42
src/Aviat/Ion/Transformer/AbstractTransformer.php
Normal file
42
src/Aviat/Ion/Transformer/AbstractTransformer.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion\Transformer;
|
||||
|
||||
/**
|
||||
* Base class for data trasformation
|
||||
*/
|
||||
abstract class AbstractTransformer implements TransformerInterface {
|
||||
|
||||
use \Aviat\Ion\StringWrapper;
|
||||
|
||||
/**
|
||||
* Mutate the data structure
|
||||
*
|
||||
* @param array|object $item
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function transform($item);
|
||||
|
||||
/**
|
||||
* Transform a set of structures
|
||||
*
|
||||
* @param array|object $collection
|
||||
* @return array
|
||||
*/
|
||||
public function transform_collection($collection)
|
||||
{
|
||||
$list = (array)$collection;
|
||||
return array_map([$this, 'transform'], $list);
|
||||
}
|
||||
}
|
||||
// End of AbstractTransformer.php
|
27
src/Aviat/Ion/Transformer/TransformerInterface.php
Normal file
27
src/Aviat/Ion/Transformer/TransformerInterface.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
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);
|
||||
}
|
261
src/Aviat/Ion/Type/ArrayType.php
Normal file
261
src/Aviat/Ion/Type/ArrayType.php
Normal file
@ -0,0 +1,261 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion\Type;
|
||||
|
||||
/**
|
||||
* 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 $native_methods = [
|
||||
'chunk' => 'array_chunk',
|
||||
'pluck' => 'array_column',
|
||||
'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',
|
||||
'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 $native_in_place_methods = [
|
||||
'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($method, $args)
|
||||
{
|
||||
// Simple mapping for the majority of methods
|
||||
if (array_key_exists($method, $this->native_methods))
|
||||
{
|
||||
$func = $this->native_methods[$method];
|
||||
// Set the current array as the first argument of the method
|
||||
array_unshift($args, $this->arr);
|
||||
return call_user_func_array($func, $args);
|
||||
}
|
||||
|
||||
// Mapping for in-place methods
|
||||
if (array_key_exists($method, $this->native_in_place_methods))
|
||||
{
|
||||
$func = $this->native_in_place_methods[$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 string $key
|
||||
* @return bool
|
||||
*/
|
||||
public function has_key($key)
|
||||
{
|
||||
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($start_index, $num, $value)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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, $strict = FALSE)
|
||||
{
|
||||
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, $strict = FALSE)
|
||||
{
|
||||
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 (is_null($key))
|
||||
{
|
||||
$value =& $this->arr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($this->has_key($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)
|
||||
{
|
||||
$this->arr[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a reference to the value of an arbitrary key on the array
|
||||
*
|
||||
* @param array $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function &get_deep_key(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 set_deep_key(array $key, $value)
|
||||
{
|
||||
$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
|
23
src/Aviat/Ion/Type/StringType.php
Normal file
23
src/Aviat/Ion/Type/StringType.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion\Type;
|
||||
|
||||
use Stringy\Stringy;
|
||||
|
||||
/**
|
||||
* Wrapper around Stringy
|
||||
*/
|
||||
class StringType extends Stringy {
|
||||
|
||||
}
|
||||
// End of StringType.php
|
137
src/Aviat/Ion/View.php
Normal file
137
src/Aviat/Ion/View.php
Normal file
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion;
|
||||
|
||||
use Aviat\Ion\Di\ContainerInterface;
|
||||
use Aviat\Ion\Type\StringType;
|
||||
|
||||
/**
|
||||
* Base view response class
|
||||
*/
|
||||
abstract class View {
|
||||
|
||||
use Di\ContainerAware;
|
||||
use StringWrapper;
|
||||
|
||||
/**
|
||||
* HTTP response Object
|
||||
*
|
||||
* @var Zend\Diactoros\Response
|
||||
*/
|
||||
public $response;
|
||||
|
||||
/**
|
||||
* Redirect response object
|
||||
*
|
||||
* @var Zend\Diactoros\RedirectResponse
|
||||
*/
|
||||
protected $redirectResponse;
|
||||
|
||||
/**
|
||||
* Response mime type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $contentType = '';
|
||||
|
||||
/**
|
||||
* String of response to be output
|
||||
*
|
||||
* @var StringType
|
||||
*/
|
||||
protected $output;
|
||||
|
||||
/**
|
||||
* If the view has sent output via
|
||||
* __toString or send method
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasRendered = FALSE;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param ContainerInterface $container
|
||||
*/
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->setContainer($container);
|
||||
$this->response = $container->get('response');
|
||||
$this->redirectResponse = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send output to client
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if ( ! $this->hasRendered)
|
||||
{
|
||||
$this->send();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return rendered output
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$this->hasRendered = TRUE;
|
||||
return $this->getOutput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the output string
|
||||
*
|
||||
* @param string $string
|
||||
* @return View
|
||||
*/
|
||||
public function setOutput($string)
|
||||
{
|
||||
$this->response->getBody()->write($string);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append additional output
|
||||
*
|
||||
* @param string $string
|
||||
* @return View
|
||||
*/
|
||||
public function appendOutput($string)
|
||||
{
|
||||
return $this->setOutput($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current output string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOutput()
|
||||
{
|
||||
return $this->response->getBody()->__toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send output to client
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract public function send();
|
||||
}
|
||||
// End of View.php
|
69
src/Aviat/Ion/View/HtmlView.php
Normal file
69
src/Aviat/Ion/View/HtmlView.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion\View;
|
||||
|
||||
use Aviat\Ion\Di\ContainerInterface;
|
||||
|
||||
/**
|
||||
* View class for outputting HTML
|
||||
*/
|
||||
class HtmlView extends HttpView {
|
||||
|
||||
/**
|
||||
* HTML generator/escaper helper
|
||||
*
|
||||
* @var Aura\Html\HelperLocator
|
||||
*/
|
||||
protected $helper;
|
||||
|
||||
/**
|
||||
* Create the Html View
|
||||
*
|
||||
* @param ContainerInterface $container
|
||||
*/
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
$this->helper = $container->get('html-helper');
|
||||
}
|
||||
|
||||
/**
|
||||
* Response mime type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $contentType = 'text/html';
|
||||
|
||||
/**
|
||||
* Render a basic html Template
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function render_template($path, $data)
|
||||
{
|
||||
$data['helper'] = $this->helper;
|
||||
$data['escape'] = $this->helper->escape();
|
||||
$data['container'] = $this->container;
|
||||
|
||||
ob_start();
|
||||
extract($data);
|
||||
include_once $path;
|
||||
$buffer = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
return $buffer;
|
||||
}
|
||||
}
|
||||
// End of HtmlView.php
|
91
src/Aviat/Ion/View/HttpView.php
Normal file
91
src/Aviat/Ion/View/HttpView.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion\View;
|
||||
|
||||
use Zend\Diactoros\Response;
|
||||
use Zend\Diactoros\Response\SapiEmitter;
|
||||
use Aviat\Ion\View as BaseView;
|
||||
|
||||
/**
|
||||
* Base view class for Http output
|
||||
*/
|
||||
class HttpView extends BaseView {
|
||||
|
||||
/**
|
||||
* Do a redirect
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @param string $url
|
||||
* @param int $code
|
||||
* @return void
|
||||
*/
|
||||
public function redirect($url, $code)
|
||||
{
|
||||
ob_start();
|
||||
$message = $this->response->getReasonPhrase($code);
|
||||
$this->setStatusCode($code);
|
||||
$this->response->withHeader('Location', $url);
|
||||
|
||||
if (PHP_SAPI !== 'cli')
|
||||
{
|
||||
header("HTTP/1.1 ${code} ${message}");
|
||||
header("Location: {$url}");
|
||||
}
|
||||
|
||||
$this->hasRendered = TRUE;
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the status code of the request
|
||||
*
|
||||
* @param int $code
|
||||
* @return HttpView
|
||||
*/
|
||||
public function setStatusCode($code)
|
||||
{
|
||||
$this->response = $this->response->withStatus($code)
|
||||
->withProtocolVersion('1.1');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send output to client
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function send()
|
||||
{
|
||||
$this->hasRendered = TRUE;
|
||||
$this->output();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the appropriate response
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @return void
|
||||
*/
|
||||
protected function output()
|
||||
{
|
||||
$this->response->withHeader('Content-type', "{$this->contentType};charset=utf-8")
|
||||
->withHeader('Content-Security-Policy', "script-src 'self'")
|
||||
->withHeader('X-Content-Type-Options', 'nosniff')
|
||||
->withHeader('X-XSS-Protection', '1;mode=block')
|
||||
->withHeader('X-Frame-Options', 'SAMEORIGIN');
|
||||
|
||||
$sender = new SapiEmitter($this->response);
|
||||
$sender->emit($this->response);
|
||||
}
|
||||
|
||||
}
|
47
src/Aviat/Ion/View/JsonView.php
Normal file
47
src/Aviat/Ion/View/JsonView.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/**
|
||||
* Ion
|
||||
*
|
||||
* Building blocks for web development
|
||||
*
|
||||
* @package Ion
|
||||
* @author Timothy J. Warren
|
||||
* @copyright Copyright (c) 2015 - 2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Aviat\Ion\View;
|
||||
|
||||
use Aviat\Ion\Json;
|
||||
use Aviat\Ion\View\HttpView;
|
||||
use Aviat\Ion\View as BaseView;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @return BaseView
|
||||
*/
|
||||
public function setOutput($string)
|
||||
{
|
||||
if ( ! is_string($string))
|
||||
{
|
||||
$string = Json::encode($string);
|
||||
}
|
||||
|
||||
return parent::setOutput($string);
|
||||
}
|
||||
}
|
||||
// End of JsonView.php
|
12
tests/Ion/BaseModelTest.php
Normal file
12
tests/Ion/BaseModelTest.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
use Aviat\Ion\Model as BaseModel;
|
||||
|
||||
class BaseModelTest extends Ion_TestCase {
|
||||
|
||||
public function testBaseModelSanity()
|
||||
{
|
||||
$baseModel = new BaseModel();
|
||||
$this->assertTrue(is_object($baseModel));
|
||||
}
|
||||
}
|
40
tests/Ion/Cache/CacheManagerTest.php
Normal file
40
tests/Ion/Cache/CacheManagerTest.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use Aviat\Ion\Friend;
|
||||
use Aviat\Ion\Cache\CacheManager;
|
||||
|
||||
class CacheManagerText extends Ion_TestCase {
|
||||
|
||||
protected $cachedTime;
|
||||
|
||||
public function __call($name, $args)
|
||||
{
|
||||
return call_user_func_array($name, $args);
|
||||
}
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->cache = new CacheManager($this->container->get('config'), $this->container);
|
||||
$this->friend = new Friend($this->cache);
|
||||
}
|
||||
|
||||
public function testGet()
|
||||
{
|
||||
$this->cachedTime = $this->cache->get($this, 'time');
|
||||
$this->assertEquals($this->cache->get($this, 'time'), $this->cachedTime);
|
||||
}
|
||||
|
||||
public function testGetFresh()
|
||||
{
|
||||
$this->assertNotEquals($this->cache->getFresh($this, 'time'), $this->cachedTime);
|
||||
}
|
||||
|
||||
public function testPurge()
|
||||
{
|
||||
$this->cachedTime = $this->cache->get($this, 'time');
|
||||
$key = $this->friend->generateHashForMethod($this, 'time', []);
|
||||
$this->cache->purge();
|
||||
$this->assertEmpty($this->friend->driver->get($key));
|
||||
}
|
||||
}
|
43
tests/Ion/Cache/Driver/CacheDriverBase.php
Normal file
43
tests/Ion/Cache/Driver/CacheDriverBase.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
trait CacheDriverBase {
|
||||
|
||||
protected $foo = [
|
||||
'bar' => [
|
||||
'baz' => 'foobar'
|
||||
]
|
||||
];
|
||||
|
||||
protected $bar = 'secondvalue';
|
||||
|
||||
public function testHasCacheDriver()
|
||||
{
|
||||
$this->assertTrue((bool) $this->driver);
|
||||
}
|
||||
|
||||
public function testDriverGetSet()
|
||||
{
|
||||
$this->driver->set('foo', $this->foo);
|
||||
$this->driver->set('bar', 'baz');
|
||||
$this->assertEquals($this->driver->get('foo'), $this->foo);
|
||||
$this->assertEquals($this->driver->get('bar'), 'baz');
|
||||
}
|
||||
|
||||
public function testInvalidate()
|
||||
{
|
||||
$this->driver->set('foo', $this->foo);
|
||||
$this->driver->invalidate('foo');
|
||||
$this->assertEmpty($this->driver->get('foo'));
|
||||
}
|
||||
|
||||
public function testInvalidateAll()
|
||||
{
|
||||
$this->driver->set('foo', $this->foo);
|
||||
$this->driver->set('bar', $this->bar);
|
||||
|
||||
$this->driver->invalidateAll();
|
||||
|
||||
$this->assertEmpty($this->driver->get('foo'));
|
||||
$this->assertEmpty($this->driver->get('bar'));
|
||||
}
|
||||
}
|
17
tests/Ion/Cache/Driver/NullDriverTest.php
Normal file
17
tests/Ion/Cache/Driver/NullDriverTest.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
require_once('CacheDriverBase.php');
|
||||
|
||||
use Aviat\Ion\Cache\Driver\NullDriver;
|
||||
|
||||
class CacheNullDriverTest extends Ion_TestCase {
|
||||
use CacheDriverBase;
|
||||
|
||||
protected $driver;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->driver = new NullDriver($this->container->get('config'));
|
||||
}
|
||||
}
|
38
tests/Ion/Cache/Driver/RedisDriver2Test.php
Normal file
38
tests/Ion/Cache/Driver/RedisDriver2Test.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
require_once('CacheDriverBase.php');
|
||||
|
||||
use Aviat\Ion\Config;
|
||||
use Aviat\Ion\Cache\Driver\RedisDriver;
|
||||
|
||||
class CacheRedisDriverTestTwo extends Ion_TestCase {
|
||||
use CacheDriverBase;
|
||||
|
||||
protected $driver;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// Setup config with port and password
|
||||
$config = new Config([
|
||||
'redis' => [
|
||||
'host' => (array_key_exists('REDIS_HOST', $_ENV)) ? $_ENV['REDIS_HOST'] : 'localhost',
|
||||
'port' => 6379,
|
||||
'password' => '',
|
||||
'database' => 13,
|
||||
]
|
||||
]);
|
||||
$this->driver = new RedisDriver($config);
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
if ( ! is_null($this->driver))
|
||||
{
|
||||
$this->driver->__destruct();
|
||||
}
|
||||
}
|
||||
}
|
29
tests/Ion/Cache/Driver/RedisDriverTest.php
Normal file
29
tests/Ion/Cache/Driver/RedisDriverTest.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
require_once('CacheDriverBase.php');
|
||||
|
||||
use Aviat\Ion\Cache\Driver\RedisDriver;
|
||||
|
||||
class CacheRedisDriverTest extends Ion_TestCase {
|
||||
use CacheDriverBase;
|
||||
|
||||
protected $driver;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->driver = new RedisDriver($this->container->get('config'));
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
if ( ! is_null($this->driver))
|
||||
{
|
||||
$this->driver->__destruct();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
20
tests/Ion/Cache/Driver/SQLDriverTest.php
Normal file
20
tests/Ion/Cache/Driver/SQLDriverTest.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
require_once('CacheDriverBase.php');
|
||||
|
||||
use Aviat\Ion\Friend;
|
||||
use Aviat\Ion\Cache\Driver\SQLDriver;
|
||||
|
||||
class CacheSQLDriverTest extends Ion_TestCase {
|
||||
use CacheDriverBase;
|
||||
|
||||
protected $driver;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->driver = new SQLDriver($this->container->get('config'));
|
||||
$friend = new Friend($this->driver);
|
||||
$friend->db->query('CREATE TABLE IF NOT EXISTS "cache" ("key" TEXT NULL, "value" TEXT NULL, PRIMARY KEY ("key"))');
|
||||
}
|
||||
}
|
120
tests/Ion/ConfigTest.php
Normal file
120
tests/Ion/ConfigTest.php
Normal file
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
use Aviat\Ion\Config;
|
||||
|
||||
class ConfigTest extends Ion_TestCase {
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->config = new Config([
|
||||
'foo' => 'bar',
|
||||
'asset_path' => '/assets',
|
||||
'bar' => 'baz'
|
||||
]);
|
||||
}
|
||||
|
||||
public function testConfigGet()
|
||||
{
|
||||
$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()
|
||||
{
|
||||
$ret = $this->config->set('foo', 'foobar');
|
||||
$this->assertInstanceOf('Aviat\Ion\Config', $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()
|
||||
{
|
||||
$this->setExpectedException('InvalidArgumentException');
|
||||
$this->config->set(NULL, FALSE);
|
||||
}
|
||||
|
||||
public function dataConfigDelete()
|
||||
{
|
||||
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, $assertKeys)
|
||||
{
|
||||
$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()
|
||||
{
|
||||
$this->assertNull($this->config->get('foobar'));
|
||||
}
|
||||
}
|
39
tests/Ion/Di/ContainerAwareTest.php
Normal file
39
tests/Ion/Di/ContainerAwareTest.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
use Aviat\Ion\Di\Container;
|
||||
use Aviat\Ion\Di\ContainerAware;
|
||||
use Aviat\Ion\Di\ContainerInterface;
|
||||
use Aviat\Ion\Di\Exception\ContainerException;
|
||||
|
||||
class Aware {
|
||||
use ContainerAware;
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ContainerAwareTest extends Ion_TestCase {
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->container = new Container();
|
||||
$this->aware = new Aware($this->container);
|
||||
}
|
||||
|
||||
public function testContainerAwareTrait()
|
||||
{
|
||||
// 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());
|
||||
}
|
||||
}
|
91
tests/Ion/Di/ContainerTest.php
Normal file
91
tests/Ion/Di/ContainerTest.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
use Aviat\Ion\Di\Container;
|
||||
use Aviat\Ion\Di\Exception\ContainerException;
|
||||
use Monolog\Logger;
|
||||
use Monolog\Handler\TestHandler;
|
||||
use Monolog\Handler\NullHandler;
|
||||
|
||||
|
||||
class ContainerTest extends Ion_TestCase {
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->container = new Container();
|
||||
}
|
||||
|
||||
public function dataGetWithException()
|
||||
{
|
||||
return [
|
||||
'Bad index type: number' => [
|
||||
'id' => 42,
|
||||
'exception' => 'Aviat\Ion\Di\Exception\ContainerException',
|
||||
'message' => 'Id must be a string'
|
||||
],
|
||||
'Bad index type: array' => [
|
||||
'id' => [],
|
||||
'exception' => 'Aviat\Ion\Di\Exception\ContainerException',
|
||||
'message' => 'Id must be a string'
|
||||
],
|
||||
'Non-existent id' => [
|
||||
'id' => 'foo',
|
||||
'exception' => 'Aviat\Ion\Di\Exception\NotFoundException',
|
||||
'message' => "Item 'foo' does not exist in container."
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataGetWithException
|
||||
*/
|
||||
public function testGetWithException($id, $exception, $message)
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->container->get($id);
|
||||
}
|
||||
catch(ContainerException $e)
|
||||
{
|
||||
$this->assertInstanceOf($exception, $e);
|
||||
$this->assertEquals($message, $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function testGetSet()
|
||||
{
|
||||
$container = $this->container->set('foo', function() {
|
||||
return function() {};
|
||||
});
|
||||
|
||||
$this->assertInstanceOf('Aviat\Ion\Di\Container', $container);
|
||||
$this->assertInstanceOf('Aviat\Ion\Di\ContainerInterface', $container);
|
||||
$this->assertTrue(is_callable($container->get('foo')));
|
||||
}
|
||||
|
||||
public function testLoggerMethods()
|
||||
{
|
||||
// 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('Aviat\Ion\Di\ContainerInterface', $container);
|
||||
$this->assertInstanceOf('Aviat\Ion\Di\Container', $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'));
|
||||
}
|
||||
}
|
68
tests/Ion/EnumTest.php
Normal file
68
tests/Ion/EnumTest.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
use Aviat\Ion\Enum;
|
||||
|
||||
class EnumTest extends Ion_TestCase {
|
||||
|
||||
protected $expectedConstList = [
|
||||
'FOO' => 'bar',
|
||||
'BAR' => 'foo',
|
||||
'FOOBAR' => 'baz'
|
||||
];
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
56
tests/Ion/FriendTest.php
Normal file
56
tests/Ion/FriendTest.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
use Aviat\Ion\Friend;
|
||||
|
||||
class FriendTest extends Ion_TestCase {
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
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-existend 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->setExpectedException('InvalidArgumentException', 'Friend must be an object');
|
||||
|
||||
$friend = new Friend('foo');
|
||||
}
|
||||
|
||||
public function testBadMethod()
|
||||
{
|
||||
$this->setExpectedException('BadMethodCallException', "Method 'foo' does not exist");
|
||||
$this->friend->foo();
|
||||
}
|
||||
}
|
68
tests/Ion/JsonTest.php
Normal file
68
tests/Ion/JsonTest.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
use Aviat\Ion\Json;
|
||||
use Aviat\Ion\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->setExpectedException(
|
||||
'Aviat\Ion\JsonException',
|
||||
'JSON_ERROR_SYNTAX - Syntax error',
|
||||
JSON_ERROR_SYNTAX
|
||||
);
|
||||
Json::decode($badJson);
|
||||
}
|
||||
}
|
12
tests/Ion/Model/BaseDBModelTest.php
Normal file
12
tests/Ion/Model/BaseDBModelTest.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
use Aviat\Ion\Model\DB as BaseDBModel;
|
||||
|
||||
class BaseDBModelTest extends Ion_TestCase {
|
||||
|
||||
public function testBaseDBModelSanity()
|
||||
{
|
||||
$baseDBModel = new BaseDBModel($this->container->get('config'));
|
||||
$this->assertTrue(is_object($baseDBModel));
|
||||
}
|
||||
}
|
89
tests/Ion/Transformer/AbstractTransformerTest.php
Normal file
89
tests/Ion/Transformer/AbstractTransformerTest.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
class AbstractTransformerTest extends Ion_TestCase {
|
||||
|
||||
protected $transformer;
|
||||
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->transformer = new TestTransformer();
|
||||
}
|
||||
|
||||
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 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->transform_collection($original);
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
}
|
173
tests/Ion/Type/ArrayTypeTest.php
Normal file
173
tests/Ion/Type/ArrayTypeTest.php
Normal file
@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
class ArrayTypeTest extends Ion_TestCase {
|
||||
use Aviat\Ion\ArrayWrapper;
|
||||
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
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->get_deep_key(['baz', 'bar']));
|
||||
$this->assertNull($obj->get_deep_key(['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->setExpectedException('InvalidArgumentException', "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->has_key('a'));
|
||||
$this->assertFalse($obj->has_key('b'));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
25
tests/Ion/View/HtmlViewTest.php
Normal file
25
tests/Ion/View/HtmlViewTest.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
include_once __DIR__ . "/HttpViewTest.php";
|
||||
|
||||
class HtmlViewTest extends HttpViewTest {
|
||||
|
||||
protected $template_path;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
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->render_template($path, [
|
||||
'var' => 'foo'
|
||||
]);
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
}
|
46
tests/Ion/View/HttpViewTest.php
Normal file
46
tests/Ion/View/HttpViewTest.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
use Aviat\Ion\Friend;
|
||||
|
||||
class HttpViewTest extends Ion_TestCase {
|
||||
|
||||
protected $view;
|
||||
protected $friend;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
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());
|
||||
}
|
||||
}
|
43
tests/Ion/View/JsonViewTest.php
Normal file
43
tests/Ion/View/JsonViewTest.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
use Aviat\Ion\Friend;
|
||||
|
||||
include_once __DIR__ . "/HttpViewTest.php";
|
||||
|
||||
class JsonViewTest extends HttpViewTest {
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
117
tests/Ion_TestCase.php
Normal file
117
tests/Ion_TestCase.php
Normal file
@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
use Aura\Web\WebFactory;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Handler\MockHandler;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use Zend\Diactoros\ServerRequestFactory;
|
||||
use Zend\Diactoros\Response as HttpResponse;
|
||||
|
||||
use Aviat\Ion\Json;
|
||||
|
||||
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 PHPUnit_Framework_TestCase {
|
||||
// Test directory constants
|
||||
const ROOT_DIR = ROOT_DIR;
|
||||
const SRC_DIR = SRC_DIR;
|
||||
const TEST_DATA_DIR = TEST_DATA_DIR;
|
||||
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()
|
||||
{
|
||||
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', self::$session_handler);
|
||||
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set arbitrary superglobal values for testing purposes
|
||||
*
|
||||
* @param array $supers
|
||||
* @return void
|
||||
*/
|
||||
public function setSuperGlobals($supers = [])
|
||||
{
|
||||
$default = [
|
||||
'_SERVER' => $_SERVER,
|
||||
'_GET' => $_GET,
|
||||
'_POST' => $_POST,
|
||||
'_COOKIE' => $_COOKIE,
|
||||
'_FILES' => $_FILES
|
||||
];
|
||||
|
||||
$request = call_user_func_array(
|
||||
['Zend\Diactoros\ServerRequestFactory', 'fromGlobals'],
|
||||
array_merge($default, $supers)
|
||||
);
|
||||
$this->container->set('request', $request);
|
||||
}
|
||||
}
|
||||
// End of Ion_TestCase.php
|
53
tests/TestSessionHandler.php
Normal file
53
tests/TestSessionHandler.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
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
|
76
tests/bootstrap.php
Normal file
76
tests/bootstrap.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?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');
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Global functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Joins paths together. Variadic to take an
|
||||
* arbitrary number of arguments
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function _dir()
|
||||
{
|
||||
return implode(DIRECTORY_SEPARATOR, func_get_args());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Autoloading
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
require 'Ion_TestCase.php';
|
||||
|
||||
// Composer autoload
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
/**
|
||||
* Set up autoloaders
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @return void
|
||||
*/
|
||||
spl_autoload_register(function ($class) {
|
||||
$class_parts = explode('\\', $class);
|
||||
$ns_path = realpath(__DIR__ . '/../src') . '/' . implode('/', $class_parts) . ".php";
|
||||
|
||||
if (file_exists($ns_path))
|
||||
{
|
||||
require_once($ns_path);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 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 supress 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
|
41
tests/di.php
Normal file
41
tests/di.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
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 function(array $config_array = []) {
|
||||
$container = new Container([
|
||||
'config' => new Config($config_array),
|
||||
]);
|
||||
|
||||
// Create Request/Response Objects
|
||||
$request = ServerRequestFactory::fromGlobals(
|
||||
$_SERVER,
|
||||
$_GET,
|
||||
$_POST,
|
||||
$_COOKIE,
|
||||
$_FILES
|
||||
);
|
||||
$container->set('request', $request);
|
||||
$container->set('response', new Response());
|
||||
|
||||
// Create session Object
|
||||
$container->set('session', function() {
|
||||
return (new SessionFactory())->newInstance($_COOKIE);
|
||||
});
|
||||
|
||||
// Create Html helper Object
|
||||
$container->set('html-helper', function() {
|
||||
return (new HelperLocatorFactory)->newInstance();
|
||||
});
|
||||
|
||||
return $container;
|
||||
};
|
134
tests/mocks.php
Normal file
134
tests/mocks.php
Normal file
@ -0,0 +1,134 @@
|
||||
<?php
|
||||
/**
|
||||
* All the mock classes that extend the classes they are used to test
|
||||
*/
|
||||
|
||||
use Aviat\Ion\Enum;
|
||||
use Aviat\Ion\Friend;
|
||||
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||
use Aviat\Ion\View;
|
||||
use Aviat\Ion\View\HtmlView;
|
||||
use Aviat\Ion\View\HttpView;
|
||||
use Aviat\Ion\View\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;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
class TestView extends View {
|
||||
public function send() {}
|
||||
protected function output()
|
||||
{
|
||||
/*$content =& $this->response->content;
|
||||
$content->set($this->output);
|
||||
$content->setType($this->contentType);
|
||||
$content->setCharset('utf-8');*/
|
||||
}
|
||||
}
|
||||
|
||||
class TestHtmlView extends HtmlView {
|
||||
use MockViewOutputTrait;
|
||||
}
|
||||
|
||||
class TestHttpView extends HttpView {
|
||||
use MockViewOutputTrait;
|
||||
}
|
||||
|
||||
class TestJsonView extends JsonView {
|
||||
public function __destruct() {}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 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
|
1
tests/test_data/invalid_json.json
Normal file
1
tests/test_data/invalid_json.json
Normal file
@ -0,0 +1 @@
|
||||
[}]
|
5
tests/test_data/valid_json.json
Normal file
5
tests/test_data/valid_json.json
Normal file
@ -0,0 +1,5 @@
|
||||
[{
|
||||
"foo": {
|
||||
"bar": [1,2,3]
|
||||
}
|
||||
}]
|
1
tests/test_views/test_view.php
Normal file
1
tests/test_views/test_view.php
Normal file
@ -0,0 +1 @@
|
||||
<tag><?= $var ?></tag>
|
Loading…
Reference in New Issue
Block a user