Address github comments

This commit is contained in:
Romain Neutron
2013-05-31 10:16:27 +02:00
parent bdcb98a3d5
commit dddf316f29
12 changed files with 131 additions and 46 deletions

View File

@@ -32,12 +32,12 @@ class PluginServiceProvider implements ServiceProviderInterface
$app['plugins.directory'] = realpath(__DIR__ . '/../../../../../plugins'); $app['plugins.directory'] = realpath(__DIR__ . '/../../../../../plugins');
$app['plugins.schema'] = realpath(__DIR__ . '/../../../../conf.d/plugin-schema.json'); $app['plugins.schema'] = realpath(__DIR__ . '/../../../../conf.d/plugin-schema.json');
$app['json-validator'] = $app->share(function (Application $app) { $app['plugins.json-validator'] = $app->share(function (Application $app) {
return new JsonValidator(); return new JsonValidator();
}); });
$app['plugins.manifest-validator'] = $app->share(function (Application $app) { $app['plugins.manifest-validator'] = $app->share(function (Application $app) {
return ManifestValidator::create($app['json-validator'], $app['plugins.schema']); return ManifestValidator::create($app);
}); });
$app['plugins.plugins-validator'] = $app->share(function (Application $app) { $app['plugins.plugins-validator'] = $app->share(function (Application $app) {

View File

@@ -1,5 +1,14 @@
<?php <?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2013 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Provider; namespace Alchemy\Phrasea\Core\Provider;
use Neutron\TemporaryFilesystem\TemporaryFilesystem; use Neutron\TemporaryFilesystem\TemporaryFilesystem;

View File

@@ -42,39 +42,66 @@ class AutoloaderGenerator
private function createLoader($manifests) private function createLoader($manifests)
{ {
$buffer = "<?php\n" $buffer = <<<EOF
."\n// This file is automatically generated, please do not edit it.\n" <?php
."// To update configuration, use bin/console plugins:* commands.\n"
."\nreturn call_user_func(function () {\n"; // This file is automatically generated, please do not edit it.
// To update configuration, use bin/console plugins:* commands.
return call_user_func(function () {
EOF;
foreach ($manifests as $manifest) { foreach ($manifests as $manifest) {
$buffer .= " require __DIR__ . '/" . $manifest->getName() . DIRECTORY_SEPARATOR . "vendor" . DIRECTORY_SEPARATOR . "autoload.php';\n"; $autoloader = '/' . $manifest->getName() . DIRECTORY_SEPARATOR . "vendor" . DIRECTORY_SEPARATOR . "autoload.php";
$buffer .= <<<EOF
require __DIR__ . '$autoloader';
EOF;
} }
// composer loader are preprent // composer loader are preprent
$buffer .= " \$loader = require __DIR__ . '/../vendor/autoload.php';\n"; $autoloader = '/../vendor/autoload.php';
$buffer .= <<<EOF
$buffer .= "\n return \$loader;\n});\n"; \$loader = require __DIR__ . '$autoloader';
return \$loader;\n});
EOF;
return $buffer; return $buffer;
} }
private function createServices($manifests) private function createServices($manifests)
{ {
$buffer = "<?php\n" $buffer = <<<EOF
."\n// This file is automatically generated, please do not edit it.\n" <?php
."// To update configuration, use bin/console plugins:* commands.\n"
."\nuse Alchemy\Phrasea\Application;\n" // This file is automatically generated, please do not edit it.
."\nreturn call_user_func(function (Application \$app) {" // To update configuration, use bin/console plugins:* commands.
."\n";
use Alchemy\Phrasea\Application;
return call_user_func(function (Application \$app) {
EOF;
foreach ($manifests as $manifest) { foreach ($manifests as $manifest) {
foreach ($manifest->getServices() as $service) { foreach ($manifest->getServices() as $service) {
$buffer .= " \$app->register(\\".$service['class']."::create(\$app));\n"; $class = $service['class'];
$buffer .= <<<EOF
\$app->register($class::create(\$app));
EOF;
} }
} }
$buffer .= "\n return \$app;\n}, \$app);\n"; $buffer .= <<<EOF
return \$app;
}, \$app);
EOF;
return $buffer; return $buffer;
} }

View File

@@ -11,22 +11,26 @@
namespace Alchemy\Phrasea\Plugin\Schema; namespace Alchemy\Phrasea\Plugin\Schema;
use Alchemy\Phrasea\Application;
use JsonSchema\Validator as JsonValidator; use JsonSchema\Validator as JsonValidator;
use Alchemy\Phrasea\Exception\InvalidArgumentException; use Alchemy\Phrasea\Exception\InvalidArgumentException;
use Alchemy\Phrasea\Plugin\Exception\JsonValidationException; use Alchemy\Phrasea\Plugin\Exception\JsonValidationException;
use Alchemy\Phrasea\Core\Version;
class ManifestValidator class ManifestValidator
{ {
private $validator; private $validator;
private $version;
private $schemaData; private $schemaData;
public function __construct(JsonValidator $validator, $schemaData) public function __construct(JsonValidator $validator, $schemaData, Version $version)
{ {
if (!is_object($schemaData)) { if (!is_object($schemaData)) {
throw new InvalidArgumentException('Json Schema must be an object'); throw new InvalidArgumentException('Json Schema must be an object');
} }
$this->validator = $validator; $this->validator = $validator;
$this->version = $version;
$this->schemaData = $schemaData; $this->schemaData = $schemaData;
} }
@@ -36,12 +40,12 @@ class ManifestValidator
throw new InvalidArgumentException('Json Schema must be an object'); throw new InvalidArgumentException('Json Schema must be an object');
} }
$validator = clone $this->validator; $this->validator->reset();
$validator->check($data, $this->schemaData); $this->validator->check($data, $this->schemaData);
if (!$validator->isValid()) { if (!$this->validator->isValid()) {
$errors = array(); $errors = array();
foreach ((array) $validator->getErrors() as $error) { foreach ((array) $this->validator->getErrors() as $error) {
$errors[] = ($error['property'] ? $error['property'].' : ' : '').$error['message']; $errors[] = ($error['property'] ? $error['property'].' : ' : '').$error['message'];
} }
throw new JsonValidationException('Manifest file does not match the expected JSON schema', $errors); throw new JsonValidationException('Manifest file does not match the expected JSON schema', $errors);
@@ -51,17 +55,35 @@ class ManifestValidator
throw new JsonValidationException('Does not match the expected JSON schema', array('"name" must not contains only alphanumeric caracters')); throw new JsonValidationException('Does not match the expected JSON schema', array('"name" must not contains only alphanumeric caracters'));
} }
// validate gainst versions if (isset($data->{'minimum-phraseanet-version'})) {
if (true !== version_compare($this->version->getNumber(), $data->{'minimum-phraseanet-version'}, '>=')) {
throw new JsonValidationException(sprintf(
'Version incomptibility : Minimum Phraseanet version required is %s, current version is %s',
$data->{'minimum-phraseanet-version'},
$this->version->getNumber()
));
}
} }
public static function create(JsonValidator $jsonValidator, $path) if (isset($data->{'maximum-phraseanet-version'})) {
if (true !== version_compare($this->version->getNumber(), $data->{'maximum-phraseanet-version'}, '<')) {
throw new JsonValidationException(sprintf(
'Version incomptibility : Maximum Phraseanet version required is %s, current version is %s',
$data->{'maximum-phraseanet-version'},
$this->version->getNumber()
));
}
}
}
public static function create(Application $app)
{ {
$data = @json_decode(@file_get_contents($path)); $data = @json_decode(@file_get_contents($app['plugins.schema']));
if (JSON_ERROR_NONE !== json_last_error()) { if (JSON_ERROR_NONE !== json_last_error()) {
throw new InvalidArgumentException(sprintf('Unable to read %s', $path)); throw new InvalidArgumentException(sprintf('Unable to read %s', $app['plugins.schema']));
} }
return new static($jsonValidator, $data); return new static($app['plugins.json-validator'], $data, $app['phraseanet.version']);
} }
} }

View File

@@ -43,8 +43,7 @@ class PluginValidator
throw new PluginValidationException('Manifest file is invalid', $e->getCode(), $e); throw new PluginValidationException('Manifest file is invalid', $e->getCode(), $e);
} }
// a ameliorer return new Manifest($this->objectToArray($data));
return new Manifest(@json_decode(@file_get_contents($manifest), true));
} }
private function ensureManifest($directory) private function ensureManifest($directory)
@@ -65,4 +64,17 @@ class PluginValidator
throw new PluginValidationException(sprintf('Required file %s is not present.', $file)); throw new PluginValidationException(sprintf('Required file %s is not present.', $file));
} }
} }
private function objectToArray($data)
{
if (is_object($data)) {
$data = get_object_vars($data);
}
if (is_array($data)) {
return array_map(array($this, 'objectToArray'), $data);
}
return $data;
}
} }

View File

@@ -16,7 +16,7 @@ class PluginServiceProvidertest extends ServiceProviderTestCase
return array( return array(
array( array(
'Alchemy\Phrasea\Core\Provider\PluginServiceProvider', 'Alchemy\Phrasea\Core\Provider\PluginServiceProvider',
'json-validator', 'plugins.json-validator',
'JsonSchema\Validator' 'JsonSchema\Validator'
), ),
array( array(

View File

@@ -0,0 +1,5 @@
{
"name": "TestPlugin",
"description" : "A custom class connector",
"minimum-phraseanet-version": "14"
}

View File

@@ -0,0 +1,5 @@
{
"name": "TestPlugin",
"description" : "A custom class connector",
"maximum-phraseanet-version": "3.8"
}

View File

@@ -33,7 +33,7 @@ class AutoloaderGeneratorTest extends \PHPUnit_Framework_TestCase
$this->assertFileExists($file); $this->assertFileExists($file);
$process = ProcessBuilder::create(array($php, '-l', $file))->getProcess(); $process = ProcessBuilder::create(array($php, '-l', $file))->getProcess();
$process->run(); $process->run();
$this->assertTrue($process->isSuccessful()); $this->assertTrue($process->isSuccessful(), basename($file) . ' is valid');
} }
// test autoload // test autoload

View File

@@ -2,8 +2,15 @@
namespace Alchemy\Tests\Phrasea\Plugin; namespace Alchemy\Tests\Phrasea\Plugin;
class PluginTestCase extends \PHPUnit_Framework_TestCase use Alchemy\Phrasea\Plugin\Schema\ManifestValidator;
class PluginTestCase extends \PhraseanetPHPUnitAbstract
{ {
protected function createManifestValidator()
{
return ManifestValidator::create(self::$DI['app']);
}
protected function getPluginDirectory() protected function getPluginDirectory()
{ {
return __DIR__ . DIRECTORY_SEPARATOR . 'PluginFolder'; return __DIR__ . DIRECTORY_SEPARATOR . 'PluginFolder';

View File

@@ -42,6 +42,8 @@ class ManifestValidatorTest extends PluginTestCase
array(__DIR__ . '/../Fixtures/manifest-wrong2.json'), array(__DIR__ . '/../Fixtures/manifest-wrong2.json'),
array(__DIR__ . '/../Fixtures/manifest-wrong3.json'), array(__DIR__ . '/../Fixtures/manifest-wrong3.json'),
array(__DIR__ . '/../Fixtures/manifest-wrong4.json'), array(__DIR__ . '/../Fixtures/manifest-wrong4.json'),
array(__DIR__ . '/../Fixtures/manifest-wrong5-min-version.json'),
array(__DIR__ . '/../Fixtures/manifest-wrong6-max-version.json'),
); );
} }
@@ -59,12 +61,12 @@ class ManifestValidatorTest extends PluginTestCase
*/ */
public function testConstructWithInvalidSchema() public function testConstructWithInvalidSchema()
{ {
$validator = new ManifestValidator(new JsonSchemaValidator(), array()); new ManifestValidator(new JsonSchemaValidator(), array(), self::$DI['app']['phraseanet.version']);
} }
public function testCreate() public function testCreate()
{ {
$validator = ManifestValidator::create(new JsonSchemaValidator(), $this->getSchemaPath()); $validator = ManifestValidator::create(self::$DI['app']);
$this->assertInstanceOf('Alchemy\Phrasea\Plugin\Schema\ManifestValidator', $validator); $this->assertInstanceOf('Alchemy\Phrasea\Plugin\Schema\ManifestValidator', $validator);
} }
@@ -73,6 +75,6 @@ class ManifestValidatorTest extends PluginTestCase
{ {
$schema = json_decode($this->getSchema()); $schema = json_decode($this->getSchema());
return new ManifestValidator(new JsonSchemaValidator(), $schema); return new ManifestValidator(new JsonSchemaValidator(), $schema, self::$DI['app']['phraseanet.version']);
} }
} }

View File

@@ -15,9 +15,7 @@ class PluginValidatorTest extends PluginTestCase
*/ */
public function testValidateInvalidPlugin($directory) public function testValidateInvalidPlugin($directory)
{ {
$schema = json_decode($this->getSchema()); $validator = new PluginValidator($this->createManifestValidator());
$validator = new PluginValidator(new ManifestValidator(new JsonValidator(), $schema));
$validator->validatePlugin($directory); $validator->validatePlugin($directory);
} }
@@ -26,9 +24,7 @@ class PluginValidatorTest extends PluginTestCase
*/ */
public function testValidatePlugin($directory) public function testValidatePlugin($directory)
{ {
$schema = json_decode($this->getSchema()); $validator = new PluginValidator($this->createManifestValidator());
$validator = new PluginValidator(new ManifestValidator(new JsonValidator(), $schema));
$validator->validatePlugin($directory); $validator->validatePlugin($directory);
} }