From 9fc3d60835427490fa160a847faadf6ca4b74182 Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Mon, 18 Jul 2016 09:47:34 -0400 Subject: [PATCH 01/65] First attempt at setting up gitlab ci --- .gitlab-ci.yml | 21 +++++++++++++++++++++ build/docker_install.sh | 22 ++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 .gitlab-ci.yml create mode 100644 build/docker_install.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..b74a5032 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,21 @@ +before_script: + # Install dependencies + - bash build/docker_install.sh > /dev/null + +services: + - redis:latest + +test:5.5: + image: php:5.5 + script: + - phpunit -c build + +test:5.6: + image: php:5.6 + script: + - phpunit -c build + +test:7: + image: php:7 + script: + - phpunit -c build \ No newline at end of file diff --git a/build/docker_install.sh b/build/docker_install.sh new file mode 100644 index 00000000..f2c8e053 --- /dev/null +++ b/build/docker_install.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# We need to install dependencies only for Docker +[[ ! -e /.dockerenv ]] && [[ ! -e /.dockerinit ]] && exit 0 + +set -xe + +# Install git (the php image doesn't have it) which is required by composer +# And for some reason apt-utils is not installed +apt-get update -yqq +apt-get install apt-utils +apt-get install git sqlite3 -yqq + +# Install phpunit, the tool that we will use for testing +curl -Lo /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar +chmod +x /usr/local/bin/phpunit + +# Install mysql driver +# Here you can install any other extension that you need +docker-php-ext-install pdo_sqlite +pecl install redis +docker-php-ext-enable redis \ No newline at end of file From 3f7711dd204f03dc7dc53a355aec3833611aced1 Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Mon, 18 Jul 2016 09:55:06 -0400 Subject: [PATCH 02/65] Gitlab CI take two --- .gitlab-ci.yml | 10 ++++++++++ build/docker_install.sh | 2 -- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b74a5032..718b39a5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,16 @@ before_script: # Install dependencies - bash build/docker_install.sh > /dev/null + # Install composer dependencies + - curl -sS https://getcomposer.org/installer | php + - php composer.phar install + +# 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 diff --git a/build/docker_install.sh b/build/docker_install.sh index f2c8e053..784e6a34 100644 --- a/build/docker_install.sh +++ b/build/docker_install.sh @@ -6,9 +6,7 @@ set -xe # Install git (the php image doesn't have it) which is required by composer -# And for some reason apt-utils is not installed apt-get update -yqq -apt-get install apt-utils apt-get install git sqlite3 -yqq # Install phpunit, the tool that we will use for testing From 8ba6e83032ce0316ce10e3cdd80d47b58604849b Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Mon, 18 Jul 2016 09:58:23 -0400 Subject: [PATCH 03/65] Make sure docker sh script doesn't have CRLF line endings --- .gitlab-ci.yml | 60 ++++++++++++++++++++--------------------- build/docker_install.sh | 38 +++++++++++++------------- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 718b39a5..373e92c3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,31 +1,31 @@ -before_script: - # Install dependencies - - bash build/docker_install.sh > /dev/null - # Install composer dependencies - - curl -sS https://getcomposer.org/installer | php - - php composer.phar install - -# 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.5: - image: php:5.5 - script: - - phpunit -c build - -test:5.6: - image: php:5.6 - script: - - phpunit -c build - -test:7: - image: php:7 - script: +before_script: + # Install dependencies + - bash build/docker_install.sh > /dev/null + # Install composer dependencies + - curl -sS https://getcomposer.org/installer | php + - php composer.phar install + +# 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.5: + image: php:5.5 + script: + - phpunit -c build + +test:5.6: + image: php:5.6 + script: + - phpunit -c build + +test:7: + image: php:7 + script: - phpunit -c build \ No newline at end of file diff --git a/build/docker_install.sh b/build/docker_install.sh index 784e6a34..16465a8d 100644 --- a/build/docker_install.sh +++ b/build/docker_install.sh @@ -1,20 +1,20 @@ -#!/bin/bash - -# We need to install dependencies only for Docker -[[ ! -e /.dockerenv ]] && [[ ! -e /.dockerinit ]] && exit 0 - -set -xe - -# Install git (the php image doesn't have it) which is required by composer -apt-get update -yqq -apt-get install git sqlite3 -yqq - -# Install phpunit, the tool that we will use for testing -curl -Lo /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar -chmod +x /usr/local/bin/phpunit - -# Install mysql driver -# Here you can install any other extension that you need -docker-php-ext-install pdo_sqlite -pecl install redis +#!/bin/bash + +# We need to install dependencies only for Docker +[[ ! -e /.dockerenv ]] && [[ ! -e /.dockerinit ]] && exit 0 + +set -xe + +# Install git (the php image doesn't have it) which is required by composer +apt-get update -yqq +apt-get install git sqlite3 -yqq + +# Install phpunit, the tool that we will use for testing +curl -Lo /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar +chmod +x /usr/local/bin/phpunit + +# Install mysql driver +# Here you can install any other extension that you need +docker-php-ext-install pdo_sqlite +pecl install redis docker-php-ext-enable redis \ No newline at end of file From 229387a972b16b07f311dc30ae6f35d5071975b2 Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Mon, 18 Jul 2016 10:07:50 -0400 Subject: [PATCH 04/65] Gitlab CI take 3 --- build/docker_install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/docker_install.sh b/build/docker_install.sh index 16465a8d..64a5c64e 100644 --- a/build/docker_install.sh +++ b/build/docker_install.sh @@ -7,7 +7,7 @@ set -xe # Install git (the php image doesn't have it) which is required by composer apt-get update -yqq -apt-get install git sqlite3 -yqq +apt-get install git libsqlite3-dev -yqq # Install phpunit, the tool that we will use for testing curl -Lo /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar From 691387b7c9e29838498617e1d35dd1862a0141d0 Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Mon, 18 Jul 2016 10:16:21 -0400 Subject: [PATCH 05/65] Attempt tests without redis for now --- build/docker_install.sh | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/build/docker_install.sh b/build/docker_install.sh index 64a5c64e..68babfdc 100644 --- a/build/docker_install.sh +++ b/build/docker_install.sh @@ -7,14 +7,8 @@ set -xe # Install git (the php image doesn't have it) which is required by composer apt-get update -yqq -apt-get install git libsqlite3-dev -yqq +apt-get install git -yqq # Install phpunit, the tool that we will use for testing curl -Lo /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar -chmod +x /usr/local/bin/phpunit - -# Install mysql driver -# Here you can install any other extension that you need -docker-php-ext-install pdo_sqlite -pecl install redis -docker-php-ext-enable redis \ No newline at end of file +chmod +x /usr/local/bin/phpunit \ No newline at end of file From 1f804919687853f5006a432cf18a85a2990bf98a Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Mon, 18 Jul 2016 12:47:51 -0400 Subject: [PATCH 06/65] Another attempt at getting gitlab ci to run --- .gitlab-ci.yml | 5 ----- build/docker_install.sh | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 373e92c3..78229a40 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,11 +15,6 @@ cache: services: - redis:latest -test:5.5: - image: php:5.5 - script: - - phpunit -c build - test:5.6: image: php:5.6 script: diff --git a/build/docker_install.sh b/build/docker_install.sh index 68babfdc..d2e3ead8 100644 --- a/build/docker_install.sh +++ b/build/docker_install.sh @@ -7,7 +7,7 @@ set -xe # Install git (the php image doesn't have it) which is required by composer apt-get update -yqq -apt-get install git -yqq +apt-get install git unzip -yqq # Install phpunit, the tool that we will use for testing curl -Lo /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar From c0c90eb56522fb40d743d873d1cf8b5bb0116fb7 Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Mon, 18 Jul 2016 12:59:34 -0400 Subject: [PATCH 07/65] Make tests skip redis integration if the extension is not installed --- tests/Ion/Cache/Driver/RedisDriver2Test.php | 35 ++++++++++++++------- tests/Ion/Cache/Driver/RedisDriverTest.php | 17 ++++++++-- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/tests/Ion/Cache/Driver/RedisDriver2Test.php b/tests/Ion/Cache/Driver/RedisDriver2Test.php index 4f2ecead..b6b6ecaa 100644 --- a/tests/Ion/Cache/Driver/RedisDriver2Test.php +++ b/tests/Ion/Cache/Driver/RedisDriver2Test.php @@ -15,22 +15,33 @@ class CacheRedisDriverTestTwo extends AnimeClient_TestCase { { parent::setUp(); - // Setup config with port and password - $container = new Container(); - $container->set('config', new Config([ - 'redis' => [ - 'host' => 'localhost', - 'port' => 6379, - 'password' => '', - 'database' => 13, - ] - ])); - $this->driver = new RedisDriver($container); + if ( ! class_exists('Redis')) + { + $this->markTestSkipped('Redis extension not installed'); + } + else + { + // Setup config with port and password + $container = new Container(); + $container->set('config', new Config([ + 'redis' => [ + 'host' => 'localhost', + 'port' => 6379, + 'password' => '', + 'database' => 13, + ] + ])); + $this->driver = new RedisDriver($container); + } } public function tearDown() { parent::tearDown(); - $this->driver->__destruct(); + + if ( ! is_null($this->driver)) + { + $this->driver->__destruct(); + } } } \ No newline at end of file diff --git a/tests/Ion/Cache/Driver/RedisDriverTest.php b/tests/Ion/Cache/Driver/RedisDriverTest.php index 171a3324..9200dc61 100644 --- a/tests/Ion/Cache/Driver/RedisDriverTest.php +++ b/tests/Ion/Cache/Driver/RedisDriverTest.php @@ -12,12 +12,25 @@ class CacheRedisDriverTest extends AnimeClient_TestCase { public function setUp() { parent::setUp(); - $this->driver = new RedisDriver($this->container); + + if ( ! class_exists('Redis')) + { + $this->markTestSkipped('Redis extension not installed'); + } + else + { + $this->driver = new RedisDriver($this->container); + } } public function tearDown() { parent::tearDown(); - $this->driver->__destruct(); + + if ( ! is_null($this->driver)) + { + $this->driver->__destruct(); + } + } } \ No newline at end of file From 23fa88bb334cd9208fcf45c1e0090f79d0eff366 Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Mon, 18 Jul 2016 13:06:37 -0400 Subject: [PATCH 08/65] Set default timezone to prevent stupid test errors --- tests/bootstrap.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index b988e8c1..9df960d1 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -6,6 +6,14 @@ use Aviat\Ion\Json; use Aviat\AnimeClient\AnimeClient; +// Work around the silly timezone error +$timezone = ini_get('date.timezone'); +if ($timezone === '' || $timezone === FALSE) +{ + ini_set('date.timezone', 'GMT'); +} + + // ----------------------------------------------------------------------------- // Global functions // ----------------------------------------------------------------------------- From d54d180090b45629950b4b532444bbf7c2f9d034 Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Tue, 19 Jul 2016 10:17:53 -0400 Subject: [PATCH 09/65] Fix failing test by installing gd in gitlab ci test --- build/docker_install.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/build/docker_install.sh b/build/docker_install.sh index d2e3ead8..e2bdfa21 100644 --- a/build/docker_install.sh +++ b/build/docker_install.sh @@ -7,8 +7,15 @@ set -xe # Install git (the php image doesn't have it) which is required by composer apt-get update -yqq -apt-get install git unzip -yqq +apt-get install git unzip libfreetype6 libjpeg62-turbo libmcrypt4 libpng12-0 sendmail -yqq # Install phpunit, the tool that we will use for testing curl -Lo /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar -chmod +x /usr/local/bin/phpunit \ No newline at end of file +chmod +x /usr/local/bin/phpunit + +# Install gd +docker-php-ext-configure gd --enable-gd-native-ttf --with-jpeg-dir=/usr/lib/x86_64-linux-gnu --with-png-dir=/usr/lib/x86_64-linux-gnu --with-freetype-dir=/usr/lib/x86_64-linux-gnu +docker-php-ext-install gd +docker-php-ext-install mcrypt +docker-php-ext-install mbstring +docker-php-ext-install zip \ No newline at end of file From b61f0b5e6cbef067ad77109a6c3da66abcc07357 Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Tue, 19 Jul 2016 10:25:54 -0400 Subject: [PATCH 10/65] Attempt 2 to install gd in gitlab ci tests --- build/docker_install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/docker_install.sh b/build/docker_install.sh index e2bdfa21..add8adbe 100644 --- a/build/docker_install.sh +++ b/build/docker_install.sh @@ -7,7 +7,7 @@ set -xe # Install git (the php image doesn't have it) which is required by composer apt-get update -yqq -apt-get install git unzip libfreetype6 libjpeg62-turbo libmcrypt4 libpng12-0 sendmail -yqq +apt-get install git unzip libfreetype6 libjpeg62-turbo libmcrypt4 libpng12-0 libfreetype6-dev libjpeg-dev libmcrypt-dev libpng12-dev zlib1g-dev -yqq # Install phpunit, the tool that we will use for testing curl -Lo /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar From 0632ebba6645434e697579618ec6db82d174ac4e Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Tue, 19 Jul 2016 10:45:16 -0400 Subject: [PATCH 11/65] Remove redundant mbstring extesion from build setup --- build/docker_install.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/build/docker_install.sh b/build/docker_install.sh index add8adbe..14aabcd5 100644 --- a/build/docker_install.sh +++ b/build/docker_install.sh @@ -17,5 +17,4 @@ chmod +x /usr/local/bin/phpunit docker-php-ext-configure gd --enable-gd-native-ttf --with-jpeg-dir=/usr/lib/x86_64-linux-gnu --with-png-dir=/usr/lib/x86_64-linux-gnu --with-freetype-dir=/usr/lib/x86_64-linux-gnu docker-php-ext-install gd docker-php-ext-install mcrypt -docker-php-ext-install mbstring docker-php-ext-install zip \ No newline at end of file From 4772c6df95721fc05abff620a3a84c3a74fced80 Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Fri, 22 Jul 2016 17:22:00 -0400 Subject: [PATCH 12/65] Update Redis cache driver to use PHP-only library, removing the dependence on an extension: --- app/config/redis.toml.example | 1 + composer.json | 1 + src/Aviat/Ion/Cache/Driver/RedisDriver.php | 36 ++++++++------------- tests/Ion/Cache/Driver/CacheDriverBase.php | 2 ++ tests/Ion/Cache/Driver/RedisDriver2Test.php | 29 +++++++---------- tests/Ion/Cache/Driver/RedisDriverTest.php | 9 +----- 6 files changed, 29 insertions(+), 49 deletions(-) diff --git a/app/config/redis.toml.example b/app/config/redis.toml.example index c45ea3c1..a3f7b996 100644 --- a/app/config/redis.toml.example +++ b/app/config/redis.toml.example @@ -3,6 +3,7 @@ ################################################################################ # Host or socket to connect to +# Socket must be prefixed with 'unix:' host = "127.0.0.1" # Connection port diff --git a/composer.json b/composer.json index 018dcfe7..bf012bc2 100644 --- a/composer.json +++ b/composer.json @@ -13,6 +13,7 @@ "filp/whoops": "2.0.*", "guzzlehttp/guzzle": "6.*", "monolog/monolog": "1.*", + "predis/predis": "1.1.*", "psr/http-message": "~1.0", "psr/log": "~1.0", "robmorgan/phinx": "0.4.*", diff --git a/src/Aviat/Ion/Cache/Driver/RedisDriver.php b/src/Aviat/Ion/Cache/Driver/RedisDriver.php index 3fedc6e0..db265e13 100644 --- a/src/Aviat/Ion/Cache/Driver/RedisDriver.php +++ b/src/Aviat/Ion/Cache/Driver/RedisDriver.php @@ -13,8 +13,11 @@ namespace Aviat\Ion\Cache\Driver; use Aviat\Ion\Di\ContainerInterface; +use Aviat\Ion\Cache\CacheDriverInterface; -class RedisDriver implements \Aviat\Ion\Cache\CacheDriverInterface { +use Predis\Client; + +class RedisDriver implements CacheDriverInterface { /** * The redis extension class instance @@ -29,34 +32,21 @@ class RedisDriver implements \Aviat\Ion\Cache\CacheDriverInterface { { $config = $container->get('config'); $redisConfig = $config->get('redis'); - - $this->redis = new \Redis(); - - (array_key_exists('port', $redisConfig)) - ? $this->redis->pconnect($redisConfig['host'], $redisConfig['port']) - : $this->redis->pconnect($redisConfig['host']); - - // If there is a password, authorize - if (array_key_exists('password', $redisConfig)) + + if (array_key_exists('password', $redisConfig) && $redisConfig['password'] === '') { - $this->redis->auth($redisConfig['password']); + unset($redisConfig['password']); } - // If there is a database selected, connect to the specified database - if (array_key_exists('database', $redisConfig)) - { - $this->redis->select($redisConfig['database']); - } - - $this->redis->setOption(\Redis::OPT_SERIALIZER, \Redis::SERIALIZER_PHP); + $this->redis = new Client($redisConfig); } - + /** - * Destructor to disconnect from redis + * Disconnect from redis */ public function __destruct() { - $this->redis->close(); + $this->redis = null; } /** @@ -67,7 +57,7 @@ class RedisDriver implements \Aviat\Ion\Cache\CacheDriverInterface { */ public function get($key) { - return $this->redis->get($key); + return unserialize($this->redis->get($key)); } /** @@ -79,7 +69,7 @@ class RedisDriver implements \Aviat\Ion\Cache\CacheDriverInterface { */ public function set($key, $value) { - $this->redis->set($key, $value); + $this->redis->set($key, serialize($value)); return $this; } diff --git a/tests/Ion/Cache/Driver/CacheDriverBase.php b/tests/Ion/Cache/Driver/CacheDriverBase.php index e0ba7a94..d1e333aa 100644 --- a/tests/Ion/Cache/Driver/CacheDriverBase.php +++ b/tests/Ion/Cache/Driver/CacheDriverBase.php @@ -18,7 +18,9 @@ trait CacheDriverBase { 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() diff --git a/tests/Ion/Cache/Driver/RedisDriver2Test.php b/tests/Ion/Cache/Driver/RedisDriver2Test.php index b6b6ecaa..8bcbb0b9 100644 --- a/tests/Ion/Cache/Driver/RedisDriver2Test.php +++ b/tests/Ion/Cache/Driver/RedisDriver2Test.php @@ -15,24 +15,17 @@ class CacheRedisDriverTestTwo extends AnimeClient_TestCase { { parent::setUp(); - if ( ! class_exists('Redis')) - { - $this->markTestSkipped('Redis extension not installed'); - } - else - { - // Setup config with port and password - $container = new Container(); - $container->set('config', new Config([ - 'redis' => [ - 'host' => 'localhost', - 'port' => 6379, - 'password' => '', - 'database' => 13, - ] - ])); - $this->driver = new RedisDriver($container); - } + // Setup config with port and password + $container = new Container(); + $container->set('config', new Config([ + 'redis' => [ + 'host' => 'localhost', + 'port' => 6379, + 'password' => '', + 'database' => 13, + ] + ])); + $this->driver = new RedisDriver($container); } public function tearDown() diff --git a/tests/Ion/Cache/Driver/RedisDriverTest.php b/tests/Ion/Cache/Driver/RedisDriverTest.php index 9200dc61..3ae45a9a 100644 --- a/tests/Ion/Cache/Driver/RedisDriverTest.php +++ b/tests/Ion/Cache/Driver/RedisDriverTest.php @@ -13,14 +13,7 @@ class CacheRedisDriverTest extends AnimeClient_TestCase { { parent::setUp(); - if ( ! class_exists('Redis')) - { - $this->markTestSkipped('Redis extension not installed'); - } - else - { - $this->driver = new RedisDriver($this->container); - } + $this->driver = new RedisDriver($this->container); } public function tearDown() From 5a69da4466b600d1b2c3a39d0df858674aecfc22 Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Fri, 22 Jul 2016 17:48:13 -0400 Subject: [PATCH 13/65] Update Redis tests to work with gitlab ci --- src/Aviat/Ion/Cache/Driver/SQLDriver.php | 3 ++- tests/Ion/Cache/Driver/RedisDriver2Test.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Aviat/Ion/Cache/Driver/SQLDriver.php b/src/Aviat/Ion/Cache/Driver/SQLDriver.php index c8a51dd2..dc1c47ef 100644 --- a/src/Aviat/Ion/Cache/Driver/SQLDriver.php +++ b/src/Aviat/Ion/Cache/Driver/SQLDriver.php @@ -13,12 +13,13 @@ namespace Aviat\Ion\Cache\Driver; use Aviat\Ion\Di\ContainerInterface; +use Aviat\Ion\Cache\CacheDriverInterface; use Aviat\AnimeClient\Model\DB; /** * Driver for caching via a traditional SQL database */ -class SQLDriver extends DB implements \Aviat\Ion\Cache\CacheDriverInterface { +class SQLDriver extends DB implements CacheDriverInterface { /** * The query builder object diff --git a/tests/Ion/Cache/Driver/RedisDriver2Test.php b/tests/Ion/Cache/Driver/RedisDriver2Test.php index 8bcbb0b9..35317251 100644 --- a/tests/Ion/Cache/Driver/RedisDriver2Test.php +++ b/tests/Ion/Cache/Driver/RedisDriver2Test.php @@ -19,7 +19,7 @@ class CacheRedisDriverTestTwo extends AnimeClient_TestCase { $container = new Container(); $container->set('config', new Config([ 'redis' => [ - 'host' => 'localhost', + 'host' => (array_key_exists('REDIS_HOST', $_ENV)) ? $_ENV['REDIS_HOST'] : 'localhost', 'port' => 6379, 'password' => '', 'database' => 13, From fec9de0e3db233f1a5367451a1d01c651b7640e9 Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Mon, 25 Jul 2016 11:58:43 -0400 Subject: [PATCH 14/65] Add redis config file for gitlab ci tests --- build/docker_install.sh | 7 +++++++ tests/redis.toml | 15 +++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 tests/redis.toml diff --git a/build/docker_install.sh b/build/docker_install.sh index 14aabcd5..88223f44 100644 --- a/build/docker_install.sh +++ b/build/docker_install.sh @@ -3,6 +3,9 @@ # We need to install dependencies only for Docker [[ ! -e /.dockerenv ]] && [[ ! -e /.dockerinit ]] && exit 0 +# Where am I? +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + set -xe # Install git (the php image doesn't have it) which is required by composer @@ -13,6 +16,10 @@ apt-get install git unzip libfreetype6 libjpeg62-turbo libmcrypt4 libpng12-0 lib curl -Lo /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar chmod +x /usr/local/bin/phpunit +# Move redis test config file into place +mv "$DIR/test/redis.toml" "$DIR/app/config/redis.toml" + + # Install gd docker-php-ext-configure gd --enable-gd-native-ttf --with-jpeg-dir=/usr/lib/x86_64-linux-gnu --with-png-dir=/usr/lib/x86_64-linux-gnu --with-freetype-dir=/usr/lib/x86_64-linux-gnu docker-php-ext-install gd diff --git a/tests/redis.toml b/tests/redis.toml new file mode 100644 index 00000000..ea731750 --- /dev/null +++ b/tests/redis.toml @@ -0,0 +1,15 @@ +################################################################################ +# Redis Cache Configuration # +################################################################################ + +# Host or socket to connect to +host = "redis" + +# Connection port +#port = 6379 + +# Connection password +#password = "" + +# Database number +database = 13 \ No newline at end of file From 1d2936df92b2717a650bb57cf8544e5c8e2a2a0e Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Mon, 25 Jul 2016 12:04:56 -0400 Subject: [PATCH 15/65] Fix typo in test path --- build/docker_install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/docker_install.sh b/build/docker_install.sh index 88223f44..42ac246f 100644 --- a/build/docker_install.sh +++ b/build/docker_install.sh @@ -17,7 +17,7 @@ curl -Lo /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar chmod +x /usr/local/bin/phpunit # Move redis test config file into place -mv "$DIR/test/redis.toml" "$DIR/app/config/redis.toml" +mv "$DIR/tests/redis.toml" "$DIR/app/config/redis.toml" # Install gd From ac76994a7005085e10c6d62b2d4613194b0cc577 Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Mon, 25 Jul 2016 12:18:51 -0400 Subject: [PATCH 16/65] Attempt moving config file in a different way --- .gitlab-ci.yml | 2 ++ build/docker_install.sh | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 78229a40..c64b9fb2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,6 +4,8 @@ before_script: # Install composer dependencies - curl -sS https://getcomposer.org/installer | php - php composer.phar install + # Move redis test config file into place + - mv "./tests/redis.toml" "./app/config/redis.toml" # Composer stores all downloaded packages in the vendor/ directory. # Do not use the following if the vendor/ directory is commited to diff --git a/build/docker_install.sh b/build/docker_install.sh index 42ac246f..7dca9c3f 100644 --- a/build/docker_install.sh +++ b/build/docker_install.sh @@ -16,10 +16,6 @@ apt-get install git unzip libfreetype6 libjpeg62-turbo libmcrypt4 libpng12-0 lib curl -Lo /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar chmod +x /usr/local/bin/phpunit -# Move redis test config file into place -mv "$DIR/tests/redis.toml" "$DIR/app/config/redis.toml" - - # Install gd docker-php-ext-configure gd --enable-gd-native-ttf --with-jpeg-dir=/usr/lib/x86_64-linux-gnu --with-png-dir=/usr/lib/x86_64-linux-gnu --with-freetype-dir=/usr/lib/x86_64-linux-gnu docker-php-ext-install gd From 756b5b51364102e65f9a4ad2411755c8cccf1b93 Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Mon, 25 Jul 2016 12:29:42 -0400 Subject: [PATCH 17/65] Update the correct file to change config for gitlab ci --- .gitlab-ci.yml | 2 -- tests/AnimeClient_TestCase.php | 2 +- tests/redis.toml | 15 --------------- 3 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 tests/redis.toml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c64b9fb2..78229a40 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,8 +4,6 @@ before_script: # Install composer dependencies - curl -sS https://getcomposer.org/installer | php - php composer.phar install - # Move redis test config file into place - - mv "./tests/redis.toml" "./app/config/redis.toml" # Composer stores all downloaded packages in the vendor/ directory. # Do not use the following if the vendor/ directory is commited to diff --git a/tests/AnimeClient_TestCase.php b/tests/AnimeClient_TestCase.php index f4a296dc..9a9a6a50 100644 --- a/tests/AnimeClient_TestCase.php +++ b/tests/AnimeClient_TestCase.php @@ -73,7 +73,7 @@ class AnimeClient_TestCase extends PHPUnit_Framework_TestCase { ] ], 'redis' => [ - 'host' => 'localhost', + 'host' => 'redis', 'database' => 13 ] ]; diff --git a/tests/redis.toml b/tests/redis.toml deleted file mode 100644 index ea731750..00000000 --- a/tests/redis.toml +++ /dev/null @@ -1,15 +0,0 @@ -################################################################################ -# Redis Cache Configuration # -################################################################################ - -# Host or socket to connect to -host = "redis" - -# Connection port -#port = 6379 - -# Connection password -#password = "" - -# Database number -database = 13 \ No newline at end of file From 1b93adefa30db91e7053a2a217ad948f8666b3ee Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Wed, 27 Jul 2016 13:18:52 -0400 Subject: [PATCH 18/65] Refactor out some Interdependency between Ion and AnimeClient namespaces --- app/bootstrap.php | 8 +- app/views/header.php | 4 +- src/Aviat/AnimeClient/AnimeClient.php | 66 +--- .../AnimeClient/Auth/HummingbirdAuth.php | 2 - src/Aviat/AnimeClient/Command/BaseCommand.php | 4 +- src/Aviat/AnimeClient/Config.php | 4 +- src/Aviat/AnimeClient/Dispatcher.php | 1 - src/Aviat/AnimeClient/Model/API.php | 18 +- src/Aviat/AnimeClient/Model/Anime.php | 3 +- src/Aviat/AnimeClient/Model/Collection.php | 2 +- src/Aviat/AnimeClient/Model/DB.php | 12 +- src/Aviat/AnimeClient/Model/Manga.php | 4 +- src/Aviat/AnimeClient/{Model.php => Util.php} | 335 ++++++++++-------- src/Aviat/Ion/Cache/CacheManager.php | 15 +- src/Aviat/Ion/Cache/Driver/NullDriver.php | 11 +- src/Aviat/Ion/Cache/Driver/RedisDriver.php | 14 +- src/Aviat/Ion/Cache/Driver/SQLDriver.php | 12 +- src/Aviat/Ion/ConfigInterface.php | 41 +++ src/Aviat/Ion/Model.php | 21 ++ src/Aviat/Ion/Model/DB.php | 51 +++ tests/AnimeClient/AnimeClientTest.php | 73 ---- tests/AnimeClient/Model/MangaModelTest.php | 1 + tests/AnimeClient/UtilTest.php | 78 ++++ tests/{AnimeClient => Ion}/BaseModelTest.php | 4 +- tests/Ion/Cache/CacheManagerTest.php | 2 +- tests/Ion/Cache/Driver/NullDriverTest.php | 2 +- tests/Ion/Cache/Driver/RedisDriver2Test.php | 7 +- tests/Ion/Cache/Driver/RedisDriverTest.php | 2 +- tests/Ion/Cache/Driver/SQLDriverTest.php | 2 +- tests/mocks.php | 12 +- 30 files changed, 473 insertions(+), 338 deletions(-) rename src/Aviat/AnimeClient/{Model.php => Util.php} (62%) create mode 100644 src/Aviat/Ion/ConfigInterface.php create mode 100644 src/Aviat/Ion/Model.php create mode 100644 src/Aviat/Ion/Model/DB.php create mode 100644 tests/AnimeClient/UtilTest.php rename tests/{AnimeClient => Ion}/BaseModelTest.php (62%) diff --git a/app/bootstrap.php b/app/bootstrap.php index c3304640..6b3701ab 100644 --- a/app/bootstrap.php +++ b/app/bootstrap.php @@ -41,7 +41,7 @@ return function(array $config_array = []) { $container->set('config', $config); // Create Cache Object - $container->set('cache', new CacheManager($container)); + $container->set('cache', new CacheManager($config)); // Create Aura Router Object $container->set('aura-router', new RouterContainer); @@ -71,9 +71,9 @@ return function(array $config_array = []) { $container->set('session', $session); // Miscellaneous helper methods - $anime_client = new AnimeClient(); - $anime_client->setContainer($container); - $container->set('anime-client', $anime_client); + $util = new Util($container); + $container->set('anime-client', $util); + $container->set('util', $util); // Models $container->set('api-model', new Model\API($container)); diff --git a/app/views/header.php b/app/views/header.php index 306f5bf9..5ec53689 100644 --- a/app/views/header.php +++ b/app/views/header.php @@ -50,8 +50,8 @@ menu($menu_name) ?>
diff --git a/src/Aviat/AnimeClient/AnimeClient.php b/src/Aviat/AnimeClient/AnimeClient.php index 435afc86..f737124d 100644 --- a/src/Aviat/AnimeClient/AnimeClient.php +++ b/src/Aviat/AnimeClient/AnimeClient.php @@ -18,12 +18,11 @@ use Yosymfony\Toml\Toml; define('SRC_DIR', realpath(__DIR__ . '/../../')); /** - * Odds and Ends class + * Application constants */ class AnimeClient { - use \Aviat\Ion\Di\ContainerAware; - + const HUMMINGBIRD_AUTH_URL = 'https://hummingbird.me/api/v1/users/authenticate'; const SESSION_SEGMENT = 'Aviat\AnimeClient\Auth'; const DEFAULT_CONTROLLER_NAMESPACE = 'Aviat\AnimeClient\Controller'; const DEFAULT_CONTROLLER = 'Aviat\AnimeClient\Controller\Anime'; @@ -32,67 +31,6 @@ class AnimeClient { const ERROR_MESSAGE_METHOD = 'error_page'; const SRC_DIR = SRC_DIR; - private static $form_pages = [ - 'edit', - 'add', - 'update', - 'update_form', - 'login', - 'logout', - 'details' - ]; - - /** - * HTML selection helper function - * - * @param string $a - First item to compare - * @param string $b - Second item to compare - * @return string - */ - public static function is_selected($a, $b) - { - return ($a === $b) ? 'selected' : ''; - } - - /** - * Inverse of selected helper function - * - * @param string $a - First item to compare - * @param string $b - Second item to compare - * @return string - */ - public static function is_not_selected($a, $b) - { - return ($a !== $b) ? 'selected' : ''; - } - - /** - * Determine whether to show the sub-menu - * - * @return bool - */ - public function is_view_page() - { - $url = $this->container->get('request') - ->getUri(); - $page_segments = explode("/", $url); - - $intersect = array_intersect($page_segments, self::$form_pages); - - return empty($intersect); - } - - /** - * Determine whether the page is a page with a form, and - * not suitable for redirection - * - * @return boolean - */ - public function is_form_page() - { - return ! $this->is_view_page(); - } - /** * Load configuration options from .toml files * diff --git a/src/Aviat/AnimeClient/Auth/HummingbirdAuth.php b/src/Aviat/AnimeClient/Auth/HummingbirdAuth.php index c6fa6d02..ac9625cf 100644 --- a/src/Aviat/AnimeClient/Auth/HummingbirdAuth.php +++ b/src/Aviat/AnimeClient/Auth/HummingbirdAuth.php @@ -15,7 +15,6 @@ namespace Aviat\AnimeClient\Auth; use Aviat\Ion\Di\ContainerInterface; use Aviat\AnimeClient\AnimeClient; -use Aviat\AnimeClient\Model\API; /** * Hummingbird API Authentication @@ -102,6 +101,5 @@ class HummingbirdAuth { { return $this->segment->get('auth_token', FALSE); } - } // End of HummingbirdAuth.php \ No newline at end of file diff --git a/src/Aviat/AnimeClient/Command/BaseCommand.php b/src/Aviat/AnimeClient/Command/BaseCommand.php index 980ccc22..2f4b9b48 100644 --- a/src/Aviat/AnimeClient/Command/BaseCommand.php +++ b/src/Aviat/AnimeClient/Command/BaseCommand.php @@ -51,7 +51,7 @@ class BaseCommand extends Command { */ protected function setupContainer() { - $CONF_DIR = __DIR__ . '/../../../../app/config/'; + $CONF_DIR = realpath(__DIR__ . '/../../../../app/config/'); require_once $CONF_DIR . '/base_config.php'; // $base_config $config = AnimeClient::load_toml($CONF_DIR); @@ -65,7 +65,7 @@ class BaseCommand extends Command { $container->set('config', $config); // Create Cache Object - $container->set('cache', new CacheManager($container)); + $container->set('cache', new CacheManager($config)); // Create session Object $session = (new SessionFactory())->newInstance($_COOKIE); diff --git a/src/Aviat/AnimeClient/Config.php b/src/Aviat/AnimeClient/Config.php index e994b42d..3cbf9195 100644 --- a/src/Aviat/AnimeClient/Config.php +++ b/src/Aviat/AnimeClient/Config.php @@ -13,12 +13,14 @@ namespace Aviat\AnimeClient; +use Aviat\Ion\ConfigInterface; + use InvalidArgumentException; /** * Wrapper for configuration values */ -class Config { +class Config implements ConfigInterface { use \Aviat\Ion\ArrayWrapper; diff --git a/src/Aviat/AnimeClient/Dispatcher.php b/src/Aviat/AnimeClient/Dispatcher.php index d1517e38..1d57e3c9 100644 --- a/src/Aviat/AnimeClient/Dispatcher.php +++ b/src/Aviat/AnimeClient/Dispatcher.php @@ -17,7 +17,6 @@ use Aura\Web\Response; use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Friend; -use Aviat\AnimeClient\AnimeClient; /** diff --git a/src/Aviat/AnimeClient/Model/API.php b/src/Aviat/AnimeClient/Model/API.php index 1fa6511a..feec4985 100644 --- a/src/Aviat/AnimeClient/Model/API.php +++ b/src/Aviat/AnimeClient/Model/API.php @@ -19,7 +19,8 @@ use GuzzleHttp\Psr7\ResponseInterface; use GuzzleHttp\Exception\ClientException; use Aviat\Ion\Di\ContainerInterface; -use Aviat\AnimeClient\Model as BaseModel; +use Aviat\Ion\Model; +use Aviat\AnimeClient\AnimeClient; /** * Base model for api interaction @@ -32,7 +33,15 @@ use Aviat\AnimeClient\Model as BaseModel; * @method ResponseInterface post(string $uri, array $options); * @method ResponseInterface put(string $uri, array $options); */ -class API extends BaseModel { +class API extends Model { + + use \Aviat\Ion\Di\ContainerAware; + + /** + * Config manager + * @var ConfigInterface + */ + protected $config; /** * Base url for making api requests @@ -65,7 +74,8 @@ class API extends BaseModel { */ public function __construct(ContainerInterface $container) { - parent::__construct($container); + $this->container = $container; + $this->config = $container->get('config'); $this->cache = $container->get('cache'); $this->init(); } @@ -171,7 +181,7 @@ class API extends BaseModel { */ public function authenticate($username, $password) { - $response = $this->post('https://hummingbird.me/api/v1/users/authenticate', [ + $response = $this->post(AnimeClient::HUMMINGBIRD_AUTH_URL, [ 'form_params' => [ 'username' => $username, 'password' => $password diff --git a/src/Aviat/AnimeClient/Model/Anime.php b/src/Aviat/AnimeClient/Model/Anime.php index 8d13c208..449b2648 100644 --- a/src/Aviat/AnimeClient/Model/Anime.php +++ b/src/Aviat/AnimeClient/Model/Anime.php @@ -226,9 +226,10 @@ class Anime extends API { $response = $this->get("users/{$username}/library", $config); $output = $this->transform($status, $response); + $util = $this->container->get('util'); foreach ($output as &$row) { - $row['anime']['image'] = $this->get_cached_image($row['anime']['image'], $row['anime']['slug'], 'anime'); + $row['anime']['image'] = $util->get_cached_image($row['anime']['image'], $row['anime']['slug'], 'anime'); } return $output; diff --git a/src/Aviat/AnimeClient/Model/Collection.php b/src/Aviat/AnimeClient/Model/Collection.php index 22e19378..0bec057b 100644 --- a/src/Aviat/AnimeClient/Model/Collection.php +++ b/src/Aviat/AnimeClient/Model/Collection.php @@ -36,7 +36,7 @@ class Collection extends DB { * Create a new collection object * * @param ContainerInterface $container - * @return boolean + * @return void */ public function __construct(ContainerInterface $container) { diff --git a/src/Aviat/AnimeClient/Model/DB.php b/src/Aviat/AnimeClient/Model/DB.php index 82167e54..8ad0e9f0 100644 --- a/src/Aviat/AnimeClient/Model/DB.php +++ b/src/Aviat/AnimeClient/Model/DB.php @@ -13,12 +13,14 @@ namespace Aviat\AnimeClient\Model; use Aviat\Ion\Di\ContainerInterface; -use Aviat\AnimeClient\Model as BaseModel; +use Aviat\Ion\Model; /** * Base model for database interaction */ -class DB extends BaseModel { +class DB extends Model { + use \Aviat\Ion\Di\ContainerAware; + /** * The query builder object * @var object $db @@ -38,8 +40,8 @@ class DB extends BaseModel { */ public function __construct(ContainerInterface $container) { - parent::__construct($container); - $this->db_config = (array)$this->config->get('database'); + $this->db_config = $container->get('config')->get('database'); + $this->setContainer($container); } } -// End of BaseDBModel.php \ No newline at end of file +// End of DB.php \ No newline at end of file diff --git a/src/Aviat/AnimeClient/Model/Manga.php b/src/Aviat/AnimeClient/Model/Manga.php index 6a6e3c94..999578af 100644 --- a/src/Aviat/AnimeClient/Model/Manga.php +++ b/src/Aviat/AnimeClient/Model/Manga.php @@ -252,9 +252,11 @@ class Manga extends API { self::COMPLETED => [], ]; + $util = $this->container->get('util'); + foreach ($data as &$entry) { - $entry['manga']['image'] = $this->get_cached_image( + $entry['manga']['image'] = $util->get_cached_image( $entry['manga']['image'], $entry['manga']['slug'], 'manga' diff --git a/src/Aviat/AnimeClient/Model.php b/src/Aviat/AnimeClient/Util.php similarity index 62% rename from src/Aviat/AnimeClient/Model.php rename to src/Aviat/AnimeClient/Util.php index ba4861fa..cfabaca3 100644 --- a/src/Aviat/AnimeClient/Model.php +++ b/src/Aviat/AnimeClient/Util.php @@ -1,140 +1,195 @@ -container = $container; - $this->config = $container->get('config'); - } - - /** - * Get the path of the cached version of the image. Create the cached image - * if the file does not already exist - * - * @codeCoverageIgnore - * @param string $api_path - The original image url - * @param string $series_slug - The part of the url with the series name, becomes the image name - * @param string $type - Anime or Manga, controls cache path - * @return string - the frontend path for the cached image - * @throws DomainException - */ - public function get_cached_image($api_path, $series_slug, $type = "anime") - { - $path_parts = explode('?', basename($api_path)); - $path = current($path_parts); - $ext_parts = explode('.', $path); - $ext = end($ext_parts); - - // Workaround for some broken file extensions - if ($ext == "jjpg") - { - $ext = "jpg"; - } - - // Failsafe for weird urls - if (strlen($ext) > 3) - { - return $api_path; - } - - $img_cache_path = $this->config->get('img_cache_path'); - $cached_image = "{$series_slug}.{$ext}"; - $cached_path = "{$img_cache_path}/{$type}/{$cached_image}"; - - // Cache the file if it doesn't already exist - if ( ! file_exists($cached_path)) - { - if (function_exists('curl_init')) - { - $ch = curl_init($api_path); - $fp = fopen($cached_path, 'wb'); - curl_setopt_array($ch, [ - CURLOPT_FILE => $fp, - CURLOPT_HEADER => 0 - ]); - curl_exec($ch); - curl_close($ch); - fclose($fp); - } - else if (ini_get('allow_url_fopen')) - { - copy($api_path, $cached_path); - } - else - { - throw new DomainException("Couldn't cache images because they couldn't be downloaded."); - } - - // Resize the image - if ($type == 'anime') - { - $resize_width = 220; - $resize_height = 319; - $this->_resize($cached_path, $resize_width, $resize_height); - } - } - - return "/public/images/{$type}/{$cached_image}"; - } - - /** - * Resize an image - * - * @codeCoverageIgnore - * @param string $path - * @param string $width - * @param string $height - */ - private function _resize($path, $width, $height) - { - try - { - $img = new SimpleImage($path); - $img->resize($width, $height)->save(); - } - catch (Exception $e) - { - // Catch image errors, since they don't otherwise affect - // functionality - } - } -} -// End of BaseModel.php \ No newline at end of file +setContainer($container); + $this->config = $container->get('config'); + } + + /** + * HTML selection helper function + * + * @param string $a - First item to compare + * @param string $b - Second item to compare + * @return string + */ + public static function is_selected($a, $b) + { + return ($a === $b) ? 'selected' : ''; + } + + /** + * Inverse of selected helper function + * + * @param string $a - First item to compare + * @param string $b - Second item to compare + * @return string + */ + public static function is_not_selected($a, $b) + { + return ($a !== $b) ? 'selected' : ''; + } + + /** + * Determine whether to show the sub-menu + * + * @return bool + */ + public function is_view_page() + { + $url = $this->container->get('request') + ->getUri(); + $page_segments = explode("/", $url); + + $intersect = array_intersect($page_segments, self::$form_pages); + + return empty($intersect); + } + + /** + * Determine whether the page is a page with a form, and + * not suitable for redirection + * + * @return boolean + */ + public function is_form_page() + { + return ! $this->is_view_page(); + } + + /** + * Get the path of the cached version of the image. Create the cached image + * if the file does not already exist + * + * @codeCoverageIgnore + * @param string $api_path - The original image url + * @param string $series_slug - The part of the url with the series name, becomes the image name + * @param string $type - Anime or Manga, controls cache path + * @return string - the frontend path for the cached image + * @throws DomainException + */ + public function get_cached_image($api_path, $series_slug, $type = "anime") + { + $path_parts = explode('?', basename($api_path)); + $path = current($path_parts); + $ext_parts = explode('.', $path); + $ext = end($ext_parts); + + // Workaround for some broken file extensions + if ($ext == "jjpg") + { + $ext = "jpg"; + } + + // Failsafe for weird urls + if (strlen($ext) > 3) + { + return $api_path; + } + + $img_cache_path = $this->config->get('img_cache_path'); + $cached_image = "{$series_slug}.{$ext}"; + $cached_path = "{$img_cache_path}/{$type}/{$cached_image}"; + + // Cache the file if it doesn't already exist + if ( ! file_exists($cached_path)) + { + if (function_exists('curl_init')) + { + $ch = curl_init($api_path); + $fp = fopen($cached_path, 'wb'); + curl_setopt_array($ch, [ + CURLOPT_FILE => $fp, + CURLOPT_HEADER => 0 + ]); + curl_exec($ch); + curl_close($ch); + fclose($fp); + } + else if (ini_get('allow_url_fopen')) + { + copy($api_path, $cached_path); + } + else + { + throw new \DomainException("Couldn't cache images because they couldn't be downloaded."); + } + + // Resize the image + if ($type == 'anime') + { + $resize_width = 220; + $resize_height = 319; + $this->_resize($cached_path, $resize_width, $resize_height); + } + } + + return "/public/images/{$type}/{$cached_image}"; + } + + /** + * Resize an image + * + * @codeCoverageIgnore + * @param string $path + * @param string $width + * @param string $height + */ + private function _resize($path, $width, $height) + { + try + { + $img = new SimpleImage($path); + $img->resize($width, $height)->save(); + } + catch (Exception $e) + { + // Catch image errors, since they don't otherwise affect + // functionality + } + } +} \ No newline at end of file diff --git a/src/Aviat/Ion/Cache/CacheManager.php b/src/Aviat/Ion/Cache/CacheManager.php index b5e32cb4..34fc4887 100644 --- a/src/Aviat/Ion/Cache/CacheManager.php +++ b/src/Aviat/Ion/Cache/CacheManager.php @@ -12,7 +12,7 @@ namespace Aviat\Ion\Cache; -use \Aviat\Ion\Di\ContainerInterface; +use Aviat\Ion\ConfigInterface; /** * Class proxying cached and fresh values from the selected cache driver @@ -25,11 +25,12 @@ class CacheManager implements CacheInterface { protected $driver; /** - * Retreive the appropriate driver from the container + * Retrieve the appropriate driver from the container + * + * @param ConfigInterface $config The configuration management class */ - public function __construct(ContainerInterface $container) + public function __construct(ConfigInterface $config) { - $config = $container->get('config'); $driverConf = $config->get('cache_driver'); if (empty($driverConf)) @@ -38,13 +39,13 @@ class CacheManager implements CacheInterface { } $driverClass = __NAMESPACE__ . "\\Driver\\{$driverConf}"; - $driver = new $driverClass($container); + $driver = new $driverClass($config); $this->driver = $driver; } /** - * Retreive 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 * * @param object $object - object to retrieve fresh value from @@ -68,7 +69,7 @@ class CacheManager implements CacheInterface { } /** - * Retreive 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 string $method - method name to call * @param [array] $args - the arguments to pass to the retrieval method diff --git a/src/Aviat/Ion/Cache/Driver/NullDriver.php b/src/Aviat/Ion/Cache/Driver/NullDriver.php index b7d0bb9c..aca42a2c 100644 --- a/src/Aviat/Ion/Cache/Driver/NullDriver.php +++ b/src/Aviat/Ion/Cache/Driver/NullDriver.php @@ -12,12 +12,13 @@ namespace Aviat\Ion\Cache\Driver; -use Aviat\Ion\Di\ContainerInterface; +use Aviat\Ion\ConfigInterface; +use Aviat\Ion\Cache\CacheDriverInterface; /** * The Driver for no real cache */ -class NullDriver implements \Aviat\Ion\Cache\CacheDriverInterface { +class NullDriver implements CacheDriverInterface { /** * 'Cache' for Null data store @@ -25,9 +26,11 @@ class NullDriver implements \Aviat\Ion\Cache\CacheDriverInterface { protected $data; /** - * Create the Redis cache driver + * Create the Null cache driver + * + * @param ConfigInterface $config The configuration management class */ - public function __construct(ContainerInterface $container) + public function __construct(ConfigInterface $config) { $this->data = []; } diff --git a/src/Aviat/Ion/Cache/Driver/RedisDriver.php b/src/Aviat/Ion/Cache/Driver/RedisDriver.php index db265e13..b0b436d6 100644 --- a/src/Aviat/Ion/Cache/Driver/RedisDriver.php +++ b/src/Aviat/Ion/Cache/Driver/RedisDriver.php @@ -12,7 +12,7 @@ namespace Aviat\Ion\Cache\Driver; -use Aviat\Ion\Di\ContainerInterface; +use Aviat\Ion\ConfigInterface; use Aviat\Ion\Cache\CacheDriverInterface; use Predis\Client; @@ -20,17 +20,19 @@ use Predis\Client; class RedisDriver implements CacheDriverInterface { /** - * The redis extension class instance - * @var Redis + * THe Predis library instance + * + * @var Client */ protected $redis; /** * Create the Redis cache driver + * + * @param ConfigInterface $config The configuration management class */ - public function __construct(ContainerInterface $container) + public function __construct(ConfigInterface $config) { - $config = $container->get('config'); $redisConfig = $config->get('redis'); if (array_key_exists('password', $redisConfig) && $redisConfig['password'] === '') @@ -50,7 +52,7 @@ class RedisDriver implements CacheDriverInterface { } /** - * Retreive a value from the cache backend + * Retrieve a value from the cache backend * * @param string $key * @return mixed diff --git a/src/Aviat/Ion/Cache/Driver/SQLDriver.php b/src/Aviat/Ion/Cache/Driver/SQLDriver.php index dc1c47ef..483494e4 100644 --- a/src/Aviat/Ion/Cache/Driver/SQLDriver.php +++ b/src/Aviat/Ion/Cache/Driver/SQLDriver.php @@ -12,9 +12,9 @@ namespace Aviat\Ion\Cache\Driver; -use Aviat\Ion\Di\ContainerInterface; +use Aviat\Ion\ConfigInterface; use Aviat\Ion\Cache\CacheDriverInterface; -use Aviat\AnimeClient\Model\DB; +use Aviat\Ion\Model\DB; /** * Driver for caching via a traditional SQL database @@ -29,15 +29,17 @@ class SQLDriver extends DB implements CacheDriverInterface { /** * Create the driver object + * + * @param ConfigInterface $config */ - public function __construct(ContainerInterface $container) + public function __construct(ConfigInterface $config) { - parent::__construct($container); + parent::__construct($config); $this->db = \Query($this->db_config['collection']); } /** - * Retreive a value from the cache backend + * Retrieve a value from the cache backend * * @param string $key * @return mixed diff --git a/src/Aviat/Ion/ConfigInterface.php b/src/Aviat/Ion/ConfigInterface.php new file mode 100644 index 00000000..9c644bae --- /dev/null +++ b/src/Aviat/Ion/ConfigInterface.php @@ -0,0 +1,41 @@ +config = $config; + $this->db_config = (array)$config->get('database'); + } +} +// End of DB.php \ No newline at end of file diff --git a/tests/AnimeClient/AnimeClientTest.php b/tests/AnimeClient/AnimeClientTest.php index ee649c85..75a89554 100644 --- a/tests/AnimeClient/AnimeClientTest.php +++ b/tests/AnimeClient/AnimeClientTest.php @@ -5,13 +5,6 @@ use Aviat\AnimeClient\AnimeClient; class AnimeClientTest extends AnimeClient_TestCase { - public function setUp() - { - parent::setUp(); - $this->anime_client = new AnimeClient(); - $this->anime_client->setContainer($this->container); - } - /** * Basic sanity test for _dir function */ @@ -19,70 +12,4 @@ class AnimeClientTest extends AnimeClient_TestCase { { $this->assertEquals('foo' . DIRECTORY_SEPARATOR . 'bar', \_dir('foo', 'bar')); } - - public function testIsSelected() - { - // Failure to match - $this->assertEquals('', AnimeClient::is_selected('foo', 'bar')); - - // Matches - $this->assertEquals('selected', AnimeClient::is_selected('foo', 'foo')); - } - - public function testIsNotSelected() - { - // Failure to match - $this->assertEquals('selected', AnimeClient::is_not_selected('foo', 'bar')); - - // Matches - $this->assertEquals('', AnimeClient::is_not_selected('foo', 'foo')); - } - - public function dataIsViewPage() - { - return [ - [ - 'uri' => '/anime/update', - 'expected' => FALSE - ], - [ - 'uri' => '/anime/watching', - 'expected' => TRUE - ], - [ - 'uri' => '/manga/reading', - 'expected' => TRUE - ], - [ - 'uri' => '/manga/update', - 'expected' => FALSE - ] - ]; - } - - /** - * @dataProvider dataIsViewPage - */ - public function testIsViewPage($uri, $expected) - { - $this->setSuperGlobals([ - '_SERVER' => [ - 'REQUEST_URI' => $uri - ] - ]); - $this->assertEquals($expected, $this->anime_client->is_view_page()); - } - - /** - * @dataProvider dataIsViewPage - */ - public function testIsFormPage($uri, $expected) - { - $this->setSuperGlobals([ - '_SERVER' => [ - 'REQUEST_URI' => $uri - ] - ]); - $this->assertEquals(!$expected, $this->anime_client->is_form_page()); - } } diff --git a/tests/AnimeClient/Model/MangaModelTest.php b/tests/AnimeClient/Model/MangaModelTest.php index d8cd4b21..bc97fca7 100644 --- a/tests/AnimeClient/Model/MangaModelTest.php +++ b/tests/AnimeClient/Model/MangaModelTest.php @@ -12,6 +12,7 @@ class MangaModelTest extends AnimeClient_TestCase { public function setUp() { parent::setUp(); + $this->container->set('util', new MockUtil($this->container)); $this->model = new Friend(new TestMangaModel($this->container)); $this->mockDir = __DIR__ . '/../../test_data/manga_list'; } diff --git a/tests/AnimeClient/UtilTest.php b/tests/AnimeClient/UtilTest.php new file mode 100644 index 00000000..67492ce5 --- /dev/null +++ b/tests/AnimeClient/UtilTest.php @@ -0,0 +1,78 @@ +util = new Util($this->container); + } + + public function testIsSelected() + { + // Failure to match + $this->assertEquals('', Util::is_selected('foo', 'bar')); + + // Matches + $this->assertEquals('selected', Util::is_selected('foo', 'foo')); + } + + public function testIsNotSelected() + { + // Failure to match + $this->assertEquals('selected', Util::is_not_selected('foo', 'bar')); + + // Matches + $this->assertEquals('', Util::is_not_selected('foo', 'foo')); + } + + public function dataIsViewPage() + { + return [ + [ + 'uri' => '/anime/update', + 'expected' => FALSE + ], + [ + 'uri' => '/anime/watching', + 'expected' => TRUE + ], + [ + 'uri' => '/manga/reading', + 'expected' => TRUE + ], + [ + 'uri' => '/manga/update', + 'expected' => FALSE + ] + ]; + } + + /** + * @dataProvider dataIsViewPage + */ + public function testIsViewPage($uri, $expected) + { + $this->setSuperGlobals([ + '_SERVER' => [ + 'REQUEST_URI' => $uri + ] + ]); + $this->assertEquals($expected, $this->util->is_view_page()); + } + + /** + * @dataProvider dataIsViewPage + */ + public function testIsFormPage($uri, $expected) + { + $this->setSuperGlobals([ + '_SERVER' => [ + 'REQUEST_URI' => $uri + ] + ]); + $this->assertEquals(!$expected, $this->util->is_form_page()); + } +} diff --git a/tests/AnimeClient/BaseModelTest.php b/tests/Ion/BaseModelTest.php similarity index 62% rename from tests/AnimeClient/BaseModelTest.php rename to tests/Ion/BaseModelTest.php index 01ff61b6..edc2a2f4 100644 --- a/tests/AnimeClient/BaseModelTest.php +++ b/tests/Ion/BaseModelTest.php @@ -1,12 +1,12 @@ container); + $baseModel = new BaseModel(); $this->assertTrue(is_object($baseModel)); } } \ No newline at end of file diff --git a/tests/Ion/Cache/CacheManagerTest.php b/tests/Ion/Cache/CacheManagerTest.php index bad7a202..7d88dcc1 100644 --- a/tests/Ion/Cache/CacheManagerTest.php +++ b/tests/Ion/Cache/CacheManagerTest.php @@ -15,7 +15,7 @@ class CacheManagerText extends AnimeClient_TestCase { public function setUp() { parent::setUp(); - $this->cache = new CacheManager($this->container); + $this->cache = new CacheManager($this->container->get('config'), $this->container); $this->friend = new Friend($this->cache); } diff --git a/tests/Ion/Cache/Driver/NullDriverTest.php b/tests/Ion/Cache/Driver/NullDriverTest.php index 6771fdea..df6606d4 100644 --- a/tests/Ion/Cache/Driver/NullDriverTest.php +++ b/tests/Ion/Cache/Driver/NullDriverTest.php @@ -12,6 +12,6 @@ class CacheNullDriverTest extends AnimeClient_TestCase { public function setUp() { parent::setUp(); - $this->driver = new NullDriver($this->container); + $this->driver = new NullDriver($this->container->get('config')); } } \ No newline at end of file diff --git a/tests/Ion/Cache/Driver/RedisDriver2Test.php b/tests/Ion/Cache/Driver/RedisDriver2Test.php index 35317251..4962c35a 100644 --- a/tests/Ion/Cache/Driver/RedisDriver2Test.php +++ b/tests/Ion/Cache/Driver/RedisDriver2Test.php @@ -16,16 +16,15 @@ class CacheRedisDriverTestTwo extends AnimeClient_TestCase { parent::setUp(); // Setup config with port and password - $container = new Container(); - $container->set('config', new Config([ + $config = new Config([ 'redis' => [ 'host' => (array_key_exists('REDIS_HOST', $_ENV)) ? $_ENV['REDIS_HOST'] : 'localhost', 'port' => 6379, 'password' => '', 'database' => 13, ] - ])); - $this->driver = new RedisDriver($container); + ]); + $this->driver = new RedisDriver($config); } public function tearDown() diff --git a/tests/Ion/Cache/Driver/RedisDriverTest.php b/tests/Ion/Cache/Driver/RedisDriverTest.php index 3ae45a9a..ed1209f5 100644 --- a/tests/Ion/Cache/Driver/RedisDriverTest.php +++ b/tests/Ion/Cache/Driver/RedisDriverTest.php @@ -13,7 +13,7 @@ class CacheRedisDriverTest extends AnimeClient_TestCase { { parent::setUp(); - $this->driver = new RedisDriver($this->container); + $this->driver = new RedisDriver($this->container->get('config')); } public function tearDown() diff --git a/tests/Ion/Cache/Driver/SQLDriverTest.php b/tests/Ion/Cache/Driver/SQLDriverTest.php index d23d9ec1..4cd98659 100644 --- a/tests/Ion/Cache/Driver/SQLDriverTest.php +++ b/tests/Ion/Cache/Driver/SQLDriverTest.php @@ -13,7 +13,7 @@ class CacheSQLDriverTest extends AnimeClient_TestCase { public function setUp() { parent::setUp(); - $this->driver = new SQLDriver($this->container); + $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"))'); } diff --git a/tests/mocks.php b/tests/mocks.php index 6b48a815..d4884bbe 100644 --- a/tests/mocks.php +++ b/tests/mocks.php @@ -99,6 +99,13 @@ trait MockViewOutputTrait { } } +class MockUtil { + public function get_cached_image($api_path, $series_slug, $type = "anime") + { + return "/public/images/{$type}/{$series_slug}.jpg"; + } +} + class TestView extends View { public function send() {} protected function output() @@ -157,11 +164,6 @@ class TestAnimeModel extends AnimeModel { class TestMangaModel extends MangaModel { use MockInjectionTrait; - public function get_cached_image($api_path, $series_slug, $type = "anime") - { - return "/public/images/{$type}/{$series_slug}.jpg"; - } - protected function _check_cache($response) { $file = __DIR__ . '/test_data/manga_list/manga-transformed.json'; From 2a3a64f0ebe68baa79aa5621590a5336df0309f2 Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Wed, 27 Jul 2016 13:35:30 -0400 Subject: [PATCH 19/65] Fix travis ci tests --- tests/AnimeClient_TestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/AnimeClient_TestCase.php b/tests/AnimeClient_TestCase.php index 9a9a6a50..04852dc8 100644 --- a/tests/AnimeClient_TestCase.php +++ b/tests/AnimeClient_TestCase.php @@ -73,7 +73,7 @@ class AnimeClient_TestCase extends PHPUnit_Framework_TestCase { ] ], 'redis' => [ - 'host' => 'redis', + 'host' => (array_key_exists('REDIS_HOST', $_ENV)) ? $_ENV['REDIS_HOST'] : 'localhost', 'database' => 13 ] ]; From 3d66fa9c11f90a220aa8bb57957c628b555af974 Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Wed, 27 Jul 2016 14:32:37 -0400 Subject: [PATCH 20/65] Finish moving get_cached_image method to Util class --- app/views/header.php | 45 +------------------ app/views/main-menu.php | 44 ++++++++++++++++++ src/Aviat/AnimeClient/Command/CacheImages.php | 10 ++--- src/Aviat/AnimeClient/Controller.php | 7 ++- .../AnimeClient/Model/AnimeCollection.php | 8 +++- 5 files changed, 59 insertions(+), 55 deletions(-) create mode 100644 app/views/main-menu.php diff --git a/app/views/header.php b/app/views/header.php index 5ec53689..d5dd4835 100644 --- a/app/views/header.php +++ b/app/views/header.php @@ -1,4 +1,3 @@ - @@ -12,49 +11,7 @@
-

- - - - get('whose_list') ?>'s List - - get("show_{$url_type}_collection")): ?> - [ Collection] - - [ List] - - - get('whose_list') ?>'s Collection - - [Anime List] - [Manga List] - - - is_authenticated()): ?> -   - - - -   - - - is_authenticated()): ?> - Logout - - [get('whose_list') ?>'s Login] - - -

- + +

+ + + + get('whose_list') ?>'s List + + get("show_{$url_type}_collection")): ?> + [ Collection] + + [ List] + + + get('whose_list') ?>'s Collection + + [Anime List] + [Manga List] + + + is_authenticated()): ?> +   + + + +   + + + is_authenticated()): ?> + Logout + + [get('whose_list') ?>'s Login] + + +

+ \ No newline at end of file diff --git a/src/Aviat/AnimeClient/Command/CacheImages.php b/src/Aviat/AnimeClient/Command/CacheImages.php index 599ef928..34e68843 100644 --- a/src/Aviat/AnimeClient/Command/CacheImages.php +++ b/src/Aviat/AnimeClient/Command/CacheImages.php @@ -13,7 +13,7 @@ namespace Aviat\AnimeClient\Command; -use Aviat\AnimeClient\Model; +use Aviat\AnimeClient\Util; /** * Generates thumbnail image cache so that cover images load faster */ @@ -21,7 +21,7 @@ class CacheImages extends BaseCommand { protected $mangaModel; protected $animeModel; - protected $model; + protected $util; /* * Convert manga images @@ -37,7 +37,7 @@ class CacheImages extends BaseCommand { $current = 0; foreach($manga_list as $item) { - $this->model->get_cached_image($item['poster_image'], $item['id'], 'manga'); + $this->util->get_cached_image($item['poster_image'], $item['id'], 'manga'); $current++; echo "Cached {$current} of {$total} manga images. \n"; @@ -57,7 +57,7 @@ class CacheImages extends BaseCommand { $current = 0; foreach($raw_list as $item) { - $this->model->get_cached_image($item['anime']['cover_image'], $item['anime']['slug'], 'anime'); + $this->util->get_cached_image($item['anime']['cover_image'], $item['anime']['slug'], 'anime'); $current++; echo "Cached {$current} of {$total} anime images. \n"; @@ -75,7 +75,7 @@ class CacheImages extends BaseCommand { public function execute(array $args, array $options = array()) { $this->setContainer($this->setupContainer()); - $this->model = new Model($this->container); + $this->util = new Util($this->container); $this->animeModel = $this->container->get('anime-model'); $this->mangaModel = $this->container->get('manga-model'); diff --git a/src/Aviat/AnimeClient/Controller.php b/src/Aviat/AnimeClient/Controller.php index 88f262eb..f558ee5b 100644 --- a/src/Aviat/AnimeClient/Controller.php +++ b/src/Aviat/AnimeClient/Controller.php @@ -21,7 +21,6 @@ use Aviat\Ion\View\JsonView; * Controller base, defines output methods * * @property Response object $response - * @property Config object $config */ class Controller { @@ -35,7 +34,7 @@ class Controller { /** * The global configuration object - * @var object $config + * @var Aviat\Ion\ConfigInterface $config */ protected $config; @@ -148,7 +147,7 @@ class Controller { return; } - $anime_client = $this->container->get('anime-client'); + $util = $this->container->get('util'); $double_form_page = $server_params['HTTP_REFERER'] == $this->request->getUri(); // Don't attempt to set the redirect url if @@ -161,7 +160,7 @@ class Controller { if (is_null($url)) { - $url = ($anime_client->is_view_page()) + $url = ($util->is_view_page()) ? $this->request->url->get() : $server_params['HTTP_REFERER']; } diff --git a/src/Aviat/AnimeClient/Model/AnimeCollection.php b/src/Aviat/AnimeClient/Model/AnimeCollection.php index 7b426344..2f54be93 100644 --- a/src/Aviat/AnimeClient/Model/AnimeCollection.php +++ b/src/Aviat/AnimeClient/Model/AnimeCollection.php @@ -129,6 +129,8 @@ class AnimeCollection extends Collection { { $anime = (object)$this->anime_model->get_anime($data['id']); + $util = $this->container->get('util'); + $this->db->set([ 'hummingbird_id' => $data['id'], 'slug' => $anime->slug, @@ -137,7 +139,7 @@ class AnimeCollection extends Collection { 'show_type' => $anime->show_type, 'age_rating' => $anime->age_rating, 'cover_image' => basename( - $this->get_cached_image($anime->cover_image, $anime->slug, 'anime') + $util->get_cached_image($anime->cover_image, $anime->slug, 'anime') ), 'episode_count' => $anime->episode_count, 'episode_length' => $anime->episode_length, @@ -222,6 +224,8 @@ class AnimeCollection extends Collection { foreach ($anime as $item) { + $util = $this->container->get('util'); + $this->db->set([ 'hummingbird_id' => $item->id, 'slug' => $item->slug, @@ -230,7 +234,7 @@ class AnimeCollection extends Collection { 'show_type' => $item->show_type, 'age_rating' => $item->age_rating, 'cover_image' => basename( - $this->get_cached_image($item->cover_image, $item->slug, 'anime') + $util->get_cached_image($item->cover_image, $item->slug, 'anime') ), 'episode_count' => $item->episode_count, 'episode_length' => $item->episode_length From ba6ada32f921dae2de66f8b035cbf3a8ff763708 Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Thu, 28 Jul 2016 10:44:13 -0400 Subject: [PATCH 21/65] Move cache class to IOn namespace, use safer json for serialization in cache drivers --- app/bootstrap.php | 1 + app/config/database.toml.example | 12 ++++++++++- src/Aviat/AnimeClient/Command/BaseCommand.php | 5 ++++- src/Aviat/Ion/Cache/Driver/RedisDriver.php | 4 ++-- src/Aviat/Ion/Cache/Driver/SQLDriver.php | 14 ++++++++++--- src/Aviat/{AnimeClient => Ion}/Config.php | 15 +++++++------- src/Aviat/Ion/Exception/ConfigException.php | 20 +++++++++++++++++++ tests/AnimeClient/DispatcherTest.php | 2 +- tests/AnimeClient/MenuGeneratorTest.php | 7 +------ .../Model/AnimeCollectionModelTest.php | 3 ++- .../{CoreTest.php => RequirementsTest.php} | 20 +++++++++++++------ tests/AnimeClient/UrlGeneratorTest.php | 3 +-- tests/AnimeClient_TestCase.php | 11 +++++++++- tests/Ion/Cache/Driver/RedisDriver2Test.php | 3 +-- tests/{AnimeClient => Ion}/ConfigTest.php | 2 +- 15 files changed, 88 insertions(+), 34 deletions(-) rename src/Aviat/{AnimeClient => Ion}/Config.php (83%) create mode 100644 src/Aviat/Ion/Exception/ConfigException.php rename tests/AnimeClient/{CoreTest.php => RequirementsTest.php} (63%) rename tests/{AnimeClient => Ion}/ConfigTest.php (98%) diff --git a/app/bootstrap.php b/app/bootstrap.php index 6b3701ab..38c96305 100644 --- a/app/bootstrap.php +++ b/app/bootstrap.php @@ -13,6 +13,7 @@ use Monolog\Handler\RotatingFileHandler; use Zend\Diactoros\ServerRequestFactory; use Zend\Diactoros\Response; +use Aviat\Ion\Config; use Aviat\Ion\Di\Container; use Aviat\Ion\Cache\CacheManager; use Aviat\AnimeClient\Auth\HummingbirdAuth; diff --git a/app/config/database.toml.example b/app/config/database.toml.example index d6d8656d..18b1ecc9 100644 --- a/app/config/database.toml.example +++ b/app/config/database.toml.example @@ -10,4 +10,14 @@ pass = "" port = "" name = "default" database = "" -file = "/../../anime_collection.sqlite" \ No newline at end of file +file = "anime_collection.sqlite" + +[cache] +type = "sqlite" +host = "" +user = "" +pass = "" +port = "" +name = "default" +database = "" +file = "anime_collection.sqlite" \ No newline at end of file diff --git a/src/Aviat/AnimeClient/Command/BaseCommand.php b/src/Aviat/AnimeClient/Command/BaseCommand.php index 2f4b9b48..bd50731f 100644 --- a/src/Aviat/AnimeClient/Command/BaseCommand.php +++ b/src/Aviat/AnimeClient/Command/BaseCommand.php @@ -17,12 +17,14 @@ use Aura\Session\SessionFactory; use ConsoleKit\Command; use ConsoleKit\Widgets\Box; +use Aviat\Ion\Config; use Aviat\Ion\Di\Container; use Aviat\Ion\Cache\CacheManager; -use Aviat\AnimeClient\Config; + use Aviat\AnimeClient\AnimeClient; use Aviat\AnimeClient\Auth\HummingbirdAuth; use Aviat\AnimeClient\Model; +use Aviat\AnimeClient\Util; /** * Base class for console command setup @@ -77,6 +79,7 @@ class BaseCommand extends Command { $container->set('manga-model', new Model\Manga($container)); $container->set('auth', new HummingbirdAuth($container)); + $container->set('util', new Util($container)); return $container; }; diff --git a/src/Aviat/Ion/Cache/Driver/RedisDriver.php b/src/Aviat/Ion/Cache/Driver/RedisDriver.php index b0b436d6..85e140d5 100644 --- a/src/Aviat/Ion/Cache/Driver/RedisDriver.php +++ b/src/Aviat/Ion/Cache/Driver/RedisDriver.php @@ -59,7 +59,7 @@ class RedisDriver implements CacheDriverInterface { */ public function get($key) { - return unserialize($this->redis->get($key)); + return json_decode($this->redis->get($key)); } /** @@ -71,7 +71,7 @@ class RedisDriver implements CacheDriverInterface { */ public function set($key, $value) { - $this->redis->set($key, serialize($value)); + $this->redis->set($key, json_encode($value)); return $this; } diff --git a/src/Aviat/Ion/Cache/Driver/SQLDriver.php b/src/Aviat/Ion/Cache/Driver/SQLDriver.php index 483494e4..f3bbc64d 100644 --- a/src/Aviat/Ion/Cache/Driver/SQLDriver.php +++ b/src/Aviat/Ion/Cache/Driver/SQLDriver.php @@ -14,6 +14,7 @@ namespace Aviat\Ion\Cache\Driver; use Aviat\Ion\ConfigInterface; use Aviat\Ion\Cache\CacheDriverInterface; +use Aviat\Ion\Exception\ConfigException; use Aviat\Ion\Model\DB; /** @@ -31,11 +32,18 @@ class SQLDriver extends DB implements CacheDriverInterface { * Create the driver object * * @param ConfigInterface $config + * @throws ConfigException */ public function __construct(ConfigInterface $config) { parent::__construct($config); - $this->db = \Query($this->db_config['collection']); + + if ( ! array_key_exists('cache', $this->db_config)) + { + throw new ConfigException("Missing '[cache]' section in database config."); + } + + $this->db = \Query($this->db_config['cache']); } /** @@ -54,7 +62,7 @@ class SQLDriver extends DB implements CacheDriverInterface { $row = $query->fetch(\PDO::FETCH_ASSOC); if ( ! empty($row)) { - return unserialize($row['value']); + return json_decode($row['value']); } return NULL; @@ -71,7 +79,7 @@ class SQLDriver extends DB implements CacheDriverInterface { { $this->db->set([ 'key' => $key, - 'value' => serialize($value), + 'value' => json_encode($value), ]); $this->db->insert('cache'); diff --git a/src/Aviat/AnimeClient/Config.php b/src/Aviat/Ion/Config.php similarity index 83% rename from src/Aviat/AnimeClient/Config.php rename to src/Aviat/Ion/Config.php index 3cbf9195..c0dea9f0 100644 --- a/src/Aviat/AnimeClient/Config.php +++ b/src/Aviat/Ion/Config.php @@ -1,19 +1,19 @@ assertTrue(version_compare(PHP_VERSION, "5.4", "ge")); } - public function testRequirements() + public function testHasGd() { - // Check required extensions $this->assertTrue(extension_loaded('gd')); - $this->assertTrue(extension_loaded('mcrypt')); + } - // Check for pdo_sqlite + public function testHasMcrypt() + { + $this->assertTrue(extension_loaded('mcrypt')); + } + + public function testHasPDO() + { $this->assertTrue(class_exists('PDO')); + } + + public function testHasPDOSqlite() + { $drivers = PDO::getAvailableDrivers(); $this->assertTrue(in_array('sqlite', $drivers)); } - } \ No newline at end of file diff --git a/tests/AnimeClient/UrlGeneratorTest.php b/tests/AnimeClient/UrlGeneratorTest.php index 3635dedb..aea2e044 100644 --- a/tests/AnimeClient/UrlGeneratorTest.php +++ b/tests/AnimeClient/UrlGeneratorTest.php @@ -1,7 +1,6 @@ 'default', 'database' => '', 'file' => ':memory:', + ], + 'cache' => [ + 'type' => 'sqlite', + 'host' => '', + 'user' => '', + 'pass' => '', + 'port' => '', + 'name' => 'default', + 'database' => '', + 'file' => ':memory:', ] ], 'routes' => [ diff --git a/tests/Ion/Cache/Driver/RedisDriver2Test.php b/tests/Ion/Cache/Driver/RedisDriver2Test.php index 4962c35a..62f5482d 100644 --- a/tests/Ion/Cache/Driver/RedisDriver2Test.php +++ b/tests/Ion/Cache/Driver/RedisDriver2Test.php @@ -2,8 +2,7 @@ require_once('CacheDriverBase.php'); -use Aviat\AnimeClient\Config; -use Aviat\Ion\Di\Container; +use Aviat\Ion\Config; use Aviat\Ion\Cache\Driver\RedisDriver; class CacheRedisDriverTestTwo extends AnimeClient_TestCase { diff --git a/tests/AnimeClient/ConfigTest.php b/tests/Ion/ConfigTest.php similarity index 98% rename from tests/AnimeClient/ConfigTest.php rename to tests/Ion/ConfigTest.php index b3134843..3cd84de2 100644 --- a/tests/AnimeClient/ConfigTest.php +++ b/tests/Ion/ConfigTest.php @@ -1,6 +1,6 @@ Date: Mon, 1 Aug 2016 13:02:26 -0400 Subject: [PATCH 22/65] Refactor cache to remove dependency on container --- build.xml | 3 +- src/Aviat/AnimeClient/Model/API.php | 2 + src/Aviat/AnimeClient/Model/Collection.php | 4 +- src/Aviat/AnimeClient/Model/Manga.php | 2 +- src/Aviat/Ion/Cache/CacheInterface.php | 4 +- src/Aviat/Ion/Cache/CacheManager.php | 3 +- .../DriverInterface.php} | 10 +-- src/Aviat/Ion/Cache/Driver/DriverTrait.php | 62 +++++++++++++++++++ src/Aviat/Ion/Cache/Driver/NullDriver.php | 22 ++----- src/Aviat/Ion/Cache/Driver/RedisDriver.php | 43 +++++++++---- src/Aviat/Ion/Cache/Driver/SQLDriver.php | 25 +++++--- src/Aviat/Ion/Json.php | 10 ++- .../Model/AnimeCollectionModelTest.php | 2 +- tests/AnimeClient_TestCase.php | 31 ++++++++++ .../Model/BaseDBModelTest.php | 4 +- tests/bootstrap.php | 3 - tests/mocks.php | 1 - 17 files changed, 171 insertions(+), 60 deletions(-) rename src/Aviat/Ion/Cache/{CacheDriverInterface.php => Driver/DriverInterface.php} (80%) create mode 100644 src/Aviat/Ion/Cache/Driver/DriverTrait.php rename tests/{AnimeClient => Ion}/Model/BaseDBModelTest.php (59%) diff --git a/build.xml b/build.xml index b8554ad5..35dbaf72 100644 --- a/build.xml +++ b/build.xml @@ -1,5 +1,6 @@ + @@ -10,7 +11,7 @@ get('config')); try { diff --git a/src/Aviat/AnimeClient/Model/Manga.php b/src/Aviat/AnimeClient/Model/Manga.php index 999578af..8cb51f26 100644 --- a/src/Aviat/AnimeClient/Model/Manga.php +++ b/src/Aviat/AnimeClient/Model/Manga.php @@ -162,7 +162,7 @@ class Manga extends API { $logger->warning("Non 200 response for search api call"); $logger->warning($response->getBody()); - throw new RuntimeException($response->getEffectiveUrl()); + throw new \RuntimeException($response->getEffectiveUrl()); } return Json::decode($response->getBody(), TRUE); diff --git a/src/Aviat/Ion/Cache/CacheInterface.php b/src/Aviat/Ion/Cache/CacheInterface.php index 94957384..4a4413bf 100644 --- a/src/Aviat/Ion/Cache/CacheInterface.php +++ b/src/Aviat/Ion/Cache/CacheInterface.php @@ -18,7 +18,7 @@ namespace Aviat\Ion\Cache; interface CacheInterface { /** - * Retreive 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 * * @param object $object - object to retrieve fresh value from @@ -29,7 +29,7 @@ interface CacheInterface { public function get($object, $method, array $args=[]); /** - * Retreive 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 string $method - method name to call diff --git a/src/Aviat/Ion/Cache/CacheManager.php b/src/Aviat/Ion/Cache/CacheManager.php index 34fc4887..d03947a2 100644 --- a/src/Aviat/Ion/Cache/CacheManager.php +++ b/src/Aviat/Ion/Cache/CacheManager.php @@ -13,6 +13,7 @@ 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 @@ -20,7 +21,7 @@ use Aviat\Ion\ConfigInterface; class CacheManager implements CacheInterface { /** - * @var CacheDriverInterface + * @var DriverInterface */ protected $driver; diff --git a/src/Aviat/Ion/Cache/CacheDriverInterface.php b/src/Aviat/Ion/Cache/Driver/DriverInterface.php similarity index 80% rename from src/Aviat/Ion/Cache/CacheDriverInterface.php rename to src/Aviat/Ion/Cache/Driver/DriverInterface.php index 9813f9bc..2f826c21 100644 --- a/src/Aviat/Ion/Cache/CacheDriverInterface.php +++ b/src/Aviat/Ion/Cache/Driver/DriverInterface.php @@ -10,12 +10,12 @@ * @license MIT */ -namespace Aviat\Ion\Cache; +namespace Aviat\Ion\Cache\Driver; /** * Interface for cache drivers */ -interface CacheDriverInterface { +interface DriverInterface { /** * Retreive a value from the cache backend * @@ -29,7 +29,7 @@ interface CacheDriverInterface { * * @param string $key * @param mixed $value - * @return CacheDriverInterface + * @return DriverInterface */ public function set($key, $value); @@ -37,7 +37,7 @@ interface CacheDriverInterface { * Invalidate a cached value * * @param string $key - * @return CacheDriverInterface + * @return DriverInterface */ public function invalidate($key); @@ -48,4 +48,4 @@ interface CacheDriverInterface { */ public function invalidateAll(); } -// End of CacheDriverInterface.php \ No newline at end of file +// End of DriverInterface.php \ No newline at end of file diff --git a/src/Aviat/Ion/Cache/Driver/DriverTrait.php b/src/Aviat/Ion/Cache/Driver/DriverTrait.php new file mode 100644 index 00000000..57b6b750 --- /dev/null +++ b/src/Aviat/Ion/Cache/Driver/DriverTrait.php @@ -0,0 +1,62 @@ +data = []; - } - - /** - * Retreive a value from the cache backend + * Retrieve a value from the cache backend * * @param string $key * @return mixed @@ -53,7 +41,7 @@ class NullDriver implements CacheDriverInterface { * * @param string $key * @param mixed $value - * @return CacheDriverInterface + * @return DriverInterface */ public function set($key, $value) { @@ -65,7 +53,7 @@ class NullDriver implements CacheDriverInterface { * Invalidate a cached value * * @param string $key - * @return CacheDriverInterface + * @return DriverInterface */ public function invalidate($key) { diff --git a/src/Aviat/Ion/Cache/Driver/RedisDriver.php b/src/Aviat/Ion/Cache/Driver/RedisDriver.php index 85e140d5..dc385aa3 100644 --- a/src/Aviat/Ion/Cache/Driver/RedisDriver.php +++ b/src/Aviat/Ion/Cache/Driver/RedisDriver.php @@ -13,11 +13,15 @@ namespace Aviat\Ion\Cache\Driver; use Aviat\Ion\ConfigInterface; -use Aviat\Ion\Cache\CacheDriverInterface; use Predis\Client; -class RedisDriver implements CacheDriverInterface { +/** + * Cache Driver for a Redis backend + */ +class RedisDriver implements DriverInterface { + + use DriverTrait; /** * THe Predis library instance @@ -35,6 +39,10 @@ class RedisDriver implements CacheDriverInterface { { $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']); @@ -54,36 +62,45 @@ class RedisDriver implements CacheDriverInterface { /** * Retrieve a value from the cache backend * - * @param string $key + * @param string $rawKey * @return mixed */ - public function get($key) + public function get($rawKey) { - return json_decode($this->redis->get($key)); + $key = $this->prefix($rawKey); + $serializedData = $this->redis->get($key); + + return $this->unserialize($serializedData); } /** * Set a cached value * - * @param string $key + * @param string $rawKey * @param mixed $value - * @return CacheDriverInterface + * @return DriverInterface */ - public function set($key, $value) + public function set($rawKey, $value) { - $this->redis->set($key, json_encode($value)); + $key = $this->prefix($rawKey); + $serializedData = $this->serialize($value); + + $this->redis->set($key, $serializedData); + return $this; } /** * Invalidate a cached value * - * @param string $key - * @return CacheDriverInterface + * @param string $rawKey + * @return DriverInterface */ - public function invalidate($key) + public function invalidate($rawKey) { + $key = $this->prefix($rawKey); $this->redis->del($key); + return $this; } @@ -94,7 +111,7 @@ class RedisDriver implements CacheDriverInterface { */ public function invalidateAll() { - $this->redis->flushDB(); + $this->redis->flushdb(); } } // End of RedisDriver.php \ No newline at end of file diff --git a/src/Aviat/Ion/Cache/Driver/SQLDriver.php b/src/Aviat/Ion/Cache/Driver/SQLDriver.php index f3bbc64d..703128ec 100644 --- a/src/Aviat/Ion/Cache/Driver/SQLDriver.php +++ b/src/Aviat/Ion/Cache/Driver/SQLDriver.php @@ -13,14 +13,15 @@ namespace Aviat\Ion\Cache\Driver; use Aviat\Ion\ConfigInterface; -use Aviat\Ion\Cache\CacheDriverInterface; use Aviat\Ion\Exception\ConfigException; use Aviat\Ion\Model\DB; /** * Driver for caching via a traditional SQL database */ -class SQLDriver extends DB implements CacheDriverInterface { +class SQLDriver extends DB implements DriverInterface { + + use DriverTrait; /** * The query builder object @@ -60,12 +61,14 @@ class SQLDriver extends DB implements CacheDriverInterface { ->get(); $row = $query->fetch(\PDO::FETCH_ASSOC); - if ( ! empty($row)) + + if (empty($row)) { - return json_decode($row['value']); + return NULL; } - - return NULL; + + $serializedData = $row['value']; + return $this->unserialize($serializedData); } /** @@ -73,15 +76,17 @@ class SQLDriver extends DB implements CacheDriverInterface { * * @param string $key * @param mixed $value - * @return CacheDriverInterface + * @return DriverInterface */ public function set($key, $value) { + $serializedData = $this->serialize($value); + $this->db->set([ 'key' => $key, - 'value' => json_encode($value), + 'value' => $serializedData, ]); - + $this->db->insert('cache'); return $this; @@ -91,7 +96,7 @@ class SQLDriver extends DB implements CacheDriverInterface { * Invalidate a cached value * * @param string $key - * @return CacheDriverInterface + * @return DriverInterface */ public function invalidate($key) { diff --git a/src/Aviat/Ion/Json.php b/src/Aviat/Ion/Json.php index 42370b19..b1581ecc 100644 --- a/src/Aviat/Ion/Json.php +++ b/src/Aviat/Ion/Json.php @@ -60,7 +60,15 @@ class Json { */ public static function decode($json, $assoc = TRUE, $depth = 512, $options = 0) { - $data = json_decode($json, $assoc, $depth, $options); + // 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; } diff --git a/tests/AnimeClient/Model/AnimeCollectionModelTest.php b/tests/AnimeClient/Model/AnimeCollectionModelTest.php index 1004b75d..5c931c15 100644 --- a/tests/AnimeClient/Model/AnimeCollectionModelTest.php +++ b/tests/AnimeClient/Model/AnimeCollectionModelTest.php @@ -31,7 +31,7 @@ class AnimeCollectionModelTest extends AnimeClient_TestCase { public function testSanity() { $friend = new Friend($this->collectionModel); - $this->assertInstanceOf('Aviat\AnimeClient\Model\DB', $this->collectionModel); + $this->assertInstanceOf('Aviat\Ion\Model\DB', $this->collectionModel); $this->assertInstanceOf('Aviat\AnimeClient\Model\Anime', $friend->anime_model); } diff --git a/tests/AnimeClient_TestCase.php b/tests/AnimeClient_TestCase.php index d778f14b..6b32e3ba 100644 --- a/tests/AnimeClient_TestCase.php +++ b/tests/AnimeClient_TestCase.php @@ -8,6 +8,7 @@ use GuzzleHttp\Psr7\Response; use Zend\Diactoros\ServerRequestFactory; use Zend\Diactoros\Response as HttpResponse; +use Aviat\Ion\Json; use Aviat\AnimeClient\AnimeClient; define('ROOT_DIR', __DIR__ . '/../'); @@ -119,6 +120,36 @@ class AnimeClient_TestCase extends PHPUnit_Framework_TestCase { $this->container->set('response', new HttpResponse()); } + /** + * Simplify getting test data + * + * Takes multiple path arguments + * + * @return string - contents of the data file + */ + public function getMockFile() + { + $args = func_get_args(); + array_unshift($args, TEST_DATA_DIR); + $filePath = implode(DIRECTORY_SEPARATOR, $args); + + return file_get_contents($filePath); + } + + /** + * Simplify getting mocked test data + * + * Takes multiple path arguments + * + * @return mixed - the decoded data + */ + public function getMockFileData() + { + $rawData = call_user_func_array([$this, 'getMockFile'], func_get_args()); + + return Json::decode($rawData); + } + /** * Create a mock guzzle client for testing * api call methods diff --git a/tests/AnimeClient/Model/BaseDBModelTest.php b/tests/Ion/Model/BaseDBModelTest.php similarity index 59% rename from tests/AnimeClient/Model/BaseDBModelTest.php rename to tests/Ion/Model/BaseDBModelTest.php index dbf9a40c..bdaf1954 100644 --- a/tests/AnimeClient/Model/BaseDBModelTest.php +++ b/tests/Ion/Model/BaseDBModelTest.php @@ -1,12 +1,12 @@ container); + $baseDBModel = new BaseDBModel($this->container->get('config')); $this->assertTrue(is_object($baseDBModel)); } } \ No newline at end of file diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 9df960d1..27f1c52e 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -3,9 +3,6 @@ * Global setup for unit tests */ -use Aviat\Ion\Json; -use Aviat\AnimeClient\AnimeClient; - // Work around the silly timezone error $timezone = ini_get('date.timezone'); if ($timezone === '' || $timezone === FALSE) diff --git a/tests/mocks.php b/tests/mocks.php index d4884bbe..fca39551 100644 --- a/tests/mocks.php +++ b/tests/mocks.php @@ -6,7 +6,6 @@ use Aviat\Ion\Enum; use Aviat\Ion\Friend; use Aviat\Ion\Json; -use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Transformer\AbstractTransformer; use Aviat\Ion\View; use Aviat\Ion\View\HtmlView; From 1ccce00e469e7b48a4644f4da56f6503944c961d Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Mon, 1 Aug 2016 13:10:00 -0400 Subject: [PATCH 23/65] Add dev dependencies, augment gitignore --- .gitignore | 4 +++- composer.json | 10 ++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 6d8a5863..72c6903d 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,6 @@ build/** !build/*.php app/config/*.toml !app/config/*.toml.example -phinx.yml \ No newline at end of file +phinx.yml +.idea/ +Caddyfile \ No newline at end of file diff --git a/composer.json b/composer.json index bf012bc2..3a168e70 100644 --- a/composer.json +++ b/composer.json @@ -16,12 +16,18 @@ "predis/predis": "1.1.*", "psr/http-message": "~1.0", "psr/log": "~1.0", - "robmorgan/phinx": "0.4.*", "yosymfony/toml": "0.3.*", "zendframework/zend-diactoros": "1.3.*", "maximebf/consolekit": "^1.0" }, "require-dev": { - "codeclimate/php-test-reporter": "dev-master" + "codeclimate/php-test-reporter": "dev-master", + "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" } } From cc65cc9cf176597f4f66acca7690bbbfac5a69e5 Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Mon, 1 Aug 2016 14:38:23 -0400 Subject: [PATCH 24/65] Set up mutation testing for unit tests --- .gitignore | 3 ++- composer.json | 3 ++- humbug.json.dist | 12 ++++++++++++ phpunit.xml | 29 +++++++++++++++++++++++++++++ tests/Ion/ConfigTest.php | 4 +++- tests/Ion/Di/ContainerTest.php | 16 ++++++++++++++-- tests/Ion/Type/ArrayTypeTest.php | 9 +++++++++ 7 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 humbug.json.dist create mode 100644 phpunit.xml diff --git a/.gitignore b/.gitignore index 72c6903d..78031d83 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,5 @@ app/config/*.toml !app/config/*.toml.example phinx.yml .idea/ -Caddyfile \ No newline at end of file +Caddyfile +build/humbuglog.txt \ No newline at end of file diff --git a/composer.json b/composer.json index 3a168e70..0a7b0777 100644 --- a/composer.json +++ b/composer.json @@ -28,6 +28,7 @@ "phploc/phploc": "^3.0", "phpmd/phpmd": "^2.4", "phpunit/phpunit": "^5.4", - "robmorgan/phinx": "^0.6.4" + "robmorgan/phinx": "^0.6.4", + "humbug/humbug": "~1.0@dev" } } diff --git a/humbug.json.dist b/humbug.json.dist new file mode 100644 index 00000000..d1e38834 --- /dev/null +++ b/humbug.json.dist @@ -0,0 +1,12 @@ +{ + "source": { + "directories": [ + "src" + ] + }, + "timeout": 10, + "logs": { + "text": "build\/humbuglog.txt", + "json": "build\/humbug.json" + } +} \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 00000000..6f5df955 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,29 @@ + + + + + src/Aviat/Ion + src/Aviat/AnimeClient + + + + + tests/Ion + + + tests/AnimeClient + + + + + + + + + + \ No newline at end of file diff --git a/tests/Ion/ConfigTest.php b/tests/Ion/ConfigTest.php index 3cd84de2..ca716cf8 100644 --- a/tests/Ion/ConfigTest.php +++ b/tests/Ion/ConfigTest.php @@ -23,7 +23,8 @@ class ConfigTest extends AnimeClient_TestCase { public function testConfigSet() { - $this->config->set('foo', 'foobar'); + $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'); @@ -31,6 +32,7 @@ class ConfigTest extends AnimeClient_TestCase { $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() diff --git a/tests/Ion/Di/ContainerTest.php b/tests/Ion/Di/ContainerTest.php index f4002582..bbf22627 100644 --- a/tests/Ion/Di/ContainerTest.php +++ b/tests/Ion/Di/ContainerTest.php @@ -51,6 +51,15 @@ class ContainerTest extends AnimeClient_TestCase { } } + public function testGetSet() + { + $container = $this->container->set('foo', 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? @@ -63,8 +72,11 @@ class ContainerTest extends AnimeClient_TestCase { $logger2->pushHandler(new TestHandler()); // Set the logger channels - $this->container->setLogger($logger1); - $this->container->setLogger($logger2, 'test'); + $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')); diff --git a/tests/Ion/Type/ArrayTypeTest.php b/tests/Ion/Type/ArrayTypeTest.php index db2d56c6..e78315ee 100644 --- a/tests/Ion/Type/ArrayTypeTest.php +++ b/tests/Ion/Type/ArrayTypeTest.php @@ -79,6 +79,15 @@ class ArrayTypeTest extends AnimeClient_TestCase { $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]; From b14413af3f8bf91af8ce7872893feab58945c80c Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Wed, 3 Aug 2016 13:47:14 -0400 Subject: [PATCH 25/65] Attempt to fix gitlab ci build --- build/docker_install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/build/docker_install.sh b/build/docker_install.sh index 7dca9c3f..df5633ea 100644 --- a/build/docker_install.sh +++ b/build/docker_install.sh @@ -20,4 +20,5 @@ chmod +x /usr/local/bin/phpunit docker-php-ext-configure gd --enable-gd-native-ttf --with-jpeg-dir=/usr/lib/x86_64-linux-gnu --with-png-dir=/usr/lib/x86_64-linux-gnu --with-freetype-dir=/usr/lib/x86_64-linux-gnu docker-php-ext-install gd docker-php-ext-install mcrypt +docker-php-ext-install xsl docker-php-ext-install zip \ No newline at end of file From aac478a455530e4ac2f1b2ee56378706c9dc88b5 Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Wed, 3 Aug 2016 14:08:02 -0400 Subject: [PATCH 26/65] Another attempt to fix gitlab ci build --- build/docker_install.sh | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/build/docker_install.sh b/build/docker_install.sh index df5633ea..e7b4a8d1 100644 --- a/build/docker_install.sh +++ b/build/docker_install.sh @@ -10,7 +10,21 @@ set -xe # Install git (the php image doesn't have it) which is required by composer apt-get update -yqq -apt-get install git unzip libfreetype6 libjpeg62-turbo libmcrypt4 libpng12-0 libfreetype6-dev libjpeg-dev libmcrypt-dev libpng12-dev zlib1g-dev -yqq +apt-get install \ + git \ + unzip \ + libfreetype6 \ + libjpeg62-turbo \ + libmcrypt4 \ + libpng12-0 \ + libfreetype6-dev \ + libjpeg-dev \ + libmcrypt-dev \ + libpng12-dev \ + libxslt1-dev \ + libxslt1.1 \ + zlib1g-dev \ + -yqq # Install phpunit, the tool that we will use for testing curl -Lo /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar From 282fb44603d997f8cb98909d6b7eabbae630db01 Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Wed, 3 Aug 2016 14:14:38 -0400 Subject: [PATCH 27/65] Don't install dev dependencies in test environments --- .gitlab-ci.yml | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 78229a40..5609409c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,7 +3,7 @@ before_script: - bash build/docker_install.sh > /dev/null # Install composer dependencies - curl -sS https://getcomposer.org/installer | php - - php composer.phar install + - php composer.phar install --no-dev # Composer stores all downloaded packages in the vendor/ directory. # Do not use the following if the vendor/ directory is commited to diff --git a/.travis.yml b/.travis.yml index a863b2c5..cf72aec6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: php install: - - composer install + - composer install --no-dev php: - 5.5 From 30834be3a8660cd620184230751d753c9fb647a6 Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Wed, 3 Aug 2016 14:30:36 -0400 Subject: [PATCH 28/65] Attempt hhvm testing on gitlab ci, adjust acceptable failures on travis --- .gitlab-ci.yml | 27 +++++++++++++++++++-------- .travis.yml | 1 + 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5609409c..0bea8b39 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,10 +1,3 @@ -before_script: - # Install dependencies - - bash build/docker_install.sh > /dev/null - # Install composer dependencies - - curl -sS https://getcomposer.org/installer | php - - php composer.phar install --no-dev - # Composer stores all downloaded packages in the vendor/ directory. # Do not use the following if the vendor/ directory is commited to # your git repository. @@ -16,11 +9,29 @@ 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 \ No newline at end of file + - phpunit -c build + +test:hhvm: + before_script: + - curl -sS https://getcomposer.org/installer | hhvm + - hhvm composer.phar install --no-dev + - curl -Lo /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar + - chmod +x /usr/local/bin/phpunit + image: diegomarangoni/hhvm:cli + script: + - hhvm `which phpunit` -c build \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index cf72aec6..8de0e34a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,6 +26,7 @@ after_script: matrix: allow_failures: + - php: 5.5 - php: nightly - php: hhvm From d30e90937b46073773434cbd1d799a95914a21bd Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Wed, 3 Aug 2016 18:09:55 -0400 Subject: [PATCH 29/65] try a different docker container for running hhvm tests --- .gitlab-ci.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0bea8b39..99346c5d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -28,10 +28,7 @@ test:7: test:hhvm: before_script: - - curl -sS https://getcomposer.org/installer | hhvm - - hhvm composer.phar install --no-dev - - curl -Lo /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar - - chmod +x /usr/local/bin/phpunit - image: diegomarangoni/hhvm:cli + - composer install -g phpunit + image: 51systems/docker-gitlab-ci-runner-hhvm script: - - hhvm `which phpunit` -c build \ No newline at end of file + - phpunit -c build \ No newline at end of file From f163ea41d6289e0d9a2434514f15a1daf5e397b7 Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Wed, 3 Aug 2016 18:25:28 -0400 Subject: [PATCH 30/65] actually use the correct composer command to install phpunit for hhvm --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 99346c5d..f3ebbddc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -28,7 +28,7 @@ test:7: test:hhvm: before_script: - - composer install -g phpunit + - composer global require "phpunit/phpunit" image: 51systems/docker-gitlab-ci-runner-hhvm script: - phpunit -c build \ No newline at end of file From 1d6e347b7877dd0f5df1c37b976c23ef497dea46 Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Wed, 3 Aug 2016 18:43:09 -0400 Subject: [PATCH 31/65] Another attempt at hhvm setup --- .gitlab-ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f3ebbddc..265afb81 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -28,7 +28,10 @@ test:7: test:hhvm: before_script: - - composer global require "phpunit/phpunit" + - /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 \ No newline at end of file From 3335093e87212eb75488ff9c3b9c9cf9e8778591 Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Tue, 9 Aug 2016 11:08:45 -0400 Subject: [PATCH 32/65] Move Ion namespace into composer dependency --- RoboFile.php | 278 ++++++++++++++++++ build/ion_header_comment.txt | 10 - build/phpunit.xml | 4 - build/update_header_comments.php | 10 - composer.json | 10 +- phpunit.xml | 4 - src/Aviat/Ion/ArrayWrapper.php | 34 --- src/Aviat/Ion/Cache/CacheInterface.php | 48 --- src/Aviat/Ion/Cache/CacheManager.php | 117 -------- .../Ion/Cache/Driver/DriverInterface.php | 51 ---- src/Aviat/Ion/Cache/Driver/DriverTrait.php | 62 ---- src/Aviat/Ion/Cache/Driver/NullDriver.php | 74 ----- src/Aviat/Ion/Cache/Driver/RedisDriver.php | 117 -------- src/Aviat/Ion/Cache/Driver/SQLDriver.php | 119 -------- src/Aviat/Ion/Config.php | 106 ------- src/Aviat/Ion/ConfigInterface.php | 41 --- src/Aviat/Ion/Di/Container.php | 134 --------- src/Aviat/Ion/Di/ContainerAware.php | 49 --- src/Aviat/Ion/Di/ContainerAwareInterface.php | 36 --- src/Aviat/Ion/Di/ContainerInterface.php | 47 --- .../Ion/Di/Exception/ContainerException.php | 21 -- .../Ion/Di/Exception/NotFoundException.php | 22 -- src/Aviat/Ion/Enum.php | 49 --- src/Aviat/Ion/Exception/ConfigException.php | 20 -- src/Aviat/Ion/Friend.php | 129 -------- src/Aviat/Ion/Json.php | 130 -------- src/Aviat/Ion/JsonException.php | 18 -- src/Aviat/Ion/Model.php | 21 -- src/Aviat/Ion/Model/DB.php | 51 ---- src/Aviat/Ion/StaticInstance.php | 63 ---- src/Aviat/Ion/StringWrapper.php | 33 --- .../Ion/Transformer/AbstractTransformer.php | 42 --- .../Ion/Transformer/TransformerInterface.php | 27 -- src/Aviat/Ion/Type/ArrayType.php | 261 ---------------- src/Aviat/Ion/Type/StringType.php | 23 -- src/Aviat/Ion/View.php | 137 --------- src/Aviat/Ion/View/HtmlView.php | 69 ----- src/Aviat/Ion/View/HttpView.php | 91 ------ src/Aviat/Ion/View/JsonView.php | 47 --- tests/Ion/BaseModelTest.php | 12 - tests/Ion/Cache/CacheManagerTest.php | 40 --- tests/Ion/Cache/Driver/CacheDriverBase.php | 43 --- tests/Ion/Cache/Driver/NullDriverTest.php | 17 -- tests/Ion/Cache/Driver/RedisDriver2Test.php | 38 --- tests/Ion/Cache/Driver/RedisDriverTest.php | 29 -- tests/Ion/Cache/Driver/SQLDriverTest.php | 20 -- tests/Ion/ConfigTest.php | 120 -------- tests/Ion/Di/ContainerAwareTest.php | 39 --- tests/Ion/Di/ContainerTest.php | 89 ------ tests/Ion/EnumTest.php | 68 ----- tests/Ion/FriendTest.php | 56 ---- tests/Ion/JsonTest.php | 68 ----- tests/Ion/Model/BaseDBModelTest.php | 12 - .../Transformer/AbstractTransformerTest.php | 89 ------ tests/Ion/Type/ArrayTypeTest.php | 173 ----------- tests/Ion/View/HtmlViewTest.php | 25 -- tests/Ion/View/HttpViewTest.php | 46 --- tests/Ion/View/JsonViewTest.php | 43 --- 58 files changed, 282 insertions(+), 3350 deletions(-) create mode 100644 RoboFile.php delete mode 100644 build/ion_header_comment.txt delete mode 100644 src/Aviat/Ion/ArrayWrapper.php delete mode 100644 src/Aviat/Ion/Cache/CacheInterface.php delete mode 100644 src/Aviat/Ion/Cache/CacheManager.php delete mode 100644 src/Aviat/Ion/Cache/Driver/DriverInterface.php delete mode 100644 src/Aviat/Ion/Cache/Driver/DriverTrait.php delete mode 100644 src/Aviat/Ion/Cache/Driver/NullDriver.php delete mode 100644 src/Aviat/Ion/Cache/Driver/RedisDriver.php delete mode 100644 src/Aviat/Ion/Cache/Driver/SQLDriver.php delete mode 100644 src/Aviat/Ion/Config.php delete mode 100644 src/Aviat/Ion/ConfigInterface.php delete mode 100644 src/Aviat/Ion/Di/Container.php delete mode 100644 src/Aviat/Ion/Di/ContainerAware.php delete mode 100644 src/Aviat/Ion/Di/ContainerAwareInterface.php delete mode 100644 src/Aviat/Ion/Di/ContainerInterface.php delete mode 100644 src/Aviat/Ion/Di/Exception/ContainerException.php delete mode 100644 src/Aviat/Ion/Di/Exception/NotFoundException.php delete mode 100644 src/Aviat/Ion/Enum.php delete mode 100644 src/Aviat/Ion/Exception/ConfigException.php delete mode 100644 src/Aviat/Ion/Friend.php delete mode 100644 src/Aviat/Ion/Json.php delete mode 100644 src/Aviat/Ion/JsonException.php delete mode 100644 src/Aviat/Ion/Model.php delete mode 100644 src/Aviat/Ion/Model/DB.php delete mode 100644 src/Aviat/Ion/StaticInstance.php delete mode 100644 src/Aviat/Ion/StringWrapper.php delete mode 100644 src/Aviat/Ion/Transformer/AbstractTransformer.php delete mode 100644 src/Aviat/Ion/Transformer/TransformerInterface.php delete mode 100644 src/Aviat/Ion/Type/ArrayType.php delete mode 100644 src/Aviat/Ion/Type/StringType.php delete mode 100644 src/Aviat/Ion/View.php delete mode 100644 src/Aviat/Ion/View/HtmlView.php delete mode 100644 src/Aviat/Ion/View/HttpView.php delete mode 100644 src/Aviat/Ion/View/JsonView.php delete mode 100644 tests/Ion/BaseModelTest.php delete mode 100644 tests/Ion/Cache/CacheManagerTest.php delete mode 100644 tests/Ion/Cache/Driver/CacheDriverBase.php delete mode 100644 tests/Ion/Cache/Driver/NullDriverTest.php delete mode 100644 tests/Ion/Cache/Driver/RedisDriver2Test.php delete mode 100644 tests/Ion/Cache/Driver/RedisDriverTest.php delete mode 100644 tests/Ion/Cache/Driver/SQLDriverTest.php delete mode 100644 tests/Ion/ConfigTest.php delete mode 100644 tests/Ion/Di/ContainerAwareTest.php delete mode 100644 tests/Ion/Di/ContainerTest.php delete mode 100644 tests/Ion/EnumTest.php delete mode 100644 tests/Ion/FriendTest.php delete mode 100644 tests/Ion/JsonTest.php delete mode 100644 tests/Ion/Model/BaseDBModelTest.php delete mode 100644 tests/Ion/Transformer/AbstractTransformerTest.php delete mode 100644 tests/Ion/Type/ArrayTypeTest.php delete mode 100644 tests/Ion/View/HtmlViewTest.php delete mode 100644 tests/Ion/View/HttpViewTest.php delete mode 100644 tests/Ion/View/JsonViewTest.php diff --git a/RoboFile.php b/RoboFile.php new file mode 100644 index 00000000..b63ee609 --- /dev/null +++ b/RoboFile.php @@ -0,0 +1,278 @@ +prepare(); + $this->lint(); + $this->phploc(TRUE); + $this->dependencyReport(); + $this->phpcpdReport(); + } + + /** + * Run all tests, generate coverage, generate docs, generate code statistics + */ + public function build() + { + $this->analyze(); + $this->coverage(); + $this->docs(); + } + + /** + * Cleanup temporary files + */ + public function clean() + { + $cleanFiles = [ + 'build/humbug.json', + 'build/humbug-log.txt', + ]; + array_map(function ($file) { + @unlink($file); + }, $cleanFiles); + + $this->_cleanDir($this->taskDirs); + $this->_deleteDir($this->taskDirs); + } + + /** + * Run unit tests and generate coverage reports + */ + public function coverage() + { + $this->taskPhpUnit() + ->configFile('build/phpunit.xml') + ->printed(true) + ->run(); + } + + /** + * Generate documentation with phpdox + */ + public function docs() + { + $cmd_parts = [ + 'cd build', + '../vendor/bin/phpdox', + 'cd ..' + ]; + $this->_run($cmd_parts, ' && '); + } + + /** + * Verify that source files are valid + */ + public function lint() + { + $files = $this->getAllSourceFiles(); + + $chunks = array_chunk($files, 6); + $collection = $this->collection(); + + foreach($chunks as $chunk) + { + $this->parallelLint($collection, $chunk); + } + + $collection->run(); + } + + + /** + * Run mutation tests with humbug + * + * @param bool $stats - if true, generates stats rather than running mutation tests + */ + public function mutate($stats = FALSE) + { + $test_parts = [ + 'vendor/bin/humbug' + ]; + + $stat_parts = [ + 'vendor/bin/humbug', + '--skip-killed=yes', + '-v', + './build/humbug.json' + ]; + + $cmd_parts = ($stats) ? $stat_parts : $test_parts; + $this->_run($cmd_parts); + } + + /** + * Run the phploc tool + * + * @param bool $report - if true, generates reports instead of direct output + */ + public function phploc($report = FALSE) + { + // Command for generating reports + $report_cmd_parts = [ + 'vendor/bin/phploc', + '--log-csv=build/logs/phploc.csv', + '--log-xml=build/logs/phploc.xml', + 'src', + 'tests' + ]; + + // Command for generating direct output + $normal_cmd_parts = [ + 'vendor/bin/phploc', + '--count-tests', + 'src', + 'tests' + ]; + + $cmd_parts = ($report) ? $report_cmd_parts : $normal_cmd_parts; + + $this->_run($cmd_parts); + } + + /** + * Create temporary directories + */ + public function prepare() + { + $this->clean(); + array_map([$this, '_mkdir'], $this->taskDirs); + } + + /** + * Lint php files and run unit tests + */ + public function test() + { + $this->lint(); + $this->taskPHPUnit() + ->configFile('phpunit.xml') + ->printed(true) + ->run(); + } + + /** + * Watches for file updates, and automatically runs appropriate actions + */ + public function watch() + { + $this->taskWatch() + ->monitor('composer.json', function() { + $this->taskComposerUpdate()->run(); + }) + ->monitor('src', function () { + $this->taskExec('test')->run(); + })->run(); + } + + /** + * Create pdepend reports + */ + protected function dependencyReport() + { + $cmd_parts = [ + 'vendor/bin/pdepend', + '--jdepend-xml=build/logs/jdepend.xml', + '--jdepend-chart=build/pdepend/dependencies.svg', + '--overview-pyramid=build/pdepend/overview-pyramid.svg', + 'src' + ]; + $this->_run($cmd_parts); + } + + /** + * Get the total list of source files, including tests + * + * @return array + */ + protected function getAllSourceFiles() + { + $files = array_merge( + glob_recursive('build/*.php'), + glob_recursive('src/*.php'), + glob_recursive('tests/*.php'), + glob('*.php') + ); + + sort($files); + + return $files; + } + + /** + * Run php's linter in one parallel task for the passed chunk + * + * @param Collection $collection + * @param array $chunk + */ + protected function parallelLint($collection, array $chunk) + { + $task = $this->taskParallelExec(); + + foreach($chunk as $file) + { + $task = $task->process("php -l {$file}"); + } + + $collection->add($task); + } + + /** + * Generate copy paste detector report + */ + protected function phpcpdReport() + { + $cmd_parts = [ + 'vendor/bin/phpcpd', + '--log-pmd build/logs/pmd-cpd.xml', + 'src' + ]; + $this->_run($cmd_parts); + } + + /** + * Short cut for joining an array of command arguments + * and then running it + * + * @param array $cmd_parts - command arguments + * @param string $join_on - what to join the command arguments with + */ + protected function _run(array $cmd_parts, $join_on = ' ') + { + $this->_exec(implode($join_on, $cmd_parts)); + } +} \ No newline at end of file diff --git a/build/ion_header_comment.txt b/build/ion_header_comment.txt deleted file mode 100644 index 50a30257..00000000 --- a/build/ion_header_comment.txt +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Ion - * - * Building blocks for web development - * - * @package Ion - * @author Timothy J. Warren - * @copyright Copyright (c) 2015 - 2016 - * @license MIT - */ \ No newline at end of file diff --git a/build/phpunit.xml b/build/phpunit.xml index 3c63f182..0b605295 100644 --- a/build/phpunit.xml +++ b/build/phpunit.xml @@ -8,14 +8,10 @@ > - ../src/Aviat/Ion ../src/Aviat/AnimeClient - - ../tests/Ion - ../tests/AnimeClient diff --git a/build/update_header_comments.php b/build/update_header_comments.php index 852cf635..a7423f3b 100644 --- a/build/update_header_comments.php +++ b/build/update_header_comments.php @@ -7,10 +7,6 @@ $animeclient_file_patterns = [ 'src/Aviat/AnimeClient/*.php' ]; -$ion_file_patterns = [ - 'src/Aviat/Ion/*.php' -]; - if ( ! function_exists('glob_recursive')) { // Does not support flag GLOB_BRACE @@ -80,10 +76,4 @@ $loose_files = [ ]; replace_files($loose_files, '/animeclient_header_comment.txt'); -foreach ($ion_file_patterns as $glob) -{ - $files = glob_recursive($glob); - replace_files($files, '/ion_header_comment.txt'); -} - echo "Successfully updated headers \n"; \ No newline at end of file diff --git a/composer.json b/composer.json index 0a7b0777..f769e115 100644 --- a/composer.json +++ b/composer.json @@ -7,13 +7,10 @@ "aura/html": "2.*", "aura/router": "3.*", "aura/session": "2.*", - "aviat4ion/query": "2.5.*", - "container-interop/container-interop": "1.*", - "danielstjules/stringy": "~2.1", + "aviat/ion": "dev-master", "filp/whoops": "2.0.*", "guzzlehttp/guzzle": "6.*", "monolog/monolog": "1.*", - "predis/predis": "1.1.*", "psr/http-message": "~1.0", "psr/log": "~1.0", "yosymfony/toml": "0.3.*", @@ -21,7 +18,6 @@ "maximebf/consolekit": "^1.0" }, "require-dev": { - "codeclimate/php-test-reporter": "dev-master", "pdepend/pdepend": "^2.2", "sebastian/phpcpd": "^2.0", "theseer/phpdox": "0.8.1.1", @@ -29,6 +25,8 @@ "phpmd/phpmd": "^2.4", "phpunit/phpunit": "^5.4", "robmorgan/phinx": "^0.6.4", - "humbug/humbug": "~1.0@dev" + "humbug/humbug": "~1.0@dev", + "consolidation/robo": "~1.0@dev", + "henrikbjorn/lurker": "^1.1.0" } } diff --git a/phpunit.xml b/phpunit.xml index 6f5df955..18ac4012 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -7,14 +7,10 @@ > - src/Aviat/Ion src/Aviat/AnimeClient - - tests/Ion - tests/AnimeClient diff --git a/src/Aviat/Ion/ArrayWrapper.php b/src/Aviat/Ion/ArrayWrapper.php deleted file mode 100644 index 74ec7da4..00000000 --- a/src/Aviat/Ion/ArrayWrapper.php +++ /dev/null @@ -1,34 +0,0 @@ -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 \ No newline at end of file diff --git a/src/Aviat/Ion/Cache/Driver/DriverInterface.php b/src/Aviat/Ion/Cache/Driver/DriverInterface.php deleted file mode 100644 index 2f826c21..00000000 --- a/src/Aviat/Ion/Cache/Driver/DriverInterface.php +++ /dev/null @@ -1,51 +0,0 @@ -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 \ No newline at end of file diff --git a/src/Aviat/Ion/Cache/Driver/RedisDriver.php b/src/Aviat/Ion/Cache/Driver/RedisDriver.php deleted file mode 100644 index dc385aa3..00000000 --- a/src/Aviat/Ion/Cache/Driver/RedisDriver.php +++ /dev/null @@ -1,117 +0,0 @@ -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 \ No newline at end of file diff --git a/src/Aviat/Ion/Cache/Driver/SQLDriver.php b/src/Aviat/Ion/Cache/Driver/SQLDriver.php deleted file mode 100644 index 703128ec..00000000 --- a/src/Aviat/Ion/Cache/Driver/SQLDriver.php +++ /dev/null @@ -1,119 +0,0 @@ -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 \ No newline at end of file diff --git a/src/Aviat/Ion/Config.php b/src/Aviat/Ion/Config.php deleted file mode 100644 index c0dea9f0..00000000 --- a/src/Aviat/Ion/Config.php +++ /dev/null @@ -1,106 +0,0 @@ -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 \ No newline at end of file diff --git a/src/Aviat/Ion/ConfigInterface.php b/src/Aviat/Ion/ConfigInterface.php deleted file mode 100644 index 9c644bae..00000000 --- a/src/Aviat/Ion/ConfigInterface.php +++ /dev/null @@ -1,41 +0,0 @@ -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 Exception\ContainerException("Id must be a string"); - } - - if ($this->has($id)) - { - return $this->container[$id]; - } - - throw new Exception\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 retreive - * @return LoggerInterface|null - */ - public function getLogger($key = 'default') - { - return ($this->hasLogger($key)) - ? $this->loggers[$key] - : NULL; - } -} -// End of Container.php \ No newline at end of file diff --git a/src/Aviat/Ion/Di/ContainerAware.php b/src/Aviat/Ion/Di/ContainerAware.php deleted file mode 100644 index 8aaf0168..00000000 --- a/src/Aviat/Ion/Di/ContainerAware.php +++ /dev/null @@ -1,49 +0,0 @@ -container = $container; - return $this; - } - - /** - * Get the container object - * - * @return ContainerInterface - */ - public function getContainer() - { - return $this->container; - } -} -// End of ContainerAware.php \ No newline at end of file diff --git a/src/Aviat/Ion/Di/ContainerAwareInterface.php b/src/Aviat/Ion/Di/ContainerAwareInterface.php deleted file mode 100644 index 64de7b6b..00000000 --- a/src/Aviat/Ion/Di/ContainerAwareInterface.php +++ /dev/null @@ -1,36 +0,0 @@ -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 \ No newline at end of file diff --git a/src/Aviat/Ion/Exception/ConfigException.php b/src/Aviat/Ion/Exception/ConfigException.php deleted file mode 100644 index ea1d21c3..00000000 --- a/src/Aviat/Ion/Exception/ConfigException.php +++ /dev/null @@ -1,20 +0,0 @@ -_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 \ No newline at end of file diff --git a/src/Aviat/Ion/Json.php b/src/Aviat/Ion/Json.php deleted file mode 100644 index b1581ecc..00000000 --- a/src/Aviat/Ion/Json.php +++ /dev/null @@ -1,130 +0,0 @@ -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 \ No newline at end of file diff --git a/src/Aviat/Ion/JsonException.php b/src/Aviat/Ion/JsonException.php deleted file mode 100644 index 5be77c4f..00000000 --- a/src/Aviat/Ion/JsonException.php +++ /dev/null @@ -1,18 +0,0 @@ -config = $config; - $this->db_config = (array)$config->get('database'); - } -} -// End of DB.php \ No newline at end of file diff --git a/src/Aviat/Ion/StaticInstance.php b/src/Aviat/Ion/StaticInstance.php deleted file mode 100644 index 7a67b931..00000000 --- a/src/Aviat/Ion/StaticInstance.php +++ /dev/null @@ -1,63 +0,0 @@ - '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 \ No newline at end of file diff --git a/src/Aviat/Ion/Type/StringType.php b/src/Aviat/Ion/Type/StringType.php deleted file mode 100644 index 02c8cd81..00000000 --- a/src/Aviat/Ion/Type/StringType.php +++ /dev/null @@ -1,23 +0,0 @@ -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 \ No newline at end of file diff --git a/src/Aviat/Ion/View/HtmlView.php b/src/Aviat/Ion/View/HtmlView.php deleted file mode 100644 index d73cad04..00000000 --- a/src/Aviat/Ion/View/HtmlView.php +++ /dev/null @@ -1,69 +0,0 @@ -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 \ No newline at end of file diff --git a/src/Aviat/Ion/View/HttpView.php b/src/Aviat/Ion/View/HttpView.php deleted file mode 100644 index 7ff97f01..00000000 --- a/src/Aviat/Ion/View/HttpView.php +++ /dev/null @@ -1,91 +0,0 @@ -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); - } - -} \ No newline at end of file diff --git a/src/Aviat/Ion/View/JsonView.php b/src/Aviat/Ion/View/JsonView.php deleted file mode 100644 index a65dd558..00000000 --- a/src/Aviat/Ion/View/JsonView.php +++ /dev/null @@ -1,47 +0,0 @@ -assertTrue(is_object($baseModel)); - } -} \ No newline at end of file diff --git a/tests/Ion/Cache/CacheManagerTest.php b/tests/Ion/Cache/CacheManagerTest.php deleted file mode 100644 index 7d88dcc1..00000000 --- a/tests/Ion/Cache/CacheManagerTest.php +++ /dev/null @@ -1,40 +0,0 @@ -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)); - } -} \ No newline at end of file diff --git a/tests/Ion/Cache/Driver/CacheDriverBase.php b/tests/Ion/Cache/Driver/CacheDriverBase.php deleted file mode 100644 index d1e333aa..00000000 --- a/tests/Ion/Cache/Driver/CacheDriverBase.php +++ /dev/null @@ -1,43 +0,0 @@ - [ - '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')); - } -} \ No newline at end of file diff --git a/tests/Ion/Cache/Driver/NullDriverTest.php b/tests/Ion/Cache/Driver/NullDriverTest.php deleted file mode 100644 index df6606d4..00000000 --- a/tests/Ion/Cache/Driver/NullDriverTest.php +++ /dev/null @@ -1,17 +0,0 @@ -driver = new NullDriver($this->container->get('config')); - } -} \ No newline at end of file diff --git a/tests/Ion/Cache/Driver/RedisDriver2Test.php b/tests/Ion/Cache/Driver/RedisDriver2Test.php deleted file mode 100644 index 62f5482d..00000000 --- a/tests/Ion/Cache/Driver/RedisDriver2Test.php +++ /dev/null @@ -1,38 +0,0 @@ - [ - '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(); - } - } -} \ No newline at end of file diff --git a/tests/Ion/Cache/Driver/RedisDriverTest.php b/tests/Ion/Cache/Driver/RedisDriverTest.php deleted file mode 100644 index ed1209f5..00000000 --- a/tests/Ion/Cache/Driver/RedisDriverTest.php +++ /dev/null @@ -1,29 +0,0 @@ -driver = new RedisDriver($this->container->get('config')); - } - - public function tearDown() - { - parent::tearDown(); - - if ( ! is_null($this->driver)) - { - $this->driver->__destruct(); - } - - } -} \ No newline at end of file diff --git a/tests/Ion/Cache/Driver/SQLDriverTest.php b/tests/Ion/Cache/Driver/SQLDriverTest.php deleted file mode 100644 index 4cd98659..00000000 --- a/tests/Ion/Cache/Driver/SQLDriverTest.php +++ /dev/null @@ -1,20 +0,0 @@ -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"))'); - } -} \ No newline at end of file diff --git a/tests/Ion/ConfigTest.php b/tests/Ion/ConfigTest.php deleted file mode 100644 index ca716cf8..00000000 --- a/tests/Ion/ConfigTest.php +++ /dev/null @@ -1,120 +0,0 @@ -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')); - } -} \ No newline at end of file diff --git a/tests/Ion/Di/ContainerAwareTest.php b/tests/Ion/Di/ContainerAwareTest.php deleted file mode 100644 index dd506721..00000000 --- a/tests/Ion/Di/ContainerAwareTest.php +++ /dev/null @@ -1,39 +0,0 @@ -container = $container; - } -} - - -class ContainerAwareTest extends AnimeClient_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()); - } -} \ No newline at end of file diff --git a/tests/Ion/Di/ContainerTest.php b/tests/Ion/Di/ContainerTest.php deleted file mode 100644 index bbf22627..00000000 --- a/tests/Ion/Di/ContainerTest.php +++ /dev/null @@ -1,89 +0,0 @@ -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() {}); - - $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')); - } -} \ No newline at end of file diff --git a/tests/Ion/EnumTest.php b/tests/Ion/EnumTest.php deleted file mode 100644 index 5a766b19..00000000 --- a/tests/Ion/EnumTest.php +++ /dev/null @@ -1,68 +0,0 @@ - '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); - } -} \ No newline at end of file diff --git a/tests/Ion/FriendTest.php b/tests/Ion/FriendTest.php deleted file mode 100644 index 1569eb42..00000000 --- a/tests/Ion/FriendTest.php +++ /dev/null @@ -1,56 +0,0 @@ -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(); - } -} \ No newline at end of file diff --git a/tests/Ion/JsonTest.php b/tests/Ion/JsonTest.php deleted file mode 100644 index 44cb4bbe..00000000 --- a/tests/Ion/JsonTest.php +++ /dev/null @@ -1,68 +0,0 @@ - [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); - } -} \ No newline at end of file diff --git a/tests/Ion/Model/BaseDBModelTest.php b/tests/Ion/Model/BaseDBModelTest.php deleted file mode 100644 index bdaf1954..00000000 --- a/tests/Ion/Model/BaseDBModelTest.php +++ /dev/null @@ -1,12 +0,0 @@ -container->get('config')); - $this->assertTrue(is_object($baseDBModel)); - } -} \ No newline at end of file diff --git a/tests/Ion/Transformer/AbstractTransformerTest.php b/tests/Ion/Transformer/AbstractTransformerTest.php deleted file mode 100644 index 246658ac..00000000 --- a/tests/Ion/Transformer/AbstractTransformerTest.php +++ /dev/null @@ -1,89 +0,0 @@ -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); - } -} \ No newline at end of file diff --git a/tests/Ion/Type/ArrayTypeTest.php b/tests/Ion/Type/ArrayTypeTest.php deleted file mode 100644 index e78315ee..00000000 --- a/tests/Ion/Type/ArrayTypeTest.php +++ /dev/null @@ -1,173 +0,0 @@ - '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); - } -} \ No newline at end of file diff --git a/tests/Ion/View/HtmlViewTest.php b/tests/Ion/View/HtmlViewTest.php deleted file mode 100644 index cab5aecf..00000000 --- a/tests/Ion/View/HtmlViewTest.php +++ /dev/null @@ -1,25 +0,0 @@ -view = new TestHtmlView($this->container); - } - - public function testRenderTemplate() - { - $path = _dir(self::TEST_VIEW_DIR, 'test_view.php'); - $expected = 'foo'; - $actual = $this->view->render_template($path, [ - 'var' => 'foo' - ]); - $this->assertEquals($expected, $actual); - } - -} \ No newline at end of file diff --git a/tests/Ion/View/HttpViewTest.php b/tests/Ion/View/HttpViewTest.php deleted file mode 100644 index 0112246d..00000000 --- a/tests/Ion/View/HttpViewTest.php +++ /dev/null @@ -1,46 +0,0 @@ -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('

'); - $this->assertEquals($same, $this->view); - $this->assertEquals('

', $this->view->getOutput()); - } - - public function testAppendOutput() - { - $this->view->setOutput('

'); - $this->view->appendOutput('

'); - $this->assertEquals('

', $this->view->getOutput()); - } - - public function testSetStatusCode() - { - $view = $this->view->setStatusCode(404); - $this->assertEquals(404, $view->response->getStatusCode()); - } -} \ No newline at end of file diff --git a/tests/Ion/View/JsonViewTest.php b/tests/Ion/View/JsonViewTest.php deleted file mode 100644 index 0c21bb54..00000000 --- a/tests/Ion/View/JsonViewTest.php +++ /dev/null @@ -1,43 +0,0 @@ -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); - } -} \ No newline at end of file From f1a6f99fc495450f054af64fc82671e608adadce Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Mon, 29 Aug 2016 14:51:32 -0400 Subject: [PATCH 33/65] Convert Dependency injection bootstrap file to use factory functions, rather than direct instances --- app/bootstrap.php | 89 ++++++++++++++++++++++++++++++----------------- composer.json | 5 +-- 2 files changed, 61 insertions(+), 33 deletions(-) diff --git a/app/bootstrap.php b/app/bootstrap.php index 38c96305..a3bcd2b2 100644 --- a/app/bootstrap.php +++ b/app/bootstrap.php @@ -38,58 +38,85 @@ return function(array $config_array = []) { // ------------------------------------------------------------------------- // Create Config Object - $config = new Config($config_array); - $container->set('config', $config); + $container->set('config', function() { + return new Config(); + }); + $container->setInstance('config', new Config($config_array)); // Create Cache Object - $container->set('cache', new CacheManager($config)); + $container->set('cache', function($container) { + return new CacheManager($container->get('config')); + }); // Create Aura Router Object - $container->set('aura-router', new RouterContainer); + $container->set('aura-router', function() { + return new RouterContainer; + }); // Create Html helper Object - $html_helper = (new HelperLocatorFactory)->newInstance(); - $html_helper->set('menu', function() use ($container) { - $menu_helper = new Helper\Menu(); - $menu_helper->setContainer($container); - return $menu_helper; + $container->set('html-helper', function($container) { + $html_helper = (new HelperLocatorFactory)->newInstance(); + $html_helper->set('menu', function() use ($container) { + $menu_helper = new Helper\Menu(); + $menu_helper->setContainer($container); + return $menu_helper; + }); + + return $html_helper; }); - $container->set('html-helper', $html_helper); // Create Request/Response Objects - $request = ServerRequestFactory::fromGlobals( - $_SERVER, - $_GET, - $_POST, - $_COOKIE, - $_FILES - ); - $container->set('request', $request); - $container->set('response', new Response()); + $container->set('request', function() { + return ServerRequestFactory::fromGlobals( + $_SERVER, + $_GET, + $_POST, + $_COOKIE, + $_FILES + ); + }); + $container->set('response', function() { + return new Response; + }); // Create session Object - $session = (new SessionFactory())->newInstance($_COOKIE); - $container->set('session', $session); + $container->set('session', function() { + return (new SessionFactory())->newInstance($_COOKIE); + }); // Miscellaneous helper methods - $util = new Util($container); - $container->set('anime-client', $util); - $container->set('util', $util); + $container->set('util', function($container) { + return new Util($container); + }); // Models - $container->set('api-model', new Model\API($container)); - $container->set('anime-model', new Model\Anime($container)); - $container->set('manga-model', new Model\Manga($container)); - $container->set('anime-collection-model', new Model\AnimeCollection($container)); + $container->set('api-model', function($container) { + return new Model\API($container); + }); + $container->set('anime-model', function($container) { + return new Model\Anime($container); + }); + $container->set('manga-model', function($container) { + return new Model\Manga($container); + }); + $container->set('anime-collection-model', function($container) { + return new Model\AnimeCollection($container); + }); // Miscellaneous Classes - $container->set('auth', new HummingbirdAuth($container)); - $container->set('url-generator', new UrlGenerator($container)); + $container->set('auth', function($container) { + return new HummingbirdAuth($container); + }); + $container->set('url-generator', function($container) { + return new UrlGenerator($container); + }); // ------------------------------------------------------------------------- // Dispatcher // ------------------------------------------------------------------------- - $container->set('dispatcher', new Dispatcher($container)); + $container->set('dispatcher', function($container) { + return new Dispatcher($container); + }); return $container; }; diff --git a/composer.json b/composer.json index f769e115..42ba9c65 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,8 @@ "phpunit/phpunit": "^5.4", "robmorgan/phinx": "^0.6.4", "humbug/humbug": "~1.0@dev", - "consolidation/robo": "~1.0@dev", - "henrikbjorn/lurker": "^1.1.0" + "consolidation/robo": "~1.0@RC", + "henrikbjorn/lurker": "^1.1.0", + "symfony/var-dumper": "^3.1" } } From d6f9ceb5c7ebc943288ffca1c957f0c170ab52d4 Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Mon, 29 Aug 2016 15:36:36 -0400 Subject: [PATCH 34/65] Fix tests broken due to changes in container --- src/Aviat/AnimeClient/Command/BaseCommand.php | 35 +++++++++++++------ .../AnimeClient/Auth/HummingbirdAuthTest.php | 2 +- tests/AnimeClient/ControllerTest.php | 2 +- tests/AnimeClient/DispatcherTest.php | 24 +++---------- tests/AnimeClient/Helper/MenuHelperTest.php | 2 +- tests/AnimeClient/MenuGeneratorTest.php | 2 +- .../Model/AnimeCollectionModelTest.php | 6 ++-- tests/AnimeClient/Model/MangaModelTest.php | 2 +- tests/AnimeClient/UrlGeneratorTest.php | 4 +-- tests/AnimeClient_TestCase.php | 14 ++++++-- 10 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/Aviat/AnimeClient/Command/BaseCommand.php b/src/Aviat/AnimeClient/Command/BaseCommand.php index bd50731f..923df39a 100644 --- a/src/Aviat/AnimeClient/Command/BaseCommand.php +++ b/src/Aviat/AnimeClient/Command/BaseCommand.php @@ -63,23 +63,38 @@ class BaseCommand extends Command { $container = new Container(); // Create Config Object - $config = new Config($config_array); - $container->set('config', $config); + $container->set('config', function() { + return new Config(); + }); + $container->setInstance('config', $config_array); // Create Cache Object - $container->set('cache', new CacheManager($config)); + $container->set('cache', function($container) { + return new CacheManager($container->get('config')); + }); // Create session Object - $session = (new SessionFactory())->newInstance($_COOKIE); - $container->set('session', $session); + $container->set('session', function() { + return (new SessionFactory())->newInstance($_COOKIE); + }); // Models - $container->set('api-model', new Model\API($container)); - $container->set('anime-model', new Model\Anime($container)); - $container->set('manga-model', new Model\Manga($container)); + $container->set('api-model', function($container) { + return new Model\API($container); + }); + $container->set('anime-model', function($container) { + return new Model\Anime($container); + }); + $container->set('manga-model', function($container) { + return new Model\Manga($container); + }); - $container->set('auth', new HummingbirdAuth($container)); - $container->set('util', new Util($container)); + $container->set('auth', function($container) { + return new HummingbirdAuth($container); + }); + $container->set('util', function($container) { + return new Util($container); + }); return $container; }; diff --git a/tests/AnimeClient/Auth/HummingbirdAuthTest.php b/tests/AnimeClient/Auth/HummingbirdAuthTest.php index db9ea932..d2476127 100644 --- a/tests/AnimeClient/Auth/HummingbirdAuthTest.php +++ b/tests/AnimeClient/Auth/HummingbirdAuthTest.php @@ -24,7 +24,7 @@ class HummingbirdAuthTest extends AnimeClient_TestCase { $auth = new HummingbirdAuth($this->container); $friend = new Friend($auth); $this->auth = $friend; - $this->container->set('session', self::$session); + $this->container->setInstance('session', self::$session); } public function dataAuthenticate() diff --git a/tests/AnimeClient/ControllerTest.php b/tests/AnimeClient/ControllerTest.php index 6b67f59c..043b587b 100644 --- a/tests/AnimeClient/ControllerTest.php +++ b/tests/AnimeClient/ControllerTest.php @@ -33,7 +33,7 @@ class ControllerTest extends AnimeClient_TestCase { 'database' => '', 'file' => ":memory:" ]); - $this->container->set('config', $config); + $this->container->setInstance('config', $config); $this->assertInstanceOf( 'Aviat\AnimeClient\Controller', diff --git a/tests/AnimeClient/DispatcherTest.php b/tests/AnimeClient/DispatcherTest.php index 4c87a4ce..811e1c6c 100644 --- a/tests/AnimeClient/DispatcherTest.php +++ b/tests/AnimeClient/DispatcherTest.php @@ -29,39 +29,25 @@ class DispatcherTest extends AnimeClient_TestCase { 'SERVER_NAME' => $host ]); - $request = ServerRequestFactory::fromGlobals( - $_SERVER, - $_GET, - $_POST, - $_COOKIE, - $_FILES - ); - - $old_config = $this->container->get('config'); + $this->setSuperGlobals([ + '_SERVER' => $_SERVER + ]); $logger = new Logger('test_logger'); $logger->pushHandler(new TestHandler(Logger::DEBUG)); - // Add the appropriate objects to the container - $this->container = new Container([ - 'config' => $old_config, - 'request' => $request, - 'response' => new Response, - 'aura-router' => new RouterContainer - ]); - $this->container->setLogger($logger, 'default'); if ( ! empty($config)) { $config = new Config($config); - $this->container->set('config', $config); + $this->container->setInstance('config', $config); } $this->router = new Dispatcher($this->container); $this->config = $this->container->get('config'); $this->urlGenerator = new UrlGenerator($this->container); - $this->container->set('url-generator', $this->urlGenerator); + $this->container->setInstance('url-generator', $this->urlGenerator); } public function testRouterSanity() diff --git a/tests/AnimeClient/Helper/MenuHelperTest.php b/tests/AnimeClient/Helper/MenuHelperTest.php index d9ec76f4..38740428 100644 --- a/tests/AnimeClient/Helper/MenuHelperTest.php +++ b/tests/AnimeClient/Helper/MenuHelperTest.php @@ -43,7 +43,7 @@ class MenuHelperTest extends AnimeClient_TestCase { // Set config for tests $config = $this->container->get('config'); $config->set('menus', $menus); - $this->container->set('config', $config); + $this->container->setInstance('config', $config); foreach($menus as $case => $config) { diff --git a/tests/AnimeClient/MenuGeneratorTest.php b/tests/AnimeClient/MenuGeneratorTest.php index 2bb1b265..5906aaec 100644 --- a/tests/AnimeClient/MenuGeneratorTest.php +++ b/tests/AnimeClient/MenuGeneratorTest.php @@ -66,7 +66,7 @@ class MenuGeneratorTest extends AnimeClient_TestCase { ]; $config = $this->container->get('config'); $config->set('menus', $menus); - $this->container->set('config', $config); + $this->container->setInstance('config', $config); $expected = ''; $this->assertEquals($expected, $this->generator->generate('manga_list')); diff --git a/tests/AnimeClient/Model/AnimeCollectionModelTest.php b/tests/AnimeClient/Model/AnimeCollectionModelTest.php index 5c931c15..faa66244 100644 --- a/tests/AnimeClient/Model/AnimeCollectionModelTest.php +++ b/tests/AnimeClient/Model/AnimeCollectionModelTest.php @@ -10,7 +10,7 @@ class AnimeCollectionModelTest extends AnimeClient_TestCase { public function setUp() { parent::setUp(); - $this->container->set('config', new Config([ + $this->container->setInstance('config', new Config([ 'database' => [ 'collection' => [ 'type' => 'sqlite', @@ -37,7 +37,7 @@ class AnimeCollectionModelTest extends AnimeClient_TestCase { public function testInvalidDatabase() { - $this->container->set('config', new Config([ + $this->container->setInstance('config', new Config([ 'database' => [ 'collection' => [ 'type' => 'sqlite', @@ -57,7 +57,7 @@ class AnimeCollectionModelTest extends AnimeClient_TestCase { public function testNonExistentDatabase() { - $this->container->set('config', new Config([ + $this->container->setInstance('config', new Config([ 'database' => [ 'collection' => [ 'type' => 'sqlite', diff --git a/tests/AnimeClient/Model/MangaModelTest.php b/tests/AnimeClient/Model/MangaModelTest.php index bc97fca7..9eca4ca0 100644 --- a/tests/AnimeClient/Model/MangaModelTest.php +++ b/tests/AnimeClient/Model/MangaModelTest.php @@ -12,7 +12,7 @@ class MangaModelTest extends AnimeClient_TestCase { public function setUp() { parent::setUp(); - $this->container->set('util', new MockUtil($this->container)); + $this->container->setInstance('util', new MockUtil($this->container)); $this->model = new Friend(new TestMangaModel($this->container)); $this->mockDir = __DIR__ . '/../../test_data/manga_list'; } diff --git a/tests/AnimeClient/UrlGeneratorTest.php b/tests/AnimeClient/UrlGeneratorTest.php index aea2e044..7ae7e07d 100644 --- a/tests/AnimeClient/UrlGeneratorTest.php +++ b/tests/AnimeClient/UrlGeneratorTest.php @@ -83,7 +83,7 @@ class UrlGeneratorTest extends AnimeClient_TestCase { public function testFullUrl($config, $path, $type, $expected) { $config = new Config($config); - $this->container->set('config', $config); + $this->container->setInstance('config', $config); $urlGenerator = new UrlGenerator($this->container); $result = $urlGenerator->full_url($path, $type); @@ -127,7 +127,7 @@ class UrlGeneratorTest extends AnimeClient_TestCase { public function testBaseUrl($config, $type, $expected) { $config = new Config($config); - $this->container->set('config', $config); + $this->container->setInstance('config', $config); $urlGenerator = new UrlGenerator($this->container); $result = $urlGenerator->base_url($type); diff --git a/tests/AnimeClient_TestCase.php b/tests/AnimeClient_TestCase.php index 6b32e3ba..9f1f7865 100644 --- a/tests/AnimeClient_TestCase.php +++ b/tests/AnimeClient_TestCase.php @@ -91,7 +91,13 @@ class AnimeClient_TestCase extends PHPUnit_Framework_TestCase { // Set up DI container $di = require _dir($APP_DIR, 'bootstrap.php'); $container = $di($config_array); - $container->set('session-handler', self::$session_handler); + + // Use mock session handler + $container->set('session-handler', function() { + $session_handler = new TestSessionHandler(); + session_set_save_handler($session_handler, TRUE); + return $session_handler; + }); $this->container = $container; } @@ -116,8 +122,10 @@ class AnimeClient_TestCase extends PHPUnit_Framework_TestCase { ['Zend\Diactoros\ServerRequestFactory', 'fromGlobals'], array_merge($default, $supers) ); - $this->container->set('request', $request); - $this->container->set('response', new HttpResponse()); + $this->container->setInstance('request', $request); + $this->container->set('repsone', function() { + return new HttpResponse(); + }); } /** From 756db0654068e96ca29d3caa1003e6f902684723 Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Mon, 29 Aug 2016 15:50:59 -0400 Subject: [PATCH 35/65] Build/doc generation updates --- RoboFile.php | 72 ++- .../ClosingFileAndLocationCommentStandard.xml | 28 + .../Utf8EncodingAndByteOrderMarkStandard.xml | 7 + .../ConstructorNameStandard.xml | 31 + .../ValidClassNameStandard.xml | 21 + .../ValidFileNameStandard.xml | 21 + .../ValidMethodNameStandard.xml | 27 + .../ValidVariableNameStandard.xml | 31 + .../StrictComparisonOperatorStandard.xml | 40 ++ .../Docs/Strings/DoubleQuoteUsageStandard.xml | 28 + .../Sniffs/Commenting/InlineCommentSniff.php | 187 ++++++ .../Sniffs/Files/ByteOrderMarkSniff.php | 98 +++ .../Sniffs/Files/Utf8EncodingSniff.php | 222 +++++++ .../Operators/LogicalOperatorAndSniff.php | 81 +++ .../StrictComparisonOperatorSniff.php | 81 +++ .../UppercaseLogicalOperatorOrSniff.php | 84 +++ .../Sniffs/Strings/DoubleQuoteUsageSniff.php | 464 +++++++++++++++ .../WhiteSpace/DisallowSpaceIndentSniff.php | 87 +++ .../DisallowWitheSpaceAroundPhpTagsSniff.php | 95 +++ .../Sniffs/WhiteSpace/ElseOnNewLineSniff.php | 82 +++ .../WhiteSpace/LogicalNotSpacingSniff.php | 75 +++ .../Files/AbstractClosingCommentSniff.php | 104 ++++ .../Files/ClosingFileCommentSniff.php | 109 ++++ .../Files/ClosingLocationCommentSniff.php | 182 ++++++ .../ConstructorNameSniff.php | 142 +++++ .../NamingConventions/ValidClassNameSniff.php | 84 +++ .../NamingConventions/ValidFileNameSniff.php | 84 +++ .../ValidMethodNameSniff.php | 161 +++++ .../ValidVariableNameSniff.php | 562 ++++++++++++++++++ build/CodeIgniter/ruleset.xml | 47 ++ build/animeclient_header_comment.txt | 7 +- build/phpcs.xml | 79 +++ build/phpdox.xml | 191 +++--- build/phpunit.xml | 4 +- composer.json | 14 +- phpdoc.dist.xml | 7 +- phpunit.xml | 2 +- 37 files changed, 3526 insertions(+), 115 deletions(-) create mode 100644 build/CodeIgniter/Docs/Files/ClosingFileAndLocationCommentStandard.xml create mode 100644 build/CodeIgniter/Docs/Files/Utf8EncodingAndByteOrderMarkStandard.xml create mode 100644 build/CodeIgniter/Docs/NamingConventions/ConstructorNameStandard.xml create mode 100644 build/CodeIgniter/Docs/NamingConventions/ValidClassNameStandard.xml create mode 100644 build/CodeIgniter/Docs/NamingConventions/ValidFileNameStandard.xml create mode 100644 build/CodeIgniter/Docs/NamingConventions/ValidMethodNameStandard.xml create mode 100644 build/CodeIgniter/Docs/NamingConventions/ValidVariableNameStandard.xml create mode 100644 build/CodeIgniter/Docs/Operators/StrictComparisonOperatorStandard.xml create mode 100755 build/CodeIgniter/Docs/Strings/DoubleQuoteUsageStandard.xml create mode 100644 build/CodeIgniter/Sniffs/Commenting/InlineCommentSniff.php create mode 100755 build/CodeIgniter/Sniffs/Files/ByteOrderMarkSniff.php create mode 100755 build/CodeIgniter/Sniffs/Files/Utf8EncodingSniff.php create mode 100644 build/CodeIgniter/Sniffs/Operators/LogicalOperatorAndSniff.php create mode 100755 build/CodeIgniter/Sniffs/Operators/StrictComparisonOperatorSniff.php create mode 100644 build/CodeIgniter/Sniffs/Operators/UppercaseLogicalOperatorOrSniff.php create mode 100755 build/CodeIgniter/Sniffs/Strings/DoubleQuoteUsageSniff.php create mode 100755 build/CodeIgniter/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php create mode 100755 build/CodeIgniter/Sniffs/WhiteSpace/DisallowWitheSpaceAroundPhpTagsSniff.php create mode 100644 build/CodeIgniter/Sniffs/WhiteSpace/ElseOnNewLineSniff.php create mode 100755 build/CodeIgniter/Sniffs/WhiteSpace/LogicalNotSpacingSniff.php create mode 100644 build/CodeIgniter/UnusedSniffs/Files/AbstractClosingCommentSniff.php create mode 100755 build/CodeIgniter/UnusedSniffs/Files/ClosingFileCommentSniff.php create mode 100755 build/CodeIgniter/UnusedSniffs/Files/ClosingLocationCommentSniff.php create mode 100755 build/CodeIgniter/UnusedSniffs/NamingConventions/ConstructorNameSniff.php create mode 100755 build/CodeIgniter/UnusedSniffs/NamingConventions/ValidClassNameSniff.php create mode 100644 build/CodeIgniter/UnusedSniffs/NamingConventions/ValidFileNameSniff.php create mode 100755 build/CodeIgniter/UnusedSniffs/NamingConventions/ValidMethodNameSniff.php create mode 100755 build/CodeIgniter/UnusedSniffs/NamingConventions/ValidVariableNameSniff.php create mode 100644 build/CodeIgniter/ruleset.xml create mode 100644 build/phpcs.xml diff --git a/RoboFile.php b/RoboFile.php index b63ee609..6198da5e 100644 --- a/RoboFile.php +++ b/RoboFile.php @@ -20,16 +20,33 @@ if ( ! function_exists('glob_recursive')) * * @see http://robo.li/ */ -class RoboFile extends \Robo\Tasks -{ +class RoboFile extends \Robo\Tasks { + + /** + * Directories used by analysis tools + * + * @var array + */ protected $taskDirs = [ - 'build/api', - 'build/coverage', 'build/logs', 'build/pdepend', 'build/phpdox', ]; + /** + * Directories to remove with the clean task + * + * @var array + */ + protected $cleanDirs = [ + 'coverage', + 'docs', + 'phpdoc', + 'build/logs', + 'build/phpdox', + 'build/pdepend' + ]; + /** * Do static analysis tasks @@ -39,6 +56,7 @@ class RoboFile extends \Robo\Tasks $this->prepare(); $this->lint(); $this->phploc(TRUE); + $this->phpcs(TRUE); $this->dependencyReport(); $this->phpcpdReport(); } @@ -66,8 +84,17 @@ class RoboFile extends \Robo\Tasks @unlink($file); }, $cleanFiles); - $this->_cleanDir($this->taskDirs); - $this->_deleteDir($this->taskDirs); + // So the task doesn't complain, + // make any 'missing' dirs to cleanup + array_map(function ($dir) { + if ( ! is_dir($dir)) + { + `mkdir -p {$dir}`; + } + }, $this->cleanDirs); + + $this->_cleanDir($this->cleanDirs); + $this->_deleteDir($this->cleanDirs); } /** @@ -135,6 +162,29 @@ class RoboFile extends \Robo\Tasks $this->_run($cmd_parts); } + /** + * Run the phpcs tool + * + * @param bool $report - if true, generates reports instead of direct output + */ + public function phpcs($report = FALSE) + { + $report_cmd_parts = [ + 'vendor/bin/phpcs', + '--standard=./build/phpcs.xml', + '--report-checkstyle=./build/logs/phpcs.xml', + ]; + + $normal_cmd_parts = [ + 'vendor/bin/phpcs', + '--standard=./build/phpcs.xml', + ]; + + $cmd_parts = ($report) ? $report_cmd_parts : $normal_cmd_parts; + + $this->_run($cmd_parts); + } + /** * Run the phploc tool * @@ -145,6 +195,7 @@ class RoboFile extends \Robo\Tasks // Command for generating reports $report_cmd_parts = [ 'vendor/bin/phploc', + '--count-tests', '--log-csv=build/logs/phploc.csv', '--log-xml=build/logs/phploc.xml', 'src', @@ -169,7 +220,6 @@ class RoboFile extends \Robo\Tasks */ public function prepare() { - $this->clean(); array_map([$this, '_mkdir'], $this->taskDirs); } @@ -196,7 +246,11 @@ class RoboFile extends \Robo\Tasks }) ->monitor('src', function () { $this->taskExec('test')->run(); - })->run(); + }) + ->monitor('tests', function () { + $this->taskExec('test')->run(); + }) + ->run(); } /** @@ -265,7 +319,7 @@ class RoboFile extends \Robo\Tasks } /** - * Short cut for joining an array of command arguments + * Shortcut for joining an array of command arguments * and then running it * * @param array $cmd_parts - command arguments diff --git a/build/CodeIgniter/Docs/Files/ClosingFileAndLocationCommentStandard.xml b/build/CodeIgniter/Docs/Files/ClosingFileAndLocationCommentStandard.xml new file mode 100644 index 00000000..5dd3d3c8 --- /dev/null +++ b/build/CodeIgniter/Docs/Files/ClosingFileAndLocationCommentStandard.xml @@ -0,0 +1,28 @@ + + + is optional to the PHP parser. However, if used, any whitespace following the closing tag, whether introduced by the developer, user, or an FTP application, can cause unwanted output, PHP errors, or if the latter are suppressed, blank pages. For this reason, all PHP files should OMIT the closing PHP tag, and instead use a comment block to mark the end of file and it's location relative to the application root. This allows you to still identify a file as being complete and not truncated. + ]]> + + + + + + + + ]]> + + + diff --git a/build/CodeIgniter/Docs/Files/Utf8EncodingAndByteOrderMarkStandard.xml b/build/CodeIgniter/Docs/Files/Utf8EncodingAndByteOrderMarkStandard.xml new file mode 100644 index 00000000..d3a0d9b2 --- /dev/null +++ b/build/CodeIgniter/Docs/Files/Utf8EncodingAndByteOrderMarkStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/build/CodeIgniter/Docs/NamingConventions/ConstructorNameStandard.xml b/build/CodeIgniter/Docs/NamingConventions/ConstructorNameStandard.xml new file mode 100644 index 00000000..46b3e695 --- /dev/null +++ b/build/CodeIgniter/Docs/NamingConventions/ConstructorNameStandard.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git a/build/CodeIgniter/Docs/NamingConventions/ValidClassNameStandard.xml b/build/CodeIgniter/Docs/NamingConventions/ValidClassNameStandard.xml new file mode 100644 index 00000000..3721b67e --- /dev/null +++ b/build/CodeIgniter/Docs/NamingConventions/ValidClassNameStandard.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + diff --git a/build/CodeIgniter/Docs/NamingConventions/ValidFileNameStandard.xml b/build/CodeIgniter/Docs/NamingConventions/ValidFileNameStandard.xml new file mode 100644 index 00000000..331fa444 --- /dev/null +++ b/build/CodeIgniter/Docs/NamingConventions/ValidFileNameStandard.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + diff --git a/build/CodeIgniter/Docs/NamingConventions/ValidMethodNameStandard.xml b/build/CodeIgniter/Docs/NamingConventions/ValidMethodNameStandard.xml new file mode 100644 index 00000000..a669c448 --- /dev/null +++ b/build/CodeIgniter/Docs/NamingConventions/ValidMethodNameStandard.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + diff --git a/build/CodeIgniter/Docs/NamingConventions/ValidVariableNameStandard.xml b/build/CodeIgniter/Docs/NamingConventions/ValidVariableNameStandard.xml new file mode 100644 index 00000000..14362b74 --- /dev/null +++ b/build/CodeIgniter/Docs/NamingConventions/ValidVariableNameStandard.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git a/build/CodeIgniter/Docs/Operators/StrictComparisonOperatorStandard.xml b/build/CodeIgniter/Docs/Operators/StrictComparisonOperatorStandard.xml new file mode 100644 index 00000000..92fc74fe --- /dev/null +++ b/build/CodeIgniter/Docs/Operators/StrictComparisonOperatorStandard.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + diff --git a/build/CodeIgniter/Docs/Strings/DoubleQuoteUsageStandard.xml b/build/CodeIgniter/Docs/Strings/DoubleQuoteUsageStandard.xml new file mode 100755 index 00000000..137130c2 --- /dev/null +++ b/build/CodeIgniter/Docs/Strings/DoubleQuoteUsageStandard.xml @@ -0,0 +1,28 @@ + + + + + + + + + + bar}" // variables in strings may be an object attribute +"SELECT foo FROM bar WHERE baz = 'bag'" +"\n" // not specified in Code Igniter coding standard, but it should be allowed + ]]> + + + diff --git a/build/CodeIgniter/Sniffs/Commenting/InlineCommentSniff.php b/build/CodeIgniter/Sniffs/Commenting/InlineCommentSniff.php new file mode 100644 index 00000000..d8e51eb9 --- /dev/null +++ b/build/CodeIgniter/Sniffs/Commenting/InlineCommentSniff.php @@ -0,0 +1,187 @@ + + * @copyright 2011 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * CodeIgniter_Sniffs_Commenting_InlineCommentSniff. + * + * Ensure the use of single line comments within code (i.e //) + * and blank lines between large comment blocks and code. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2011 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +namespace CodeIgniter\Sniffs\Commenting; + +use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Files\File; + +class InlineCommentSniff implements Sniff +{ + /** + * @var int Limit defining long comments. + * Long comments count $longCommentLimit or more lines. + */ + public $longCommentLimit = 5; + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_COMMENT + ); + }//end register() + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // keep testing only if it's about the first comment of the block + $previousCommentPtr = $phpcsFile->findPrevious($tokens[$stackPtr]['code'], $stackPtr - 1); + if ($tokens[$previousCommentPtr]['line'] !== $tokens[$stackPtr]['line'] - 1) { + if (TRUE !== $this->_checkCommentStyle($phpcsFile, $stackPtr)) { + return; + } + + $commentLines = $this->_getCommentBlock($phpcsFile, $stackPtr); + + if (count($commentLines) >= $this->longCommentLimit) { + $this->_checkBlankLinesAroundLongComment($phpcsFile, $commentLines); + } + } + }//end process() + + + /** + * Add error to $phpcsFile, if comment pointed by $stackPtr doesn't start + * with '//'. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * that has to be a comment. + * + * @return bool TRUE if the content of the token pointed by $stackPtr starts + * with //, FALSE if an error was added to $phpcsFile. + */ + private function _checkCommentStyle(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + if ($tokens[$stackPtr]['content']{0} === '#') { + $error = 'Perl-style comments are not allowed; use "// Comment" or DocBlock comments instead'; + $phpcsFile->addError($error, $stackPtr, 'WrongStyle'); + return FALSE; + } else if (substr($tokens[$stackPtr]['content'], 0, 2) === '/*' + || $tokens[$stackPtr]['content']{0} === '*' + ) { + $error = 'Multi lines comments are not allowed; use "// Comment" DocBlock comments instead'; + $phpcsFile->addError($error, $stackPtr, 'WrongStyle'); + return FALSE; + } else if (substr($tokens[$stackPtr]['content'], 0, 2) !== '//') { + $error = 'Use single line or DocBlock comments within code'; + $phpcsFile->addError($error, $stackPtr, 'WrongStyle'); + return FALSE; + } + return TRUE; + }//_checkCommentStyle() + + + /** + * Gather into an array all comment lines to which $stackPtr belongs. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr Pointer to the first comment line. + * + * @return type array Pointers to tokens making up the comment block. + */ + private function _getCommentBlock(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $commentLines = array($stackPtr); + $nextComment = $stackPtr; + $lastLine = $tokens[$stackPtr]['line']; + + while (($nextComment = $phpcsFile->findNext($tokens[$stackPtr]['code'], ($nextComment + 1), null, false)) !== false) { + if (($tokens[$nextComment]['line'] - 1) !== $lastLine) { + // Not part of the block. + break; + } + + $lastLine = $tokens[$nextComment]['line']; + $commentLines[] = $nextComment; + } + + return $commentLines; + }//_getCommentBlock() + + + /** + * Add errors to $phpcsFile, if $commentLines isn't enclosed with blank lines. + * + * @param File $phpcsFile The current file being scanned. + * @param array $commentLines Lines of the comment block being checked. + * + * @return bool TRUE if $commentLines is enclosed with at least a blank line + * before and after, FALSE otherwise. + */ + private function _checkBlankLinesAroundLongComment(File $phpcsFile, array $commentLines) + { + $hasBlankLinesAround = TRUE; + $tokens = $phpcsFile->getTokens(); + + // check blank line before the long comment + $firstCommentPtr = reset($commentLines); + $firstPreviousSpacePtr = $firstCommentPtr - 1; + while (T_WHITESPACE === $tokens[$firstPreviousSpacePtr]['code'] && $firstPreviousSpacePtr > 0) { + $firstPreviousSpacePtr--; + } + if ($tokens[$firstPreviousSpacePtr]['line'] >= $tokens[$firstCommentPtr]['line'] - 1) { + $error = "Please add a blank line before comments counting more than {$this->longCommentLimit} lines."; + $phpcsFile->addError($error, $firstCommentPtr, 'LongCommentWithoutSpacing'); + $hasBlankLinesAround = FALSE; + } + + // check blank line after the long comment + $lastCommentPtr = end($commentLines); + $lastNextSpacePtr = $lastCommentPtr + 1; + while (T_WHITESPACE === $tokens[$lastNextSpacePtr]['code'] && $lastNextSpacePtr < count($tokens)) { + $lastNextSpacePtr++; + } + if ($tokens[$lastNextSpacePtr]['line'] <= $tokens[$lastCommentPtr]['line'] + 1) { + $error = "Please add a blank line after comments counting more than {$this->longCommentLimit} lines."; + $phpcsFile->addError($error, $lastCommentPtr, 'LongCommentWithoutSpacing'); + $hasBlankLinesAround = FALSE; + } + + return $hasBlankLinesAround; + }//end _checkBlanksAroundLongComment() + +}//end class + +?> \ No newline at end of file diff --git a/build/CodeIgniter/Sniffs/Files/ByteOrderMarkSniff.php b/build/CodeIgniter/Sniffs/Files/ByteOrderMarkSniff.php new file mode 100755 index 00000000..edd534e5 --- /dev/null +++ b/build/CodeIgniter/Sniffs/Files/ByteOrderMarkSniff.php @@ -0,0 +1,98 @@ + + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * CodeIgniter_Sniffs_Files_ByteOrderMarkSniff. + * + * Ensures that no BOM appears at the beginning of file. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +namespace CodeIgniter\Sniffs\Files; + +use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Files\File; + +class ByteOrderMarkSniff implements Sniff +{ + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( T_OPEN_TAG ); + }//end register() + + /** + * List of supported BOM definitions. + * + * Use encoding names as keys and hex BOM representations as values. + * + * @return array + */ + protected function getBomDefinitions() + { + return array( + 'UTF-8' => 'efbbbf', + 'UTF-16 (BE)' => 'feff', + 'UTF-16 (LE)' => 'fffe', + 'UTF-32 (BE)' => '0000feff', + 'UTF-32 (LE)' => 'fffe0000' + ); + }//end getBomDefinitions() + + /** + * Process tokens. + * + * Actually, only proceed when we're at index 0, this should be the only case + * that will contain BOM. Then check if BOM definition matches what + * we've found as file's inline HTML. Inline HTML could be longer than just BOM + * so make sure you test as much as needed. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr ) + { + // We are only interested if this is the first open tag. + if ($stackPtr !== 0) { + if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { + return; + } + } + + $tokens = $phpcsFile->getTokens(); + $fileStartString = $tokens[0]['content']; + foreach ($this->getBomDefinitions() as $bomName => $expectedBomHex) { + $bomByteLength = strlen($expectedBomHex) / 2; + $fileStartHex = bin2hex(substr($fileStartString, 0, $bomByteLength)); + if ($fileStartHex === $expectedBomHex) { + $error = "File contains a $bomName byte order mark (BOM)."; + $phpcsFile->addError($error, $stackPtr); + break; + } + } + }//end process() +} diff --git a/build/CodeIgniter/Sniffs/Files/Utf8EncodingSniff.php b/build/CodeIgniter/Sniffs/Files/Utf8EncodingSniff.php new file mode 100755 index 00000000..9c13bbc2 --- /dev/null +++ b/build/CodeIgniter/Sniffs/Files/Utf8EncodingSniff.php @@ -0,0 +1,222 @@ + + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * CodeIgniter_Sniffs_Files_Utf8EncodingSniff. + * + * Ensures that PHP files are encoded with Unicode (UTF-8) encoding. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +namespace CodeIgniter\Sniffs\Files; + +use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Files\File; + +class Utf8EncodingSniff implements Sniff +{ + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_OPEN_TAG + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + // We are only interested if this is the first open tag. + if ($stackPtr !== 0) { + if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { + return; + } + } + + $file_path = $phpcsFile->getFilename(); + $file_name = basename($file_path); + $file_content = file_get_contents($file_path); + if (false === mb_check_encoding($file_content, 'UTF-8')) { + $error = 'File "' . $file_name . '" should be saved with Unicode (UTF-8) encoding.'; + $phpcsFile->addError($error, 0); + } + if ( ! self::_checkUtf8W3c($file_content)) { + $error = 'File "' . $file_name . '" should be saved with Unicode (UTF-8) encoding, but it did not successfully pass the W3C test.'; + $phpcsFile->addError($error, 0); + } + if ( ! self::_checkUtf8Rfc3629($file_content)) { + $error = 'File "' . $file_name . '" should be saved with Unicode (UTF-8) encoding, but it did not meet RFC3629 requirements.'; + $phpcsFile->addError($error, 0); + } + }//end process() + + + /** + * Checks that the string $content contains only valid UTF-8 chars + * using W3C's method. + * Returns true if $content contains only UTF-8 chars, false otherwise. + * + * @param string $content String to check. + * + * @return bool true if $content contains only UTF-8 chars, false otherwise. + * + * @see http://w3.org/International/questions/qa-forms-utf-8.html + */ + private static function _checkUtf8W3c($content) + { + $content_chunks=self::mb_chunk_split($content, 4096, ''); + foreach($content_chunks as $content_chunk) + { + $preg_result= preg_match( + '%^(?: + [\x09\x0A\x0D\x20-\x7E] # ASCII + | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 + | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 + )*$%xs', + $content_chunk + ); + if($preg_result!==1) + { + return false; + } + + } + return true; + }//end _checkUtf8W3c() + + /** + * Checks that the string $content contains only valid UTF-8 chars + * using the method described in RFC 3629. + * Returns true if $content contains only UTF-8 chars, false otherwise. + * + * @param string $content String to check. + * + * @return bool true if $content contains only UTF-8 chars, false otherwise. + * + * @see http://www.php.net/manual/en/function.mb-detect-encoding.php#85294 + */ + private static function _checkUtf8Rfc3629($content) + { + $len = strlen($content); + for ($i = 0; $i < $len; $i++) { + $c = ord($content[$i]); + if ($c > 128) { + if (($c >= 254)) { + return false; + } elseif ($c >= 252) { + $bits=6; + } elseif ($c >= 248) { + $bits=5; + } elseif ($c >= 240) { + $bytes = 4; + } elseif ($c >= 224) { + $bytes = 3; + } elseif ($c >= 192) { + $bytes = 2; + } else { + return false; + } if (($i + $bytes) > $len) { + return false; + } while ($bytes > 1) { + $i++; + $b = ord($content[$i]); + if ($b < 128 || $b > 191) { + return false; + } + $bytes--; + } + } + } + return true; + }//_checkUtf8Rfc3629() + + /** + * Splits a string to chunks of given size + * This helps to avoid segmentation fault errors when large text is given + * Returns array of strings after splitting + * + * @param string $str String to split. + * @param int $len number of characters per chunk + * + * @return array string array after splitting + * + * @see http://php.net/manual/en/function.chunk-split.php + */ + private static function mb_chunk_split($str, $len, $glue) + { + if (empty($str)) return false; + $array = self::mbStringToArray ($str); + $n = -1; + $new = Array(); + foreach ($array as $char) { + $n++; + if ($n < $len) $new []= $char; + elseif ($n == $len) { + $new []= $glue . $char; + $n = 0; + } + } + return $new; + }//mb_chunk_split + /** + * Supporting function for mb_chunk_split + * + * @param string $str + * + * @return array + * + * @see http://php.net/manual/en/function.chunk-split.php + */ + private static function mbStringToArray ($str) + { + if (empty($str)) return false; + $len = mb_strlen($str); + $array = array(); + for ($i = 0; $i < $len; $i++) { + $array[] = mb_substr($str, $i, 1); + } + return $array; + } + + + +}//end class + +?> diff --git a/build/CodeIgniter/Sniffs/Operators/LogicalOperatorAndSniff.php b/build/CodeIgniter/Sniffs/Operators/LogicalOperatorAndSniff.php new file mode 100644 index 00000000..072181b5 --- /dev/null +++ b/build/CodeIgniter/Sniffs/Operators/LogicalOperatorAndSniff.php @@ -0,0 +1,81 @@ + + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * CodeIgniter_Sniffs_Operators_LogicalOperatorAndSniff. + * + * Ensures that the logical operator 'AND' is in upper case and suggest the use of its symbolic equivalent. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +namespace CodeIgniter\Sniffs\Operators; + +use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Files\File; + +class LogicalOperatorAndSniff implements Sniff +{ + /** + * Returns an array of tokens this test wants to listen for: symbolic and literal operators and. + * + * @return array + */ + public function register() + { + return array( + T_LOGICAL_AND, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $operator_token = $tokens[$stackPtr]; + $operator_string = $operator_token['content']; + $operator_code = $operator_token['code']; + + if ($operator_string !== strtoupper($operator_string)) { + $error_message = 'Logical operator should be in upper case;' + . ' use "' . strtoupper($operator_string) + . '" instead of "' . $operator_string . '"'; + $phpcsFile->addError($error_message, $stackPtr); + } + + $warning_message = 'The symbolic form "&&" is preferred over the literal form "AND"'; + $phpcsFile->addWarning($warning_message, $stackPtr); + + }//end process() + + +}//end class + +?> \ No newline at end of file diff --git a/build/CodeIgniter/Sniffs/Operators/StrictComparisonOperatorSniff.php b/build/CodeIgniter/Sniffs/Operators/StrictComparisonOperatorSniff.php new file mode 100755 index 00000000..fe229f62 --- /dev/null +++ b/build/CodeIgniter/Sniffs/Operators/StrictComparisonOperatorSniff.php @@ -0,0 +1,81 @@ + + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * CodeIgniter_Sniffs_Operators_StrictComparisonOperatorSniff. + * + * Ensures that only strict comparison operators are used instead of + * equal and not equal operators. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +namespace CodeIgniter\Sniffs\Operators; + +use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Files\File; + +class StrictComparisonOperatorSniff implements Sniff +{ + private static $_replacements = array( + T_IS_EQUAL => '===', + T_IS_NOT_EQUAL => '!==', + ); + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_IS_EQUAL, + T_IS_NOT_EQUAL, + ); + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $operator_token = $tokens[$stackPtr]; + $operator_string = $operator_token['content']; + $operator_code = $operator_token['code']; + + $error_message = '"==" and "!=" are prohibited; use "' + . self::$_replacements[$operator_code] . '" instead of "' + . $operator_string . '".'; + $phpcsFile->addError($error_message, $stackPtr); + }//end process() + + +}//end class + +?> \ No newline at end of file diff --git a/build/CodeIgniter/Sniffs/Operators/UppercaseLogicalOperatorOrSniff.php b/build/CodeIgniter/Sniffs/Operators/UppercaseLogicalOperatorOrSniff.php new file mode 100644 index 00000000..cda26c01 --- /dev/null +++ b/build/CodeIgniter/Sniffs/Operators/UppercaseLogicalOperatorOrSniff.php @@ -0,0 +1,84 @@ + + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * CodeIgniter_Sniffs_Operators_UppercaseLogicalOperatorOrSniff. + * + * Ensures that the logical operator 'OR' is in upper cases and its symbolic equivalent. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +namespace CodeIgniter\Sniffs\Operators; + +use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Files\File; + +class UppercaseLogicalOperatorOrSniff implements Sniff +{ + /** + * Returns an array of tokens this test wants to listen for: literal and symbolic operators or. + * + * @return array + */ + public function register() + { + return array( + T_BOOLEAN_OR, + T_LOGICAL_OR, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $operator_token = $tokens[$stackPtr]; + $operator_string = $operator_token['content']; + $operator_code = $operator_token['code']; + + if ($operator_code == T_BOOLEAN_OR) { + $error_message = 'Logical operator "' . $operator_string + . '" is prohibited; use "OR" instead'; + $phpcsFile->addError($error_message, $stackPtr, 'UseOf||InsteadOfOR'); + } + // it is literal, if it is not symbolic + else if ($operator_string !== strtoupper($operator_string)) { + $error_message = 'Logical operator should be in upper case;' + . ' use "' . strtoupper($operator_string) + . '" instead of "' . $operator_string . '"'; + $phpcsFile->addError($error_message, $stackPtr, 'UseOfLowercaseOr'); + } + }//end process() + + +}//end class + +?> \ No newline at end of file diff --git a/build/CodeIgniter/Sniffs/Strings/DoubleQuoteUsageSniff.php b/build/CodeIgniter/Sniffs/Strings/DoubleQuoteUsageSniff.php new file mode 100755 index 00000000..2c54d71d --- /dev/null +++ b/build/CodeIgniter/Sniffs/Strings/DoubleQuoteUsageSniff.php @@ -0,0 +1,464 @@ + + * @copyright 2011 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +namespace CodeIgniter\Sniffs\Strings; + +use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Files\File; + +/** + * CodeIgniter_Sniffs_Strings_DoubleQuoteUsageSniff. + * + * Ensures that double-quoted strings are used only to parse variables, + * to avoid escape characters before single quotes or for chars that need + * to be interpreted like \r, \n or \t. + * If a double-quoted string contain both single and double quotes + * but no variable, then a warning is raised to encourage the use of + * single-quoted strings. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2011 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class VariableUsageSniff implements Sniff +{ + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + /* + return array( + T_DOUBLE_QUOTED_STRING, + T_CONSTANT_ENCAPSED_STRING, + ); + */ + return array(); + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $string = $tokens[$stackPtr]['content']; + // makes sure that it is about a double quote string, + // since variables are not parsed out of double quoted string + $openDblQtStr = substr($string, 0, 1); + if (0 === strcmp($openDblQtStr, '"')) { + $this->processDoubleQuotedString($phpcsFile, $stackPtr, $string); + } else if (0 === strcmp($openDblQtStr, "'")) { + $this->processSingleQuotedString($phpcsFile, $stackPtr, $string); + } + }//end process() + + + /** + * Processes this test, when the token encountered is a double-quoted string. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * @param string $dblQtString The double-quoted string content, + * i.e. without quotes. + * + * @return void + */ + protected function processDoubleQuotedString (File $phpcsFile, $stackPtr, $dblQtString) + { + $variableFound = FALSE; + $strTokens = token_get_all('_parseVariable($strTokens, $strPtr); + } catch (Exception $err) { + $error = 'There is no variable, object nor array between curly braces. Please use the escape char for $ or {.'; + $phpcsFile->addError($error, $stackPtr); + } + $variableFound = TRUE; + if ('}' !== $strTokens[$strPtr]) { + $error = 'There is no matching closing curly brace.'; + $phpcsFile->addError($error, $stackPtr); + } + // don't move forward, since it will be done in the main loop + // $strPtr++; + } else if (T_VARIABLE === $strToken[0]) { + $variableFound = TRUE; + $error = "Variable {$strToken[1]} in double-quoted strings should be enclosed with curly braces. Please consider {{$strToken[1]}}"; + $phpcsFile->addError($error, $stackPtr); + } + } + $strPtr++; + } + return $variableFound; + }//end processDoubleQuotedString() + + + /** + * Processes this test, when the token encountered is a single-quoted string. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * @param string $sglQtString The single-quoted string content, + * i.e. without quotes. + * + * @return void + */ + protected function processSingleQuotedString (File $phpcsFile, $stackPtr, $sglQtString) + { + $variableFound = FALSE; + $strTokens = token_get_all('addError($error, $stackPtr); + } + } + $strPtr++; + } + return $variableFound; + }//end processSingleQuotedString() + + /** + * Grammar rule to parse the use of a variable. Please notice that it + * doesn't manage the leading $. + * + * _parseVariable ::= + * | _parseObjectAttribute() + * | _parseArrayIndexes() + * + * @exception Exception raised if $strTokens starting from $strPtr + * doesn't matched the rule. + * + * @param array $strTokens Tokens to parse. + * @param int $strPtr Pointer to the token where parsing starts. + * + * @return array The attribute name associated to index 'var', an array with + * indexes 'obj' and 'attr' or an array with indexes 'arr' and 'idx'. + */ + private function _parseVariable ($strTokens, &$strPtr) + { + if ( ! in_array($strTokens[$strPtr][0], array(T_VARIABLE, T_STRING_VARNAME))) { + throw new Exception ('Expected variable name.'); + } + $var = $strTokens[$strPtr][1]; + $strPtr++; + $startStrPtr = $strPtr; + try { + $attr = $this->_parseObjectAttribute($strTokens, $strPtr); + return array ('obj' => $var, 'attr' => $attr); + } catch (Exception $err) { + if ($strPtr !== $startStrPtr) { + throw $err; + } + } + try { + $idx = $this->_parseArrayIndexes($strTokens, $strPtr); + return array ('arr' => $var, 'idx' => $idx); + } catch (Exception $err) { + if ($strPtr !== $startStrPtr) { + throw $err; + } + } + return array ('var' => $var); + }//end _parseVariable() + + + /** + * Grammar rule to parse the use of an object attribute. + * + * _parseObjectAttribute ::= -> + * | ->_parseObjectAttribute() + * | ->_parseArrayIndexes() + * + * @exception Exception raised if $strTokens starting from $strPtr + * doesn't matched the rule. + * + * @param array $strTokens Tokens to parse. + * @param int $strPtr Pointer to the token where parsing starts. + * + * @return mixed The attribute name as a string, an array with indexes + * 'obj' and 'attr' or an array with indexes 'arr' and 'idx'. + */ + private function _parseObjectAttribute ($strTokens, &$strPtr) + { + if (T_OBJECT_OPERATOR !== $strTokens[$strPtr][0]) { + throw new Exception ('Expected ->.'); + } + $strPtr++; + if (T_STRING !== $strTokens[$strPtr][0]) { + throw new Exception ('Expected an object attribute.'); + } + $attr = $strTokens[$strPtr][1]; + $strPtr++; + $startStrPtr = $strPtr; + try { + $sub_attr = $this->_parseObjectAttribute($strTokens, $strPtr); + return array ('obj' => $attr, 'attr' => $sub_attr); + } catch (Exception $err) { + if ($strPtr !== $startStrPtr) { + throw $err; + } + } + try { + $idx = $this->_parseArrayIndexes($strTokens, $strPtr); + return array ('arr' => $attr, 'idx' => $idx); + } catch (Exception $err) { + if ($strPtr !== $startStrPtr) { + throw $err; + } + } + return $attr; + }//end _parseObjectAttribute() + + + /** + * Grammar rule to parse the use of one or more array indexes. + * + * _parseArrayIndexes ::= _parseArrayIndex()+ + * + * @exception Exception raised if $strTokens starting from $strPtr + * doesn't matched the rule. + * + * @param array $strTokens Tokens to parse. + * @param int $strPtr Pointer to the token where parsing starts. + * + * @return array Indexes in the same order as in the string. + */ + private function _parseArrayIndexes ($strTokens, &$strPtr) + { + $indexes = array($this->_parseArrayIndex($strTokens, $strPtr)); + try { + while (1) { + $startStrPtr = $strPtr; + $indexes [] = $this->_parseArrayIndex($strTokens, $strPtr); + } + } catch (Exception $err) { + if (0 !== ($strPtr - $startStrPtr)) { + throw $err; + } + return $indexes; + } + }//end _parseArrayIndexes() + + + /** + * Grammar rule to parse the use of array index. + * + * _parseArrayIndex ::= [] + * + * @exception Exception raised if $strTokens starting from $strPtr + * doesn't matched the rule. + * + * @param array $strTokens Tokens to parse. + * @param int $strPtr Pointer to the token where parsing starts. + * + * @return string Index between the 2 square brackets + */ + private function _parseArrayIndex ($strTokens, &$strPtr) + { + if ('[' !== $strTokens[$strPtr]) { + throw new Exception ('Expected [.'); + } + $strPtr++; + if (! in_array($strTokens[$strPtr][0], array(T_CONSTANT_ENCAPSED_STRING, T_LNUMBER))) { + throw new Exception ('Expected an array index.'); + } + $index = $strTokens[$strPtr][1]; + $strPtr++; + if (']' !== $strTokens[$strPtr]) { + throw new Exception ('Expected ].'); + } + $strPtr++; + return $index; + }//end _parseArrayIndex() + +}//end class + +/** + * CodeIgniter_Sniffs_Strings_VariableUsageSniff. + * + * Ensures that variables parsed in double-quoted strings are enclosed with + * braces to prevent greedy token parsing. + * Single-quoted strings don't parse variables, so there is no risk of greedy + * token parsing. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2011 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class DoubleQuoteUsageSniff extends VariableUsageSniff +{ + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_DOUBLE_QUOTED_STRING, + T_CONSTANT_ENCAPSED_STRING, + ); + }//end register() + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + // no variable are in the string from here + $tokens = $phpcsFile->getTokens(); + $qtString = $tokens[$stackPtr]['content']; + // makes sure that it is about a double quote string, + // since variables are not parsed out of double quoted string + $open_qt_str = substr($qtString, 0, 1); + + // clean the enclosing quotes + $qtString = substr($qtString, 1, strlen($qtString) - 1 - 1); + + if (0 === strcmp($open_qt_str, '"')) { + $this->processDoubleQuotedString($phpcsFile, $stackPtr, $qtString); + } else if (0 === strcmp($open_qt_str, "'")) { + $this->processSingleQuotedString($phpcsFile, $stackPtr, $qtString); + } + }//end process() + + + /** + * Processes this test, when the token encountered is a double-quoted string. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * @param string $qtString The double-quoted string content, + * i.e. without quotes. + * + * @return void + */ + protected function processDoubleQuotedString (File $phpcsFile, $stackPtr, $qtString) + { + // so there should be at least a single quote or a special char + // if there are the 2 kinds of quote and no special char, then add a warning + $has_variable = parent::processDoubleQuotedString($phpcsFile, $stackPtr, '"'.$qtString.'"'); + $has_specific_sequence = $this->_hasSpecificSequence($qtString); + $dbl_qt_at = strpos($qtString, '"'); + $smpl_qt_at = strpos($qtString, "'"); + if (false === $has_variable && false === $has_specific_sequence + && false === $smpl_qt_at + ) { + $error = 'Single-quoted strings should be used unless it contains variables, special chars like \n or single quotes.'; + $phpcsFile->addError($error, $stackPtr); + } else if (false !== $smpl_qt_at && false !== $dbl_qt_at + && false === $has_variable && false === $has_specific_sequence + ) { + $warning = 'It is encouraged to use a single-quoted string, since it doesn\'t contain any variable nor special char though it mixes single and double quotes.'; + $phpcsFile->addWarning($warning, $stackPtr); + } + }//end processDoubleQuotedString() + + + /** + * Processes this test, when the token encountered is a single-quoted string. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * @param string $qtString The single-quoted string content, + * i.e. without quotes. + * + * @return void + */ + protected function processSingleQuotedString (File $phpcsFile, $stackPtr, $qtString) + { + // if there is single quotes without additional double quotes, + // then user is allowed to use double quote to avoid having to + // escape single quotes. Don't add the warning, if an error was + // already added, because a variable was found in a single-quoted + // string. + $has_variable = parent::processSingleQuotedString($phpcsFile, $stackPtr, "'".$qtString."'"); + $dbl_qt_at = strpos($qtString, '"'); + $smpl_qt_at = strpos($qtString, "'"); + if (false === $has_variable && false !== $smpl_qt_at && false === $dbl_qt_at) { + $warning = 'You may also use double-quoted strings if the string contains single quotes, so you do not have to use escape characters.'; + $phpcsFile->addWarning($warning, $stackPtr); + } + }//end processSingleQuotedString() + + /** + * Return TRUE, if a sequence of chars that is parsed in a specific way + * in double-quoted strings is found, FALSE otherwise. + * + * @param string $string String in which sequence of special chars will + * be researched. + * + * @return TRUE, if a sequence of chars that is parsed in a specific way + * in double-quoted strings is found, FALSE otherwise. + * + * @link http://www.php.net/manual/en/language.types.string.php#language.types.string.syntax.double + */ + private function _hasSpecificSequence($string) + { + $hasSpecificSequence = FALSE; + $specialMeaningStrs = array('\n', '\r', '\t', '\v', '\f'); + foreach ($specialMeaningStrs as $splStr) { + if (FALSE !== strpos($string, $splStr)) { + $hasSpecificSequence = TRUE; + } + } + $specialMeaningPtrns = array('\[0-7]{1,3}', '\x[0-9A-Fa-f]{1,2}'); + foreach ($specialMeaningPtrns as $splPtrn) { + if (1 === preg_match("/{$splPtrn}/", $string)) { + $hasSpecificSequence = TRUE; + } + } + return $hasSpecificSequence; + }//end _hasSpecificSequence() + +}//end class + +?> diff --git a/build/CodeIgniter/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php b/build/CodeIgniter/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php new file mode 100755 index 00000000..55eb4d9b --- /dev/null +++ b/build/CodeIgniter/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php @@ -0,0 +1,87 @@ + + * @copyright 2011 Thomas ERNEST + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * CodeIgniter_Sniffs_WhiteSpace_DisallowSpaceIndentSniff. + * + * Ensures the use of tabs for indentation. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2011 Thomas ERNEST + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +namespace CodeIgniter\Sniffs\WhiteSpace; + +use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Files\File; + +class DisallowSpaceIndentSniff implements Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + 'CSS', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_WHITESPACE); + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param File $phpcsFile All the tokens found in the document. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Make sure this is whitespace used for indentation. + $line = $tokens[$stackPtr]['line']; + if ($stackPtr > 0 && $tokens[($stackPtr - 1)]['line'] === $line) { + return; + } + + if (strpos($tokens[$stackPtr]['content'], " ") !== false) { + $error = 'Tabs must be used to indent lines; spaces are not allowed for code indentation'; + $phpcsFile->addError($error, $stackPtr); + } + }//end process() + + +}//end class + +?> diff --git a/build/CodeIgniter/Sniffs/WhiteSpace/DisallowWitheSpaceAroundPhpTagsSniff.php b/build/CodeIgniter/Sniffs/WhiteSpace/DisallowWitheSpaceAroundPhpTagsSniff.php new file mode 100755 index 00000000..615271e7 --- /dev/null +++ b/build/CodeIgniter/Sniffs/WhiteSpace/DisallowWitheSpaceAroundPhpTagsSniff.php @@ -0,0 +1,95 @@ + + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * CodeIgniter_Sniffs_WhiteSpace_DisallowWitheSpaceAroundPhpTagsSniff. + * + * Ensures that no whitespace precedes the opening PHP tag + * or follows the closing PHP tag. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +namespace CodeIgniter\Sniffs\WhiteSpace; + +use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Files\File; + +class DisallowWitheSpaceAroundPhpTagsSniff implements Sniff +{ + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_OPEN_TAG, + T_CLOSE_TAG + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $php_tag_token = $tokens[$stackPtr]; + $php_tag_code = $php_tag_token['code']; + + if (T_OPEN_TAG === $php_tag_code) { + // opening php tag should be the first token. + // any whitespace beofre an opening php tag is tokenized + // as T_INLINE_HTML, so no need to check the content of the token. + $isFirst = 0 === $stackPtr; + if ( ! $isFirst) { + $error = 'Any char before the opening PHP tag is prohibited. Please remove newline or indentation before the opening PHP tag.'; + $phpcsFile->addError($error, $stackPtr); + } + } else { + // if (T_CLOSE_TAG === $php_tag_code) + // closing php tag should be the last token + // and it must not contain any whitespace. + $php_tag_string = $php_tag_token['content']; + $isLast = count($tokens) - 1 === $stackPtr; + // both of the two closing php tags contains 2 chars exactly. + $containsEndTagOnly = strlen($php_tag_string) > 2; + if ( ! $isLast || ! $containsEndTagOnly ) { + $error = 'Any char after the closing PHP tag is prohibited. Please removes newline or spaces after the closing PHP tag.'; + $phpcsFile->addError($error, $stackPtr); + } + } + }//end process() + + +}//end class + +?> \ No newline at end of file diff --git a/build/CodeIgniter/Sniffs/WhiteSpace/ElseOnNewLineSniff.php b/build/CodeIgniter/Sniffs/WhiteSpace/ElseOnNewLineSniff.php new file mode 100644 index 00000000..03687d7d --- /dev/null +++ b/build/CodeIgniter/Sniffs/WhiteSpace/ElseOnNewLineSniff.php @@ -0,0 +1,82 @@ + + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * CodeIgniter_Sniffs_WhiteSpace_ElseOnNewLineSniff. + * + * Ensures that control structures else and elseif stand on new lines. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +namespace CodeIgniter\Sniffs\WhiteSpace; + +use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Files\File; + +class ElseOnNewLineSniff implements Sniff +{ + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_ELSE, + T_ELSEIF, + ); + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $else_token = $tokens[$stackPtr]; + $previous_non_blank_token_ptr = $phpcsFile->findPrevious(array(T_WHITESPACE), $stackPtr - 1, null, true); + + if (false === $previous_non_blank_token_ptr) { + // else is no preceded with any symbol, but it is not the responsibility of this sniff. + return; + } + + $previous_non_blank_token = $tokens[$previous_non_blank_token_ptr]; + if ($previous_non_blank_token['line'] === $else_token['line']) { + $error = '"' . $else_token['content'] . '" should be on a new line.'; + $phpcsFile->addError($error, $stackPtr); + } + + }//end process() + + +}//end class + +?> \ No newline at end of file diff --git a/build/CodeIgniter/Sniffs/WhiteSpace/LogicalNotSpacingSniff.php b/build/CodeIgniter/Sniffs/WhiteSpace/LogicalNotSpacingSniff.php new file mode 100755 index 00000000..2e242e4d --- /dev/null +++ b/build/CodeIgniter/Sniffs/WhiteSpace/LogicalNotSpacingSniff.php @@ -0,0 +1,75 @@ + + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * CodeIgniter_Sniffs_WhiteSpace_LogicalNotSpacingSniff. + * + * Ensures that at exactly a space precedes and follows the logical operator !. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +namespace CodeIgniter\Sniffs\WhiteSpace; + +use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Files\File; + +class LogicalNotSpacingSniff implements Sniff +{ + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_BOOLEAN_NOT, + ); + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $operator_token = $tokens[$stackPtr]; + + $previous_token = $tokens[$stackPtr - 1]; + $next_token = $tokens[$stackPtr + 1]; + if (T_WHITESPACE !== $previous_token['code'] || T_WHITESPACE !== $next_token['code']) { + $error = 'Logical operator ! should always be preceded and followed with a whitespace.'; + $phpcsFile->addError($error, $stackPtr); + } + }//end process() + + +}//end class + +?> \ No newline at end of file diff --git a/build/CodeIgniter/UnusedSniffs/Files/AbstractClosingCommentSniff.php b/build/CodeIgniter/UnusedSniffs/Files/AbstractClosingCommentSniff.php new file mode 100644 index 00000000..dfdde6fa --- /dev/null +++ b/build/CodeIgniter/UnusedSniffs/Files/AbstractClosingCommentSniff.php @@ -0,0 +1,104 @@ + + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * CodeIgniter_Sniffs_Files_AbstractClosingCommentSniff. + * + * Defines some methods used by + * CodeIgniter_Sniffs_Files_ClosingFileCommentSniff + * and CodeIgniter_Sniffs_Files_ClosingLocationCommentSniff. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +namespace CodeIgniter\Sniffs\Files; + +use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Files\File; + +class AbstractClosingCommentSniff implements Sniff +{ + /** + * As an abstract class, this sniff is not associated to any token. + */ + public function register() + { + return array(); + } + + /** + * As an abstract class, this sniff is not dedicated to process a token. + */ + public function process(File $phpcsFile, $stackPtr) + { + $error = __CLASS__.'::'.__METHOD__.' is abstract. Please develop this method in a child class.'; + throw new PHP_CodeSniffer_Exception($error); + } + + /** + * Returns the comment without its delimiter(s) as well as leading + * and traling whitespaces. + * + * It removes the first #, the two first / (i.e. //) or the first /* + * and last \*\/. If a comment starts with /**, then the last * will remain + * as well as whitespaces between this star and the comment content. + * + * @param string $comment Comment containing either comment delimiter(s) and + * trailing or leading whitspaces to clean. + * + * @return string Comment without comment delimiter(s) and whitespaces. + */ + protected static function _getCommentContent ($comment) + { + if (self::_stringStartsWith($comment, '#')) { + $comment = substr($comment, 1); + } else if (self::_stringStartsWith($comment, '//')) { + $comment = substr($comment, 2); + } else if (self::_stringStartsWith($comment, '/*')) { + $comment = substr($comment, 2, strlen($comment) - 2 - 2); + } + $comment = trim($comment); + return $comment; + }//_getCommentContent() + + + /** + * Binary safe string comparison between $needle and + * the beginning of $haystack. Returns true if $haystack starts with + * $needle, false otherwise. + * + * @param string $haystack The string to search in. + * @param string $needle The string to search for. + * + * @return bool true if $haystack starts with $needle, false otherwise. + */ + protected static function _stringStartsWith ($haystack, $needle) + { + $startsWith = false; + if (strlen($needle) <= strlen($haystack)) { + $haystackBeginning = substr($haystack, 0, strlen($needle)); + if (0 === strcmp($haystackBeginning, $needle)) { + $startsWith = true; + } + } + return $startsWith; + }//_stringStartsWith() +}//end class + +?> diff --git a/build/CodeIgniter/UnusedSniffs/Files/ClosingFileCommentSniff.php b/build/CodeIgniter/UnusedSniffs/Files/ClosingFileCommentSniff.php new file mode 100755 index 00000000..d060e082 --- /dev/null +++ b/build/CodeIgniter/UnusedSniffs/Files/ClosingFileCommentSniff.php @@ -0,0 +1,109 @@ + + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * CodeIgniter_Sniffs_Files_ClosingFileCommentSniff. + * + * Ensures that a comment containing the file name is available at the end of file. + * Only other comments and whitespaces are allowed to follow this specific comment. + * + * It may be all kind of comment like multi-line and inline C-style comments as + * well as PERL-style comments. Any number of white may separate comment delimiters + * from comment content. However, content has to be equal to template + * "End of file ". Comparison between content and template is + * case-sensitive. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +namespace CodeIgniter\Sniffs\Files; + +use PHP_CodeSniffer\Files\File; + +class ClosingFileCommentSniff extends AbstractClosingCommentSniff +{ + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_OPEN_TAG, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + // We are only interested if this is the first open tag. + if ($stackPtr !== 0) { + if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { + return; + } + } + + $fullFilename = $phpcsFile->getFilename(); + $filename = basename($fullFilename); + $commentTemplate = "End of file $filename"; + + $tokens = $phpcsFile->getTokens(); + $currentToken = count($tokens) - 1; + $hasClosingFileComment = false; + $isNotAWhitespaceOrAComment = false; + while ($currentToken >= 0 + && ! $isNotAWhitespaceOrAComment + && ! $hasClosingFileComment + ) { + $token = $tokens[$currentToken]; + $tokenCode = $token['code']; + if (T_COMMENT === $tokenCode) { + $commentString = self::_getCommentContent($token['content']); + if (0 === strcmp($commentString, $commentTemplate)) { + $hasClosingFileComment = true; + } + } else if (T_WHITESPACE === $tokenCode) { + // Whitespaces are allowed between the closing file comment, + // other comments and end of file + } else { + $isNotAWhitespaceOrAComment = true; + } + $currentToken--; + } + + if ( ! $hasClosingFileComment) { + $error = 'No comment block marks the end of file instead of the closing PHP tag. Please add a comment block containing only "' . $commentTemplate . '".'; + $phpcsFile->addError($error, $currentToken); + } + }//end process() +}//end class + +?> diff --git a/build/CodeIgniter/UnusedSniffs/Files/ClosingLocationCommentSniff.php b/build/CodeIgniter/UnusedSniffs/Files/ClosingLocationCommentSniff.php new file mode 100755 index 00000000..ed842114 --- /dev/null +++ b/build/CodeIgniter/UnusedSniffs/Files/ClosingLocationCommentSniff.php @@ -0,0 +1,182 @@ + + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * CodeIgniter_Sniffs_Files_ClosingLocationCommentSniff. + * + * Ensures that a comment containing the file location exists at the end of file. + * Only other comments and whitespaces are allowed between this comment and + * the end of file. + * + * It may be all kind of comment like multi-line and inline C-style comments as + * well as PERL-style comments. Any number of white may separate comment delimiters + * from comment content. However, content has to be equal to template + * "Location: ". + * Comparison between content and template is case-sensitive. + * + * There are several ways to configure the application root. In order of priority : + * - Configuration variable ci_application_root. + * - Rule property applicationRoot. + * - Default value '/application/' + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2006 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +namespace CodeIgniter\Sniffs\Files; + +use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Util\Common; + +class ClosingLocationCommentSniff extends AbstractClosingCommentSniff +{ + public $applicationRoot = '/application/'; + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_OPEN_TAG + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + // We are only interested if this is the first open tag. + if ($stackPtr !== 0) { + if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { + return; + } + } + + $filePath = $phpcsFile->getFilename(); + $tokens = $phpcsFile->getTokens(); + // removes the application root from the beginning of the file path + $locationPath = self::_getLocationPath($filePath, $this->_getAppRoot()); + // add an error, if application root doesn't exist in current file path + if (false === $locationPath) { + $error = 'Unable to find "' . $this->_getAppRoot() . '" in file path "' . $filePath . '". Please set your project\'s application root.'; + $phpcsFile->addError($error, count($tokens) - 1); + return; + } + // generates the expected comment + $commentTemplate = "Location: $locationPath"; + + $currentToken = count($tokens) - 1; + $hasClosingLocationComment = false; + $isNotAWhitespaceOrAComment = false; + while ($currentToken >= 0 + && ! $isNotAWhitespaceOrAComment + && ! $hasClosingLocationComment + ) { + $token = $tokens[$currentToken]; + $tokenCode = $token['code']; + if (T_COMMENT === $tokenCode) { + $commentString = self::_getCommentContent($token['content']); + if (0 === strcmp($commentString, $commentTemplate)) { + $hasClosingLocationComment = true; + } + } else if (T_WHITESPACE === $tokenCode) { + // Whitespaces are allowed between the closing file comment, + //other comments and end of file + } else { + $isNotAWhitespaceOrAComment = true; + } + $currentToken--; + } + + if ( ! $hasClosingLocationComment) { + $error = 'No comment block marks the end of file instead of the closing PHP tag. Please add a comment block containing only "' . $commentTemplate . '".'; + $phpcsFile->addError($error, $currentToken); + } + }//end process() + + + /** + * Returns the relative path from $appRoot to $filePath, or false if + * $appRoot cannot be found in $filePath, because $appRoot is not a parent + * of $filePath. + * + * @param string $filePath Full path to the file being proceed. + * @param string $appRoot Partial or full path to the CodeIgniter + * application root of the file being proceed. It must not contain the + * full path to the application root, but at least the name of the + * application root. Parent directory of the application root are allowed + * but not mandatory. + * + * @return string|bool The relative path from $appRoot to $filePath, or + * false if $appRoot cannot be found in $filePath. + */ + private static function _getLocationPath ($filePath, $appRoot) + { + // removes the path to application root + // from the beginning of the file path + $appRootAt = strpos($filePath, $appRoot); + if (false === $appRootAt) { + return false; + } + $localPath = substr($filePath, $appRootAt + strlen($appRoot)); + // ensures the location path to be a relative path starting with "./". + if ( ! self::_stringStartsWith($localPath, './')) { + $localPath = './' . $localPath; + } else if ( ! self::_stringStartsWith($localPath, '.') + && self::_stringStartsWith($localPath, '/') + ) { + $localPath = '.' . $localPath; + } + return $localPath; + }//end _getLocationPath() + + + /** + * Returns the application root that should be used first. + * + * There are several ways to configure the application root. + * In order of priority : + * - Configuration variable ci_application_root. + * - Rule property applicationRoot. + * - Default value '/application/' + * + * @return string Path to your project application root. + */ + private function _getAppRoot() + { + $appRoot = Common::getConfigData('ci_application_root'); + if (null === $appRoot) { + $appRoot = $this->applicationRoot; + } + return $appRoot; + }//end _getAppRoot() +}//end class + +?> diff --git a/build/CodeIgniter/UnusedSniffs/NamingConventions/ConstructorNameSniff.php b/build/CodeIgniter/UnusedSniffs/NamingConventions/ConstructorNameSniff.php new file mode 100755 index 00000000..983bb287 --- /dev/null +++ b/build/CodeIgniter/UnusedSniffs/NamingConventions/ConstructorNameSniff.php @@ -0,0 +1,142 @@ + + * @copyright 2011 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +namespace CodeIgniter\Sniffs\NamingConventions; + +use PHP_CodeSniffer\Sniffs\AbstractScopeSniff; +use PHP_CodeSniffer\Files\File; + +/** + * CodeIgniter_Sniffs_NamingConventions_ConstructorNameSniff. + * + * Favor PHP 4 constructor syntax, which uses "function ClassName()". + * Avoid PHP 5 constructor syntax, which uses "function __construct()". + * + * @todo Try to avoid overly long and verbose names. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2010 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class ConstructorNameSniff extends AbstractScopeSniff +{ + + + public $php5Constructors = '1'; + + + /** + * Constructs the test with the tokens it wishes to listen for. + * + * @return void + */ + public function __construct() + { + parent::__construct(array(T_CLASS, T_INTERFACE), array(T_FUNCTION), true); + + }//end __construct() + + + /** + * Processes this test when one of its tokens is encountered. + * + * @param File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * @param int $currScope A pointer to the start of the scope. + * + * @return void + */ + protected function processTokenWithinScope( + File $phpcsFile, + $stackPtr, + $currScope + ) { + $methodName = $phpcsFile->getDeclarationName($stackPtr); + $className = $phpcsFile->getDeclarationName($currScope); + + $isPhp4Constructor = strcasecmp($methodName, $className) === 0; + $isPhp5Constructor = strcasecmp($methodName, '__construct') === 0; + if ($this->php5Constructors != '0') { + if ($isPhp4Constructor) { + $error = "PHP4 style constructors are not allowed; use \"__construct\" instead"; + $phpcsFile->addError($error, $stackPtr); + } + } else { + if ($isPhp5Constructor) { + $error = "PHP5 style constructors are not allowed; use \"$className\" instead"; + $phpcsFile->addError($error, $stackPtr); + } + } + if ( ! $isPhp4Constructor && ! $isPhp5Constructor ) { + return; + } + + $tokens = $phpcsFile->getTokens(); + + $parentClassName = $phpcsFile->findExtendedClassName($currScope); + $wrongConstructor = ''; + // prepares the error message and wrong constructor + if ($this->php5Constructors != '0') { + $error = 'PHP4 style calls to parent constructors are not allowed.'; + $error = "$error Please use \"parent::__construct\" instead."; + if (false !== $parentClassName) { + $wrongConstructor = $parentClassName; + } + // Else $wrongConstructor will be empty + // and the test expression will always be false. + // It doesn't check that no parent method should be called + // when no parent class is defined. + } else { + $error = 'PHP5 style calls to parent constructors are not allowed.'; + if (false !== $parentClassName) { + $error = "$error Please use \"parent::$parentClassName\" instead."; + } + $wrongConstructor = '__construct'; + } + + // looks for the use of a wrong constructor. + $endFunctionIndex = $tokens[$stackPtr]['scope_closer']; + $doubleColonIndex = $phpcsFile->findNext( + array(T_DOUBLE_COLON), + $stackPtr, + $endFunctionIndex + ); + while ($doubleColonIndex) { + if ($tokens[($doubleColonIndex + 1)]['code'] === T_STRING + && $tokens[($doubleColonIndex + 1)]['content'] === $wrongConstructor + ) { + $phpcsFile->addError($error, ($doubleColonIndex + 1)); + } + + $doubleColonIndex = $phpcsFile->findNext( + array(T_DOUBLE_COLON), + $doubleColonIndex + 1, + $endFunctionIndex + ); + } + + }//end processTokenWithinScope() + + protected function processTokenOutsideScope(File $phpcsFile, $stackPtr) + { + // TODO: Implement processTokenOutsideScope() method. + } + +}//end class + +?> diff --git a/build/CodeIgniter/UnusedSniffs/NamingConventions/ValidClassNameSniff.php b/build/CodeIgniter/UnusedSniffs/NamingConventions/ValidClassNameSniff.php new file mode 100755 index 00000000..2b24327d --- /dev/null +++ b/build/CodeIgniter/UnusedSniffs/NamingConventions/ValidClassNameSniff.php @@ -0,0 +1,84 @@ + + * @copyright 2010 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * CodeIgniter_Sniffs_NamingConventions_ValidClassNameSniff. + * + * Ensures that class and interface names have their first letter uppercase + * and that words are separated with an underscore, and not CamelCased. + * + * @todo Try to avoid overly long and verbose names in using property rule and + * configuration variable to set limits. Have a look at + * CodeIgniter_Sniffs_NamingConventions_ValidMethodNameSniff. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2010 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +namespace CodeIgniter\Sniffs\NamingConventions; + +use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Files\File; + +class ValidClassNameSniff implements Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_CLASS, + T_INTERFACE, + ); + + }//end register() + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param File $phpcsFile The current file being processed. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + // get the class name + $className = trim($phpcsFile->getDeclarationName($stackPtr)); + // compute the expected class name + // [^_] means "something different from _", but not "nothing or something different from _" + $lcClassNameChunk = preg_replace('/([^_])([A-Z])/', '${1}_${2}', $className); + $expectedClassName + = strtoupper($className[0]) . strtolower(substr($lcClassNameChunk,1)); + // ensures that the current class name + // and the expected class name are identical + if (0 !== strcmp($className, $expectedClassName)) { + $error = 'Class names should always have their first letter uppercase. Multiple words should be separated with an underscore, and not CamelCased. Please consider ' . $expectedClassName . ' instead of ' . $className . '.'; + $phpcsFile->addError($error, $stackPtr); + } + }//end process() + +}//end class + +?> diff --git a/build/CodeIgniter/UnusedSniffs/NamingConventions/ValidFileNameSniff.php b/build/CodeIgniter/UnusedSniffs/NamingConventions/ValidFileNameSniff.php new file mode 100644 index 00000000..7f10fa44 --- /dev/null +++ b/build/CodeIgniter/UnusedSniffs/NamingConventions/ValidFileNameSniff.php @@ -0,0 +1,84 @@ + + * @copyright 2011 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * CodeIgniter_Sniffs_NamingConventions_ValidFileNameSniff. + * + * Tests that the file name matchs the name of the class that it contains in lower case. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2011 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +namespace CodeIgniter\Sniffs\NamingConventions; + +use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Files\File; + +class ValidFileNameSniff implements Sniff +{ + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_CLASS, + T_INTERFACE, + ); + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + // computes the expected filename based on the name of the class or interface that it contains. + $decNamePtr = $phpcsFile->findNext(T_STRING, $stackPtr); + $decName = $tokens[$decNamePtr]['content']; + $expectedFileName = strtolower($decName); + // extracts filename without extension from its path. + $fullPath = $phpcsFile->getFilename(); + $fileNameAndExt = basename($fullPath); + $fileName = substr($fileNameAndExt, 0, strrpos($fileNameAndExt, '.')); + + if ($expectedFileName !== $fileName) { + $errorTemplate = 'Filename "%s" doesn\'t match the name of the %s that it contains "%s" in lower case. "%s" was expected.'; + $errorMessage = sprintf( + $errorTemplate, + $fileName, + strtolower($tokens[$stackPtr]['content']), // class or interface + $decName, + $expectedFileName + ); + $phpcsFile->addError($errorMessage, 0); + } + }//end process() +}//end class + +?> diff --git a/build/CodeIgniter/UnusedSniffs/NamingConventions/ValidMethodNameSniff.php b/build/CodeIgniter/UnusedSniffs/NamingConventions/ValidMethodNameSniff.php new file mode 100755 index 00000000..34e973c6 --- /dev/null +++ b/build/CodeIgniter/UnusedSniffs/NamingConventions/ValidMethodNameSniff.php @@ -0,0 +1,161 @@ + + * @copyright 2010 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +/** + * CodeIgniter_Sniffs_NamingConventions_ValidMethodNameSniff. + * + * Ensures that class methods and functions areentirely lowercased and that + * words are separated with an underscore, and not CamelCased. + * Ensures that private class methods are prefixed with an underscore and that + * all other methods are not prefixed with an underscored. + * Ensures that names longer than 50 chars are prohibited. Likewise names longer + * than 35 chars raise a warning. + * + * @todo Use a rule property or a configuration variable to allow users to set + * their own maximum lengths for function and method names. Have a look at + * CodeIgniter_Sniffs_Files_ClosingLocationCommentSniff and application root. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2010 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +namespace CodeIgniter\Sniffs\NamingConventions; + +use PHP_CodeSniffer\Sniffs\AbstactScopeSniff; +use PHP_CodeSniffer\Files\File; + +class ValidMethodNameSniff extends AbstractScopeSniff +{ + /** + * A list of all PHP magic methods. + * + * @var array + */ + protected static $magicMethods = array( + 'construct', + 'destruct', + 'call', + 'callStatic', + 'get', + 'set', + 'isset', + 'unset', + 'sleep', + 'wakeup', + 'toString', + 'set_state', + 'clone', + ); + + /** + * Defines which token(s) in which scope(s) will be proceed. + */ + public function __construct() + { + parent::__construct(array(T_CLASS, T_INTERFACE), array(T_FUNCTION), true); + + }//end __construct() + + + /** + * Processes the tokens within the scope. + * + * @param File $phpcsFile The file being processed. + * @param int $stackPtr The position where this token was + * found. + * @param int $currScope The position of the current scope. + * + * @return void + */ + protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScope) + { + $methodName = $phpcsFile->getDeclarationName($stackPtr); + if ($methodName === null) { + // Ignore closures. + return; + } + + $className = $phpcsFile->getDeclarationName($currScope); + + // Is this a magic method i.e. is prefixed with "__". + if (0 === strcmp(substr($methodName, 0, 2), '__')) { + $magicPart = substr($methodName, 2); + if (in_array($magicPart, self::$magicMethods) === false) { + $error = "Method name \"$className::$methodName\" is invalid; only PHP magic methods should be prefixed with a double underscore"; + $phpcsFile->addError($error, $stackPtr); + } + + return; + } + + // PHP4 constructors are allowed to break our rules. + if ($methodName === $className) { + return; + } + + // PHP4 destructors are allowed to break our rules. + if ($methodName === '_'.$className) { + return; + } + + if (0 !== strcmp($methodName, strtolower($methodName))) { + $uscrdMethodName = preg_replace('/([A-Z])/', '_${1}', $methodName); + $expectedMethodName = strtolower($uscrdMethodName); + $error = "Class methods should be entirely lowercased. Please consider \"$expectedMethodName\" instead of \"$methodName\"."; + $phpcsFile->addError($error, $stackPtr); + return; + } + + $methodProps = $phpcsFile->getMethodProperties($stackPtr); + $scope = $methodProps['scope']; + $scopeSpecified = $methodProps['scope_specified']; + + // If it's a private method, it must have an underscore on the front. + if ($scope === 'private' && $methodName{0} !== '_') { + $error = "Private method name \"$className::$methodName\" must be prefixed with an underscore"; + $phpcsFile->addError($error, $stackPtr); + return; + } + + // If it's not a private method, it must not have an underscore on the front. + if ($scope !== 'private' && $methodName{0} === '_') { + if (true === $scopeSpecified) { + $error = "Public method name \"$className::$methodName\" must not be prefixed with an underscore"; + } else { + $error = ucfirst($scope)." method name \"$className::$methodName\" must not be prefixed with an underscore"; + } + $phpcsFile->addError($error, $stackPtr); + return; + } + + // If name is too verbose, + // then either an error or a warning is displayed. + $error_limit = 50; + $warning_limit = 35; + if (strlen($methodName) > $error_limit) { + $error = "Overly long and verbose names are prohibited. Please find a name shorter than $error_limit chars."; + $phpcsFile->addError($error, $stackPtr); + return; + } else if (strlen($methodName) > $warning_limit) { + $warning = "Try to avoid overly long and verbose names in finding a name shorter than $warning_limit chars."; + $phpcsFile->addWarning($warning, $stackPtr); + } + }//end processTokenWithinScope() + +}//end class + +?> diff --git a/build/CodeIgniter/UnusedSniffs/NamingConventions/ValidVariableNameSniff.php b/build/CodeIgniter/UnusedSniffs/NamingConventions/ValidVariableNameSniff.php new file mode 100755 index 00000000..c4d8798c --- /dev/null +++ b/build/CodeIgniter/UnusedSniffs/NamingConventions/ValidVariableNameSniff.php @@ -0,0 +1,562 @@ + + * @copyright 2010 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +/** + * CodeIgniter_Sniffs_NamingConventions_ValidVariableNameSniff. + * + * Ensures that variable names contain only lowercase letters, + * use underscore separators. + * Ensures that class attribute names are prefixed with an underscore, + * only when they are private. + * Ensure that variable names are longer than 3 chars except those declared + * in for loops. + * + * @todo Try to avoid overly long and verbose names in using property rule and + * configuration variable to set limits. Have a look at + * CodeIgniter_Sniffs_NamingConventions_ValidMethodNameSniff. + * @todo Use a property rule or a configuration variable to allow users to set + * minimum variable name length. Have a look at + * CodeIgniter_Sniffs_Files_ClosingLocationCommentSniff and application root. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Thomas Ernest + * @copyright 2010 Thomas Ernest + * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +namespace CodeIgniter\Sniffs\NamingConventions; + +use PHP_CodeSniffer\Sniffs\AbstractVariableSniff; +use PHP_CodeSniffer\Files\File; + +class ValidVariableNameSniff extends AbstractVariableSniff +{ + + + /** + * Processes class member variables. + * + * @param File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + protected function processMemberVar(File $phpcsFile, $stackPtr) + { + // get variable name and properties + $tokens = $phpcsFile->getTokens(); + $varTk = $tokens[$stackPtr]; + $varName = substr($varTk['content'], 1); + $varProps = $phpcsFile->getMemberProperties($stackPtr); + // check(s) + if ( ! $this->checkLowerCase($phpcsFile, $stackPtr, $varName) ) { + return; + } + if ( ! $this->checkVisibilityPrefix($phpcsFile, $stackPtr, $varName, $varProps)) { + return; + } + if ( ! $this->checkLength($phpcsFile, $stackPtr, $varName)) { + return; + } + + }//end processMemberVar() + + + /** + * Processes normal variables. + * + * @param File $phpcsFile The file where this token was found. + * @param int $stackPtr The position where the token was found. + * + * @return void + */ + protected function processVariable(File $phpcsFile, $stackPtr) + { + // get variable name + $tokens = $phpcsFile->getTokens(); + $varTk = $tokens[$stackPtr]; + $varName = substr($varTk['content'], 1); + // skip the current object variable, i.e. $this + if (0 === strcmp($varName, 'this')) { + return; + } + // check(s) + if ( ! $this->checkLowerCase($phpcsFile, $stackPtr, $varName)) { + return; + } + if ( ! $this->checkLength($phpcsFile, $stackPtr, $varName)) { + return; + } + + }//end processVariable() + + + /** + * Processes variables in double quoted strings. + * + * @param File $phpcsFile The file where this token was found. + * @param int $stackPtr The position where the token was found. + * + * @return void + */ + protected function processVariableInString(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $stringTk = $tokens[$stackPtr]; + $stringString = $stringTk['content']; + $varAt = self::_getVariablePosition($stringString, 0); + while (false !== $varAt) { + // get variable name + $matches = array(); + preg_match('/^\$\{?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}?/', substr($stringString, $varAt), $matches); + $varName = $matches[1]; + // check(s) + if ( ! $this->checkLowerCase($phpcsFile, $stackPtr, $varName)) { + return; + } + if ( ! $this->checkLength($phpcsFile, $stackPtr, $varName)) { + return; + } + // prepare checking next variable + $varAt = self::_getVariablePosition($stringString, $varAt + 1); + } + + }//end processVariableInString() + + + /** + * Checks that the variable name is all in lower case, else it add an error + * to $phpcsFile. Returns true if variable name is all in lower case, false + * otherwise. + * + * @param File $phpcsFile The current file being processed. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * @param string $varName The name of the variable to + * procced without $, { nor }. + * + * @return bool true if variable name is all in lower case, false otherwise. + */ + protected function checkLowerCase(File $phpcsFile, $stackPtr, $varName) + { + $isInLowerCase = true; + if (0 !== strcmp($varName, strtolower($varName))) { + // get the expected variable name + $varNameWithUnderscores = preg_replace('/([A-Z])/', '_${1}', $varName); + $expectedVarName = strtolower(ltrim($varNameWithUnderscores, '_')); + // adapts the error message to the error case + if (strlen($varNameWithUnderscores) > strlen($varName)) { + $error = 'Variables should not use CamelCasing or start with a Capital.'; + } else { + $error = 'Variables should be entirely lowercased.'; + } + $error = $error . 'Please consider "' . $expectedVarName + . '" instead of "' . $varName . '".'; + // adds the error and changes return value + $phpcsFile->addError($error, $stackPtr); + $isInLowerCase = false; + } + return $isInLowerCase; + }//end checkLowerCase() + + /** + * Checks that an underscore is used at the beginning of a variable only if + * it is about a private variable. If it isn't a private variable, then it + * must not be prefixed with an underscore. Returns true if $varName is + * properly prefixed according to the variable visibility provided in + * $varProps, false otherwise. + * + * @param File $phpcsFile The current file being processed. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * @param string $varName The name of the variable to + * procced without $, { nor }. + * @param array $varProps Member variable properties like + * its visibility. + * + * @return bool true if variable name is prefixed with an underscore only + * when it is about a private variable, false otherwise. + */ + protected function checkVisibilityPrefix(File $phpcsFile, $stackPtr, $varName, $varProps) + { + $isVisibilityPrefixRight = true; + $scope = $varProps['scope']; + // If it's a private variable, it must have an underscore on the front. + if ($scope === 'private' && $varName{0} !== '_') { + $error = "Private variable name \"$varName\" must be prefixed with an underscore"; + $phpcsFile->addError($error, $stackPtr); + $isVisibilityPrefixRight = false; + } else if ($scope !== 'private' && $varName{0} === '_') { + // If it's not a private variable, + // then it must not start with an underscore. + if (isset ($scopeSpecified) && true === $scopeSpecified) { + $error = "Public variable name \"$varName\" must not be prefixed with an underscore"; + } else { + $error = ucfirst($scope) . " variable name \"$varName\" must not be prefixed with an underscore"; + } + $phpcsFile->addError($error, $stackPtr); + $isVisibilityPrefixRight = false; + } + return $isVisibilityPrefixRight; + }//end checkVisibilityPrefix() + + /** + * Checks that variable name length is not too short. Returns true, if it + * meets minimum length requirement, false otherwise. + * + * A variable name is too short if it is shorter than the minimal + * length and it isn't in the list of allowed short names nor declared in a + * for loop (in which it would be nested). + * The minimal length is defined in the function. It is 3 chars now. + * The list of allowed short names is defined in the function. + * It is case-sensitive. It contains only 'ci' now. + * + * @param File $phpcsFile The current file being processed. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * @param string $varName The name of the variable to + * procced without $, { nor }. + * + * @return bool false if variable name $varName is shorter than the minimal + * length and it isn't in the list of allowed short names nor declared in a + * for loop (in which it would be nested), otherwise true. + */ + protected function checkLength(File $phpcsFile, $stackPtr, $varName) + { + $minLength = 3; + $allowedShortName = array('ci'); + + $isLengthRight = true; + // cleans variable name + $varName = ltrim($varName, '_'); + if (strlen($varName) <= $minLength) { + // skips adding an error, if it is a specific variable name + if (in_array($varName, $allowedShortName)) { + return $isLengthRight; + } + // skips adding an error, if the variable is in a for loop + if (false !== self::_isInForLoop($phpcsFile, $stackPtr, $varName)) { + return $isLengthRight; + } + // adds the error message finally + $error = 'Very short' + . ( + $minLength > 0 ? + ' (i.e. less than ' . ($minLength + 1) . ' chars)' + : '' + ) + . ', non-word variables like "' . $varName + . '" should only be used as iterators in for() loops.'; + $phpcsFile->addError($error, $stackPtr); + $isLengthRight = false; + } + return $isLengthRight; + }//end checkLength() + + /** + * Returns the position of closest previous T_FOR, if token associated with + * $stackPtr in $phpcsFile is in a for loop, otherwise false. + * + * @param File $phpcsFile The current file being processed. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * @param string $varName The name of the variable to + * procced without $, { nor }. + * + * @return int|bool Position of T_FOR if token associated with $stackPtr in + * $phpcsFile is in the head of a for loop, otherwise false. + */ + private static function _isInForLoop(File $phpcsFile, $stackPtr, $varName) + { + $keepLookingFromPtr = $stackPtr; + while (false !== $keepLookingFromPtr) { + // looks if it is in (head or body) of a for loop + $forPtr = self::_isInForLoopHead($phpcsFile, $keepLookingFromPtr); + if (false === $forPtr) { + $forPtr = self::_isInForLoopBody($phpcsFile, $keepLookingFromPtr); + } + // checks if it is declared in here and prepares next step + if (false !== $forPtr) { + if (false !== self::_isDeclaredInForLoop($phpcsFile, $forPtr, $varName)) { + return $forPtr; + } + $keepLookingFromPtr = $forPtr; + } else { + $keepLookingFromPtr = false; + } + } + return false; + }//end _isInForLoop() + + /** + * Returns the position of closest previous T_FOR, if token associated with + * $stackPtr in $phpcsFile is in the head of a for loop, otherwise false. + * The head is the code placed between parenthesis next to the key word + * 'for' : for () {}. + * + * @param File $phpcsFile The current file being processed. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return int|bool Position of T_FOR if token associated with $stackPtr in + * $phpcsFile is in the head of a for loop, otherwise false. + */ + private static function _isInForLoopHead(File $phpcsFile, $stackPtr) + { + $isInForLoop = false; + $tokens = $phpcsFile->getTokens(); + $currentTk = $tokens[$stackPtr]; + if (array_key_exists('nested_parenthesis', $currentTk)) { + $nestedParenthesis = $currentTk['nested_parenthesis']; + foreach ( $nestedParenthesis as $openParPtr => $closeParPtr) { + $nonWhitspacePtr = $phpcsFile->findPrevious( + array(T_WHITESPACE), + $openParPtr - 1, + null, + true, + null, + true + ); + if (false !== $nonWhitspacePtr) { + $isFor = T_FOR === $tokens[$nonWhitspacePtr]['code']; + if ($isFor) { + $isInForLoop = $nonWhitspacePtr; + break; + } + } + } + } + return $isInForLoop; + }//end _isInForLoopHead() + + /** + * Returns the position of closest previous T_FOR, if token associated with + * $stackPtr in $phpcsFile is in the body of a for loop, otherwise false. + * The body are the instructions placed after parenthesis of a 'for' + * declaration, enclosed with curly brackets usually. + * 'for' : for () {}. + * + * @param File $phpcsFile The current file being processed. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return int|bool Position of T_FOR if token associated with $stackPtr in + * $phpcsFile is in the body of a for loop, otherwise false. + */ + private static function _isInForLoopBody(File $phpcsFile, $stackPtr) + { + $isInForLoop = false; + $tokens = $phpcsFile->getTokens(); + // get englobing hierarchy + $parentPtrAndCode = $tokens[$stackPtr]['conditions']; + krsort($parentPtrAndCode); + + // looks for a for loop having a body not enclosed with curly brackets, + // which involves that its body contains only one instruction. + if (is_array($parentPtrAndCode) && ! empty($parentPtrAndCode)) { + $parentCode = reset($parentPtrAndCode); + $parentPtr = key($parentPtrAndCode); + $openBracketPtr = $tokens[$parentPtr]['scope_opener']; + } else { + $parentCode = 0; + $parentPtr = 0; + $openBracketPtr = 0; + } + $openResearchScopePtr = $stackPtr; + // recursive search, since a for statement may englobe other inline + // control statement or may be near to function calls, etc... + while (false !== $openResearchScopePtr) { + $closeParPtr = $phpcsFile->findPrevious( + array(T_CLOSE_PARENTHESIS), + $openResearchScopePtr, + null, + false, + null, + true + ); + // is there a closing parenthesis with a control statement before + // the previous instruction ? + if (false !== $closeParPtr) { + // is there no opening curly bracket specific to + // set of instructions, between the closing parenthesis + // and the current token ? + if ($openBracketPtr < $closeParPtr) { + // starts the search from the token before the closing + // parenthesis, if it isn't a for statement + $openResearchScopePtr = $closeParPtr - 1; + // is this parenthesis associated with a for statement ? + $closeParenthesisTk = $tokens[$closeParPtr]; + if (array_key_exists('parenthesis_owner', $closeParenthesisTk)) { + $mayBeForPtr = $closeParenthesisTk['parenthesis_owner']; + $mayBeForTk = $tokens[$mayBeForPtr]; + if (T_FOR === $mayBeForTk['code']) { + return $mayBeForPtr; + } + } + } else { + // if it is about a for loop, don't go further + // and detect it after one more loop execution, do it now + if (T_FOR === $parentCode) { + return $parentPtr; + } + // starts the search from the token before the one + // englobing the current statement + $openResearchScopePtr = $parentPtr - 1; + // re-initialize variables about the englobing structure + if (is_array($parentPtrAndCode)) { + $parentCode = next($parentPtrAndCode); + $parentPtr = key($parentPtrAndCode); + $openBracketPtr = $tokens[$parentPtr]['scope_opener']; + } + } + } else { + $openResearchScopePtr = false; + } + } + // looks for a for loop having a body enclosed with curly brackets + foreach ($parentPtrAndCode as $parentPtr => $parentCode) { + if (T_FOR === $parentCode) { + return $parentPtr; + } + } + return false; + }//end _isInForLoopBody() + + /** + * Returns true if a variable declared in the head of the for loop pointed + * by $forPtr in file $phpcsFile has the name $varName. + * + * @param File $phpcsFile The current file being processed. + * @param int $forPtr The position of the 'for' token + * in the stack passed in $tokens. + * @param string $varName The name of the variable to + * procced without $, { nor }. + * + * @return int|bool true if a variable declared in the head of the for loop + * pointed by $forPtr in file $phpcsFile has the name $varName. + */ + private static function _isDeclaredInForLoop(File $phpcsFile, $forPtr, $varName) + { + $isDeclaredInFor = false; + $tokens = $phpcsFile->getTokens(); + $forVarPtrs = self::_getVarDeclaredInFor($phpcsFile, $forPtr); + foreach ($forVarPtrs as $forVarPtr) { + $forVarTk = $tokens[$forVarPtr]; + // get variable name + $matches = array(); + preg_match('/^\$\{?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}?/', $forVarTk['content'], $matches); + $forVarName = $matches[1]; + if (0 === strcmp($forVarName, $varName)) { + $isDeclaredInFor = $forVarPtr; + break; + } + } + return $isDeclaredInFor; + }//end _isDeclaredInForLoop() + + /** + * Returns list of pointers to variables declared in for loop associated to + * $forPtr in file $phpcsFile. + * + * All pointers in the result list are pointing to token with code + * T_VARIABLE. An exception is raised, if $forPtr doesn't point a token with + * code T_FOR. + * + * @param File $phpcsFile The current file being processed. + * @param int $forPtr The position of the current token + * in the stack passed in $tokens. + * + * @return array List of pointers to variables declared in for loop $forPtr. + */ + private static function _getVarDeclaredInFor(File $phpcsFile, $forPtr) + { + $tokens = $phpcsFile->getTokens(); + $forTk = $tokens[$forPtr]; + if (T_FOR !== $forTk['code']) { + throw new PHP_CodeSniffer_Exception('$forPtr must be of type T_FOR'); + } + $openParPtr = $forTk['parenthesis_opener']; + $openParenthesisTk = $tokens[$openParPtr]; + $endOfDeclPtr = $phpcsFile->findNext(array(T_SEMICOLON), $openParPtr); + $forVarPtrs = array(); + $varPtr = $phpcsFile->findNext( + array(T_VARIABLE), + $openParPtr + 1, + $endOfDeclPtr + ); + while (false !== $varPtr) { + $forVarPtrs [] = $varPtr; + $varPtr = $phpcsFile->findNext( + array(T_VARIABLE), + $varPtr + 1, + $endOfDeclPtr + ); + } + return $forVarPtrs; + }//end _getVarDeclaredInFor() + + /** + * Returns the position of first occurrence of a PHP variable starting with + * $ in $haystack from $offset. + * + * @param string $haystack The string to search in. + * @param int $offset The optional offset parameter allows you to + * specify which character in haystack to start + * searching. The returned position is still + * relative to the beginning of haystack. + * + * @return mixed The position as an integer + * or the boolean false, if no variable is found. + */ + private static function _getVariablePosition($haystack, $offset = 0) + { + $var_starts_at = strpos($haystack, '$', $offset); + $is_a_var = false; + while (false !== $var_starts_at && ! $is_a_var) { + // makes sure that $ is used for a variable and not as a symbol, + // if $ is protected with the escape char, then it is a symbol. + if (0 !== strcmp($haystack[$var_starts_at - 1], '\\')) { + if (0 === strcmp($haystack[$var_starts_at + 1], '{')) { + // there is an opening brace in the right place + // so it looks for the closing brace in the right place + $hsChunk2 = substr($haystack, $var_starts_at + 2); + if (1 === preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\}/', $hsChunk2)) { + $is_a_var = true; + } + } else { + $hsChunk1 = substr($haystack, $var_starts_at + 1); + if (1 === preg_match('/^[a-zA-Z_\x7f-\xff]/', $hsChunk1)) { + // $ is used for a variable and not as a symbol, + // since what follows $ matchs the definition of + // a variable label for PHP. + $is_a_var = true; + } + } + } + // update $var_starts_at for the next variable + // only if no variable was found, since it is returned otherwise. + if ( ! $is_a_var) { + $var_starts_at = strpos($haystack, '$', $var_starts_at + 1); + } + } + if ($is_a_var) { + return $var_starts_at; + } else { + return false; + } + }//end _getVariablePosition() +}//end class + +?> diff --git a/build/CodeIgniter/ruleset.xml b/build/CodeIgniter/ruleset.xml new file mode 100644 index 00000000..83974072 --- /dev/null +++ b/build/CodeIgniter/ruleset.xml @@ -0,0 +1,47 @@ + + + CodeIgniter coding standard as described at http://codeigniter.com/user_guide/general/styleguide.html. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/animeclient_header_comment.txt b/build/animeclient_header_comment.txt index a2a4ecb8..66b34887 100644 --- a/build/animeclient_header_comment.txt +++ b/build/animeclient_header_comment.txt @@ -3,9 +3,12 @@ * * An API client for Hummingbird to manage anime and manga watch lists * + * PHP version 5.6 + * * @package HummingbirdAnimeClient - * @author Timothy J. Warren - * @copyright Copyright (c) 2015 - 2016 + * @author Timothy J. Warren + * @copyright 2015 - 2016 Timothy J. Warren * @link https://github.com/timw4mail/HummingBirdAnimeClient + * @version 3.1 * @license MIT */ \ No newline at end of file diff --git a/build/phpcs.xml b/build/phpcs.xml new file mode 100644 index 00000000..58d9c542 --- /dev/null +++ b/build/phpcs.xml @@ -0,0 +1,79 @@ + + + A variation of the CodeIgniter standard + + ../src/ + + utf-8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/phpdox.xml b/build/phpdox.xml index 0be4b97d..09f85dce 100644 --- a/build/phpdox.xml +++ b/build/phpdox.xml @@ -1,131 +1,128 @@ - + - - - - + + + + - - - - - + + + + + - - + + - - + + --> - - - - - + + + + + - - - + + + - - - + + + - - - - + + + + - + - - - + + + - + - - + + - - - + + + - - - + + + - - - - + + + + - - - - - + + + + + - - + + + + - - + + - - - - - - - - + + + + + + + + + + + - + - - - - + + + + - + - - -