Skip to content

Commit

Permalink
Throw a JsonMapperException if php configuration discards comments. (#13
Browse files Browse the repository at this point in the history
)

- Throw a JsonMapperException if php configuration discards comments, by some setting in the configuration file. 
- Add tests related to the changes.
- Enable tests in .yml file for PHP 8.1 and related changes.
  • Loading branch information
Mohammad-Haris authored May 23, 2022
1 parent 9a2ceb1 commit 731ecf2
Show file tree
Hide file tree
Showing 20 changed files with 175 additions and 4 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
if: "! contains(toJSON(github.event.head_commit.message), 'skip ci')"
strategy:
matrix:
php: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0']
php: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1']
include:
- php: 5.6
phpunit: 5
Expand All @@ -26,6 +26,8 @@ jobs:
phpunit: 7
- php: 8.0
phpunit: 8
- php: 8.1
phpunit: 9
steps:
- name: Checkout
uses: actions/checkout@v2
Expand Down
4 changes: 3 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ gives you, but for JSON.
Note that it does not rely on any schema, only your class definitions.

Type detection works by parsing ``@var`` docblock annotations of
class properties, as well as type hints in setter methods.
class properties, as well as type hints in setter methods. If docblock comments,
or comments in general are discarded through some configuration setting like ``opcache.save_comments=0``,
or any other similar configuration, an exception is thrown, blocking any further operation.

You do not have to modify your model classes by adding JSON specific code;
it works automatically by parsing already-existing docblocks.
Expand Down
76 changes: 74 additions & 2 deletions src/JsonMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,75 @@ class JsonMapper
*/
protected $arInspectedClasses = array();

/**
* An array of directives from php defined configuration files.
*
* @var array|null Array of values from the configuration files.
*/
protected $config = null;

protected $zendOptimizerPlusExtensionLoaded = null;

/**
* Constructor for JsonMapper.
*
* @throws JsonMapperException
*/
function __construct()
{
$zendOptimizerPlus = "Zend Optimizer+";
$zendOptimizerPlusSaveCommentKey = "zend_optimizerplus.save_comments";
$opCacheSaveCommentKey = "opcache.save_comments";

if (!isset($this->config)) {
$this->config = parse_ini_file(php_ini_loaded_file());
}
if (!isset($this->zendOptimizerPlusExtensionLoaded)) {
$this->zendOptimizerPlusExtensionLoaded
= extension_loaded($zendOptimizerPlus);
}

$zendOptimizerDiscardedComments
= $this->zendOptimizerPlusExtensionLoaded === true
&& $this->commentsDiscardedFor($zendOptimizerPlusSaveCommentKey);

$opCacheDiscardedComments
= $this->commentsDiscardedFor($opCacheSaveCommentKey);

if ($zendOptimizerDiscardedComments || $opCacheDiscardedComments) {
throw JsonMapperException::commentsDisabledInConfigurationException(
array($zendOptimizerPlusSaveCommentKey, $opCacheSaveCommentKey)
);
}
}

/**
* Returns true if comments are disabled locally or in php.ini file.
* However, if comments are enabled locally by overwriting global
* php.ini configurations then returns false.
*
* @param string $configKey Configuration key to be checked.
*
* @return bool Whether comments are disabled in environment or php.ini file.
*/
protected function commentsDiscardedFor($configKey)
{
$localConfigVal = strtolower(ini_get($configKey));
$phpIniConfigVal = !array_key_exists($configKey, $this->config) ? ''
: strtolower($this->config[$configKey]);

$enableValues = ["1", "on", "true", "yes"];
$disableValues = ["0", "off", "false", "no"];

$notEnabled = in_array($localConfigVal, $enableValues, true) === false;
$isDisabled = in_array($localConfigVal, $disableValues, true) === true;
$isDisabledInPhpIniFile = in_array(
$phpIniConfigVal, $disableValues, true
) === true;

return $notEnabled && ($isDisabled || $isDisabledInPhpIniFile);
}

/**
* Map data all data in $json into the given $object instance.
*
Expand Down Expand Up @@ -1428,12 +1497,15 @@ protected function isFlatType($type)
/**
* Is type registered with mapper
*
* @param string $type Class name
* @param string|null $type Class name
*
* @return boolean True if registered with $this->arChildClasses
* @return boolean True if registered with $this->arChildClasses
*/
protected function isRegisteredType($type)
{
if (!isset($type)) {
return false;
}
return isset($this->arChildClasses[ltrim($type, "\\")]);
}

Expand Down
18 changes: 18 additions & 0 deletions src/JsonMapperException.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,23 @@
*/
class JsonMapperException extends \Exception
{
/**
* Exception for discarded comments setting in configuration.
*
* @param array $concernedKeys Keys (PHP directives) with issues
*
* @return JsonMapperException
*/
static function commentsDisabledInConfigurationException($concernedKeys)
{
$concernedKeys = implode(", ", $concernedKeys);

return new self(
"Comments cannot be discarded in the configuration file i.e." .
" the php.ini file; doc comments are a requirement for JsonMapper." .
" Following configuration keys must have a value set to \"1\":" .
" {$concernedKeys}."
);
}
}
?>
43 changes: 43 additions & 0 deletions tests/JsonMapperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* @license OSL-3.0 http://opensource.org/licenses/osl-3.0
* @link http://www.netresearch.de/
*/

require_once 'JsonMapperTest/Array.php';
require_once 'JsonMapperTest/Broken.php';
require_once 'JsonMapperTest/DependencyInjector.php';
Expand All @@ -26,6 +27,7 @@
require_once 'JsonMapperTest/MapsWithSetters.php';
require_once 'JsonMapperTest/ClassWithCtor.php';
require_once 'JsonMapperTest/ComplexClassWithCtor.php';
require_once 'JsonMapperTest/JsonMapperCommentsDiscardedException.php';

if (PHP_VERSION_ID >= 70000) {
require_once 'JsonMapperTest/Php7TypedClass.php';
Expand Down Expand Up @@ -406,6 +408,47 @@ public function testMapClassWithNonObject()
$sn = $jm->mapClass(123, 'JsonMapperTest_Simple');
}

public function testOpCacheSaveCommentsDiscarded()
{
$On = ["1", "on", "true", "yes"];

$opCahceSaveCommentsLocal = in_array(
strtolower(ini_get("opcache.save_comments")), $On, true
);

if ($opCahceSaveCommentsLocal === false) {
$this->expectException(JsonMapperException::class);
$this->expectExceptionMessage("Comments cannot be discarded in the configuration file i.e. the php.ini file; doc comments are a requirement for JsonMapper. Following configuration keys must have a value set to \"1\": zend_optimizerplus.save_comments, opcache.save_comments.");

$config = parse_ini_file(php_ini_loaded_file());

$config["opcache.save_comments"] = "0";

new JsonMapperCommentsDiscardedException($config);
}

else {
$this->assertInstanceOf(JsonMapper::class, new JsonMapper());
}
}

/**
* This test assumes that zend_optimizerplus.save_comments key is either not present in the local PHP directives or is set to "0".
* This is true, at the time of writing, for the Github Actions environment, hence an exception is thrown.
* Furthermore, the class JsonMapperCommentsDiscardedException mocks the loading of Zend Optimizer+ extension.
*/
public function testZendOptimizerPlusCommentsDiscarded()
{
$this->expectException(JsonMapperException::class);
$this->expectExceptionMessage("Comments cannot be discarded in the configuration file i.e. the php.ini file; doc comments are a requirement for JsonMapper. Following configuration keys must have a value set to \"1\": zend_optimizerplus.save_comments, opcache.save_comments.");

$config = parse_ini_file(php_ini_loaded_file());

$config["zend_optimizerplus.save_comments"] = "0";

new JsonMapperCommentsDiscardedException($config);
}

public function testMapNullJson()
{
$this->expectException(InvalidArgumentException::class);
Expand Down
20 changes: 20 additions & 0 deletions tests/JsonMapperTest/JsonMapperCommentsDiscardedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

use apimatic\jsonmapper\JsonMapperException;
use apimatic\jsonmapper\JsonMapper;

class JsonMapperCommentsDiscardedException extends JsonMapper
{
/**
* @throws JsonMapperException
*/
function __construct($config)
{
$this->config = $config;

$this->zendOptimizerPlusExtensionLoaded = true;

parent::__construct();
}
}
?>
1 change: 1 addition & 0 deletions tests/multitypetest/model/Atom.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public function setNumberOfProtons($numberOfProtons)
*
* @return array|stdClass
*/
#[\ReturnTypeWillChange]
public function jsonSerialize($asArrayWhenEmpty = false)
{
$json = [];
Expand Down
1 change: 1 addition & 0 deletions tests/multitypetest/model/Car.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public function setHaveTrunk($haveTrunk)
*
* @return array|stdClass
*/
#[\ReturnTypeWillChange]
public function jsonSerialize($asArrayWhenEmpty = false)
{
$json = [];
Expand Down
1 change: 1 addition & 0 deletions tests/multitypetest/model/ComplexCaseA.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ public function setOptional($optional)
*
* @return array|stdClass
*/
#[\ReturnTypeWillChange]
public function jsonSerialize($asArrayWhenEmpty = false)
{
$json = [];
Expand Down
1 change: 1 addition & 0 deletions tests/multitypetest/model/ComplexCaseB.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public function setOptional($optional)
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public function jsonSerialize($asArrayWhenEmpty = false)
{
$json = [];
Expand Down
1 change: 1 addition & 0 deletions tests/multitypetest/model/Employee.php
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ public function addAdditionalProperty($name, $value)
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public function jsonSerialize($asArrayWhenEmpty = false)
{
$json = [];
Expand Down
1 change: 1 addition & 0 deletions tests/multitypetest/model/Evening.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ public function setSessionType($sessionType)
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public function jsonSerialize($asArrayWhenEmpty = false)
{
$json = [];
Expand Down
1 change: 1 addition & 0 deletions tests/multitypetest/model/Morning.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ public function setSessionType($sessionType)
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public function jsonSerialize($asArrayWhenEmpty = false)
{
$json = [];
Expand Down
1 change: 1 addition & 0 deletions tests/multitypetest/model/Orbit.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public function setNumberOfElectrons($numberOfElectrons)
*
* @return array|stdClass
*/
#[\ReturnTypeWillChange]
public function jsonSerialize($asArrayWhenEmpty = false)
{
$json = [];
Expand Down
1 change: 1 addition & 0 deletions tests/multitypetest/model/OuterArrayCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public function setValue($value)
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public function jsonSerialize($asArrayWhenEmpty = false)
{
$json = [];
Expand Down
1 change: 1 addition & 0 deletions tests/multitypetest/model/Person.php
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ public function addAdditionalProperty($name, $value)
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public function jsonSerialize($asArrayWhenEmpty = false)
{
$json = [];
Expand Down
1 change: 1 addition & 0 deletions tests/multitypetest/model/Postman.php
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ public function addAdditionalProperty($name, $value)
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public function jsonSerialize($asArrayWhenEmpty = false)
{
$json = [];
Expand Down
1 change: 1 addition & 0 deletions tests/multitypetest/model/SimpleCaseA.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public function setValue($value)
*
* @return array|stdClass
*/
#[\ReturnTypeWillChange]
public function jsonSerialize($asArrayWhenEmpty = false)
{
$json = [];
Expand Down
1 change: 1 addition & 0 deletions tests/multitypetest/model/SimpleCaseB.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public function setValue($value)
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public function jsonSerialize($asArrayWhenEmpty = false)
{
$json = [];
Expand Down
1 change: 1 addition & 0 deletions tests/multitypetest/model/Vehicle.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public function setNumberOfTyres($numberOfTyres)
*
* @return array|stdClass
*/
#[\ReturnTypeWillChange]
public function jsonSerialize($asArrayWhenEmpty = false)
{
$json = [];
Expand Down

0 comments on commit 731ecf2

Please sign in to comment.