From d79974923928fda8694ab407f62362db963416de Mon Sep 17 00:00:00 2001 From: rotimi Date: Tue, 13 Apr 2021 23:06:08 -0600 Subject: [PATCH] Rector tweaks --- .github/workflows/php.yml | 80 +++++++++ composer.json | 8 +- psalm.xml | 15 ++ rector.php | 156 +---------------- src/Renderer.php | 355 ++++++++++++++++---------------------- tests/RendererTest.php | 102 ----------- 6 files changed, 253 insertions(+), 463 deletions(-) create mode 100644 .github/workflows/php.yml create mode 100644 psalm.xml diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml new file mode 100644 index 0000000..90dd061 --- /dev/null +++ b/.github/workflows/php.yml @@ -0,0 +1,80 @@ +name: Run PHP Tests and Code Quality Tools + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + schedule: + # Also run every Sunday at midnight + - cron: '0 0 * * 0' + +jobs: + build: + + runs-on: ${{ matrix.os }} + + strategy: + matrix: + php: [8.0, 7.4, 7.3, 7.2] +# prefer-lowest is causing unit tests to fail when php 7.2 is run against PHPunit 7.x, +# PHPUnit 8.x is the latest stable release that supports PHP 7.2 and that runs fine +# dependency-version: [prefer-lowest, prefer-stable] + dependency-version: [prefer-stable] + os: [ubuntu-18.04, ubuntu-20.04] + include: + - os: ubuntu-18.04 + php: 7.2 + - os: ubuntu-18.04 + php: 7.3 + - os: ubuntu-18.04 + php: 7.4 + - os: ubuntu-18.04 + php: 8.0 + - os: ubuntu-20.04 + php: 7.4 + - os: ubuntu-20.04 + php: 8.0 + exclude: + - os: ubuntu-20.04 + php: 7.3 + + name: PHP-${{ matrix.php }} - ${{ matrix.dependency-version }} - ${{ matrix.os }} + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + ini-values: pcre.jit=0, pcre.backtrack_limit=9999999, pcre.recursion_limit=9999999 + coverage: none + + - name: PHP version + run: php -v + + - name: Composer version + run: composer --version + + - name: Validate composer.json and composer.lock + run: composer validate + + - name: Install Dependencies + run: composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-progress + + # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" + # Docs: https://getcomposer.org/doc/articles/scripts.md + - name: Run PHPUnit Test Suite + run: vendor/bin/phpunit + + - name: Run Rector + # Run rector for PHP 7.X but not 8.0, rector is currently blowing up with PHP 8.0 + #if: matrix.php != '8.0' + run: vendor/bin/rector process src --dry-run + + - name: Run Psalm + # Run psalm for PHP 7.4 & 8.0 but not 7.2 & 7.3, psalm is currently blowing up with PHP 7.2 & 7.3 + #if: matrix.php != '7.2' && matrix.php != '7.3' + run: vendor/bin/psalm diff --git a/composer.json b/composer.json index 16e8544..2820bae 100644 --- a/composer.json +++ b/composer.json @@ -18,9 +18,10 @@ "laminas/laminas-escaper": "^2.6.1" }, "require-dev": { - "phpunit/phpunit": "^8.0", + "phpunit/phpunit": "^9.0 || ^8.0", "php-coveralls/php-coveralls": "^2.0", - "rector/rector": "^0.8.56" + "rector/rector": "^0.10.4 || ^0.8.56", + "vimeo/psalm": "^4.7" }, "autoload": { "classmap": ["src/"], @@ -35,5 +36,8 @@ "Rotexsoft\\FileRenderer\\": "src/", "Rotexsoft\\FileRenderer\\Tests\\": "tests/" } + }, + "scripts": { + "test": "vendor/bin/phpunit --coverage-text" } } diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..30258a7 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/rector.php b/rector.php index bd75ca7..f767272 100644 --- a/rector.php +++ b/rector.php @@ -11,167 +11,25 @@ return static function (ContainerConfigurator $containerConfigurator): void { // get parameters $parameters = $containerConfigurator->parameters(); - - $parameters->set(Option::EXCLUDE_PATHS, [ - // single file - //__DIR__ . '/src/ComplicatedFile.php', - // or directory - //__DIR__ . '/src/views/*/*', - ]); - - $parameters->set(Option::EXCLUDE_RECTORS, [ - - \Rector\CodeQuality\Rector\If_\MoveOutMethodCallInsideIfConditionRector::class, - \Rector\CodeQuality\Rector\Ternary\SimplifyTautologyTernaryRector::class, - \Rector\CodeQuality\Rector\FunctionLike\RemoveAlwaysTrueConditionSetInConstructorRector::class, - \Rector\CodeQuality\Rector\Ternary\ArrayKeyExistsTernaryThenValueToCoalescingRector::class, - \Rector\CodeQuality\Rector\Include_\AbsolutizeRequireAndIncludePathRector::class, - \Rector\CodeQuality\Rector\Foreach_\ForeachItemsAssignToEmptyArrayToAssignRector::class, - \Rector\CodeQuality\Rector\Foreach_\UnusedForeachValueToArrayKeysRector::class, - \Rector\CodeQuality\Rector\Expression\InlineIfToExplicitIfRector::class, - \Rector\CodeQuality\Rector\Array_\ArrayThisCallToThisMethodCallRector::class, - \Rector\CodeQuality\Rector\New_\NewStaticToNewSelfRector::class, - \Rector\CodeQuality\Rector\Identical\SimplifyBoolIdenticalTrueRector::class, - - \Rector\CodingStyle\Rector\Use_\RemoveUnusedAliasRector::class, - \Rector\CodingStyle\Rector\Include_\FollowRequireByDirRector::class, - \Rector\CodingStyle\Rector\Encapsed\EncapsedStringsToSprintfRector::class, - \Rector\CodingStyle\Rector\Assign\ManualJsonStringToJsonEncodeArrayRector::class, - \Rector\CodingStyle\Rector\ClassMethod\MakeInheritedMethodVisibilitySameAsParentRector::class, - \Rector\CodingStyle\Rector\FuncCall\VersionCompareFuncCallToConstantRector::class, - \Rector\CodingStyle\Rector\Function_\CamelCaseFunctionNamingToUnderscoreRector::class, - \Rector\CodingStyle\Rector\ClassMethod\RemoveDoubleUnderscoreInMethodNameRector::class, - - \Rector\CodingStyle\Rector\MethodCall\UseMessageVariableForSprintfInSymfonyStyleRector::class, - - \Rector\DeadCode\Rector\ClassConst\RemoveUnusedClassConstantRector::class, - \Rector\DeadCode\Rector\Array_\RemoveDuplicatedArrayKeyRector::class, - \Rector\DeadCode\Rector\ClassMethod\RemoveEmptyClassMethodRector::class, - \Rector\DeadCode\Rector\Property\RemoveUnusedPrivatePropertyRector::class, - \Rector\DeadCode\Rector\ClassMethod\RemoveUnusedParameterRector::class, - \Rector\DeadCode\Rector\ClassConst\RemoveUnusedPrivateConstantRector::class, - \Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodRector::class, - \Rector\DeadCode\Rector\ClassMethod\RemoveDeadConstructorRector::class, - \Rector\DeadCode\Rector\For_\RemoveDeadIfForeachForRector::class, - \Rector\DeadCode\Rector\MethodCall\RemoveDefaultArgumentValueRector::class, - \Rector\DeadCode\Rector\Property\RemoveSetterOnlyPropertyAndMethodCallRector::class, - \Rector\DeadCode\Rector\PropertyProperty\RemoveNullPropertyInitializationRector::class, - \Rector\DeadCode\Rector\Assign\RemoveUnusedVariableAssignRector::class, - \Rector\DeadCode\Rector\Function_\RemoveUnusedFunctionRector::class, - \Rector\DeadCode\Rector\ClassMethod\RemoveDeadRecursiveClassMethodRector::class, - \Rector\DeadCode\Rector\MethodCall\RemoveEmptyMethodCallRector::class, - - \Rector\Naming\Rector\ClassMethod\RenameParamToMatchTypeRector::class, - \Rector\Naming\Rector\Class_\RenamePropertyToMatchTypeRector::class, - \Rector\Naming\Rector\ClassMethod\RenameVariableToMatchNewTypeRector::class, - \Rector\Naming\Rector\Assign\RenameVariableToMatchMethodCallReturnTypeRector::class, - \Rector\Naming\Rector\ClassMethod\MakeGetterClassMethodNameStartWithGetRector::class, - \Rector\Naming\Rector\ClassMethod\MakeIsserClassMethodNameStartWithIsRector::class, - \Rector\Naming\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector::class, - \Rector\Naming\Rector\Property\MakeBoolPropertyRespectIsHasWasMethodNamingRector::class, - - \Rector\Php70\Rector\Assign\ListSwapArrayOrderRector::class, - - \Rector\Php71\Rector\BinaryOp\BinaryOpBetweenNumberAndStringRector::class, - - \Rector\Php72\Rector\ConstFetch\BarewordStringRector::class, - - \Rector\Php74\Rector\FuncCall\ArraySpreadInsteadOfArrayMergeRector::class, - - \Rector\Php80\Rector\Catch_\RemoveUnusedVariableInCatchRector::class, - - \Rector\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector::class, - ]); // Define what rule sets will be applied $parameters->set(Option::SETS, [ - SetList::DEAD_CODE, - // No Rector - // \Rector\DeadCode\Rector\ClassConst\RemoveUnusedClassConstantRector::class, - // \Rector\DeadCode\Rector\Array_\RemoveDuplicatedArrayKeyRector::class, - // \Rector\DeadCode\Rector\ClassMethod\RemoveEmptyClassMethodRector::class - // \Rector\DeadCode\Rector\Property\RemoveUnusedPrivatePropertyRector::class, - // \Rector\DeadCode\Rector\ClassMethod\RemoveUnusedParameterRector::class, - // \Rector\DeadCode\Rector\ClassConst\RemoveUnusedPrivateConstantRector::class, - // \Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodRector::class, - // \Rector\DeadCode\Rector\ClassMethod\RemoveDeadConstructorRector::class, - // \Rector\DeadCode\Rector\For_\RemoveDeadIfForeachForRector::class, - // \Rector\DeadCode\Rector\MethodCall\RemoveDefaultArgumentValueRector::class, - // \Rector\DeadCode\Rector\Property\RemoveSetterOnlyPropertyAndMethodCallRector::class, - // \Rector\DeadCode\Rector\PropertyProperty\RemoveNullPropertyInitializationRector::class, - // \Rector\DeadCode\Rector\Assign\RemoveUnusedVariableAssignRector::class, - // \Rector\DeadCode\Rector\Function_\RemoveUnusedFunctionRector::class, - // \Rector\DeadCode\Rector\ClassMethod\RemoveDeadRecursiveClassMethodRector::class, - // \Rector\DeadCode\Rector\MethodCall\RemoveEmptyMethodCallRector::class, - SetList::PERFORMANCE, - SetList::CODE_QUALITY, - // No Rector: - // \Rector\CodeQuality\Rector\Ternary\SimplifyTautologyTernaryRector::class, - // \Rector\CodeQuality\Rector\FunctionLike\RemoveAlwaysTrueConditionSetInConstructorRector::class, - // \Rector\CodeQuality\Rector\Ternary\ArrayKeyExistsTernaryThenValueToCoalescingRector::class, - // \Rector\CodeQuality\Rector\Include_\AbsolutizeRequireAndIncludePathRector::class, - // \Rector\CodeQuality\Rector\Foreach_\ForeachItemsAssignToEmptyArrayToAssignRector::class, - // \Rector\CodeQuality\Rector\Foreach_\UnusedForeachValueToArrayKeysRector::class, - // \Rector\CodeQuality\Rector\Expression\InlineIfToExplicitIfRector::class, - // \Rector\CodeQuality\Rector\Array_\ArrayThisCallToThisMethodCallRector::class, - // \Rector\CodeQuality\Rector\New_\NewStaticToNewSelfRector::class, - // \Rector\CodeQuality\Rector\Identical\SimplifyBoolIdenticalTrueRector::class, - SetList::CODE_QUALITY_STRICT, - // No Rector: - // \Rector\CodeQuality\Rector\If_\MoveOutMethodCallInsideIfConditionRector::class, - SetList::CODING_STYLE, - // No Rector: - // \Rector\CodingStyle\Rector\Use_\RemoveUnusedAliasRector::class, - // \Rector\CodingStyle\Rector\Include_\FollowRequireByDirRector::class, - // \Rector\CodingStyle\Rector\Encapsed\EncapsedStringsToSprintfRector::class, - // \Rector\CodingStyle\Rector\Assign\ManualJsonStringToJsonEncodeArrayRector::class, - // \Rector\CodingStyle\Rector\ClassMethod\MakeInheritedMethodVisibilitySameAsParentRector::class, - // \Rector\CodingStyle\Rector\FuncCall\VersionCompareFuncCallToConstantRector::class, - // \Rector\CodingStyle\Rector\Function_\CamelCaseFunctionNamingToUnderscoreRector::class, - // \Rector\CodingStyle\Rector\ClassMethod\RemoveDoubleUnderscoreInMethodNameRector::class, //only use in projects where you really wanna do this - SetList::CODING_STYLE_ADVANCED, - // No Rector: - // \Rector\CodingStyle\Rector\MethodCall\UseMessageVariableForSprintfInSymfonyStyleRector::class, - //SetList::LARAVEL_STATIC_TO_INJECTION, // only in laravel projects - //SetList::ARRAY_STR_FUNCTIONS_TO_STATIC_CALL, // only in laravel projects - SetList::MYSQL_TO_MYSQLI, // only use in web-apps with db access and db / orm packages - SetList::NAMING, - // No Rector: - // \Rector\Naming\Rector\ClassMethod\RenameParamToMatchTypeRector::class, - // \Rector\Naming\Rector\Class_\RenamePropertyToMatchTypeRector::class, - // \Rector\Naming\Rector\ClassMethod\RenameVariableToMatchNewTypeRector::class, - // \Rector\Naming\Rector\Assign\RenameVariableToMatchMethodCallReturnTypeRector::class, - // \Rector\Naming\Rector\ClassMethod\MakeGetterClassMethodNameStartWithGetRector::class, - // \Rector\Naming\Rector\ClassMethod\MakeIsserClassMethodNameStartWithIsRector::class, - // \Rector\Naming\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector::class, - // \Rector\Naming\Rector\Property\MakeBoolPropertyRespectIsHasWasMethodNamingRector::class, - SetList::PERFORMANCE, - SetList::PHPEXCEL_TO_PHPSPREADSHEET, // only use in projects that use phpexcel SetList::PHP_52, SetList::PHP_53, SetList::PHP_54, SetList::PHP_55, SetList::PHP_56, SetList::PHP_70, - // No Rector - // \Rector\Php70\Rector\Assign\ListSwapArrayOrderRector::class, SetList::PHP_71, - // No Rector - // \Rector\Php71\Rector\BinaryOp\BinaryOpBetweenNumberAndStringRector::class, SetList::PHP_72, - // No Rector - // \Rector\Php72\Rector\ConstFetch\BarewordStringRector::class, - SetList::PHP_73, - SetList::PHP_74, - // No Rector - // \Rector\Php74\Rector\FuncCall\ArraySpreadInsteadOfArrayMergeRector::class, - //SetList::PHP_80 - // No Rector - // \Rector\Php80\Rector\Catch_\RemoveUnusedVariableInCatchRector::class, - //SetList::PSR_4, + SetList::DEAD_CODE, + //SetList::PHP_73, + //SetList::PHP_74, + //SetList::PHP_80, + SetList::DEAD_CODE, + SetList::PSR_4, SetList::TYPE_DECLARATION, - // No Rector - // \Rector\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector::class, + SetList::TYPE_DECLARATION_STRICT, ]); // get services (needed for register a single rule) diff --git a/src/Renderer.php b/src/Renderer.php index 2e11f17..574217a 100644 --- a/src/Renderer.php +++ b/src/Renderer.php @@ -30,7 +30,7 @@ class Renderer * @var array * */ - protected $file_paths = array(); + protected $file_paths = []; /** * @@ -55,7 +55,7 @@ class Renderer * @var array * */ - protected $data = array(); + protected $data = []; /** * @@ -68,7 +68,7 @@ class Renderer * @var array * */ - protected $data_vars_2_html_escape = array(); + protected $data_vars_2_html_escape = []; /** * @@ -81,7 +81,7 @@ class Renderer * @var array * */ - protected $data_vars_2_html_attr_escape = array(); + protected $data_vars_2_html_attr_escape = []; /** * @@ -98,7 +98,7 @@ class Renderer * @var array * */ - protected $data_vars_2_css_escape = array(); + protected $data_vars_2_css_escape = []; /** * @@ -115,7 +115,7 @@ class Renderer * @var array * */ - protected $data_vars_2_js_escape = array(); + protected $data_vars_2_js_escape = []; /** * @@ -176,7 +176,7 @@ class Renderer * @var \Laminas\Escaper\Escaper * */ - protected $escaper = null; + protected $escaper; /** @@ -190,7 +190,7 @@ class Renderer * @var array * */ - protected $multi_escape_prevention_guard = array(); + protected $multi_escape_prevention_guard = []; /** * @@ -236,24 +236,15 @@ class Renderer * @throws \InvalidArgumentException */ public function __construct( - $file_name='', - array $data = array(), - array $file_paths = array(), + string $file_name='', + array $data = [], + array $file_paths = [], $escape_encoding = 'utf-8', - array $data_vars_2_html_escape = array(), - array $data_vars_2_html_attr_escape = array(), - array $data_vars_2_css_escape = array(), - array $data_vars_2_js_escape = array() + array $data_vars_2_html_escape = [], + array $data_vars_2_html_attr_escape = [], + array $data_vars_2_css_escape = [], + array $data_vars_2_js_escape = [] ) { - if( !is_string($file_name) ) { - - $msg = "ERROR: ". get_class($this) ."::__construct(...) expects first parameter (the name of the php file to be rendered) to be a `string`." - . PHP_EOL .'`'. $this->getVarType($file_name, true).'` was supplied with the value below:' - . PHP_EOL . var_export($file_name, true). PHP_EOL ; - - throw new InvalidArgumentException($msg); - } - $this->data = $data; $this->file_name = $file_name; $this->file_paths = $file_paths; @@ -336,30 +327,28 @@ public function __unset($key) { } /** - * + * * Adds a new item to the $this->data array. - * + * * @param string $key key for a data value to be added to the $this->data array. * @param mixed $value a data value to be added to the $this->data array. - * - * @return void */ - public function setVar($key, $value) { + public function setVar(string $key, $value): void { $this->__set($key, $value); } /** - * + * * Retreives a data value associated with the given key in the $this->data array. - * + * * @param string $key key for a data value to be retreived from the $this->data array. - * - * + * + * * @throws \OutOfBoundsException if item with specified key is not in the $this->data array. * @return mixed */ - public function getVar($key) { + public function getVar(string $key) { return $this->__get($key); } @@ -372,7 +361,7 @@ public function getVar($key) { * files to be rendered via this class. * */ - public function getFilePaths() { + public function getFilePaths(): array { return $this->file_paths; } @@ -385,47 +374,40 @@ public function getFilePaths() { * to be rendered via an instance of this class. * */ - public function getData() { + public function getData(): array { return $this->data; } /** - * + * * Add a path to the end of the array of path(s) to directorie(s) containing * (*.php) files to be rendered via this class. - * + * * @param string $path a path to the end of the $this->file_paths array. - * - * @return void */ - public function appendPath( $path ) { + public function appendPath( string $path ): void { $this->file_paths[] = $path; } /** - * + * * Add a path to the beginning of the array of path(s) to directorie(s) * containing (*.php) files to be rendered via this class. - * + * * @param string $path a path to the beginning of the $this->file_paths array. - * - * @return void */ - public function prependPath( $path ) { + public function prependPath( string $path ): void { array_unshift($this->file_paths, $path); } /** - * + * * Checks if a path has been registered for an instance of this class - * - * @param string $path - * @return bool */ - public function hasPath($path) { + public function hasPath(string $path): bool { return in_array($path, $this->file_paths); } @@ -440,27 +422,22 @@ public function hasPath($path) { * * @return array an array of the removed elements. */ - public function removeFirstNPaths($number_of_paths_2_remove) { + public function removeFirstNPaths(int $number_of_paths_2_remove): array { - $removed_paths = array(); - - if( is_numeric($number_of_paths_2_remove) ) { - - $number_of_paths_2_remove = (int) $number_of_paths_2_remove; - - while ( - $number_of_paths_2_remove > 0 - && count($this->file_paths) > 0 - ) { - $removed_path = array_shift($this->file_paths); - - if( !is_null($removed_path) ) { - - $removed_paths[] = $removed_path; - } - - $number_of_paths_2_remove--; + $removed_paths = []; + + while ( + $number_of_paths_2_remove > 0 + && count($this->file_paths) > 0 + ) { + $removed_path = array_shift($this->file_paths); + + if( !is_null($removed_path) ) { + + $removed_paths[] = $removed_path; } + + $number_of_paths_2_remove--; } return $removed_paths; @@ -471,31 +448,26 @@ public function removeFirstNPaths($number_of_paths_2_remove) { * Removes the last `n` elements in the array of path(s) to directorie(s) * containing (*.php) files to be rendered via this class. * - * @param string $number_of_paths_2_remove number of elements to remove from the back of $this->file_paths. + * @param int $number_of_paths_2_remove number of elements to remove from the back of $this->file_paths. * * @return array an array of the removed elements. */ - public function removeLastNPaths($number_of_paths_2_remove) { + public function removeLastNPaths(int $number_of_paths_2_remove): array { - $removed_paths = array(); + $removed_paths = []; - if( is_numeric($number_of_paths_2_remove) ) { - - $number_of_paths_2_remove = (int) $number_of_paths_2_remove; - - while ( - $number_of_paths_2_remove > 0 - && count($this->file_paths) > 0 - ) { - $removed_path = array_pop($this->file_paths); - - if( !is_null($removed_path) ) { - - $removed_paths[] = $removed_path; - } - - $number_of_paths_2_remove--; + while ( + $number_of_paths_2_remove > 0 + && count($this->file_paths) > 0 + ) { + $removed_path = array_pop($this->file_paths); + + if( !is_null($removed_path) ) { + + $removed_paths[] = $removed_path; } + + $number_of_paths_2_remove--; } return array_reverse($removed_paths); @@ -557,23 +529,14 @@ public function removeLastNPaths($number_of_paths_2_remove) { * @throws \Rotexsoft\FileRenderer\FileNotFoundException */ public function renderToString( - $file_name='', - array $data = array(), - $escape_encoding = 'utf-8', - array $data_vars_2_html_escape = array(), - array $data_vars_2_html_attr_escape = array(), - array $data_vars_2_css_escape = array(), - array $data_vars_2_js_escape = array() - ) { - if( !is_string($file_name) ) { - - $msg = "ERROR: ". get_class($this) ."::".__FUNCTION__."(..) expects" - . " first parameter (the name of the php file to be rendered) to be a `string`." - . PHP_EOL .'`'. $this->getVarType($file_name, true).'` was supplied with the value below:' - . PHP_EOL . var_export($file_name, true). PHP_EOL ; - - throw new InvalidArgumentException($msg); - } + string $file_name='', + array $data = [], + string $escape_encoding = 'utf-8', + array $data_vars_2_html_escape = [], + array $data_vars_2_html_attr_escape = [], + array $data_vars_2_css_escape = [], + array $data_vars_2_js_escape = [] + ): string { $located_file = $this->locateFile($file_name); @@ -609,14 +572,16 @@ public function renderToString( array_merge($this->data_vars_2_js_escape, $data_vars_2_js_escape) ); - return $this->doRender($located_file, $merged_data); + $output = $this->doRender($located_file, $merged_data); + + return is_string($output) ? $output : ''; } /** - * @return string + * @return string|bool|void */ - protected function doRender(){ - + protected function doRender() { + //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// //// @@ -631,7 +596,7 @@ protected function doRender(){ //// //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// - + try { //func_get_arg(0): the name of the file to be included whose output @@ -643,30 +608,25 @@ protected function doRender(){ ob_start(); $this->includeFile(func_get_arg(0), func_get_arg(1)); - + // Get the captured output and close the buffer return ob_get_clean(); - + } catch(Throwable $e) { // PHP 7+ - + ob_end_clean(); throw $e; - + } catch(Exception $e) { // PHP < 7 - + ob_end_clean(); throw $e; + } // technically, we should never get here } - return ''; // technically, we should never get here - } - - /** - * @param string $file_to_include - * @param array $data - */ - protected function includeFile ($file_to_include, array $data) { - extract(func_get_arg(1)); + protected function includeFile (string $file_to_include, array $data): void { + $funcGetArg = func_get_arg(1); + extract($funcGetArg); include func_get_arg(0); } @@ -685,9 +645,9 @@ public function __toString() { } /** - * + * * Captures and prints out the output that is generated when a renderable php file is executed. - * + * * @param string $file_name Name of php file to be included (with/without * the directory path). If the directory path is * included & the file exists, it is included and @@ -695,30 +655,30 @@ public function __toString() { * not included, the file will be searched for from * the list of directories registered in * $this->file_paths. - * + * * If $file_name still can't be found or is an empty * string or is not supplied, this method tries to * locate $this->file_name if possible and renders * it instead. - * + * * @param array $data Array of data to be extracted to make local variables. * It is combined together with $this->data. For item(s) with * the same key in $data & $this->data, the value of those item(s) * in $data will be used instead of their $this->data value(s). - * + * * @param string $escape_encoding Encoding to be used for escaping data values in $data and $this->data. * See documentation for $this->escape_encoding for more info. - * + * * @param array $data_vars_2_html_escape An array of keys in $data and $this->data whose values (only strings) will be * individually escaped using Laminas\Escaper\Escaper::escapeHtml($string). * Set this for keys in $data and $this->data whose values (only strings) should be * html escaped (anything you would normally escape via htmlspecialchars). - * + * * @param array $data_vars_2_html_attr_escape An array of keys in $data and $this->data whose values (only strings) will be * individually escaped using Laminas\Escaper\Escaper::escapeHtmlAttr($string). * Set this for keys in $data and $this->data with values (only strings) that will be * rendered as attributes within html tags. - * + * * @param array $data_vars_2_css_escape An array of keys in $data and $this->data whose values (only strings) will be * individually escaped using Laminas\Escaper\Escaper::escapeCss($string). * Set this for keys in $data and $this->data with values (only strings) that will be @@ -726,7 +686,7 @@ public function __toString() { * html element. CSS escaping via Laminas\Escaper\Escaper::escapeCss($string) * excludes only basic alphanumeric characters and escapes all other * characters into valid CSS hexadecimal escapes. - * + * * @param array $data_vars_2_js_escape An array of keys in $data and $this->data whose values (only strings) will be * individually escaped using Laminas\Escaper\Escaper::escapeJs($string). * Set this for keys in $data and $this->data with values (only strings) that will be @@ -734,20 +694,19 @@ public function __toString() { * Javascript escaping via Laminas\Escaper\Escaper::escapeJs($string) applies * to all literal strings and digits. It is not possible to safely escape * other Javascript markup. - * - * @return void - * + * + * * @throws \Rotexsoft\FileRenderer\FileNotFoundException */ public function renderToScreen( - $file_name='', - array $data = array(), - $escape_encoding = 'utf-8', - array $data_vars_2_html_escape = array(), - array $data_vars_2_html_attr_escape = array(), - array $data_vars_2_css_escape = array(), - array $data_vars_2_js_escape = array() - ) { + string $file_name='', + array $data = [], + string $escape_encoding = 'utf-8', + array $data_vars_2_html_escape = [], + array $data_vars_2_html_attr_escape = [], + array $data_vars_2_css_escape = [], + array $data_vars_2_js_escape = [] + ): void { echo $this->renderToString( $file_name, $data, @@ -762,11 +721,8 @@ public function renderToScreen( /** * Escape a string for the HTML Body context where there are very few characters * of special meaning. Internally this will use htmlspecialchars(). - * - * @param string $string - * @return string */ - public function escapeHtml($string) { + public function escapeHtml(string $string): string { return $this->escaper->escapeHtml($string); } @@ -775,11 +731,8 @@ public function escapeHtml($string) { * Escape a string for the HTML Attribute context. We use an extended set of characters * to escape that are not covered by htmlspecialchars() to cover cases where an attribute * might be unquoted or quoted illegally (e.g. backticks are valid quotes for IE). - * - * @param string $string - * @return string */ - public function escapeHtmlAttr($string) { + public function escapeHtmlAttr(string $string): string { return $this->escaper->escapeHtmlAttr($string); } @@ -787,11 +740,8 @@ public function escapeHtmlAttr($string) { /** * Escape a string for the CSS context. CSS escaping can be applied to any string being * inserted into CSS and escapes everything except alphanumerics. - * - * @param string $string - * @return string */ - public function escapeCss($string) { + public function escapeCss(string $string): string { return $this->escaper->escapeCss($string); } @@ -804,11 +754,8 @@ public function escapeCss($string) { * of cases where HTML escaping was not applied on top of Javascript escaping correctly. * Backslash escaping is not used as it still leaves the escaped character as-is and so * is not useful in a HTML context. - * - * @param string $string - * @return string */ - public function escapeJs($string) { + public function escapeJs(string $string): string { return $this->escaper->escapeJs($string); } @@ -817,53 +764,49 @@ public function escapeJs($string) { * Escape a string for the URI or Parameter contexts. This should not be used to escape * an entire URI - only a subcomponent being inserted. The function is a simple proxy * to rawurlencode() which now implements RFC 3986 since PHP 5.3 completely. - * - * @param string $string - * @return string */ - public function escapeUrl($string) { + public function escapeUrl(string $string): string { return $this->escaper->escapeUrl($string); } /** - * + * * Escapes values in an array and all its sub-arrays. - * + * * @param array $data Array of data to be escaped. This array will be modifed during the escape operation. - * + * * @param string $escape_encoding Encoding to be used for escaping data values in $data and $this->data. * If this value is empty, the value of $this->escape_encoding will be used * if it's not empty, else the default value of 'utf-8' will be finally used. * See documentation for $this->escape_encoding for more info. - * + * * @param array $data_vars_2_html_escape An array of keys in $data whose values (only strings) will be * individually escaped using Laminas\Escaper\Escaper::escapeHtml($string). - * + * * @param array $data_vars_2_html_attr_escape An array of keys in $data whose values (only strings) will be * individually escaped using Laminas\Escaper\Escaper::escapeHtmlAttr($string). - * + * * @param array $data_vars_2_css_escape An array of keys in $data whose values (only strings) will be * individually escaped using Laminas\Escaper\Escaper::escapeCss($string). - * + * * @param array $data_vars_2_js_escape An array of keys in $data whose values (only strings) will be * individually escaped using Laminas\Escaper\Escaper::escapeJs($string). - * + * * @param \Laminas\Escaper\Escaper $escaper An optional escaper object that will be used for escaping. - * - * @return void + * * * @throws \Rotexsoft\FileRenderer\FileNotFoundException */ protected function escapeData( array &$data, - $escape_encoding = 'utf-8', - array $data_vars_2_html_escape = array(), - array $data_vars_2_html_attr_escape = array(), - array $data_vars_2_css_escape = array(), - array $data_vars_2_js_escape = array(), + string $escape_encoding = 'utf-8', + array $data_vars_2_html_escape = [], + array $data_vars_2_html_attr_escape = [], + array $data_vars_2_css_escape = [], + array $data_vars_2_js_escape = [], Escaper $escaper = null - ) { + ): void { if ( count($data) <= 0 ) { //no data supplied; nothing to do @@ -912,21 +855,23 @@ protected function escapeData( } foreach( $data as $key => $value ) { - - $methods = array(); - + + $methods = []; + if(in_array($key, $data_vars_2_html_escape) || in_array('*', $data_vars_2_html_escape)) { $methods[] = 'escapeHtml'; } - + if(in_array($key, $data_vars_2_html_attr_escape) || in_array('*', $data_vars_2_html_attr_escape)) { $methods[] = 'escapeHtmlAttr'; } - + if(in_array($key, $data_vars_2_css_escape) || in_array('*', $data_vars_2_css_escape)) { $methods[] = 'escapeCss'; } - + if(in_array($key, $data_vars_2_js_escape) || in_array('*', $data_vars_2_js_escape)) { $methods[] = 'escapeJs'; } - - if( count($methods) > 0 || is_array($data[$key]) ) { - + + /** @noRector \Rector\Php71\Rector\FuncCall\CountOnNullRector */ + if( + count($methods) > 0 || is_array($data[$key]) + ) { if( is_array($data[$key]) ) { - + // recursively escape sub-array $this->escapeData( $data[$key], @@ -937,11 +882,11 @@ protected function escapeData( $data_vars_2_js_escape, $escaper // pass already instantiated escaper ); - + } else if( is_string($data[$key]) ) { - + foreach($methods as $method) { - + // escape the value $data[$key] = $escaper->$method($data[$key]); } @@ -983,16 +928,7 @@ protected function escapeData( * * @throws \InvalidArgumentException */ - public function locateFile($file_name) { - - if( !is_string($file_name) ) { - - $msg = "ERROR: ". get_class($this) ."::".__FUNCTION__."(...) expects first parameter (the name of the php file to be located) to be a `string`." - . PHP_EOL .'`'. $this->getVarType($file_name, true).'` was supplied with the value below:' - . PHP_EOL . var_export($file_name, true). PHP_EOL ; - - throw new InvalidArgumentException($msg); - } + public function locateFile(string $file_name) { $ds = DIRECTORY_SEPARATOR; @@ -1028,12 +964,11 @@ public function locateFile($file_name) { } /** - * + * * Trims off the right-most character at the end of the string `$file_path` * if it is a directory separator charater (ie. '\' or '/'). - * - * @param string $file_path - * + * + * * @return string `$file_path` as is if right-most character at the end of the * string is not a directory separator charater (ie. '\' or '/'). * If the right-most character at the end of the string `$file_path` @@ -1041,7 +976,7 @@ public function locateFile($file_name) { * `$file_path` without the right-most directory separator charater * at the end. */ - protected function normalizeFolderPath($file_path) { + protected function normalizeFolderPath(string $file_path): string { //trim right-most linux style path separator if any $trimed_path = rtrim($file_path, '/'); @@ -1065,7 +1000,7 @@ protected function normalizeFolderPath($file_path) { * * @return string the variable's type. */ - protected function getVarType($var, $cap_first=false) { + protected function getVarType($var, bool $cap_first=false): string { if( is_object($var) ) { return $cap_first ? ucfirst(get_class($var)) : get_class($var); } diff --git a/tests/RendererTest.php b/tests/RendererTest.php index ab003f2..9a89cba 100644 --- a/tests/RendererTest.php +++ b/tests/RendererTest.php @@ -166,39 +166,6 @@ public function testThatConstructorWorksAsExpected() { $this->assertEquals(array(), $js_escaper_keys_in_obj->getValue($renderer)); } - public function testThatExceptionIsThrownWhenNonStringFileNameIsPassedToConstructor() { - - $this->expectException(\InvalidArgumentException::class); - - $invalid_file_name = array(); - $renderer = new FileRendererWrapper($invalid_file_name); - } - - public function testExceptionMessageWhenNonStringFileNameIsPassedToConstructor() { - - $expected_msg = <<getMessage().PHP_EOL.'yoooo'.PHP_EOL; - $this->assertEquals($expected_msg, $e->getMessage()); - } - } - public function testThat__setWorksAsExpected() { $renderer = new FileRendererWrapper('file.txt'); @@ -527,50 +494,6 @@ public function testThatRenderToScreenWorksAsExpected() { $this->assertEquals($data['var1'], $result); } - public function testThatExceptionIsThrownWhenNonStringFileNameIsPassedToLocateFile() { - - $this->expectException(\InvalidArgumentException::class); - - $renderer = new FileRendererWrapper('file.txt'); - $invalid_file_name = array(); - $renderer->locateFile($invalid_file_name); - } - - - public function testExceptionMessageWhenNonStringFileNameIsPassedToLocateFile() { - - $expected_msg = <<locateFile($invalid_file_name); - - //if the call to locateFile above did not throw an exception, then this test should fail - $message = __FUNCTION__. '(): Expected exception not thrown when locating file with an' - . ' invalid (non-string) file name'; - throw new \Exception($message); - - } catch (\Exception $e) { - - $this->assertEquals($expected_msg, $e->getMessage()); - } - } - - public function testThatExceptionIsThrownWhenNonStringFileNameIsPassedToRenderToString() { - - $this->expectException(\InvalidArgumentException::class); - - $renderer = new FileRendererWrapper('file.txt'); - $invalid_file_name = array(); - $renderer->renderToString($invalid_file_name); - } - public function testThatExceptionIsThrownWhenNonExistentFileNameIsPassedToRenderToString() { $this->expectException(\Rotexsoft\FileRenderer\FileNotFoundException::class); @@ -606,31 +529,6 @@ public function testExceptionMessageWhenNonExistentFileNameIsPassedToRenderToStr } } - public function testExceptionMessageWhenNonStringFileNameIsPassedToRenderToString() { - - $expected_msg = <<renderToString($invalid_file_name); - - //if the call to locateFile above did not throw an exception, then this test should fail - $message = __FUNCTION__. '(): Expected exception not thrown when rendering file with an' - . ' invalid (non-string) file name'; - throw new \Exception($message); - - } catch (\Exception $e) { - - $this->assertEquals($expected_msg, $e->getMessage()); - } - } - public function testThatEscapeDataWorksAsExpected() { $file_name = 'view.php';