Compare commits

...

69 Commits

Author SHA1 Message Date
Timothy Warren 73e646da5a Try to be less clever in redis get method
Gitea - aviat/banker/pipeline/head This commit looks good Details
2023-03-16 22:09:17 -04:00
Timothy Warren a1279b2980 See if reverting predis helps with a bug upstream
Gitea - aviat/banker/pipeline/head This commit looks good Details
2023-03-16 22:02:08 -04:00
Timothy Warren 37d8e1c718 Try again to make Jenkins happy
Gitea - aviat/banker/pipeline/head This commit looks good Details
2023-03-16 16:34:47 -04:00
Timothy Warren 7d9f1711e0 Try again to make Jenkins happy
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2023-03-16 16:28:32 -04:00
Timothy Warren 3df3ca9671 Bump version
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2023-03-16 16:24:11 -04:00
Timothy Warren df61334bb4 Code tweaks for slightly better test coverage 2023-03-16 16:23:41 -04:00
Timothy Warren cef8d2c944 Fix phpstan errors 2023-03-16 16:22:31 -04:00
Timothy Warren 9690e3f4b3 Attempt to add code quality stuff back to Jenkins
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2023-03-16 15:18:10 -04:00
Timothy Warren 57bb3c859c Attempt to add code quality stuff back to Jenkins
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2023-03-16 15:03:45 -04:00
Timothy Warren 989df7dae2 Attempt to add code quality stuff back to Jenkins
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2023-03-16 15:00:52 -04:00
Timothy Warren 5a11bea69b Attempt to add code quality stuff back to Jenkins
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2023-03-16 14:59:49 -04:00
Timothy Warren 8123d99bee Attempt to add code quality stuff back to Jenkins
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2023-03-16 14:54:13 -04:00
Timothy Warren b1d7c887ee Attempt to add code quality stuff back to Jenkins
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2023-03-16 14:50:51 -04:00
Timothy Warren d39c39dab8 Attempt to add code quality stuff back to Jenkins
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2023-03-16 14:42:05 -04:00
Timothy Warren 81407e49b1 Attempt to add code quality stuff back to Jenkins
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2023-03-16 14:38:39 -04:00
Timothy Warren f67e4c41e4 Attempt to add code quality stuff back to Jenkins
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2023-03-16 14:25:46 -04:00
Timothy Warren 5719b42308 Fix method signature issue
Gitea - aviat/banker/pipeline/head This commit looks good Details
2023-03-16 14:24:39 -04:00
Timothy Warren f55c9c7c8e Cleanup old tooling 2023-03-16 14:22:49 -04:00
Timothy Warren e1bc7bcafe Bump version to 4.1.0
Gitea - aviat/banker/pipeline/head This commit looks good Details
2023-03-16 13:09:36 -04:00
Timothy Warren 00e709181f Test PHP 8.2 on Jenkins
Gitea - aviat/banker/pipeline/head This commit looks good Details
2023-02-03 14:11:39 -05:00
Timothy Warren db431e6b2a Some code tweaks and fixes
Gitea - aviat/banker/pipeline/head This commit looks good Details
2023-02-03 14:01:25 -05:00
Timothy Warren 49399b80ef Update dependencies, and update the provide section of composer.json
Gitea - aviat/banker/pipeline/head This commit looks good Details
2021-12-02 15:38:15 -05:00
Timothy Warren 3c8d23e78b Update version in PHP header comments
Gitea - aviat/banker/pipeline/head This commit looks good Details
2021-12-02 15:30:20 -05:00
Timothy Warren ee65b2d287 Move changes to version 4, as it hasn't been released yet 2021-12-02 15:29:29 -05:00
Timothy Warren 0f46dcb2ee Properly use PHP argument types instead of the silly Exception type juggling 2021-12-02 14:26:59 -05:00
Timothy Warren f3b958d17f Restore full test coverage
Gitea - aviat/banker/pipeline/head This commit looks good Details
2021-12-01 13:38:54 -05:00
Timothy Warren 274ad3e2e4 Fix tests related to logging checks
Gitea - aviat/banker/pipeline/head This commit looks good Details
2021-12-01 12:56:28 -05:00
Timothy Warren 6f36f572a0 Attempt to fix code quality check
Gitea - aviat/banker/pipeline/head This commit looks good Details
2021-12-01 12:32:50 -05:00
Timothy Warren e905599778 Attempt to fix code quality check
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-11-30 15:21:38 -05:00
Timothy Warren 0f9cf8dcd2 Attempt to fix code quality check
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-11-30 15:19:27 -05:00
Timothy Warren fbbb612b1f Attempt to fix code quality check
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-11-30 15:17:35 -05:00
Timothy Warren 3c67f8056c Attempt to fix code quality check
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-11-30 15:09:00 -05:00
Timothy Warren a0e97ec7c7 Attempt to fix code quality check
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-11-30 15:06:58 -05:00
Timothy Warren 4bf4ecf77c Attempt to fix code quality check
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-11-30 15:03:24 -05:00
Timothy Warren 3f1a9acfc5 Attempt to fix code quality check
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-11-30 14:58:11 -05:00
Timothy Warren f3df87daae Attempt to fix code quality check
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-11-30 14:55:15 -05:00
Timothy Warren eeb38379a5 Get tests passing again
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-11-30 13:47:51 -05:00
Timothy Warren 1206a47224 Update version headers
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-11-30 11:56:15 -05:00
Timothy Warren 9fb427dff6 Update method interface to match newer PSR interface
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-11-30 11:55:25 -05:00
Timothy Warren 526f32b868 Test PHP 8.1
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-11-30 11:48:49 -05:00
Timothy Warren 3362d66663 Fix a bunch of phpstan issues
Gitea - aviat/banker/pipeline/head This commit looks good Details
2021-02-19 12:18:38 -05:00
Timothy Warren 0f874ab0f9 Update header comments
Gitea - aviat/banker/pipeline/head This commit looks good Details
2021-02-19 11:47:20 -05:00
Timothy Warren 18e61abd37 Add appropriate parameter types for updated psr/cache interface
Gitea - aviat/banker/pipeline/head This commit looks good Details
2021-02-18 19:23:20 -05:00
Timothy Warren 94f40e6cd0 Add PHPStan checks to CI
Gitea - aviat/banker/pipeline/head This commit looks good Details
2021-02-18 13:27:07 -05:00
Timothy Warren d30f20c6aa Update Changelog
Gitea - aviat/banker/pipeline/head This commit looks good Details
2021-02-05 17:06:15 -05:00
Timothy Warren cc77d69538 Update header comments 2021-02-05 17:05:56 -05:00
Timothy Warren adb40903ae Fix Code coverage collection?
Gitea - aviat/banker/pipeline/head This commit looks good Details
2021-02-05 16:52:40 -05:00
Timothy Warren dec0eaebe8 Don't checkout code twice for CI
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-02-05 16:42:12 -05:00
Timothy Warren ca37e716fd Attempt to log unit test output
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-02-05 16:40:15 -05:00
Timothy Warren 354912a6c9 Attempt to run CI in stages
Gitea - aviat/banker/pipeline/head This commit looks good Details
2021-02-05 16:29:27 -05:00
Timothy Warren 1fe72c7212 Attempt to run CI in stages
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-02-05 16:12:53 -05:00
Timothy Warren 1a4553cb4c Attempt to run CI in stages
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-02-05 16:06:54 -05:00
Timothy Warren ebef8075b8 Attempt to run CI in stages
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-02-05 16:03:15 -05:00
Timothy Warren f7a754ef56 Attempt to fix build
Gitea - aviat/banker/pipeline/head This commit looks good Details
2021-02-05 15:42:20 -05:00
Timothy Warren b87a92296d Attempt to fix build
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-02-05 15:31:59 -05:00
Timothy Warren 2cd44f4645 Attempt to fix build
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-02-05 15:23:49 -05:00
Timothy Warren cc3f555d41 Attempt to fix build
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-02-05 15:22:34 -05:00
Timothy Warren 52c125d249 Attempt to fix build
Gitea - aviat/banker/pipeline/head Something is wrong with the build of this commit Details
2021-02-05 15:05:07 -05:00
Timothy Warren 2f75279113 Attempt to fix build
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-02-05 15:03:19 -05:00
Timothy Warren 44ace2d143 Attempt to fix tests
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-02-05 14:58:26 -05:00
Timothy Warren afac369573 Attempt to fix tests
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-02-05 14:57:22 -05:00
Timothy Warren fb08e5c787 Attempt to fix tests
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-02-05 13:54:59 -05:00
Timothy Warren 7379170ca8 Attempt to fix tests
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-02-05 13:47:37 -05:00
Timothy Warren 3215c392aa Improve validation of cache keys and update dependencies
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2021-02-05 13:26:01 -05:00
Timothy Warren 624e0efd97 Fix provide key of composer.json
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2020-10-22 09:56:29 -04:00
Timothy Warren c4e4ce938e More tests and fixes
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2020-05-08 18:58:25 -04:00
Timothy Warren 7c121934a2 Fix bug with handling of optional expirations, use driver to get multiple items if possible
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2020-05-08 15:53:47 -04:00
Timothy Warren fa0fb9ce1c Update header comments
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2020-05-08 12:30:43 -04:00
Timothy Warren dc53bf5ccc Refactor shared implementation methods into a trait, check keys in pool
Gitea - aviat/banker/pipeline/head There was a failure building this commit Details
2020-05-08 10:54:09 -04:00
68 changed files with 732 additions and 4132 deletions

3
.gitignore vendored
View File

@ -26,4 +26,5 @@ app/config/*.toml
phinx.yml
.idea/
Caddyfile
build/humbuglog.txt
build/humbuglog.txt
tools/phpdocumentor

4
.phive/phars.xml Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
<phar name="phpdocumentor" version="^3.3.1" installed="3.3.1" location="./tools/phpdocumentor" copy="false"/>
</phive>

View File

@ -1,5 +1,20 @@
# Changelog
## 4.1.0
* Updates for PHP 8.2 compatibility
## 4.0.0
* Updated interfaces to match newer PSR interfaces
* Updates for PHP 8.1 compatibility
* Increased required PHP version to 8
## 3.2.0
* Improved validation of cache keys
* Updated dependencies
## 3.1.0
* Added key name checks to `Pool` class
## 3.0.0
* Updated dependencies
* Increased required PHP version to 7.4

88
Jenkinsfile vendored
View File

@ -1,15 +1,81 @@
node {
checkout scm
docker.image('memcached:latest').withRun('-p 11211:11211') { c ->
docker.image('redis:latest').withRun('-p 6379:6379') { d ->
docker.image('php:7.2') {
steps {
sh 'sh build/docker_install.sh > /dev/null'
sh 'curl -sS https://getcomposer.org/installer | php'
sh 'php composer.phar install --ignore-platform-reqs'
sh 'phpdbg -qrr -- ./vendor/bin/phpunit --coverage-text --colors=never'
pipeline {
agent any
stages {
stage("Setup") {
steps {
sh 'curl -sS https://getcomposer.org/installer | php'
sh 'rm -rf ./vendor'
sh 'rm -f composer.lock'
sh 'phive --no-progress install --trust-gpg-keys 67F861C3D889C656'
sh 'php composer.phar install --ignore-platform-reqs'
}
}
stage("Test PHP 8") {
steps {
script {
docker.image("memcached:latest").withRun("-p 11212:11211") { c ->
docker.image("redis:latest").withRun("-p 6380:6379") { d ->
docker.image("php:8").withRun("-e REDIS_HOST=redis -e REDIS_PORT=11212 -e MEMCACHED_HOST=mem -e MEMCACHED_PORT=6380 --link ${d.id}:redis --link ${c.id}:mem") { p ->
sh "sh build/docker_install.sh"
sh "php ./vendor/bin/phpunit -c build --no-coverage --colors=never"
}
}
}
}
}
}
stage("Test PHP 8.1") {
steps {
script {
docker.image("memcached:latest").withRun("-p 11212:11211") { c ->
docker.image("redis:latest").withRun("-p 6380:6379") { d ->
docker.image("php:8.1").withRun("-e REDIS_HOST=redis -e REDIS_PORT=11212 -e MEMCACHED_HOST=mem -e MEMCACHED_PORT=6380 --link ${d.id}:redis --link ${c.id}:mem") { p ->
sh "sh build/docker_install.sh"
sh "php ./vendor/bin/phpunit -c build --no-coverage --colors=never"
}
}
}
}
}
}
stage("Test PHP 8.2") {
steps {
script {
docker.image("memcached:latest").withRun("-p 11212:11211") { c ->
docker.image("redis:latest").withRun("-p 6380:6379") { d ->
docker.image("php:8.2").withRun("-e REDIS_HOST=redis -e REDIS_PORT=11212 -e MEMCACHED_HOST=mem -e MEMCACHED_PORT=6380 --link ${d.id}:redis --link ${c.id}:mem") { p ->
sh "sh build/docker_install.sh"
sh "php ./vendor/bin/phpunit -c build --no-coverage --colors=never"
}
}
}
}
}
}
stage('Code Cleanliness') {
agent any
steps {
sh 'cd tools && composer install --ignore-platform-reqs && cd ..'
sh 'mkdir -p build/logs'
sh 'mkdir -p build/tmp'
sh 'touch build/logs/phpstan.log'
/* sh 'composer run-script ci:phpstan' */
recordIssues(
failOnError: false,
tools: [phpStan(reportEncoding: 'UTF-8', pattern: 'build/logs/phpstan.log')]
)
}
}
}
}
post {
success {
sh 'php composer.phar run-script coverage'
step([
$class: 'CloverPublisher',
cloverReportDir: '',
cloverReportFileName: 'build/logs/clover.xml',
])
junit 'build/logs/junit.xml'
}
}
}

View File

@ -1,327 +0,0 @@
<?php declare(strict_types=1);
if ( ! function_exists('glob_recursive'))
{
// Does not support flag GLOB_BRACE
function glob_recursive($pattern, $flags = 0)
{
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir)
{
$files = array_merge($files, glob_recursive($dir.'/'.basename($pattern), $flags));
}
return $files;
}
}
/**
* This is project's console commands configuration for Robo task runner.
*
* @see http://robo.li/
*/
class RoboFile extends \Robo\Tasks {
/**
* Directories used by analysis tools
*
* @var array
*/
protected $taskDirs = [
'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
*/
public function analyze(): void
{
$this->prepare();
$this->lint();
$this->phploc(TRUE);
$this->phpcs(TRUE);
$this->dependencyReport();
$this->phpcpdReport();
}
/**
* Run all tests, generate coverage, generate docs, generate code statistics
*/
public function build(): void
{
$this->analyze();
$this->coverage();
$this->docs();
}
/**
* Cleanup temporary files
*/
public function clean(): void
{
$cleanFiles = [
'build/humbug.json',
'build/humbug-log.txt',
];
array_map(static function ($file) {
@unlink($file);
}, $cleanFiles);
// So the task doesn't complain,
// make any 'missing' dirs to cleanup
array_map(static function ($dir) {
if ( ! is_dir($dir))
{
shell_exec("mkdir -p {$dir}");
}
}, $this->cleanDirs);
$this->_cleanDir($this->cleanDirs);
$this->_deleteDir($this->cleanDirs);
}
/**
* Run unit tests and generate coverage reports
*/
public function coverage(): void
{
$this->_run(['phpdbg -qrr -- vendor/bin/phpunit -c build']);
}
/**
* Generate documentation with phpdox
*/
public function docs(): void
{
$cmd_parts = [
'cd build',
'../vendor/bin/phpdox',
'cd ..'
];
$this->_run($cmd_parts, ' && ');
}
/**
* Verify that source files are valid
*/
public function lint(): void
{
$files = $this->getAllSourceFiles();
$chunks = array_chunk($files, 6);
foreach($chunks as $chunk)
{
$this->parallelLint($chunk);
}
}
/**
* Run mutation tests with humbug
*
* @param bool $stats - if true, generates stats rather than running mutation tests
*/
public function mutate($stats = FALSE): void
{
$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 phpcs tool
*
* @param bool $report - if true, generates reports instead of direct output
*/
public function phpcs($report = FALSE): void
{
$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
*
* @param bool $report - if true, generates reports instead of direct output
*/
public function phploc($report = FALSE): void
{
// 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',
'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(): void
{
array_map([$this, '_mkdir'], $this->taskDirs);
}
/**
* Lint php files and run unit tests
*/
public function test(): void
{
$this->lint();
$this->taskPHPUnit()
->configFile('phpunit.xml')
->printed(true)
->run();
}
/**
* Watches for file updates, and automatically runs appropriate actions
*/
public function watch(): void
{
$this->taskWatch()
->monitor('composer.json', function() {
$this->taskComposerUpdate()->run();
})
->monitor('src', function () {
$this->taskExec('test')->run();
})
->monitor('tests', function () {
$this->taskExec('test')->run();
})
->run();
}
/**
* Create pdepend reports
*/
protected function dependencyReport(): void
{
$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(): array
{
$files = array_unique(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 array $chunk
*/
protected function parallelLint(array $chunk): void
{
$task = $this->taskParallelExec()
->timeout(5)
->printed(FALSE);
foreach($chunk as $file)
{
$task = $task->process("php -l {$file}");
}
$task->run();
}
/**
* Generate copy paste detector report
*/
protected function phpcpdReport(): void
{
$cmd_parts = [
'vendor/bin/phpcpd',
'--log-pmd build/logs/pmd-cpd.xml',
'src'
];
$this->_run($cmd_parts);
}
/**
* Shortcut 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 = ' '): void
{
$this->taskExec(implode($join_on, $cmd_parts))->run();
}
}

View File

@ -1,28 +0,0 @@
<documentation title="Closing comments instead of PHP closing tag">
<standard>
<![CDATA[
The PHP closing tag on a PHP document ?> 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.
]]>
</standard>
<code_comparison>
<code title="Examples of valid closing comments">
<![CDATA[
<?php
echo "Here's my code!";
/* End of file myfile.php */
/* Location: ./system/modules/mymodule/myfile.php */
]]>
</code>
<code title="Examples of invalid closing comments">
<![CDATA[
<?php
echo "Here's my code!";
?>
]]>
</code>
</code_comparison>
</documentation>

View File

@ -1,7 +0,0 @@
<documentation title="Unicode (UTF-8) encoding without BOM">
<standard>
<![CDATA[
Files should be saved with Unicode (UTF-8) encoding. The BOM should not be used. Unlike UTF-16 and UTF-32, there's no byte order to indicate in a UTF-8 encoded file, and the BOM can have a negative side effect in PHP of sending output, preventing the application from being able to set its own headers. Unix line endings should be used (LF).
]]>
</standard>
</documentation>

View File

@ -1,31 +0,0 @@
<documentation title="Constructor Names">
<standard>
<![CDATA[
Class names should always start with an uppercase letter. Multiple words should be separated with an underscore, and not CamelCased. All other class methods should be entirely lowercased and named to clearly indicate their function, preferably including a verb. Try to avoid overly long and verbose names.
]]>
</standard>
<code_comparison>
<code title="Examples of valid constructor name">
<![CDATA[
class Super_class
{
function Super_class()
{
echo 'Some code here !';
}
}
]]>
</code>
<code title="Examples of invalid constructor name">
<![CDATA[
class Super_class
{
function __constructor()
{
echo 'Some code here !';
}
}
]]>
</code>
</code_comparison>
</documentation>

View File

@ -1,21 +0,0 @@
<documentation title="Class names">
<standard>
<![CDATA[
Class names should always start with an uppercase letter. Multiple words should be separated with an underscore, and not CamelCased. All other class methods should be entirely lowercased and named to clearly indicate their function, preferably including a verb. Try to avoid overly long and verbose names.
]]>
</standard>
<code_comparison>
<code title="Examples of valid class names">
<![CDATA[
class Super_class
]]>
</code>
<code title="Examples of invalid class names">
<![CDATA[
class SuperClass // words not separated with underscores and words next to the first one start with an upper case
class superclass // words not separated with underscores
class Super_Class // words next to the first one start with an upper case
]]>
</code>
</code_comparison>
</documentation>

View File

@ -1,21 +0,0 @@
<documentation title="File names">
<standard>
<![CDATA[
To be able to find which class is contained in a file, file names should be case-insensitively equal to class names. Some operating systems and tools are case-insensitive, though other are. So, file names should be in lower case to avoid any trouble.
]]>
</standard>
<code_comparison>
<code title="Examples of valid file names">
<![CDATA[
super_class.php
]]>
</code>
<code title="Examples of invalid file names">
<![CDATA[
superclass.php // words not separated with underscores
SuperClass.php // not in lower case and words not separated with underscores
Super_class.php // not in lower case
]]>
</code>
</code_comparison>
</documentation>

View File

@ -1,27 +0,0 @@
<documentation title="Function and Method Names">
<standard>
<![CDATA[
Class names should always start with an uppercase letter. Multiple words should be separated with an underscore, and not CamelCased. All other class methods should be entirely lowercased and named to clearly indicate their function, preferably including a verb. Try to avoid overly long and verbose names.
Methods and variables that are only accessed internally by your class, such as utility and helper functions that your public methods use for code abstraction, should be prefixed with an underscore.
]]>
</standard>
<code_comparison>
<code title="Examples of valid method names">
<![CDATA[
function get_file_properties() // descriptive, underscore separator, and all lowercase letters
private function _get_file_properties()
]]>
</code>
<code title="Examples of invalid method names">
<![CDATA[
function fileproperties() // not descriptive and needs underscore separator
function fileProperties() // not descriptive and uses CamelCase
function getfileproperties() // Better! But still missing underscore separator
function getFileProperties() // uses CamelCase
function get_the_file_properties_from_the_file() // wordy
private function get_the_file_properties() // not prefixed with an underscor, though private
function _get_the_file_properties() // prefixed with an underscor, though public
]]>
</code>
</code_comparison>
</documentation>

View File

@ -1,31 +0,0 @@
<documentation title="Variable names">
<standard>
<![CDATA[
Namely, variables should contain only lowercase letters, use underscore separators, and be reasonably named to indicate their purpose and contents. Very short, non-word variables should only be used as iterators in for() loops.
Methods and variables that are only accessed internally by your class, such as utility and helper functions that your public methods use for code abstraction, should be prefixed with an underscore.
]]>
</standard>
<code_comparison>
<code title="Examples of valid variable names">
<![CDATA[
for ($j = 0; $j < 10; $j++)
$str
$buffer
$group_id
$last_city
private $_internal_data;
]]>
</code>
<code title="Examples of invalid variable names">
<![CDATA[
$j = 'foo'; // single letter variables should only be used in for() loops
$Str // contains uppercase letters
$bufferedText // uses CamelCasing, and could be shortened without losing semantic meaning
$groupid // multiple words, needs underscore separator
$name_of_last_city_used // too long
private $internal_data; // not prefixed with an underscor, though private
$_public_attribute; // prefixed with an underscor, though public
]]>
</code>
</code_comparison>
</documentation>

View File

@ -1,40 +0,0 @@
<documentation title="Strict comparison operators">
<standard>
<![CDATA[
Some PHP functions return FALSE on failure, but may also have a valid return value of "" or 0, which would evaluate to FALSE in loose comparisons. Be explicit by comparing the variable type when using these return values in conditionals to ensure the return value is indeed what you expect, and not a value that has an equivalent loose-type evaluation.
Use the same stringency in returning and checking your own variables. Use === and !== as necessary.
]]>
</standard>
<code_comparison>
<code title="Valid strict comparison">
<![CDATA[
if (strpos($str, 'foo') === FALSE) {
echo 'Do something.';
}
function build_string($str = "")
{
if ($str === "") {
echo 'Buid string.';
}
}
]]>
</code>
<code title="Invalid loose comparison">
<![CDATA[
// If 'foo' is at the beginning of the string, strpos will return a 0,
// resulting in this conditional evaluating as TRUE
if (strpos($str, 'foo') == FALSE) {
echo 'Do something.';
}
function build_string($str = "")
{
if ($str == "") { // uh-oh! What if FALSE or the integer 0 is passed as an argument?
echo 'Buid string.';
}
}
]]>
</code>
</code_comparison>
</documentation>

View File

@ -1,28 +0,0 @@
<documentation title="Double-quoted strings">
<standard>
<![CDATA[
Always use single quoted strings unless you need variables parsed, and in cases where you do need variables parsed, use braces to prevent greedy token parsing. You may also use double-quoted strings if the string contains single quotes, so you do not have to use escape characters.
]]>
</standard>
<code_comparison>
<code title="Examples of invalid double-quoted strings">
<![CDATA[
"My String" // no variable parsing, so no use for double quotes
"My string $foo" // needs braces
'SELECT foo FROM bar WHERE baz = \'bag\'' // ugly
'\r\n' // it isn't wrong, but it won't be interpreted as a new line feed
]]>
</code>
<code title="Examples of valid double-quoted strings">
<![CDATA[
'My String'
"My string {$foo}" // variables in strings may be enclosed with braces in 2 ways
"My string ${foo}"
"My string {$foo['bar']}" // variables in strings may be an array entry
"My string {$foo->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
]]>
</code>
</code_comparison>
</documentation>

View File

@ -1,187 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Commenting_InlineCommentSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @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 <thomas.ernest@baobaz.com>
* @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
?>

View File

@ -1,98 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Files_ByteOrderMarkSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @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 <thomas.ernest@baobaz.com>
* @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()
}

View File

@ -1,222 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Files_Utf8EncodingSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @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 <thomas.ernest@baobaz.com>
* @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
?>

View File

@ -1,81 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Operators_LogicalOperatorAndSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @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 <thomas.ernest@baobaz.com>
* @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, 'LowercaseLogicalOperator');
}
$warning_message = 'The symbolic form "&&" is preferred over the literal form "AND"';
$phpcsFile->addWarning($warning_message, $stackPtr, 'UseOfLiteralAndOperator');
}//end process()
}//end class
?>

View File

@ -1,81 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Operators_StrictComparisonOperatorSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @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 <thomas.ernest@baobaz.com>
* @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, 'NonStrictComparisonUsed');
}//end process()
}//end class
?>

View File

@ -1,84 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Operators_UppercaseLogicalOperatorOrSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @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 <thomas.ernest@baobaz.com>
* @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
?>

View File

@ -1,464 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Strings_DoubleQuoteUsageSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @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 <thomas.ernest@baobaz.com>
* @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('<?php '.$dblQtString);
$strPtr = 1; // skip php opening tag added by ourselves
$requireDblQuotes = FALSE;
while ($strPtr < count($strTokens)) {
$strToken = $strTokens[$strPtr];
if (is_array($strToken)) {
if (in_array($strToken[0], array(T_DOLLAR_OPEN_CURLY_BRACES, T_CURLY_OPEN))) {
$strPtr++;
try {
$this->_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('<?php '.$sglQtString);
$strPtr = 1; // skip php opening tag added by ourselves
while ($strPtr < count($strTokens)) {
$strToken = $strTokens[$strPtr];
if (is_array($strToken)) {
if (T_VARIABLE === $strToken[0]) {
$error = "Variables like {$strToken[1]} should be in double-quoted strings only.";
$phpcsFile->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 ::= <variable>
* | <variable>_parseObjectAttribute()
* | <variable>_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 ::= -><attribute>
* | -><attribute>_parseObjectAttribute()
* | -><attribute>_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 ::= [<index>]
*
* @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 <thomas.ernest@baobaz.com>
* @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
?>

View File

@ -1,87 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_WhiteSpace_DisallowSpaceIndentSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@gmail.com>
* @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 <thomas.ernest@gmail.com>
* @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, 'SpacesUsedForIndentation');
}
}//end process()
}//end class
?>

View File

@ -1,95 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_WhiteSpace_DisallowWitheSpaceAroundPhpTagsSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @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 <thomas.ernest@baobaz.com>
* @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
?>

View File

@ -1,82 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_WhiteSpace_ElseOnNewLineSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @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 <thomas.ernest@baobaz.com>
* @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
?>

View File

@ -1,75 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_WhiteSpace_LogicalNotSpacingSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @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 <thomas.ernest@baobaz.com>
* @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
?>

View File

@ -1,104 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Files_AbstractClosingCommentSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @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 <thomas.ernest@baobaz.com>
* @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
?>

View File

@ -1,109 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Files_ClosingFileCommentSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @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 <file_name>". Comparison between content and template is
* case-sensitive.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @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
?>

View File

@ -1,182 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Files_ClosingLocationCommentSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @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: <file_path_relative_to_application_root>".
* 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 <thomas.ernest@baobaz.com>
* @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
?>

View File

@ -1,142 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_NamingConventions_ConstructorNameSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@gmail.com>
* @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 <thomas.ernest@gmail.com>
* @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
?>

View File

@ -1,84 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_NamingConventions_ValidClassNameSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baoabz.com>
* @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 <thomas.ernest@baoabz.com>
* @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
?>

View File

@ -1,84 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_NamingConventions_ValidFileNameSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @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 <thomas.ernest@baobaz.com>
* @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
?>

View File

@ -1,161 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_NamingConventions_ValidMethodNameSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baoabz.com>
* @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 <thomas.ernest@baoabz.com>
* @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
?>

View File

@ -1,562 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_NamingConventions_ValidVariableNameSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baoabz.com>
* @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 <thomas.ernest@baoabz.com>
* @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 (<loop_head>) {<loop_body>}.
*
* @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 (<loop_head>) {<loop_body>}.
*
* @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
?>

View File

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ruleset name="CodeIgniter">
<description>CodeIgniter coding standard as described at http://codeigniter.com/user_guide/general/styleguide.html.</description>
<rule ref="Generic.Files.LineEndings">
<properties>
<property name="eolChar" value="\n"/>
</properties>
</rule>
<!-- PHP files should OMIT the closing PHP tag -->
<rule ref="Zend.Files.ClosingTag"/>
<!-- Always use full PHP opening tags -->
<rule ref="Generic.PHP.DisallowShortOpenTag"/>
<!-- Constants should always be fully uppercase -->
<rule ref="Generic.NamingConventions.UpperCaseConstantName"/>
<!-- TRUE, FALSE, and NULL keywords should always be fully uppercase -->
<rule ref="Generic.PHP.UpperCaseConstant"/>
<!-- One statement per line -->
<rule ref="Generic.Formatting.DisallowMultipleStatements"/>
<!-- Classes and functions should be commented -->
<rule ref="PEAR.Commenting.ClassComment"/>
<rule ref="PEAR.Commenting.FunctionComment"/>
<rule ref="Squiz.Commenting.FunctionCommentThrowTag"/>
<!-- Use warnings for docblock comments for files and variables, since nothing is cleary explained -->
<rule ref="PEAR.Commenting.FileComment">
<properties>
<property name="error" value="false"/>
</properties>
</rule>
<rule ref="Squiz.Commenting.VariableComment">
<properties>
<property name="error" value="false"/>
</properties>
</rule>
<!-- Use Allman style indenting. With the exception of Class declarations,
braces are always placed on a line by themselves, and indented at the same level as the control statement that "owns" them. -->
<rule ref="Generic.Functions.OpeningFunctionBraceBsdAllman"/>
<rule ref="PEAR.WhiteSpace.ScopeClosingBrace"/>
<rule ref="Generic.Functions.FunctionCallArgumentSpacing"/>
<!-- @todo Please see PHP_CodeSniffer_Standards_CodeIgniter_CodeIgniterCodingStandard for more details about what there is to do -->
</ruleset>

View File

@ -5,12 +5,6 @@
set -xe
# Install git (the php image doesn't have it) which is required by composer
#echo -e 'http://dl-cdn.alpinelinux.org/alpine/edge/main\nhttp://dl-cdn.alpinelinux.org/alpine/edge/community\nhttp://dl-cdn.alpinelinux.org/alpine/edge/testing' > /etc/apk/repositories
#apk upgrade --update --no-cache \
# curl \
# git
apt-get update && apt-get install -y \
libz-dev \
libmemcached-dev \
@ -20,4 +14,5 @@ apt-get update && apt-get install -y \
docker-php-ext-install zip
pecl install apcu
pecl install memcached
docker-php-ext-enable apcu memcached
pecl install pcov
docker-php-ext-enable apcu memcached pcov

View File

@ -3,12 +3,12 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/

View File

@ -1,128 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- This is a skeleton phpDox config file - Check http://phpDox.de for latest version and more info -->
<phpdox xmlns="http://xml.phpdox.net/config" silent="false">
<!-- @silent: true | false to enable or disable visual output of progress -->
<!-- Additional bootstrap files to load for additional parsers, enrichers and/or engines -->
<!-- Place as many require nodes as you feel like in this container -->
<!-- syntax: <require file="/path/to/file.php" /> -->
<bootstrap />
<!-- A phpDox project to process, you can have multiple projects in one config file -->
<project name="Cache" source="../src" workdir="phpdox/xml">
<!-- @name - The name of the project -->
<!-- @source - The source directory of the application to process -->
<!-- @workdir - The directory to store the xml data files in -->
<!-- A phpDox config file can define additional variables (properties) per project -->
<!-- <property name="some.name" value="the.value" /> -->
<!-- Values can make use of previously defined properties -->
<!-- The following are defined by default:
${basedir} Directory the loaded config file is in
${phpDox.home} Directory of the phpDox installation
${phpDox.file} The current config file
${phpDox.version} phpDox' version number
${phpDox.project.name} The value of project/@name if set, otherwise 'unnamed'
${phpDox.project.source} The value of project/@source if set, otherwise '${basedir}/src'
${phpDox.project.workdir} The value of project/@workdir if set, otherwise '${basedir}/build/phpdox/xml'
${phpDox.php.version} The PHP Version of the interpreter in use
-->
<!-- Additional configuration for the collecting process (parsing of php code, generation of xml data) -->
<collector publiconly="false" backend="parser" encoding="auto">
<!-- @publiconly - Flag to disable/enable processing of non public methods and members -->
<!-- @backend - The collector backend to use, currently only shipping with 'parser' -->
<!-- @encoding - Charset encoding of source files (overwrite default 'auto' if detection fails) -->
<!-- <include / exclude filter for filelist generator, mask must follow fnmatch() requirements -->
<include mask="*.php" />
<exclude mask="" />
<!-- How to handle inheritance -->
<inheritance resolve="true">
<!-- @resolve - Flag to enable/disable resolving of inheritance -->
<!-- You can define multiple (external) dependencies to be included -->
<!-- <dependency path="" -->
<!-- @path - path to a directory containing an index.xml for a dependency project -->
</inheritance>
</collector>
<!-- Configuration of generation process -->
<generator output="../docs">
<!-- @output - (Base-)Directory to store output data in -->
<!-- A generation process consists of one or more build tasks and of (optional) enrich sources -->
<enrich base="logs">
<!-- @base - (Base-)Directory of datafiles used for enrich process -->
<!--<source type="...">-->
<!-- @type - the handler for the enrichment -->
<!-- known types by default are: build, checkstyle, git, phpcs, phploc, phpunit, pmd -->
<!-- every enrichment source can have additional configuration nodes, most probably need a logfile -->
<!-- <file name="path/to/log.xml" /> -->
<!--</source> -->
<!-- add phploc output -->
<source type="phploc">
<file name="phploc.xml" />
</source>
<!-- git vcs information -->
<source type="git">
<git binary="/usr/bin/git" />
<history enabled="true" limit="15" cache="${phpDox.project.workdir}/gitlog.xml" />
</source>
<!-- PHP Code Sniffer findings -->
<source type="checkstyle">
<file name="phpcs.xml" />
</source>
<!-- PHPMessDetector -->
<!--
<source type="pmd">
<file name="pmd.xml" />
</source>
-->
<!-- PHPUnit Coverage XML -->
<source type="phpunit">
<coverage path="coverage/clover.xml" />
<!-- <coverage path="clover.xml" />-->
<!-- @path - the directory where the xml code coverage report can be found -->
<!--<filter directory="${phpDox.project.source}" />-->
<!-- @directory - path of the phpunit config whitelist filter directory -->
</source>
<source type="phpunit">
<filter directory="${phpDox.project.source}" />
</source>
</enrich>
<!-- <build engine="..." enabled="true" output="..." /> -->
<!-- @engine - The name of the engine this build task uses, use ./phpDox - -engines to get a list of available engines -->
<!-- @enabled - Flag to enable/disable this engine, default: enabled=true -->
<!-- @output - (optional) Output directory; if relative (no / as first char) it is interpreted as relative to generator/@output -->
<!-- An engine and thus build node can have additional configuration child nodes, please check the documentation for the engine to find out more -->
<!-- default engine "html" -->
<build engine="html" enabled="true">
<template dir="${phpDox.home}/templates/html" />
<file extension="html" />
</build>
</generator>
</project>
</phpdox>

View File

@ -1,25 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
colors="true"
stopOnFailure="false"
bootstrap="../tests/bootstrap.php"
beStrictAboutTestsThatDoNotTestAnything="true"
>
<filter>
<whitelist>
<directory suffix=".php">../src</directory>
</whitelist>
</filter>
<testsuites>
<testsuite name="Cache">
<directory>../tests</directory>
</testsuite>
</testsuites>
<logging>
<log type="coverage-html" target="../coverage"/>
<log type="coverage-clover" target="logs/clover.xml"/>
<log type="coverage-crap4j" target="logs/crap4j.xml"/>
<log type="coverage-xml" target="logs/coverage" />
<log type="junit" target="logs/junit.xml" />
</logging>
</phpunit>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" colors="true" stopOnFailure="false" bootstrap="../tests/bootstrap.php" beStrictAboutTestsThatDoNotTestAnything="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage>
<include>
<directory suffix=".php">../src</directory>
</include>
<report>
<clover outputFile="logs/clover.xml"/>
<crap4j outputFile="logs/crap4j.xml"/>
<html outputDirectory="../coverage"/>
<xml outputDirectory="logs/coverage"/>
</report>
</coverage>
<testsuites>
<testsuite name="Cache">
<directory>../tests</directory>
</testsuite>
</testsuites>
<logging>
<junit outputFile="logs/junit.xml"/>
</logging>
</phpunit>

View File

@ -12,8 +12,8 @@
"psr-16"
],
"provide": {
"psr/cache": "1.0.1",
"psr/simple-cache": "1.0.1"
"psr/cache-implementation": "^3.0.0",
"psr/simple-cache-implementation": "^3.0.0"
},
"autoload": {
"psr-4": {
@ -26,26 +26,18 @@
}
},
"require": {
"php": ">=7.4",
"php": ">= 8",
"ext-json": "*",
"predis/predis": "^1.1",
"psr/log": "^1.0",
"psr/cache": "^1.0.1",
"psr/simple-cache": "^1.0.1"
"predis/predis": "^v2.1.2",
"psr/log": "^1.1.0 || ^3.0.0",
"psr/cache": "^3.0.0",
"psr/simple-cache": "^3.0.0"
},
"require-dev": {
"ext-apcu": "*",
"ext-memcached": "*",
"consolidation/robo": "^2.0.0",
"monolog/monolog": "^2.0.1",
"pdepend/pdepend": "^2.2",
"phploc/phploc": "^5.0",
"phpmd/phpmd": "^2.4",
"phpunit/phpunit": "^8.5.0",
"sebastian/phpcpd": "^4.1",
"squizlabs/php_codesniffer": "^3.3.2",
"theseer/phpdox": "^0.12.0",
"phpstan/phpstan": "^0.12.2"
"monolog/monolog": "^3.3.1",
"phpunit/phpunit": "^10.0.16"
},
"suggest": {
"monolog/monolog": "A good standard logging library",
@ -62,7 +54,9 @@
],
"scripts": {
"test": "vendor/bin/phpunit -c build --no-coverage",
"coverage": "phpdbg -qrr -- vendor/bin/phpunit -c build",
"phpstan": "vendor/bin/phpstan analyse src tests"
"docs": "tools/phpdocumentor run --sourcecode",
"coverage": "php -dpcov.enabled=1 -dpcov.directory=. -dpcov.exclude=\"~vendor~\" ./vendor/bin/phpunit -c build",
"phpstan": "tools/vendor/bin/phpstan analyse src tests",
"ci:phpstan": "tools/vendor/bin/phpstan analyse -c phpstan.neon -n --no-progress --no-ansi --error-format=checkstyle > build/logs/phpstan.log"
}
}

View File

@ -1,15 +1,29 @@
<?xml version="1.0" encoding="UTF-8" ?>
<phpdoc>
<parser>
<target>build/phpdoc</target>
</parser>
<transformer>
<target>phpdoc</target>
</transformer>
<transformations>
<template name="zend" />
</transformations>
<files>
<directory>src</directory>
</files>
</phpdoc>
<phpdocumentor
configVersion="3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://www.phpdoc.org"
xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/phpDocumentor/phpDocumentor/master/data/xsd/phpdoc.xsd"
>
<paths>
<output>docs</output>
<cache>build/cache</cache>
</paths>
<version number="4.0.0">
<api>
<source dsn=".">
<path>src</path>
</source>
<markers>
<marker>TODO</marker>
<marker>FIXME</marker>
</markers>
<default-package-name>Banker</default-package-name>
<visibility>public</visibility>
<include-source>true</include-source>
</api>
</version>
<!-- <template name="clean" /> -->
<setting name="graphs.enabled" value="true"/>
<setting name="guides.enabled" value="true"/>
</phpdocumentor>

12
phpstan.neon Normal file
View File

@ -0,0 +1,12 @@
parameters:
checkMissingIterableValueType: false
level: 9
paths:
- src
excludePaths:
- tests
- vendor
tmpDir: build/tmp
# These are objects that basically can return anything
universalObjectCratesClasses:
- Aviat\Ion\Friend

View File

@ -4,18 +4,20 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Driver;
use Aviat\Banker\LoggerTrait;
use Aviat\Banker\KeyValidateTrait;
use DateInterval;
use Psr\Log\LoggerAwareInterface;
/**
@ -23,6 +25,7 @@ use Psr\Log\LoggerAwareInterface;
*/
abstract class AbstractDriver implements DriverInterface, LoggerAwareInterface {
use KeyValidateTrait;
use LoggerTrait;
/**
@ -34,11 +37,8 @@ abstract class AbstractDriver implements DriverInterface, LoggerAwareInterface {
/**
* Common constructor interface for driver classes
*
* @param array $config - Connection parameters for the specified backend
* @param array $options - Special connection options for the specified backend
*/
abstract public function __construct(array $config = [], array $options = []);
abstract public function __construct();
/**
* Retrieve a set of values by their cache key
@ -48,6 +48,8 @@ abstract class AbstractDriver implements DriverInterface, LoggerAwareInterface {
*/
public function getMultiple(array $keys = []): array
{
$this->validateKeys($keys);
$output = [];
foreach ($keys as $key)
@ -60,4 +62,27 @@ abstract class AbstractDriver implements DriverInterface, LoggerAwareInterface {
return $output;
}
/**
* Set multiple cache values
*
* @param array $items
* @param DateInterval|int|null $expires
* @return bool
*/
public function setMultiple(array $items, DateInterval|int|null $expires = NULL): bool
{
$this->validateKeys($items, TRUE);
$setResults = [];
foreach ($items as $k => $v)
{
$setResults[] = ($expires === NULL)
? $this->set($k, $v)
: $this->set($k, $v, $expires);
}
// Only return true if all the results are true
return array_reduce($setResults, fn ($carry, $item) => $item && $carry, TRUE);
}
}

View File

@ -4,19 +4,20 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Driver;
use Aviat\Banker\Exception\CacheException;
use DateInterval;
use function apcu_clear_cache;
use function apcu_delete;
use function apcu_exists;
@ -31,12 +32,10 @@ class ApcuDriver extends AbstractDriver {
/**
* Constructor
*
* @param array $config - Not used by this driver
* @param array $options - Not used by this driver
* @throws CacheException
* @codeCoverageIgnore
*/
public function __construct(array $config = [], array $options = [])
public function __construct()
{
if ( ! extension_loaded('apcu'))
{
@ -61,7 +60,7 @@ class ApcuDriver extends AbstractDriver {
* @param string $key
* @return mixed
*/
public function get(string $key)
public function get(string $key): mixed
{
return apcu_fetch($key);
}
@ -74,8 +73,10 @@ class ApcuDriver extends AbstractDriver {
*/
public function getMultiple(array $keys = []): array
{
$this->validateKeys($keys);
$status = FALSE;
return apcu_fetch($keys, $status);
return (array)apcu_fetch($keys, $status);
}
/**
@ -83,16 +84,34 @@ class ApcuDriver extends AbstractDriver {
*
* @param string $key
* @param mixed $value
* @param int $expires
* @param int|DateInterval|null $expires
* @return bool
*/
public function set(string $key, $value, ?int $expires = 0): bool
public function set(string $key, mixed $value, int|DateInterval|null $expires = NULL): bool
{
$ttl = $this->getTTLFromExpiration($expires);
return apcu_store($key, $value, $ttl);
}
/**
* Set multiple cache values
*
* @param array $items
* @param DateInterval|int|null $expires
* @return bool
*/
public function setMultiple(array $items, DateInterval|int|null $expires = NULL): bool
{
$this->validateKeys($items, TRUE);
$errorKeys = ($expires === NULL)
? apcu_store($items)
: apcu_store($items, NULL, $this->getTTLFromExpiration($expires));
return empty($errorKeys);
}
/**
* Remove an item from the cache
*
@ -112,8 +131,10 @@ class ApcuDriver extends AbstractDriver {
*/
public function deleteMultiple(array $keys = []): bool
{
$deleted = apcu_delete($keys);
return ($keys <=> $deleted) === 0;
$this->validateKeys($keys);
$failedToDelete = apcu_delete($keys);
return empty($failedToDelete);
}
/**
@ -150,12 +171,17 @@ class ApcuDriver extends AbstractDriver {
/**
* Convert expiration date argument into TTL argument
*
* @param int $expires
* @param DateInterval|int|null $expires
* @return int
*/
protected function getTTLFromExpiration(int $expires): int
protected function getTTLFromExpiration(DateInterval|int|null $expires): int
{
$ttl = $expires - time();
if ($expires instanceof DateInterval)
{
return $expires->s;
}
$ttl = (int)$expires - time();
return ($ttl < 0) ? 0 : $ttl;
}

View File

@ -4,17 +4,19 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Driver;
use DateInterval;
/**
* Interface for different cache backends
*/
@ -33,10 +35,10 @@ interface DriverInterface {
*
* @param string $key
* @param mixed $value
* @param int $expires
* @param DateInterval|int|null $expires
* @return bool
*/
public function set(string $key, $value, ?int $expires = 0): bool;
public function set(string $key, mixed $value, DateInterval|int|null $expires = NULL): bool;
/**
* Get the value for the selected cache key
@ -44,7 +46,7 @@ interface DriverInterface {
* @param string $key
* @return mixed
*/
public function get(string $key);
public function get(string $key): mixed;
/**
* Retrieve a set of values by their cache key
@ -54,6 +56,15 @@ interface DriverInterface {
*/
public function getMultiple(array $keys = []): array;
/**
* Set multiple cache values
*
* @param array $items
* @param int|null $expires
* @return bool
*/
public function setMultiple(array $items, ?int $expires = NULL): bool;
/**
* Remove an item from the cache
*

View File

@ -4,19 +4,21 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Driver;
use Aviat\Banker\Exception\CacheException;
use Aviat\Banker\Exception\InvalidArgumentException;
use DateInterval;
use Memcached;
use MemcachedException;
@ -26,9 +28,9 @@ use MemcachedException;
class MemcachedDriver extends AbstractDriver {
/**
* @var Memcached
* The Memcached connection
*/
private ?Memcached $conn;
private Memcached $conn;
/**
* Driver for PHP Memcache extension
@ -96,7 +98,7 @@ class MemcachedDriver extends AbstractDriver {
* @param string $key
* @return mixed
*/
public function get(string $key)
public function get(string $key): mixed
{
return $this->conn->get($key);
}
@ -109,6 +111,8 @@ class MemcachedDriver extends AbstractDriver {
*/
public function getMultiple(array $keys = []): array
{
$this->validateKeys($keys);
$response = $this->conn->getMulti($keys);
return (is_array($response)) ? $response : [];
}
@ -118,12 +122,43 @@ class MemcachedDriver extends AbstractDriver {
*
* @param string $key
* @param mixed $value
* @param int $expires
* @param int|DateInterval|null $expires
* @return bool
* @throws InvalidArgumentException
*/
public function set(string $key, mixed $value, int|DateInterval|null $expires = NULL): bool
{
$this->validateKey($key);
if ($expires instanceof DateInterval)
{
$expires = time() + $expires->s;
}
return ($expires === NULL)
? $this->conn->set($key, $value)
: $this->conn->set($key, $value, $expires);
}
/**
* Set multiple cache values
*
* @param array $items
* @param DateInterval|int|null $expires
* @return bool
*/
public function set(string $key, $value, ?int $expires = 0): bool
public function setMultiple(array $items, DateInterval|int|null $expires = NULL): bool
{
return $this->conn->set($key, $value, $expires);
$this->validateKeys($items, TRUE);
if ($expires instanceof DateInterval)
{
$expires = $expires->s;
}
return ($expires === NULL)
? $this->conn->setMulti($items)
: $this->conn->setMulti($items, $expires);
}
/**
@ -145,8 +180,22 @@ class MemcachedDriver extends AbstractDriver {
*/
public function deleteMultiple(array $keys = []): bool
{
$this->validateKeys($keys);
$deleted = $this->conn->deleteMulti($keys);
return ($keys <=> $deleted) === 0;
if (is_array($deleted))
{
foreach ($deleted as $key => $status)
{
if ($status !== TRUE)
{
return FALSE;
}
}
return TRUE;
}
}
/**

View File

@ -4,17 +4,18 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Driver;
use DateInterval;
/**
* Cache backend for use without a cache server. Only does transient
@ -30,12 +31,9 @@ class NullDriver extends AbstractDriver {
protected array $store = [];
/**
* NullDriver constructor.
*
* @param array $config
* @param array $options
* NullDriver constructor
*/
public function __construct(array $config = [], array $options = [])
public function __construct()
{
$this->store = [];
}
@ -57,7 +55,7 @@ class NullDriver extends AbstractDriver {
* @param string $key
* @return mixed
*/
public function get(string $key)
public function get(string $key): mixed
{
return $this->exists($key)
? $this->store[$key]
@ -69,10 +67,10 @@ class NullDriver extends AbstractDriver {
*
* @param string $key
* @param mixed $value
* @param int $expires
* @param DateInterval|int|null $expires
* @return bool
*/
public function set(string $key, $value, ?int $expires = 0): bool
public function set(string $key, mixed $value, DateInterval|int|null $expires = NULL): bool
{
$this->store[$key] = $value;
return $this->store[$key] === $value;
@ -86,6 +84,12 @@ class NullDriver extends AbstractDriver {
*/
public function delete(string $key): bool
{
// Don't return true if the key didn't exist to begin with
if ( ! array_key_exists($key, $this->store))
{
return FALSE;
}
unset($this->store[$key]);
return ( ! array_key_exists($key, $this->store));
}
@ -98,6 +102,8 @@ class NullDriver extends AbstractDriver {
*/
public function deleteMultiple(array $keys = []): bool
{
$this->validateKeys($keys);
$res = TRUE;
foreach($keys as $key)

View File

@ -4,13 +4,13 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Driver;
@ -18,6 +18,8 @@ namespace Aviat\Banker\Driver;
use Aviat\Banker\Exception\CacheException;
use Predis\Client;
use DateInterval;
/**
* Redis cache backend
*/
@ -28,7 +30,7 @@ class RedisDriver extends AbstractDriver {
*
* @var Client
*/
protected ?Client $conn;
protected Client $conn;
/**
* RedisDriver constructor.
@ -74,9 +76,9 @@ class RedisDriver extends AbstractDriver {
* @param string $key
* @return mixed
*/
public function get(string $key)
public function get(string $key): mixed
{
$raw = $this->conn->get($key);
$raw = $this->conn->get($key) ?? '';
return unserialize($raw);
}
@ -85,19 +87,18 @@ class RedisDriver extends AbstractDriver {
*
* @param string $key
* @param mixed $value
* @param int $expires
* @param DateInterval|int|null $expires
* @return bool
*/
public function set(string $key, $value, ?int $expires = 0): bool
public function set(string $key, mixed $value, DateInterval|int|null $expires = NULL): bool
{
$value = serialize($value);
if ($expires !== 0)
{
return (bool) $this->conn->set($key, $value, 'EX', $expires);
}
$status = ($expires !== NULL)
? $this->conn->set($key, $value, 'EX', $expires)
: $this->conn->set($key, $value);
return (bool)$this->conn->set($key, $value);
return (string)$status === 'OK';
}
/**
@ -108,7 +109,8 @@ class RedisDriver extends AbstractDriver {
*/
public function delete(string $key): bool
{
return (bool) $this->conn->del([$key]);
// This call returns the number of keys deleted
return $this->conn->del([$key]) === 1;
}
/**
@ -119,7 +121,9 @@ class RedisDriver extends AbstractDriver {
*/
public function deleteMultiple(array $keys = []): bool
{
$res = $this->conn->del(...$keys);
$this->validateKeys($keys);
$res = $this->conn->del(...array_values($keys));
return $res === count($keys);
}

View File

@ -4,13 +4,13 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Exception;

View File

@ -4,13 +4,13 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Exception;

View File

@ -4,13 +4,13 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker;
@ -59,7 +59,7 @@ class Item implements CacheItemInterface {
*
* @var mixed
*/
protected $value;
protected mixed $value = null;
/**
* Create a Cache Item object
@ -102,7 +102,7 @@ class Item implements CacheItemInterface {
* @return mixed
* The value corresponding to this cache item's key, or null if not found.
*/
public function get()
public function get(): mixed
{
if ($this->isHit())
{
@ -136,10 +136,10 @@ class Item implements CacheItemInterface {
* @param mixed $value
* The serializable value to be stored.
*
* @return Item
* @return static
* The invoked object.
*/
public function set($value): Item
public function set(mixed $value): static
{
$this->value = $value;
return $this;
@ -154,10 +154,10 @@ class Item implements CacheItemInterface {
* the value should be stored permanently or for as long as the
* implementation allows.
*
* @return Item
* @return static
* The called object.
*/
public function expiresAt($expiration = NULL): Item
public function expiresAt(DateTimeInterface $expiration = NULL): static
{
if ($expiration instanceof DateTimeInterface)
{
@ -172,17 +172,17 @@ class Item implements CacheItemInterface {
/**
* Sets the expiration time for this cache item.
*
* @param int|DateInterval|null $time
* @param DateInterval|int|null $time
* The period of time from the present after which the item MUST be considered
* expired. An integer parameter is understood to be the time in seconds until
* expiration. If null is passed explicitly, a default value MAY be used.
* If none is set, the value should be stored permanently or for as long as the
* implementation allows.
*
* @return Item
* @return static
* The called object.
*/
public function expiresAfter($time = NULL): Item
public function expiresAfter(DateInterval|int $time = NULL): static
{
if ($time instanceof DateInterval)
{

View File

@ -4,13 +4,13 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker;
@ -25,6 +25,7 @@ use JsonSerializable;
*
* @see http://php.net/manual/en/class.arrayiterator.php
* @see http://php.net/manual/en/class.jsonserializable.php
* @extends ArrayIterator<string, CacheItemInterface>
*/
class ItemCollection extends ArrayIterator implements JsonSerializable {
@ -33,16 +34,16 @@ class ItemCollection extends ArrayIterator implements JsonSerializable {
*
* @var CacheItemInterface[]
*/
protected $items = [];
protected array $items = [];
/**
* Create the collection object from the raw
* CacheItemInterface array
*
* @param array $items - array of CacheItemInterface objects
* @param CacheItemInterface[] $items - array of CacheItemInterface objects
* @param int $flags - flags
*/
public function __construct(array $items = [], $flags = 0)
public function __construct(array $items = [], int $flags = 0)
{
parent::__construct($items, $flags);
$this->items = $items;
@ -51,9 +52,9 @@ class ItemCollection extends ArrayIterator implements JsonSerializable {
/**
* Specify what data to serialize when using `json_encode`
*
* @return mixed - The full set of data to be serialized
* @return CacheItemInterface[] - The full set of data to be serialized
*/
public function jsonSerialize()
public function jsonSerialize(): array
{
return $this->items;
}

48
src/KeyValidateTrait.php Normal file
View File

@ -0,0 +1,48 @@
<?php declare(strict_types=1);
/**
* Banker
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker;
use Aviat\Banker\Exception\InvalidArgumentException;
trait KeyValidateTrait {
/**
* @param iterable $keys
* @param bool $hash
*/
protected function validateKeys(iterable $keys, bool $hash = FALSE): void
{
$keys = ($hash) ? array_keys((array)$keys) : (array)$keys;
// Check each key
array_walk($keys, [$this, 'validateKey']);
}
/**
* @param mixed $key
* @throws InvalidArgumentException
*/
protected function validateKey(mixed $key): void
{
if ( ! is_string($key))
{
throw new InvalidArgumentException('Cache key must be a string.');
}
else if (preg_match("`[{}()/@:\\\]`", $key) === 1)
{
throw new InvalidArgumentException('Invalid characters in cache key');
}
}
}

View File

@ -4,13 +4,13 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker;
@ -32,8 +32,6 @@ trait LoggerTrait {
/**
* Return the existing logger instance or
* a NullLogger, if no instance set
*
* @return LoggerInterface
*/
protected function getLogger(): LoggerInterface
{
@ -46,11 +44,8 @@ trait LoggerTrait {
/**
* Set a logger to keep track of errors
*
* @param LoggerInterface $logger
* @return self
*/
public function setLogger(LoggerInterface $logger): self
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
@ -59,7 +54,5 @@ trait LoggerTrait {
{
$this->driver->setLogger($logger);
}
return $this;
}
}

View File

@ -4,18 +4,17 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker;
use Aviat\Banker\Driver\DriverInterface;
use Aviat\Banker\Exception\InvalidArgumentException;
use Psr\Cache\{CacheItemInterface, CacheItemPoolInterface};
use Psr\Log\{LoggerAwareInterface, LoggerInterface};
@ -26,16 +25,10 @@ use function is_string;
* The main cache manager
*/
final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
use _Driver;
use KeyValidateTrait;
use LoggerTrait;
/**
* Driver class for handling the chosen caching backend
*
* @var DriverInterface
*/
protected DriverInterface $driver;
/**
* Cache Items to be saved
*
@ -47,7 +40,7 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
* Set up the cache backend
*
* @param array $config
* @param LoggerInterface $logger
* @param LoggerInterface|null $logger
*/
public function __construct(array $config, ?LoggerInterface $logger = NULL)
{
@ -75,12 +68,9 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
* @return CacheItemInterface
* The corresponding Cache Item.
*/
public function getItem($key): CacheItemInterface
public function getItem(string $key): CacheItemInterface
{
if ( ! is_string($key))
{
throw new InvalidArgumentException();
}
$this->validateKey($key);
// If a deferred item exists, return that
if (array_key_exists($key, $this->deferred))
@ -101,14 +91,16 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
* If any of the keys in $keys are not a legal value a \Psr\Cache\InvalidArgumentException
* MUST be thrown.
*
* @return array|\Traversable
* @return iterable
* A traversable collection of Cache Items keyed by the cache keys of
* each item. A Cache item will be returned for each key, even if that
* key is not found. However, if no keys are specified then an empty
* traversable MUST be returned instead.
*/
public function getItems(array $keys = [])
public function getItems(array $keys = []): iterable
{
$this->validateKeys($keys);
if (empty($keys))
{
return new ItemCollection([]);
@ -118,11 +110,6 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
$items = [];
foreach($keys as $key)
{
if ( ! is_string($key))
{
throw new InvalidArgumentException();
}
$items[$key] = array_key_exists($key, $this->deferred)
? $this->deferred[$key]
: new Item($this->driver, $key);
@ -148,12 +135,9 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
* @return bool
* True if item exists in the cache, false otherwise.
*/
public function hasItem($key): bool
public function hasItem(string $key): bool
{
if ( ! is_string($key))
{
throw new InvalidArgumentException();
}
$this->validateKey($key);
// See if there are any deferred items
if (array_key_exists($key, $this->deferred))
@ -188,12 +172,9 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
* @return bool
* True if the item was successfully removed. False if there was an error.
*/
public function deleteItem($key): bool
public function deleteItem(string $key): bool
{
if ( ! is_string($key))
{
throw new InvalidArgumentException();
}
$this->validateKey($key);
if ( ! $this->hasItem($key))
{
@ -218,13 +199,7 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
*/
public function deleteItems(array $keys): bool
{
foreach ($keys as $key)
{
if ( ! is_string($key))
{
throw new InvalidArgumentException();
}
}
$this->validateKeys($keys);
return $this->driver->deleteMultiple($keys);
}
@ -240,7 +215,12 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
*/
public function save(CacheItemInterface $item): bool
{
return $item->save();
if (method_exists($item, 'save'))
{
return $item->save();
}
return FALSE;
}
/**
@ -287,21 +267,4 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
return $result;
}
/**
* Instantiate the appropriate cache backend based on the config
*
* @param array $driverConfig
* @return DriverInterface
*/
protected function loadDriver(array $driverConfig = []): DriverInterface
{
$driver = ucfirst(strtolower($driverConfig['driver'] ?? 'null'));
$class = __NAMESPACE__ . "\\Driver\\${driver}Driver";
$driverConfig['connection'] = $driverConfig['connection'] ?? [];
$driverConfig['options'] = $driverConfig['options'] ?? [];
return new $class($driverConfig['connection'], $driverConfig['options']);
}
}

View File

@ -4,33 +4,34 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker;
use Aviat\Banker\Driver\DriverInterface;
use Aviat\Banker\Exception\InvalidArgumentException;
use Psr\Log\LoggerAwareInterface;
use DateInterval;
use Psr\Log\{LoggerInterface, LoggerAwareInterface};
use Psr\SimpleCache;
use Psr\Log\LoggerInterface;
class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface {
/**
* Implements PSR-16 (SimpleCache)
*/
class Teller implements LoggerAwareInterface, SimpleCache\CacheInterface {
use _Driver;
use KeyValidateTrait;
use LoggerTrait;
private DriverInterface $driver;
/**
* Set up the cache backend
*
* @param array $config
* @param LoggerInterface $logger
* @param LoggerInterface|null $logger
*/
public function __construct(array $config, ?LoggerInterface $logger = NULL)
{
@ -42,6 +43,16 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface {
}
}
/**
* Wipes clean the entire cache's keys.
*
* @return bool True on success and false on failure.
*/
public function clear(): bool
{
return $this->driver->flush();
}
/**
* Fetches a value from the cache.
*
@ -53,7 +64,7 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface {
* @throws SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
public function get($key, $default = null)
public function get(string $key, mixed $default = null): mixed
{
$this->validateKey($key);
@ -65,7 +76,7 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface {
*
* @param string $key The key of the item to store.
* @param mixed $value The value of the item to store, must be serializable.
* @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and
* @param null|int|DateInterval $ttl Optional. The TTL value of this item. If no value is sent and
* the driver supports TTL then the library may set a default value
* for it or let the driver take care of that.
*
@ -74,7 +85,7 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface {
* @throws SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
public function set($key, $value, $ttl = null): bool
public function set(string $key, mixed $value, null|int|DateInterval $ttl = null): bool
{
$this->validateKey($key);
@ -91,23 +102,13 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface {
* @throws SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
public function delete($key): bool
public function delete(string $key): bool
{
$this->validateKey($key);
return $this->driver->delete($key);
}
/**
* Wipes clean the entire cache's keys.
*
* @return bool True on success and false on failure.
*/
public function clear(): bool
{
return $this->driver->flush();
}
/**
* Obtains multiple cache items by their unique keys.
*
@ -120,18 +121,34 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface {
* MUST be thrown if $keys is neither an array nor a Traversable,
* or if any of the $keys are not a legal value.
*/
public function getMultiple($keys, $default = null)
public function getMultiple(iterable $keys, mixed $default = null): iterable
{
$keys = (array)$keys;
$this->validateKeys($keys);
$foundValues = $this->driver->getMultiple($keys);
$foundKeys = array_keys($foundValues);
return $this->driver->getMultiple((array)$keys);
// If all the values are found, just return them
if ($keys === $foundKeys)
{
return $foundValues;
}
// Otherwise, return a default value for missing keys
$result = $foundValues;
foreach (array_diff($keys, $foundKeys) as $key)
{
$result[$key] = $default;
}
return $result;
}
/**
* Persists a set of key => value pairs in the cache, with an optional TTL.
*
* @param iterable $values A list of key => value pairs for a multiple-set operation.
* @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and
* @param null|int|DateInterval $ttl Optional. The TTL value of this item. If no value is sent and
* the driver supports TTL then the library may set a default value
* for it or let the driver take care of that.
*
@ -141,18 +158,13 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface {
* MUST be thrown if $values is neither an array nor a Traversable,
* or if any of the $values are not a legal value.
*/
public function setMultiple($values, $ttl = null): bool
public function setMultiple(iterable $values, null|int|DateInterval $ttl = null): bool
{
$this->validateKeys($values, TRUE);
$setResults = [];
foreach ($values as $k => $v)
{
$setResults[] = $this->set($k, $v, $ttl);
}
// Only return true if all the results are true
return array_reduce($setResults, fn ($carry, $item) => $item && $carry, TRUE);
return ($ttl === NULL)
? $this->driver->setMultiple((array)$values)
: $this->driver->setMultiple((array)$values, $ttl);
}
/**
@ -166,7 +178,7 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface {
* MUST be thrown if $keys is neither an array nor a Traversable,
* or if any of the $keys are not a legal value.
*/
public function deleteMultiple($keys): bool
public function deleteMultiple(iterable $keys): bool
{
$this->validateKeys($keys);
@ -188,63 +200,10 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface {
* @throws SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
public function has($key): bool
public function has(string $key): bool
{
$this->validateKey($key);
return $this->driver->exists($key);
}
/**
* @param $keys
* @param bool $hash
* @throws InvalidArgumentException
*/
private function validateKeys($keys, bool $hash = FALSE): void
{
// Check type of keys
if ( ! is_iterable($keys))
{
throw new InvalidArgumentException('Keys must be an array or a traversable object');
}
$keys = ($hash) ? array_keys((array)$keys) : (array)$keys;
// Check each key
array_walk($keys, fn($key) => $this->validateKey($key));
}
/**
* @param string $key
* @throws InvalidArgumentException
*/
private function validateKey($key): void
{
if ( ! is_string($key))
{
throw new InvalidArgumentException('Cache key must be a string.');
}
if (is_string($key) && preg_match("`[{}()/@:\\\]`", $key) === 1)
{
throw new InvalidArgumentException('Invalid characters in cache key');
}
}
/**
* Instantiate the appropriate cache backend based on the config
*
* @param array $driverConfig
* @return DriverInterface
*/
protected function loadDriver(array $driverConfig = []): DriverInterface
{
$driver = ucfirst(strtolower($driverConfig['driver'] ?? 'null'));
$class = __NAMESPACE__ . "\\Driver\\${driver}Driver";
$driverConfig['connection'] = $driverConfig['connection'] ?? [];
$driverConfig['options'] = $driverConfig['options'] ?? [];
return new $class($driverConfig['connection'], $driverConfig['options']);
}
}

43
src/_Driver.php Normal file
View File

@ -0,0 +1,43 @@
<?php declare(strict_types=1);
/**
* Banker
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker;
use Aviat\Banker\Driver\AbstractDriver;
/**
* Private trait for shared driver-related functionality
*/
trait _Driver {
/**
* Driver class for handling the chosen caching backend
*/
private AbstractDriver $driver;
/**
* Instantiate the appropriate cache backend based on the config
*/
protected function loadDriver(array $driverConfig = []): AbstractDriver
{
$driver = ucfirst(strtolower($driverConfig['driver'] ?? 'null'));
$class = __NAMESPACE__ . "\\Driver\\{$driver}Driver";
$driverConfig['connection'] = $driverConfig['connection'] ?? [];
$driverConfig['options'] = $driverConfig['options'] ?? [];
// @phpstan-ignore-next-line
return new $class($driverConfig['connection'], $driverConfig['options']);
}
}

View File

@ -4,13 +4,13 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Tests\Driver;
@ -21,6 +21,12 @@ class ApcuDriverTest extends DriverTestBase {
public function setup(): void
{
if ( ! extension_loaded('apcu'))
{
$this->markTestSkipped();
return;
}
$this->driver = new ApcuDriver();
$this->driver->flush();
}

View File

@ -4,26 +4,26 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Tests\Driver;
use Aviat\Banker\Driver\DriverInterface;
use Aviat\Banker\Exception\InvalidArgumentException;
use PHPUnit\Framework\TestCase;
use TypeError;
class DriverTestBase extends TestCase {
protected DriverInterface $driver;
public function testGetSet(): void
{
$this->driver->set('foo', 'bar');
@ -37,7 +37,7 @@ class DriverTestBase extends TestCase {
'bar' => 'baz'
];
$this->driver->set('bar', $bar);
$this->assertTrue($this->driver->set('bar', $bar));
$this->assertEquals($bar, $this->driver->get('bar'));
}
@ -74,12 +74,65 @@ class DriverTestBase extends TestCase {
$this->assertEquals($expected, $actual);
}
public function testSetMultiple(): void
{
$data = [
'foo' => [
'apple' => 'orange'
],
'bar' => 'baz',
'baz' => 123456,
'a' => [1, 2, 3],
'b' => false,
'c' => true,
'd' => null,
];
$this->assertTrue($this->driver->setMultiple($data));
$this->assertEquals($data, $this->driver->getMultiple(array_keys($data)));
}
public function testSetMultipleInvalidKey(): void
{
$this->expectException(InvalidArgumentException::class);
$data = [
128 => 0,
0x123 => 1,
];
$this->driver->setMultiple($data);
}
public function testSetMultipleExpires(): void
{
$data = [
'foo' => [
'apple' => 'orange'
],
'bar' => 'baz',
'baz' => 123456,
'a' => [1, 2, 3],
'b' => false,
'c' => true,
'd' => null,
];
$this->assertTrue($this->driver->setMultiple($data, 30));
$this->assertEquals($data, $this->driver->getMultiple(array_keys($data)));
}
public function testSetWithExpires(): void
{
$this->driver->set('foo', 'bar', 30);
$this->assertEquals('bar', $this->driver->get('foo'));
}
public function testSetInvalidKey(): void
{
$this->expectException(\TypeError::class);
$this->driver->set(0x12, 'foo');
}
public function testDelete(): void
{
$this->driver->set('a1', 'b2');
@ -98,12 +151,20 @@ class DriverTestBase extends TestCase {
$this->assertTrue($this->driver->exists('a'));
$this->assertTrue($this->driver->exists('b'));
/*$this->assertTrue(*/$this->driver->deleteMultiple(['a', 'b']);//);
$this->assertTrue($this->driver->deleteMultiple(['a', 'b']));
$this->assertFalse($this->driver->exists('a'));
$this->assertFalse($this->driver->exists('b'));
}
public function testDeleteMultipleBadKey(): void
{
$this->assertFalse($this->driver->exists('foo'));
$this->assertFalse($this->driver->exists('bar'));
$this->assertFalse($this->driver->deleteMultiple(['foo', 'bar']));
}
public function testExpiresAt(): void
{
$this->driver->set('abc', 'def');

View File

@ -4,13 +4,13 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Tests\Driver;
@ -21,6 +21,12 @@ class MemcachedDriverTest extends DriverTestBase {
public function setUp(): void
{
if ( ! class_exists('Memcached'))
{
$this->markTestSkipped();
return;
}
$config = [
'host' => '127.0.0.1',
'port' => 11211
@ -28,6 +34,7 @@ class MemcachedDriverTest extends DriverTestBase {
if (array_key_exists('MEMCACHED_HOST', $_ENV))
{
$config['host'] = $_ENV['MEMCACHED_HOST'];
$config['port'] = $_ENV['MEMCACHED_PORT'] ?? 11211;
}
$this->driver = new MemcachedDriver($config);

View File

@ -4,13 +4,13 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Tests\Driver;

View File

@ -4,13 +4,13 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Tests\Driver;
@ -26,7 +26,7 @@ class RedisDriverTest extends DriverTestBase {
{
$config['scheme'] = 'tcp';
$config['host'] = $_ENV['REDIS_HOST'];
$config['port'] = 6379;
$config['port'] = $_ENV['REDIS_PORT'] ?? 6379;
}
$this->driver = new RedisDriver($config);

View File

@ -4,18 +4,20 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Tests;
use Exception;
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
use ReflectionProperty;
use InvalidArgumentException;
@ -28,23 +30,21 @@ class Friend {
/**
* Object to create a friend of
* @var object
*/
private $_friend_;
private mixed $_friend_;
/**
* Reflection class of the object
* @var object
*/
private $_reflect_;
private mixed $_reflect_;
/**
* Create a friend object
*
* @param object $obj
* @throws InvalidArgumentException
* @throws InvalidArgumentException|ReflectionException
*/
public function __construct($obj)
public function __construct(mixed $obj)
{
if ( ! is_object($obj))
{
@ -61,7 +61,7 @@ class Friend {
* @param string $key
* @return mixed
*/
public function __get($key)
public function __get(string $key): mixed
{
if ($this->_reflect_->hasProperty($key))
{
@ -79,7 +79,7 @@ class Friend {
* @param mixed $value
* @return void
*/
public function __set($key, $value)
public function __set(string $key, mixed $value): void
{
if ($this->_reflect_->hasProperty($key))
{
@ -91,12 +91,13 @@ class Friend {
/**
* Calls a protected or private method on the friend
*
* @param string $method
* @param array $args
* @param string $method
* @param array $args
* @return mixed
* @throws BadMethodCallException
* @throws ReflectionException
*/
public function __call($method, $args)
public function __call(string $method, array $args): mixed
{
if ( ! $this->_reflect_->hasMethod($method))
{
@ -115,7 +116,7 @@ class Friend {
* @param string $name
* @return ReflectionProperty|null
*/
private function _get_property($name)
private function _get_property(string $name): ?ReflectionProperty
{
try
{
@ -125,7 +126,7 @@ class Friend {
}
// Return NULL on any exception, so no further logic needed
// in the catch block
catch (\Exception $e)
catch (Exception)
{
return NULL;
}

View File

@ -4,13 +4,13 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Tests;
@ -20,7 +20,7 @@ use PHPUnit\Framework\TestCase;
class ItemCollectionTest extends TestCase {
protected $collection;
protected ItemCollection $collection;
public function setUp(): void
{

View File

@ -4,13 +4,13 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Tests;
@ -60,10 +60,11 @@ class ItemTest extends TestCase {
$friend = new Friend($this->item);
$this->assertEquals($expected, $friend->expiresAt, "DateTimeInterface");
$time2 = strtotime("July 16, 2024");
$time2stamp = strtotime("July 16, 2024");
$time2 = new DateTime("July 16, 2024");
$this->item->expiresAt($time2);
$friend2 = new Friend($this->item);
$this->assertEquals($time2, $friend2->expiresAt, "Unix Timestamp");
$this->assertEquals($time2stamp, $friend2->expiresAt, "Unix Timestamp");
}
public function testExpiresAfter(): void

View File

@ -4,13 +4,13 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Tests;
@ -21,6 +21,7 @@ use Monolog\Logger;
use Monolog\Handler\SyslogHandler;
use PHPUnit\Framework\TestCase;
use Psr\Log\{LoggerInterface, NullLogger};
use TypeError;
class PoolTest extends TestCase {
@ -97,8 +98,7 @@ class PoolTest extends TestCase {
public function testItemBadKey(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Cache key must be a string.');
$this->expectException(TypeError::class);
$this->pool->getItem([]);
}
@ -173,8 +173,7 @@ class PoolTest extends TestCase {
{
$this->pool->clear();
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Cache key must be a string.');
$this->expectException(TypeError::class);
$this->pool->hasItem(34);
}
@ -213,8 +212,8 @@ class PoolTest extends TestCase {
public function testDeleteItemBadKey(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Cache key must be a string.');
$this->expectException(TypeError::class);
// $this->expectExceptionMessage('Cache key must be a string.');
$this->pool->deleteItem(34);
}

View File

@ -4,18 +4,17 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Tests;
use Aviat\Banker\Pool;
use Aviat\Banker\Teller;
use Aviat\Banker\Exception\InvalidArgumentException;
use Monolog\Handler\SyslogHandler;
@ -123,6 +122,34 @@ class TellerTest extends TestCase {
}
}
public function testGetMultipleWithDefaultValues(): void
{
$setValues = [
'foo' => 24,
'bar' => '87',
'baz' => [1, 2, 3],
];
$expectedValues = [
'foo' => 24,
'bar' => '87',
'baz' => [1, 2, 3],
'a' => NULL,
'b' => NULL,
'c' => NULL,
'd' => NULL,
'e' => NULL,
'f' => NULL,
];
$searchKeys = array_keys($expectedValues);
$this->assertTrue($this->teller->setMultiple($setValues));
$received = $this->teller->getMultiple($searchKeys);
$this->assertEquals($expectedValues, $received);
}
public function testGetSetMultiple(): void
{
$this->assertTrue($this->teller->setMultiple($this->testValues));
@ -182,27 +209,12 @@ class TellerTest extends TestCase {
array_walk($hasKeys, fn ($key) => $this->assertTrue($this->teller->has($key)));
}
public function testBadKeyType(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Cache key must be a string.');
$this->teller->get(546567);
}
public function testBadKeysType (): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Keys must be an array or a traversable object');
$keys = (object)[];
$this->teller->getMultiple($keys);
}
/**
* @dataProvider keyValidationTests
* @param string $key
* @throws \Psr\SimpleCache\InvalidArgumentException
*/
public function testKeyValidation($key): void
public function testKeyValidation(string $key): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid characters in cache key');
@ -210,7 +222,7 @@ class TellerTest extends TestCase {
$this->teller->get($key);
}
public function keyValidationTests(): array
public static function keyValidationTests(): array
{
// {}()/@:\\\
return [

View File

@ -4,13 +4,13 @@
*
* A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
*
* PHP version 7.4
* PHP version 8+
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2020 Timothy J. Warren
* @copyright 2016 - 2023 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @version 4.1.1
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Tests;

7
tools/composer.json Normal file
View File

@ -0,0 +1,7 @@
{
"require": {
"pdepend/pdepend": "^2.12.1",
"phpmd/phpmd": "^2.13",
"phpstan/phpstan": "^1.9.14"
}
}