Really ugly progress commit

This commit is contained in:
Timothy Warren 2016-08-26 17:21:50 -04:00
parent 9e6549a9f3
commit 6354a816db
52 changed files with 497 additions and 239 deletions

20
.editorconfig Normal file
View File

@ -0,0 +1,20 @@
# EditorConfig is awesome: http://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = false
charset = utf-8
indent_style = tab
trim_trailing_whitespace = true
[*.{cpp,c,h,hpp,cxx}]
insert_final_newline = true
# Yaml files
[*.{yml,yaml}]
indent_style = space
indent_size = 4

View File

@ -20,8 +20,13 @@ if ( ! function_exists('glob_recursive'))
* *
* @see http://robo.li/ * @see http://robo.li/
*/ */
class RoboFile extends \Robo\Tasks class RoboFile extends \Robo\Tasks {
{
/**
* Directories used by analysis tools
*
* @var array
*/
protected $taskDirs = [ protected $taskDirs = [
'build/api', 'build/api',
'build/coverage', 'build/coverage',
@ -41,6 +46,7 @@ class RoboFile extends \Robo\Tasks
$this->phploc(TRUE); $this->phploc(TRUE);
$this->dependencyReport(); $this->dependencyReport();
$this->phpcpdReport(); $this->phpcpdReport();
$this->phpcsReport();
} }
/** /**
@ -135,6 +141,20 @@ class RoboFile extends \Robo\Tasks
$this->_run($cmd_parts); $this->_run($cmd_parts);
} }
/**
* Run the phpcs tool
*/
public function phpcs()
{
$cmd_parts = [
'vendor/bin/phpcs',
'--standard=./build/phpcs.xml',
'--report=summary'
];
$this->_run($cmd_parts);
}
/** /**
* Run the phploc tool * Run the phploc tool
* *
@ -145,6 +165,7 @@ class RoboFile extends \Robo\Tasks
// Command for generating reports // Command for generating reports
$report_cmd_parts = [ $report_cmd_parts = [
'vendor/bin/phploc', 'vendor/bin/phploc',
'--count-tests',
'--log-csv=build/logs/phploc.csv', '--log-csv=build/logs/phploc.csv',
'--log-xml=build/logs/phploc.xml', '--log-xml=build/logs/phploc.xml',
'src', 'src',
@ -263,6 +284,19 @@ class RoboFile extends \Robo\Tasks
$this->_run($cmd_parts); $this->_run($cmd_parts);
} }
/**
* Generate code style report
*/
protected function phpcsReport()
{
$cmd_parts = [
'vendor/bin/phpcs',
'--standard=./build/phpcs.xml',
'--report-xml=./build/logs/phpcs.xml'
];
$this->_run($cmd_parts);
}
/** /**
* Short cut for joining an array of command arguments * Short cut for joining an array of command arguments
* and then running it * and then running it

@ -0,0 +1 @@
Subproject commit b501f01403216a917754e3f76ba7022d4ad37a4e

53
build/phpcs.xml Normal file
View File

@ -0,0 +1,53 @@
<?xml version="1.0"?>
<ruleset name="Tim's Coding Standard">
<description>A variation of the CodeIgniter standard</description>
<file>../src/</file>
<rule ref="Generic.Files.LineEndings">
<properties>
<property name="eolChar" value="\n"/>
</properties>
</rule>
<!-- PHP files should OMIT the closing PHP tag -->
<rule ref="Zend.Files.ClosingTag"/>
<!-- Always use full PHP opening tags -->
<rule ref="Generic.PHP.DisallowShortOpenTag"/>
<!-- Constants should always be fully uppercase -->
<rule ref="Generic.NamingConventions.UpperCaseConstantName"/>
<!-- TRUE, FALSE, and NULL keywords should always be fully uppercase -->
<rule ref="Generic.PHP.UpperCaseConstant"/>
<!-- One statement per line -->
<rule ref="Generic.Formatting.DisallowMultipleStatements"/>
<!-- Classes and functions should be commented -->
<rule ref="PEAR.Commenting.ClassComment"/>
<rule ref="PEAR.Commenting.FunctionComment"/>
<rule ref="Squiz.Commenting.FunctionCommentThrowTag"/>
<!-- Use warnings for docblock comments for files and variables, since nothing is cleary explained -->
<rule ref="PEAR.Commenting.FileComment">
<properties>
<property name="error" value="false"/>
</properties>
</rule>
<rule ref="Squiz.Commenting.VariableComment">
<properties>
<property name="error" value="false"/>
</properties>
</rule>
<!-- Use Allman style indenting. With the exception of Class declarations,
braces are always placed on a line by themselves, and indented at the same level as the control statement that "owns" them. -->
<rule ref="Generic.Functions.OpeningFunctionBraceBsdAllman"/>
<rule ref="PEAR.WhiteSpace.ScopeClosingBrace"/>
<rule ref="Generic.Functions.FunctionCallArgumentSpacing"/>
<rule ref="Generic.PHP.ForbiddenFunctions">
<properties>
<property name="forbiddenFunctions" type="array" value="create_function=>null,eval=>null" />
</properties>
</rule>
</ruleset>

View File

@ -48,6 +48,7 @@
<inheritance resolve="true"> <inheritance resolve="true">
<!-- @resolve - Flag to enable/disable resolving of inheritance --> <!-- @resolve - Flag to enable/disable resolving of inheritance -->
<!-- You can define multiple (external) dependencies to be included --> <!-- You can define multiple (external) dependencies to be included -->
<!-- <dependency path="" --> <!-- <dependency path="" -->
<!-- @path - path to a directory containing an index.xml for a dependency project --> <!-- @path - path to a directory containing an index.xml for a dependency project -->
@ -84,11 +85,9 @@
</source> </source>
<!-- PHP Code Sniffer findings --> <!-- PHP Code Sniffer findings -->
<!--
<source type="phpcs"> <source type="phpcs">
<file name="logs/phpcs.xml" /> <file name="phpcs.xml" />
</source> </source>
-->
<!-- PHPMessDetector --> <!-- PHPMessDetector -->
<!-- <!--
@ -99,7 +98,7 @@
<!-- PHPUnit Coverage XML --> <!-- PHPUnit Coverage XML -->
<source type="phpunit"> <source type="phpunit">
<coverage path="coverage" /> <coverage path="coverage/clover.xml" />
<!-- <coverage path="clover.xml" />--> <!-- <coverage path="clover.xml" />-->
<!-- @path - the directory where the xml code coverage report can be found --> <!-- @path - the directory where the xml code coverage report can be found -->
<!--<filter directory="${phpDox.project.source}" />--> <!--<filter directory="${phpDox.project.source}" />-->

View File

@ -8,7 +8,7 @@
> >
<filter> <filter>
<whitelist> <whitelist>
<directory suffix=".php">../src/Aviat/Ion</directory> <directory suffix=".php">../src/Ion</directory>
</whitelist> </whitelist>
</filter> </filter>
<testsuites> <testsuites>

View File

@ -1,7 +1,7 @@
<?php <?php
$ion_file_patterns = [ $ion_file_patterns = [
'src/Aviat/Ion/*.php' 'src/*.php'
]; ];
if ( ! function_exists('glob_recursive')) if ( ! function_exists('glob_recursive'))

View File

@ -4,7 +4,12 @@
"license":"MIT", "license":"MIT",
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"": "src/" "Aviat\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Aviat\\Ion\\Tests\\": "tests/Ion/"
} }
}, },
"require": { "require": {
@ -13,8 +18,6 @@
"container-interop/container-interop": "1.*", "container-interop/container-interop": "1.*",
"danielstjules/stringy": "~2.1", "danielstjules/stringy": "~2.1",
"guzzlehttp/guzzle": "6.*", "guzzlehttp/guzzle": "6.*",
"monolog/monolog": "1.*",
"predis/predis": "1.1.*",
"psr/http-message": "~1.0", "psr/http-message": "~1.0",
"psr/log": "~1.0", "psr/log": "~1.0",
"zendframework/zend-diactoros": "1.3.*" "zendframework/zend-diactoros": "1.3.*"
@ -22,13 +25,22 @@
"require-dev": { "require-dev": {
"pdepend/pdepend": "^2.2", "pdepend/pdepend": "^2.2",
"sebastian/phpcpd": "^2.0", "sebastian/phpcpd": "^2.0",
"theseer/phpdox": "0.8.1.1", "theseer/phpdox": "~0.9.0",
"phploc/phploc": "^3.0", "phploc/phploc": "^3.0",
"phpmd/phpmd": "^2.4", "phpmd/phpmd": "^2.4",
"phpunit/phpunit": "^5.4", "phpunit/phpunit": "^5.4",
"robmorgan/phinx": "^0.6.4", "robmorgan/phinx": "^0.6.4",
"humbug/humbug": "~1.0@dev", "humbug/humbug": "~1.0@dev",
"consolidation/robo": "~1.0@dev", "consolidation/robo": "~1.0@RC",
"henrikbjorn/lurker": "^1.1.0" "henrikbjorn/lurker": "^1.1.0",
"nikic/php-parser": "3.0.*@alpha",
"monolog/monolog": "1.*",
"predis/predis": "1.1.*",
"squizlabs/php_codesniffer": "^2.6"
},
"suggest": {
"monolog/monolog": "Provides implementation of psr/log",
"predis/predis": "Required for redis cache driver",
"zendframework/zend-diactoros": "Provides implementation of psr/http-message"
} }
} }

View File

@ -7,7 +7,7 @@
> >
<filter> <filter>
<whitelist> <whitelist>
<directory suffix=".php">src/Aviat/Ion</directory> <directory suffix=".php">src/Ion</directory>
</whitelist> </whitelist>
</filter> </filter>
<testsuites> <testsuites>

View File

@ -21,9 +21,9 @@ interface CacheInterface {
* Retrieve a cached value if it exists, otherwise, get the value * Retrieve a cached value if it exists, otherwise, get the value
* from the passed arguments * from the passed arguments
* *
* @param object $object - object to retrieve fresh value from * @param object $object - object to retrieve fresh value from
* @param string $method - method name to call * @param string $method - method name to call
* @param [array] $args - the arguments to pass to the retrieval method * @param [array] $args - the arguments to pass to the retrieval method
* @return mixed - the cached or fresh data * @return mixed - the cached or fresh data
*/ */
public function get($object, $method, array $args=[]); public function get($object, $method, array $args=[]);
@ -31,9 +31,9 @@ interface CacheInterface {
/** /**
* Retrieve a fresh value, and update the cache * Retrieve a fresh value, and update the cache
* *
* @param object $object - object to retrieve fresh value from * @param object $object - object to retrieve fresh value from
* @param string $method - method name to call * @param string $method - method name to call
* @param [array] $args - the arguments to pass to the retrieval method * @param [array] $args - the arguments to pass to the retrieval method
* @return mixed - the fresh data * @return mixed - the fresh data
*/ */
public function getFresh($object, $method, array $args=[]); public function getFresh($object, $method, array $args=[]);

View File

@ -51,9 +51,9 @@ class CacheManager implements CacheInterface {
* Retrieve a cached value if it exists, otherwise, get the value * Retrieve a cached value if it exists, otherwise, get the value
* from the passed arguments * from the passed arguments
* *
* @param object $object - object to retrieve fresh value from * @param object $object - object to retrieve fresh value from
* @param string $method - method name to call * @param string $method - method name to call
* @param [array] $args - the arguments to pass to the retrieval method * @param [array] $args - the arguments to pass to the retrieval method
* @return mixed - the cached or fresh data * @return mixed - the cached or fresh data
*/ */
public function get($object, $method, array $args=[]) public function get($object, $method, array $args=[])
@ -73,9 +73,9 @@ class CacheManager implements CacheInterface {
/** /**
* Retrieve a fresh value from the method, and update the cache * Retrieve a fresh value from the method, and update the cache
* @param object $object - object to retrieve fresh value from * @param object $object - object to retrieve fresh value from
* @param string $method - method name to call * @param string $method - method name to call
* @param [array] $args - the arguments to pass to the retrieval method * @param [array] $args - the arguments to pass to the retrieval method
* @return mixed - the fresh data * @return mixed - the fresh data
*/ */
public function getFresh($object, $method, array $args=[]) public function getFresh($object, $method, array $args=[])
@ -101,7 +101,7 @@ class CacheManager implements CacheInterface {
* *
* @param object $object * @param object $object
* @param string $method * @param string $method
* @param array $args * @param array $args
* @return string * @return string
*/ */
protected function generateHashForMethod($object, $method, array $args) protected function generateHashForMethod($object, $method, array $args)

View File

@ -28,7 +28,7 @@ interface DriverInterface {
* Set a cached value * Set a cached value
* *
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @return DriverInterface * @return DriverInterface
*/ */
public function set($key, $value); public function set($key, $value);

View File

@ -40,7 +40,7 @@ class NullDriver implements DriverInterface {
* Set a cached value * Set a cached value
* *
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @return DriverInterface * @return DriverInterface
*/ */
public function set($key, $value) public function set($key, $value)

View File

@ -56,7 +56,7 @@ class RedisDriver implements DriverInterface {
*/ */
public function __destruct() public function __destruct()
{ {
$this->redis = null; $this->redis = NULL;
} }
/** /**
@ -77,7 +77,7 @@ class RedisDriver implements DriverInterface {
* Set a cached value * Set a cached value
* *
* @param string $rawKey * @param string $rawKey
* @param mixed $value * @param mixed $value
* @return DriverInterface * @return DriverInterface
*/ */
public function set($rawKey, $value) public function set($rawKey, $value)

View File

@ -75,7 +75,7 @@ class SQLDriver extends DB implements DriverInterface {
* Set a cached value * Set a cached value
* *
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @return DriverInterface * @return DriverInterface
*/ */
public function set($key, $value) public function set($key, $value)

View File

@ -81,7 +81,7 @@ class Config implements ConfigInterface {
* Set a config value * Set a config value
* *
* @param integer|string|array $key * @param integer|string|array $key
* @param mixed $value * @param mixed $value
* @throws InvalidArgumentException * @throws InvalidArgumentException
* @return Config * @return Config
*/ */

View File

@ -28,7 +28,7 @@ interface ConfigInterface {
* Set a config value * Set a config value
* *
* @param integer|string|array $key * @param integer|string|array $key
* @param mixed $value * @param mixed $value
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
* @return ConfigInterface * @return ConfigInterface
*/ */

View File

@ -86,7 +86,7 @@ class Container implements ContainerInterface {
* Add a value to the container * Add a value to the container
* *
* @param string $id * @param string $id
* @param mixed $value * @param mixed $value
* @return ContainerInterface * @return ContainerInterface
*/ */
public function set($id, $value) public function set($id, $value)
@ -110,7 +110,7 @@ class Container implements ContainerInterface {
/** /**
* Determine whether a logger channel is registered * Determine whether a logger channel is registered
* @param string $key The logger channel * @param string $key The logger channel
* @return boolean * @return boolean
*/ */
public function hasLogger($key = 'default') public function hasLogger($key = 'default')

View File

@ -23,14 +23,14 @@ interface ContainerInterface extends \Interop\Container\ContainerInterface {
* Add a value to the container * Add a value to the container
* *
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @return ContainerInterface * @return ContainerInterface
*/ */
public function set($key, $value); public function set($key, $value);
/** /**
* Determine whether a logger channel is registered * Determine whether a logger channel is registered
* @param string $key The logger channel * @param string $key The logger channel
* @return boolean * @return boolean
*/ */
public function hasLogger($key = 'default'); public function hasLogger($key = 'default');

View File

@ -37,7 +37,7 @@ abstract class Enum {
/** /**
* Verify that a constant value is valid * Verify that a constant value is valid
* @param mixed $key * @param mixed $key
* @return boolean * @return boolean
*/ */
protected function isValid($key) protected function isValid($key)

View File

@ -0,0 +1,31 @@
<?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 called when a view is attempted to be sent twice
*/
class DoubleRenderException extends \LogicException {
/**
* DoubleRenderException constructor.
*
* @param string $message
* @param int $code
* @param null $previous
*/
public function __construct($message = 'A view can only be rendered once, because headers can only be sent once.', $code = 0, $previous = NULL)
{
parent::__construct($message, $code, $previous);
}
}

View File

@ -72,7 +72,7 @@ class Friend {
* Set a friend's property * Set a friend's property
* *
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @return void * @return void
*/ */
public function __set($key, $value) public function __set($key, $value)
@ -88,7 +88,7 @@ class Friend {
* Calls a protected or private method on the friend * Calls a protected or private method on the friend
* *
* @param string $method * @param string $method
* @param array $args * @param array $args
* @return mixed * @return mixed
*/ */
public function __call($method, $args) public function __call($method, $args)

View File

@ -23,8 +23,8 @@ class Json {
* Encode data in json format * Encode data in json format
* *
* @param mixed $data * @param mixed $data
* @param int $options * @param int $options
* @param int $depth * @param int $depth
* @return string * @return string
*/ */
public static function encode($data, $options = 0, $depth = 512) public static function encode($data, $options = 0, $depth = 512)
@ -38,9 +38,9 @@ class Json {
* Encode data in json format and save to a file * Encode data in json format and save to a file
* *
* @param string $filename * @param string $filename
* @param mixed $data * @param mixed $data
* @param int $json_options - Options to pass to json_encode * @param int $json_options - Options to pass to json_encode
* @param int $file_options - Options to pass to file_get_contents * @param int $file_options - Options to pass to file_get_contents
* @return int * @return int
*/ */
public static function encodeFile($filename, $data, $json_options = 0, $file_options = 0) public static function encodeFile($filename, $data, $json_options = 0, $file_options = 0)
@ -53,9 +53,9 @@ class Json {
* Decode data from json * Decode data from json
* *
* @param string $json * @param string $json
* @param bool $assoc * @param bool $assoc
* @param int $depth * @param int $depth
* @param int $options * @param int $options
* @return mixed * @return mixed
*/ */
public static function decode($json, $assoc = TRUE, $depth = 512, $options = 0) public static function decode($json, $assoc = TRUE, $depth = 512, $options = 0)
@ -77,9 +77,9 @@ class Json {
* Decode json data loaded from the passed filename * Decode json data loaded from the passed filename
* *
* @param string $filename * @param string $filename
* @param bool $assoc * @param bool $assoc
* @param int $depth * @param int $depth
* @param int $options * @param int $options
* @return mixed * @return mixed
*/ */
public static function decodeFile($filename, $assoc = TRUE, $depth = 512, $options = 0) public static function decodeFile($filename, $assoc = TRUE, $depth = 512, $options = 0)
@ -91,7 +91,7 @@ class Json {
/** /**
* Determines whether a string is valid json * Determines whether a string is valid json
* *
* @param string $string * @param string $string
* @return boolean * @return boolean
*/ */
public static function isJson($string) public static function isJson($string)

View File

@ -1,21 +1,21 @@
<?php <?php
/** /**
* Ion * Ion
* *
* Building blocks for web development * Building blocks for web development
* *
* @package Ion * @package Ion
* @author Timothy J. Warren * @author Timothy J. Warren
* @copyright Copyright (c) 2015 - 2016 * @copyright Copyright (c) 2015 - 2016
* @license MIT * @license MIT
*/ */
namespace Aviat\Ion; namespace Aviat\Ion;
/** /**
* Common base for all Models * Common base for all Models
*/ */
class Model { class Model {
use StringWrapper; use StringWrapper;
} }
// End of Model.php // End of Model.php

View File

@ -1,51 +1,51 @@
<?php <?php
/** /**
* Ion * Ion
* *
* Building blocks for web development * Building blocks for web development
* *
* @package Ion * @package Ion
* @author Timothy J. Warren * @author Timothy J. Warren
* @copyright Copyright (c) 2015 - 2016 * @copyright Copyright (c) 2015 - 2016
* @license MIT * @license MIT
*/ */
namespace Aviat\Ion\Model; namespace Aviat\Ion\Model;
use Aviat\Ion\ConfigInterface; use Aviat\Ion\ConfigInterface;
use Aviat\Ion\Model as BaseModel; use Aviat\Ion\Model as BaseModel;
/** /**
* Base model for database interaction * Base model for database interaction
*/ */
class DB extends BaseModel { class DB extends BaseModel {
/** /**
* The query builder object * The query builder object
* @var object $db * @var object $db
*/ */
protected $db; protected $db;
/** /**
* The config manager * The config manager
* @var ConfigInterface * @var ConfigInterface
*/ */
protected $config; protected $config;
/** /**
* The database connection information array * The database connection information array
* @var array $db_config * @var array $db_config
*/ */
protected $db_config; protected $db_config;
/** /**
* Constructor * Constructor
* *
* @param ConfigInterface $config * @param ConfigInterface $config
*/ */
public function __construct(ConfigInterface $config) public function __construct(ConfigInterface $config)
{ {
$this->config = $config; $this->config = $config;
$this->db_config = (array)$config->get('database'); $this->db_config = (array)$config->get('database');
} }
} }
// End of DB.php // End of DB.php

View File

@ -30,7 +30,7 @@ trait StaticInstance {
* *
* @codeCoverageIgnore * @codeCoverageIgnore
* @param string $method * @param string $method
* @param array $args * @param array $args
* @retun mixed * @retun mixed
*/ */
public function __call($method, $args) public function __call($method, $args)
@ -46,7 +46,7 @@ trait StaticInstance {
* an instance of the class isn't required * an instance of the class isn't required
* *
* @param string $method * @param string $method
* @param array $args * @param array $args
* @return mixed * @return mixed
*/ */
public static function __callStatic($method, $args) public static function __callStatic($method, $args)

View File

@ -80,7 +80,7 @@ class ArrayType {
* Call one of the dynamically created methods * Call one of the dynamically created methods
* *
* @param string $method * @param string $method
* @param array $args * @param array $args
* @return mixed * @return mixed
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*/ */
@ -120,8 +120,8 @@ class ArrayType {
/** /**
* Fill an array with the specified value * Fill an array with the specified value
* *
* @param int $start_index * @param int $start_index
* @param int $num * @param int $num
* @param mixed $value * @param mixed $value
* @return array * @return array
*/ */
@ -145,7 +145,7 @@ class ArrayType {
* Find an array key by its associated value * Find an array key by its associated value
* *
* @param mixed $value * @param mixed $value
* @param bool $strict * @param bool $strict
* @return false|integer|string * @return false|integer|string
*/ */
public function search($value, $strict = FALSE) public function search($value, $strict = FALSE)
@ -157,7 +157,7 @@ class ArrayType {
* Determine if the array has the passed value * Determine if the array has the passed value
* *
* @param mixed $value * @param mixed $value
* @param bool $strict * @param bool $strict
* @return bool * @return bool
*/ */
public function has($value, $strict = FALSE) public function has($value, $strict = FALSE)
@ -233,7 +233,7 @@ class ArrayType {
* Sets the value of an arbitrarily deep key in the array * Sets the value of an arbitrarily deep key in the array
* and returns the modified array * and returns the modified array
* *
* @param array $key * @param array $key
* @param mixed $value * @param mixed $value
* @return array * @return array
*/ */

View File

@ -12,13 +12,16 @@
namespace Aviat\Ion; namespace Aviat\Ion;
use Psr\Http\Message\ResponseInterface;
use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\Exception\DoubleRenderException;
use Aviat\Ion\Type\StringType; use Aviat\Ion\Type\StringType;
/** /**
* Base view response class * Base view response class
*/ */
abstract class View { abstract class View /* partially */ implements ViewInterface {
use Di\ContainerAware; use Di\ContainerAware;
use StringWrapper; use StringWrapper;
@ -26,31 +29,10 @@ abstract class View {
/** /**
* HTTP response Object * HTTP response Object
* *
* @var Zend\Diactoros\Response * @var ResponseInterface
*/ */
public $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 * If the view has sent output via
* __toString or send method * __toString or send method
@ -68,7 +50,6 @@ abstract class View {
{ {
$this->setContainer($container); $this->setContainer($container);
$this->response = $container->get('response'); $this->response = $container->get('response');
$this->redirectResponse = NULL;
} }
/** /**
@ -83,21 +64,20 @@ abstract class View {
} }
/** /**
* Return rendered output * @inheritdoc
*
* @return string
*/ */
public function __toString() public function __toString()
{ {
if ($this->hasRendered)
{
throw new DoubleRenderException();
}
$this->hasRendered = TRUE; $this->hasRendered = TRUE;
return $this->getOutput(); return $this->getOutput();
} }
/** /**
* Set the output string * @inheritdoc
*
* @param string $string
* @return View
*/ */
public function setOutput($string) public function setOutput($string)
{ {
@ -107,10 +87,7 @@ abstract class View {
} }
/** /**
* Append additional output * @inheritdoc
*
* @param string $string
* @return View
*/ */
public function appendOutput($string) public function appendOutput($string)
{ {
@ -118,20 +95,11 @@ abstract class View {
} }
/** /**
* Get the current output string * @inheritdoc
*
* @return string
*/ */
public function getOutput() public function getOutput()
{ {
return $this->response->getBody()->__toString(); return $this->response->getBody()->__toString();
} }
/**
* Send output to client
*
* @return void
*/
abstract public function send();
} }
// End of View.php // End of View.php

View File

@ -26,6 +26,13 @@ class HtmlView extends HttpView {
*/ */
protected $helper; protected $helper;
/**
* Response mime type
*
* @var string
*/
protected $contentType = 'text/html';
/** /**
* Create the Html View * Create the Html View
* *
@ -37,18 +44,11 @@ class HtmlView extends HttpView {
$this->helper = $container->get('html-helper'); $this->helper = $container->get('html-helper');
} }
/**
* Response mime type
*
* @var string
*/
protected $contentType = 'text/html';
/** /**
* Render a basic html Template * Render a basic html Template
* *
* @param string $path * @param string $path
* @param array $data * @param array $data
* @return string * @return string
*/ */
public function render_template($path, $data) public function render_template($path, $data)

View File

@ -12,8 +12,9 @@
namespace Aviat\Ion\View; namespace Aviat\Ion\View;
use Zend\Diactoros\Response;
use Zend\Diactoros\Response\SapiEmitter; use Zend\Diactoros\Response\SapiEmitter;
use Aviat\Ion\Exception\DoubleRenderException;
use Aviat\Ion\View as BaseView; use Aviat\Ion\View as BaseView;
/** /**
@ -21,12 +22,19 @@ use Aviat\Ion\View as BaseView;
*/ */
class HttpView extends BaseView { class HttpView extends BaseView {
/**
* Response mime type
*
* @var string
*/
protected $contentType = '';
/** /**
* Do a redirect * Do a redirect
* *
* @codeCoverageIgnore * @codeCoverageIgnore
* @param string $url * @param string $url
* @param int $code * @param int $code
* @return void * @return void
*/ */
public function redirect($url, $code) public function redirect($url, $code)
@ -60,13 +68,10 @@ class HttpView extends BaseView {
} }
/** /**
* Send output to client * @inheritdoc
*
* @return void
*/ */
public function send() public function send()
{ {
$this->hasRendered = TRUE;
$this->output(); $this->output();
} }
@ -74,11 +79,17 @@ class HttpView extends BaseView {
* Send the appropriate response * Send the appropriate response
* *
* @codeCoverageIgnore * @codeCoverageIgnore
* @throws DoubleRenderException
* @return void * @return void
*/ */
protected function output() protected function output()
{ {
$this->response->withHeader('Content-type', "{$this->contentType};charset=utf-8") if ($this->hasRendered)
{
throw new DoubleRenderException();
}
$this->response = $this->response->withHeader('Content-type', "{$this->contentType};charset=utf-8")
->withHeader('Content-Security-Policy', "script-src 'self'") ->withHeader('Content-Security-Policy', "script-src 'self'")
->withHeader('X-Content-Type-Options', 'nosniff') ->withHeader('X-Content-Type-Options', 'nosniff')
->withHeader('X-XSS-Protection', '1;mode=block') ->withHeader('X-XSS-Protection', '1;mode=block')
@ -86,6 +97,7 @@ class HttpView extends BaseView {
$sender = new SapiEmitter($this->response); $sender = new SapiEmitter($this->response);
$sender->emit($this->response); $sender->emit($this->response);
}
$this->hasRendered = TRUE;
}
} }

View File

@ -13,8 +13,7 @@
namespace Aviat\Ion\View; namespace Aviat\Ion\View;
use Aviat\Ion\Json; use Aviat\Ion\Json;
use Aviat\Ion\View\HttpView; use Aviat\Ion\ViewInterface;
use Aviat\Ion\View as BaseView;
/** /**
* View class to serialize Json * View class to serialize Json
@ -32,7 +31,7 @@ class JsonView extends HttpView {
* Set the output string * Set the output string
* *
* @param mixed $string * @param mixed $string
* @return BaseView * @return ViewInterface
*/ */
public function setOutput($string) public function setOutput($string)
{ {

62
src/Ion/ViewInterface.php Normal file
View 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;
use Aviat\Ion\Exception\DoubleRenderException;
/**
* View Interface abstracting a Response
*/
interface ViewInterface {
/**
* Return rendered output as string. Renders the view,
* and any attempts to call again will result in a DoubleRenderException
*
* @throws DoubleRenderException
* @return string
*/
public function __toString();
/**
* Set the output string
*
* @param string $string
* @return ViewInterface
*/
public function setOutput($string);
/**
* Append additional output.
*
* @param string $string
* @return ViewInterface
*/
public function appendOutput($string);
/**
* Get the current output as a string. Does not
* render view or send headers.
*
* @return string
*/
public function getOutput();
/**
* Send output to client. As it renders the view,
* any attempt to call again will result in a DoubleRenderException.
*
* @throws DoubleRenderException
* @return void
*/
public function send();
}

View File

@ -1,15 +1,17 @@
<?php <?php
namespace Aviat\Ion\Tests\Cache;
use Aviat\Ion\Friend; use Aviat\Ion\Friend;
use Aviat\Ion\Cache\CacheManager; use Aviat\Ion\Cache\CacheManager;
class CacheManagerText extends Ion_TestCase { class CacheManagerTest extends \Ion_TestCase {
protected $cachedTime; protected $cachedTime;
public function __call($name, $args) public function __call($name, $args)
{ {
return call_user_func_array($name, $args); return \call_user_func_array($name, $args);
} }
public function setUp() public function setUp()

View File

@ -0,0 +1,14 @@
<?php
use Aviat\Ion\Exception\DoubleRenderException;
class DoubleRenderExceptionTest extends Ion_TestCase {
public function testDefaultMessage()
{
$this->expectException(DoubleRenderException::class);
$this->expectExceptionMessage('A view can only be rendered once, because headers can only be sent once.');
throw new DoubleRenderException();
}
}

View File

@ -1,9 +1,11 @@
<?php <?php
namespace Aviat\Ion\Tests;
use Aviat\Ion\Json; use Aviat\Ion\Json;
use Aviat\Ion\JsonException; use Aviat\Ion\JsonException;
class JsonTest extends Ion_TestCase { class JsonTest extends \Ion_TestCase {
public function testEncode() public function testEncode()
{ {

View File

@ -1,6 +1,6 @@
<?php <?php
include_once __DIR__ . "/HttpViewTest.php"; namespace Aviat\Ion\Tests\View;
class HtmlViewTest extends HttpViewTest { class HtmlViewTest extends HttpViewTest {
@ -9,7 +9,7 @@ class HtmlViewTest extends HttpViewTest {
public function setUp() public function setUp()
{ {
parent::setUp(); parent::setUp();
$this->view = new TestHtmlView($this->container); $this->view = new \TestHtmlView($this->container);
} }
public function testRenderTemplate() public function testRenderTemplate()

View File

@ -1,8 +1,11 @@
<?php <?php
use Aviat\Ion\Friend; namespace Aviat\Ion\Tests\View;
class HttpViewTest extends Ion_TestCase { use Aviat\Ion\Friend;
use Aviat\Ion\Exception\DoubleRenderException;
class HttpViewTest extends \Ion_TestCase {
protected $view; protected $view;
protected $friend; protected $friend;
@ -10,7 +13,7 @@ class HttpViewTest extends Ion_TestCase {
public function setUp() public function setUp()
{ {
parent::setUp(); parent::setUp();
$this->view = new TestHttpView($this->container); $this->view = new \TestHttpView($this->container);
$this->friend = new Friend($this->view); $this->friend = new Friend($this->view);
} }
@ -43,4 +46,28 @@ class HttpViewTest extends Ion_TestCase {
$view = $this->view->setStatusCode(404); $view = $this->view->setStatusCode(404);
$this->assertEquals(404, $view->response->getStatusCode()); $this->assertEquals(404, $view->response->getStatusCode());
} }
public function testSendDoubleRenderException()
{
$this->expectException(DoubleRenderException::class);
$this->expectExceptionMessage('A view can only be rendered once, because headers can only be sent once.');
// First render
$this->view->__toString();
// Second render
$this->view->send();
}
public function test__toStringDoubleRenderException()
{
$this->expectException(DoubleRenderException::class);
$this->expectExceptionMessage('A view can only be rendered once, because headers can only be sent once.');
// First render
$this->view->send();
// Second render
$this->view->__toString();
}
} }

View File

@ -1,8 +1,8 @@
<?php <?php
use Aviat\Ion\Friend; namespace Aviat\Ion\Tests\View;
include_once __DIR__ . "/HttpViewTest.php"; use Aviat\Ion\Friend;
class JsonViewTest extends HttpViewTest { class JsonViewTest extends HttpViewTest {
@ -10,14 +10,14 @@ class JsonViewTest extends HttpViewTest {
{ {
parent::setUp(); parent::setUp();
$this->view = new TestJsonView($this->container); $this->view = new \TestJsonView($this->container);
$this->friend = new Friend($this->view); $this->friend = new Friend($this->view);
} }
public function testSetOutputJSON() public function testSetOutputJSON()
{ {
// Extend view class to remove destructor which does output // Extend view class to remove destructor which does output
$view = new TestJsonView($this->container); $view = new \TestJsonView($this->container);
// Json encode non-string // Json encode non-string
$content = ['foo' => 'bar']; $content = ['foo' => 'bar'];
@ -29,7 +29,7 @@ class JsonViewTest extends HttpViewTest {
public function testSetOutput() public function testSetOutput()
{ {
// Directly set string // Directly set string
$view = new TestJsonView($this->container); $view = new \TestJsonView($this->container);
$content = '{}'; $content = '{}';
$expected = '{}'; $expected = '{}';
$view->setOutput($content); $view->setOutput($content);

View File

@ -35,30 +35,13 @@ require 'Ion_TestCase.php';
// Composer autoload // Composer autoload
require __DIR__ . '/../vendor/autoload.php'; 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 Settings
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
ini_set('session.use_cookies', 0); ini_set('session.use_cookies', 0);
ini_set("session.use_only_cookies",0); ini_set("session.use_only_cookies",0);
ini_set("session.use_trans_sid",1); ini_set("session.use_trans_sid",1);
// Start session here to supress error about headers not sent // Start session here to surpress error about headers not sent
session_start(); session_start();
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -4,6 +4,7 @@
*/ */
use Aviat\Ion\Enum; use Aviat\Ion\Enum;
use Aviat\Ion\Exception\DoubleRenderException;
use Aviat\Ion\Friend; use Aviat\Ion\Friend;
use Aviat\Ion\Transformer\AbstractTransformer; use Aviat\Ion\Transformer\AbstractTransformer;
use Aviat\Ion\View; use Aviat\Ion\View;
@ -70,7 +71,7 @@ class TestTransformer extends AbstractTransformer {
} }
trait MockViewOutputTrait { trait MockViewOutputTrait {
protected function output() { /*protected function output() {
$reflect = new ReflectionClass($this); $reflect = new ReflectionClass($this);
$properties = $reflect->getProperties(); $properties = $reflect->getProperties();
$props = []; $props = [];
@ -88,31 +89,69 @@ trait MockViewOutputTrait {
$friend->__set($name, $val); $friend->__set($name, $val);
} }
$friend->output(); //$friend->output();
}*/
public function send()
{
if ($this->hasRendered)
{
throw new DoubleRenderException();
}
$this->hasRendered = TRUE;
} }
} }
class TestView extends View { class TestView extends View {
public function send() {} public function send()
protected function output()
{ {
/*$content =& $this->response->content; if ($this->hasRendered)
$content->set($this->output); {
$content->setType($this->contentType); throw new DoubleRenderException();
$content->setCharset('utf-8');*/ }
$this->hasRendered = TRUE;
} }
public function output() {}
} }
class TestHtmlView extends HtmlView { class TestHtmlView extends HtmlView {
use MockViewOutputTrait; protected function output()
{
if ($this->hasRendered)
{
throw new DoubleRenderException();
}
$this->hasRendered = TRUE;
}
} }
class TestHttpView extends HttpView { class TestHttpView extends HttpView {
use MockViewOutputTrait; protected function output()
{
if ($this->hasRendered)
{
throw new DoubleRenderException();
}
$this->hasRendered = TRUE;
}
} }
class TestJsonView extends JsonView { class TestJsonView extends JsonView {
public function __destruct() {} public function __destruct() {}
protected function output()
{
if ($this->hasRendered)
{
throw new DoubleRenderException();
}
$this->hasRendered = TRUE;
}
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------