diff --git a/lib/Alchemy/Phrasea/Command/Plugin/AddPlugin.php b/lib/Alchemy/Phrasea/Command/Plugin/AddPlugin.php
index ceaa403933..d8891093fb 100644
--- a/lib/Alchemy/Phrasea/Command/Plugin/AddPlugin.php
+++ b/lib/Alchemy/Phrasea/Command/Plugin/AddPlugin.php
@@ -50,6 +50,13 @@ class AddPlugin extends AbstractPluginCommand
$this->container['filesystem']->mirror($temporaryDir, $targetDir);
$output->writeln(" OK");
+ $output->write("Copying public files ".$manifest->getName()."...");
+ $this->container['filesystem']->mirror(
+ $targetDir . DIRECTORY_SEPARATOR . 'public',
+ $this->container['root.path'] . DIRECTORY_SEPARATOR . 'www' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . $manifest->getName()
+ );
+ $output->writeln(" OK");
+
$output->write("Removing temporary directory...");
$this->container['filesystem']->remove($temporaryDir);
$output->writeln(" OK");
diff --git a/lib/Alchemy/Phrasea/Plugin/Schema/PluginValidator.php b/lib/Alchemy/Phrasea/Plugin/Schema/PluginValidator.php
index 0b0cadbdde..416b09d2aa 100644
--- a/lib/Alchemy/Phrasea/Plugin/Schema/PluginValidator.php
+++ b/lib/Alchemy/Phrasea/Plugin/Schema/PluginValidator.php
@@ -29,6 +29,7 @@ class PluginValidator
{
$this->ensureComposer($directory);
$this->ensureManifest($directory);
+ $this->ensureDir($directory . DIRECTORY_SEPARATOR . 'public');
$manifest = $directory . DIRECTORY_SEPARATOR . 'manifest.json';
$data = @json_decode(@file_get_contents($manifest));
@@ -58,6 +59,13 @@ class PluginValidator
$this->ensureFile($composer);
}
+ private function ensureDir($dir)
+ {
+ if (!file_exists($dir) || !is_dir($dir) || !is_readable($dir)) {
+ throw new PluginValidationException(sprintf('Missing mandatory directory %s', $dir));
+ }
+ }
+
private function ensureFile($file)
{
if (!file_exists($file) || !is_file($file) || !is_readable($file)) {
diff --git a/tests/Alchemy/Tests/Phrasea/Command/Plugin/AddPluginTest.php b/tests/Alchemy/Tests/Phrasea/Command/Plugin/AddPluginTest.php
index f5949dc939..b3816695b3 100644
--- a/tests/Alchemy/Tests/Phrasea/Command/Plugin/AddPluginTest.php
+++ b/tests/Alchemy/Tests/Phrasea/Command/Plugin/AddPluginTest.php
@@ -62,6 +62,10 @@ class AddPluginTest extends PluginCommandTestCase
->with('tempdir', self::$DI['app']['plugins.directory'].'/TestPlugin');
self::$DI['app']['filesystem']->expects($this->at(1))
+ ->method('mirror')
+ ->with(self::$DI['app']['plugins.directory'].'/TestPlugin/public', self::$DI['app']['root.path'].'/www/plugins/TestPlugin');
+
+ self::$DI['app']['filesystem']->expects($this->at(2))
->method('remove')
->with('tempdir');
diff --git a/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/PluginDir/TestPlugin/public/.placeholder b/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/PluginDir/TestPlugin/public/.placeholder
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/PluginDirInstalled/TestPlugin/public/.placeholder b/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/PluginDirInstalled/TestPlugin/public/.placeholder
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/WrongPlugins/TestPluginInvalidManifest/public/.placeholder b/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/WrongPlugins/TestPluginInvalidManifest/public/.placeholder
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/WrongPlugins/TestPluginMissingComposer/public/.placeholder b/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/WrongPlugins/TestPluginMissingComposer/public/.placeholder
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/WrongPlugins/TestPluginMissingManifest/public/.placeholder b/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/WrongPlugins/TestPluginMissingManifest/public/.placeholder
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/WrongPlugins/TestPluginNoPublicDirectory/composer.json b/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/WrongPlugins/TestPluginNoPublicDirectory/composer.json
new file mode 100644
index 0000000000..9e71751641
--- /dev/null
+++ b/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/WrongPlugins/TestPluginNoPublicDirectory/composer.json
@@ -0,0 +1,10 @@
+{
+ "name" : "test/test",
+ "description" : "test file",
+ "license" : "MIT",
+ "autoload": {
+ "psr-0": {
+ "Vendor" : "src"
+ }
+ }
+}
diff --git a/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/WrongPlugins/TestPluginNoPublicDirectory/manifest.json b/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/WrongPlugins/TestPluginNoPublicDirectory/manifest.json
new file mode 100644
index 0000000000..c732805a54
--- /dev/null
+++ b/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/WrongPlugins/TestPluginNoPublicDirectory/manifest.json
@@ -0,0 +1,25 @@
+{
+ "name": "TestPlugin",
+ "description" : "A custom class connector",
+ "keywords" : ["connector"],
+ "authors" : [
+ {
+ "name" : "Author name",
+ "homepage" : "http://example.com",
+ "email" : "email@example.com"
+ }
+ ],
+ "homepage" : "http://example.com/project/example",
+ "license" : "MIT",
+ "version" : "0.1",
+ "minimum-phraseanet-version": "3.8",
+ "maximum-phraseanet-version": "3.9",
+ "services" : [
+ {
+ "class": "Vendor\\PluginService"
+ }
+ ],
+ "extra" : {
+ "property" : "value"
+ }
+}
diff --git a/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/WrongPlugins/TestPluginNoPublicDirectory/src/Vendor/PluginService.php b/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/WrongPlugins/TestPluginNoPublicDirectory/src/Vendor/PluginService.php
new file mode 100644
index 0000000000..19b9dfd44a
--- /dev/null
+++ b/tests/Alchemy/Tests/Phrasea/Plugin/Fixtures/WrongPlugins/TestPluginNoPublicDirectory/src/Vendor/PluginService.php
@@ -0,0 +1,24 @@
+