Imported code from old repository

This commit is contained in:
2022-11-22 15:46:36 +01:00
parent 976fdc0199
commit 77cf9e05f1
91 changed files with 18969 additions and 2 deletions
@@ -0,0 +1,90 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\PhpMAE\Commands;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class AbstractAddDependenciesCommand extends AbstractObjectCommand {
protected function configure() {
$this->addOption('confjob', null, InputOption::VALUE_NONE, 'Calls "cloudobjects" to create a configuration job for the updated class.');
}
protected function dependencyPrecheck() {
$this->assertRDF();
$this->assertPHPExists();
}
protected function getObjectAndAssertType(string $coid, string $type) {
// Retrieve configuration
$config = shell_exec("cloudobjects get ".$coid);
if (!isset($config))
throw new \Exception("Could not retrieve <".$coid.">.");
// Parse and validate configuration
$parser = \ARC2::getRDFXMLParser();
$parser->parse('', $config);
$index = $parser->getSimpleIndex(false);
if (!isset($index) || !isset($index[$coid])
|| !isset($index[$coid]['http://www.w3.org/1999/02/22-rdf-syntax-ns#type']))
throw new \Exception("<".$coid."> is not a valid CloudObjects object.");
$hasType = false;
foreach ($index[$coid]['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'] as $property => $values) {
if ($values['value'] == $type) {
$hasType = true;
break;
}
}
if (!$hasType)
throw new \Exception("<".$coid."> must have the type <".$type.">.");
}
protected function addDependency(string $key, string $type, array $valuesToMerge,
InputInterface $input, OutputInterface $output) {
$this->index['_:dep-'.$key] = array_merge([
'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' => [
[ 'type' => 'uri', 'value' => $type ]
],
'coid://phpmae.dev/hasKey' => [
[ 'type' => 'literal', 'value' => $key ]
]
], $valuesToMerge);
// Edit configuration
$object = $this->index[(string)$this->coid];
if (isset($object['coid://phpmae.dev/hasDependency'])) {
foreach ($object['coid://phpmae.dev/hasDependency'] as $o) {
if ($o['type'] != 'bnode') continue;
$bnode = $this->index[$o['value']];
if (isset($bnode['coid://phpmae.dev/hasKey']) && $bnode['coid://phpmae.dev/hasKey'][0]['value'] == $key)
throw new \Exception("A dependency with the key '".$key."' already exists.");
foreach ($valuesToMerge as $k => $values)
if (isset($bnode[$k]))
foreach ($bnode[$k] as $a)
foreach ($valuesToMerge[$k] as $b)
if ($a['type'] == $b['type'] && $a['value'] == $b['value'])
throw new \Exception("This dependency was already added.");
}
$object['coid://phpmae.dev/hasDependency'][] = [ 'type' => 'bnode', 'value' => '_:dep-'.$key ];
} else
$object['coid://phpmae.dev/hasDependency'] = [['type' => 'bnode', 'value' => '_:dep-'.$key ]];
// Persist configuration
$this->index[(string)$this->coid] = $object;
$this->updateRDFLocally($output);
if ($input->getOption('confjob'))
$this->createConfigurationJob($output);
}
}
+133
View File
@@ -0,0 +1,133 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\PhpMAE\Commands;
use Exception;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Output\OutputInterface;
use ML\IRI\IRI;
use CloudObjects\SDK\COIDParser;
use CloudObjects\PhpMAE\CredentialManager;
abstract class AbstractObjectCommand extends Command {
protected $coid;
protected $fullName;
protected $phpFileName;
protected $xmlFileName;
protected $rdfTypes;
protected $index;
protected function requireCloudObjectsCLI() {
if (!CredentialManager::isConfigured())
throw new Exception("The 'cloudobjects' CLI tool must be installed and authorized.");
}
protected function parse($coid) {
$this->coid = COIDParser::fromString($coid);
if (COIDParser::getType($this->coid)!=COIDParser::COID_VERSIONED
&& COIDParser::getType($this->coid)!=COIDParser::COID_UNVERSIONED)
throw new Exception("Invalid COID: ".(string)$this->coid);
$name = COIDParser::getName($this->coid);
$version = COIDParser::getVersion($this->coid);
$this->fullName = isset($version) ? $name.".".$version : $name;
$this->phpFileName = $this->fullName.'.php';
$this->xmlFileName = $this->fullName.'.xml';
}
protected function assertRDF() {
if (!file_exists($this->xmlFileName))
throw new Exception("File not found: ".$this->xmlFileName);
$parser = \ARC2::getRDFXMLParser();
$parser->parse('', file_get_contents($this->xmlFileName));
$index = $parser->getSimpleIndex(false);
$id = (string)$this->coid;
if (!isset($index) || !isset($index[$id])
|| !isset($index[$id]['http://www.w3.org/1999/02/22-rdf-syntax-ns#type']))
throw new Exception($this->xmlFileName." does not contain a valid RDF description of the object.");
$this->rdfTypes = [];
foreach ($index[$id]['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'] as $o)
if ($o['type'] == 'uri') $this->rdfTypes[] = $o['value'];
$this->index = $index;
}
protected function updateRDFLocally(OutputInterface $output) {
file_put_contents($this->xmlFileName,
$this->getSerializer()->getSerializedIndex($this->index));
$output->writeln("Updated ".$this->xmlFileName);
}
protected function createConfigurationJob(OutputInterface $output) {
$output->writeln("Calling cloudobjects configuration-job:create ...");
passthru("cloudobjects configuration-job:create ".$this->xmlFileName);
}
protected function ensureFilenameInConfig(OutputInterface $output, $interface = false) {
$property = ($interface ? 'coid://phpmae.dev/hasDefinitionFile'
: 'coid://phpmae.dev/hasSourceFile');
$object = $this->index[(string)$this->coid];
if (!isset($object[$property])) {
$object[$property] = [[
'value' => 'file:///'.$this->fullName.'.php',
'type' => 'uri'
]];
$this->index[(string)$this->coid] = $object;
$this->updateRDFLocally($output);
return true;
} else
return false;
}
protected function assertPHPExists() {
if (!file_exists($this->phpFileName))
throw new Exception("File not found: ".$this->phpFileName);
}
protected function getSerializer() {
return \ARC2::getRDFXMLSerializer(array(
'serializer_type_nodes' => true,
'ns' => array(
'co' => 'coid://cloudobjects.io/',
'phpmae' => 'coid://phpmae.dev/'
)
));
}
protected function watchPHPFile(OutputInterface $output, callable $callable) {
$fileTime = filemtime($this->phpFileName);
$output->writeln('Watching for changes ...');
set_time_limit(0);
while (true) {
clearstatcache();
if (filemtime($this->phpFileName) != $fileTime) {
// File has changed ...
sleep(1);
$fileTime = filemtime($this->phpFileName);
$callable();
$output->writeln('Watching for changes ...');
}
sleep(0.5);
}
}
protected function getAdditionalTypes() {
$coids = [];
foreach ($this->rdfTypes as $t) {
if (in_array($t, [ 'coid://phpmae.dev/Class',
'coid://phpmae.dev/HTTPInvokableClass',
'coid://phpmae.dev/Interface' ]))
continue;
$coids[] = new IRI($t);
}
return $coids;
}
}
+243
View File
@@ -0,0 +1,243 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\PhpMAE\Commands;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Command\Command;
use ML\IRI\IRI;
use CloudObjects\SDK\COIDParser;
use CloudObjects\PhpMAE\CredentialManager, CloudObjects\PhpMAE\ClassValidator;
use CloudObjects\PhpMAE\Exceptions\PhpMAEException;
class ClassCreateCommand extends Command {
protected function configure() {
$this->setName('class:create')
->setDescription('Create a new class for the phpMAE.')
->addArgument('coid', InputArgument::REQUIRED, 'The COID of the object.')
->addOption('http-invokable', 'hi', InputOption::VALUE_NONE, 'Makes the class HTTP-invokable.')
->addOption('force', 'f', InputOption::VALUE_NONE, 'Forces new object creation and replaces existing files.')
->addOption('public', null, InputOption::VALUE_NONE, 'Marks new object as public.')
->addOption('confjob', null, InputOption::VALUE_NONE, 'Calls "cloudobjects" to create a configuration job for the new class.')
->addOption('autowire', null, InputOption::VALUE_REQUIRED, 'Creates a constructor that autowires a PHP dependency.', null)
->addOption('implements', null, InputOption::VALUE_REQUIRED, 'Make this class an implementation of the phpMAE interface with the specified COID.', null);
}
private function getAndValidateInterfaceConfig($implements) {
// Check interface COID
$interfaceCoid = COIDParser::fromString($implements);
if (COIDParser::getType($interfaceCoid) != COIDParser::COID_VERSIONED
&& COIDParser::getType($interfaceCoid) != COIDParser::COID_UNVERSIONED)
throw new \Exception("Invalid Interface COID: ".(string)$interfaceCoid);
// Retrieve interface configuration
$implements = (string)$interfaceCoid;
$interfaceConfig = shell_exec("cloudobjects get ".$implements);
if (!isset($interfaceConfig))
throw new \Exception("Could not retrieve interface configuration.");
// Parse and validate interface configuration
$parser = \ARC2::getRDFXMLParser();
$parser->parse('', $interfaceConfig);
$index = $parser->getSimpleIndex(false);
if (!isset($index) || !isset($index[$implements])
|| !isset($index[$implements]['http://www.w3.org/1999/02/22-rdf-syntax-ns#type']))
throw new \Exception("<".$implements."> is not a valid CloudObjects object.");
$isInterface = false;
foreach ($index[$implements]['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'] as $property => $values) {
if ($values['value'] == 'coid://phpmae.dev/Interface')
$isInterface = true;
}
if (!$isInterface || !isset($index[$implements]['coid://phpmae.dev/hasDefinitionFile']))
throw new \Exception("<".$implements."> is not a valid phpMAE interface.");
return [
'classname' => COIDParser::getName($interfaceCoid),
'filename' => basename($index[$implements]['coid://phpmae.dev/hasDefinitionFile'][0]['value']),
'coid' => (string)$interfaceCoid,
];
}
private function getAndParseInterfaceCode($interface, $filename) {
// Retrieve interface code
$interfaceCode = shell_exec("cloudobjects attachment:get ".$interface
." ".$filename);
// Run through validator
$validator = new ClassValidator;
$validator->validateInterface($interfaceCode, new IRI($interface));
// Find use statements
$matches = [];
preg_match_all("/use\s+(.+);/", $interfaceCode, $matches);
$use = $matches[1];
// Parse method definitions
// (this is the same algorithm as the DirectoryTemplateVariableGenerator,
// but less filtering on comment string)
$matches = [];
preg_match_all("/(?:\/\*\*((?:[\s\S](?!\/\*))*?)\*\/+\s*)?public\s+function\s+(\w+)\s*\((.+)\)/",
$interfaceCode, $matches);
// The following groups are captured through RegExes:
// 0 - complete definition block
// 1 - comment string
// 2 - method name
// 3 - method parameters
$methods = [];
for ($i = 0; $i < count($matches[0]); $i++) {
// List methods with parameters and comment
$methods[] = [
'name' => $matches[2][$i],
'params' => trim($matches[3][$i]),
'comment' => trim($matches[1][$i])
];
}
return [
'methods' => $methods,
'use' => $use
];
}
protected function execute(InputInterface $input, OutputInterface $output) {
if (!CredentialManager::isConfigured())
throw new \Exception("The 'cloudobjects' CLI tool must be installed and authorized.");
$coid = COIDParser::fromString($input->getArgument('coid'));
if (COIDParser::getType($coid) != COIDParser::COID_VERSIONED
&& COIDParser::getType($coid) != COIDParser::COID_UNVERSIONED)
throw new \Exception("Invalid COID: ".(string)$coid);
$name = COIDParser::getName($coid);
$version = COIDParser::getVersion($coid);
$fullName = isset($version) ? $name.".".$version : $name;
$invokable = $input->getOption('http-invokable');
if ($input->getOption('implements') != null) {
if ($invokable)
throw new \Exception("The 'implements' option cannot be used with 'http-invokable'.");
$implements = $input->getOption('implements');
$output->writeln("Fetching configuration for ".$implements." ...");
$interfaceData = $this->getAndValidateInterfaceConfig($implements);
}
if (!file_exists($fullName.'.xml') || $input->getOption('force')) {
// Create RDF configuration file
$content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
. "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n"
. " xmlns:co=\"coid://cloudobjects.io/\"\n"
. " xmlns:phpmae=\"coid://phpmae.dev/\">\n"
. "\n"
. " <phpmae:".($invokable ? "HTTPInvokable" : "")."Class rdf:about=\"".(string)$coid."\">\n";
// Mark as public if option was defined
if ($input->getOption('public'))
$content .= " <co:isVisibleTo rdf:resource=\"coid://cloudobjects.io/Public\" />\n"
. " <co:permitsUsageTo rdf:resource=\"coid://cloudobjects.io/Public\" />\n";
else
$content .= " <co:isVisibleTo rdf:resource=\"coid://cloudobjects.io/Vendor\" />\n";
if (isset($implements))
$content .= " <rdf:type rdf:resource=\"".$interfaceData['coid']."\" />\n";
$content .=" </phpmae:".($invokable ? "HTTPInvokable" : "")."Class>\n"
. "</rdf:RDF>";
file_put_contents($fullName.'.xml', $content);
$output->writeln("Written ".$fullName.".xml.");
} else {
// RDF configuration file already exists
$output->writeln($fullName.".xml already exists.");
}
if (!file_exists($fullName.'.php') || $input->getOption('force') !== false) {
$useStatements = [];
$classVariables = [];
$constructor = '';
if ($input->getOption('autowire') != null) {
$fullyQualifiedClassname = $input->getOption('autowire');
$validator = new ClassValidator;
if (!$validator->isWhitelisted($fullyQualifiedClassname))
throw new PhpMAEException('Cannot autowire non-whitelisted type <'.$fullyQualifiedClassname.'>.');
$useStatements[] = $fullyQualifiedClassname;
$className = substr($fullyQualifiedClassname, strrpos($fullyQualifiedClassname, '\\') + 1);
$variableName = strtolower($className[0]).substr($className, 1);
$classVariables[] = $variableName;
$constructor = " public function __construct(".$className." \$".$variableName.") {\n"
. " \$this->".$variableName." = \$".$variableName.";\n"
. " }\n\n";
}
if (isset($implements)) {
// Retrieve interface code
$output->writeln("Fetching code for ".$interfaceData['coid']." ...");
$parsedInterface = $this->getAndParseInterfaceCode($interfaceData['coid'], $interfaceData['filename']);
// Add use statements
foreach ($parsedInterface['use'] as $u)
$useStatements[] = $u;
}
// Create PHP source file
$content = "<?php\n"
. "\n";
foreach ($useStatements as $u)
$content .= "use ".$u.";\n";
if (count($useStatements) > 0)
$content .= "\n";
$content .= "/**\n"
. " * Implementation for ".(string)$coid."\n"
. (isset($implements) ? " * Using interface ".$interfaceData['coid']."\n" : "")
. " */\n"
. "class ".$name." ".(isset($implements) ? "implements ".$interfaceData['classname']." " : "")
. "{\n"
. "\n";
foreach ($classVariables as $v)
$content .= " private \$".$v.";\n";
if (count($classVariables) > 0)
$content .= "\n"
. $constructor;
if (isset($implements)) {
// Build PHP template with interface methods
foreach ($parsedInterface['methods'] as $m) {
$content .= ($m['comment'] != "" ? " /**\n ".$m['comment']."\n */\n" : "")
. " public function ".$m['name']."(".$m['params'].") {\n"
. " // TODO: Implement this\n"
. " }\n\n";
}
} else {
// Build PHP template for standard or HTTP-invokable class
$content .= ($invokable
? " public function __invoke(\$args) {\n // TODO: Add your code here\n }\n"
: " // TODO: Add methods here ...\n")
. "\n";
}
$content .= "}";
file_put_contents($fullName.'.php', $content);
$output->writeln("Written ".$fullName.".php.");
} else {
$output->writeln($fullName.".php already exists.");
}
if ($input->getOption('confjob')) {
$output->writeln("Calling cloudobjects ...");
passthru("cloudobjects configuration-job:create ".$fullName.".xml");
}
}
}
+72
View File
@@ -0,0 +1,72 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\PhpMAE\Commands;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use CloudObjects\SDK\COIDParser;
use CloudObjects\PhpMAE\ClassValidator;
class ClassDeployCommand extends AbstractObjectCommand {
protected function configure() {
$this->setName('class:deploy')
->setDescription('Validates a class for the phpMAE and uploads it into CloudObjects. Updates the configuration if necessary.')
->addArgument('coid', InputArgument::REQUIRED, 'The COID of the object.');
}
protected function execute(InputInterface $input, OutputInterface $output) {
$this->requireCloudObjectsCLI();
$this->parse($input->getArgument('coid'));
$this->assertRDF();
if (!in_array('coid://phpmae.dev/Class', $this->rdfTypes)
&& !in_array('coid://phpmae.dev/HTTPInvokableClass', $this->rdfTypes))
throw new \Exception("Object does not have a valid class type.");
$this->assertPHPExists();
// Running validator
$validator = new ClassValidator;
$validator->validate(file_get_contents($this->fullName.'.php'),
$this->coid, $this->getAdditionalTypes());
$output->writeln("Validated successfully, calling cloudobjects ...");
passthru("cloudobjects attachment:put ".(string)$this->coid." ".$this->fullName.".php");
// Updates configuration if necessary
if ($this->ensureFilenameInConfig($output, false))
$this->createConfigurationJob($output);
// Print URL so developer can easily access it
$output->writeln("");
$visibility = isset($object['coid://cloudobjects.io/isVisibleTo'])
? $object['coid://cloudobjects.io/isVisibleTo'][0]['value']
: 'coid://cloudobjects.io/Vendor';
$path = $this->coid->getHost().$this->coid->getPath();
switch ($visibility) {
case "coid://cloudobjects.io/Private":
$output->writeln("<info>Private URL for Class Execution:</info>");
$output->writeln("➡️ http://YOUR_PHPMAE_INSTANCE/".$path);
break;
case "coid://cloudobjects.io/Public":
$output->writeln("<info>Public URL for Class Execution:</info>");
$output->writeln("➡️ https://phpmae.dev/".$path);
break;
case "coid://cloudobjects.io/Vendor":
$output->writeln("<info>Authenticated URL for Class Execution:</info>");
$output->writeln("➡️ https://".$this->coid->getHost().":SECRET@phpmae.dev/".$path);
$output->writeln("");
$output->writeln("To get value for SECRET:");
$output->writeln("➡️ cloudobjects domain-providers:secret ".$this->coid->getHost()." phpmae.dev");
break;
}
$output->writeln("");
}
}
+98
View File
@@ -0,0 +1,98 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\PhpMAE\Commands;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use ML\IRI\IRI;
use Guzzle\Http\Exception\BadResponseException;
use CloudObjects\SDK\COIDParser;
use CloudObjects\PhpMAE\ClassValidator, CloudObjects\PhpMAE\TestEnvironmentManager;
class ClassTestEnvCommand extends AbstractObjectCommand {
private $container;
protected function getContainer() {
if (!isset($this->container)) {
$this->container = TestEnvironmentManager::getContainer();
}
return $this->container;
}
protected function configure() {
$this->setName('class:testenv')
->setDescription('Uploads a class into the current test environment.')
->addArgument('coid', InputArgument::REQUIRED, 'The COID of the object.')
->addOption('config', null, InputOption::VALUE_NONE, 'Upload the local configuration of the class to the test environment instead of retrieving it from CloudObjects.')
->addOption('watch', null, InputOption::VALUE_NONE, 'Keep watching for changes of the file and reupload automatically.');
}
private function upload(OutputInterface $output) {
try {
$this->validator->validate(file_get_contents($this->phpFileName),
$this->coid, $this->getAdditionalTypes());
$this->getContainer()->get('testenv.client')->put('/uploadTestenv?type=source&coid='.urlencode((string)$this->coid), [
'body' => file_get_contents($this->phpFileName)
]);
$output->writeln('File uploaded successfully!');
} catch (BadResponseException $e) {
if ($e->getResponse()->getContentType()=='application/json') {
$errorMessage = $e->getResponse()->json();
$output->writeln('<error>'.$errorMessage['error_code'].':</error> '
.$errorMessage['error_message']);
} else
$output->writeln('<error>'.get_class($e).'</error> '.(string)$e->getResponse());
} catch (\Exception $e) {
$output->writeln('<error>'.get_class($e).'</error> '.$e->getMessage());
}
}
protected function execute(InputInterface $input, OutputInterface $output) {
$this->requireCloudObjectsCLI();
$container = $this->getContainer();
if (!$container->has('testenv.client'))
throw new \Exception("No test environment configured.");
$this->parse($input->getArgument('coid'));
$this->assertRDF();
if (!in_array('coid://phpmae.dev/Class', $this->rdfTypes)
&& !in_array('coid://phpmae.dev/HTTPInvokableClass', $this->rdfTypes))
throw new \Exception("Object does not have a valid class type.");
$this->assertPHPExists();
// Print URL so developer can easily access it
$output->writeln("<info>Test Environment Base URL for Class Execution:</info>");
$output->writeln("➡️ ".$container->get('testenv.url').$this->coid->getHost()
.$this->coid->getPath());
$output->writeln("");
if ($input->getOption('config')) {
// Upload configuration before uploading implementation
$this->ensureFilenameInConfig($output);
$container->get('testenv.client')->put('/uploadTestenv?type=config&coid='.urlencode((string)$this->coid), [
'body' => file_get_contents($this->xmlFileName)
]);
$output->writeln('Configuration uploaded successfully!');
}
$this->validator = new ClassValidator;
$this->upload($output);
if ($input->getOption('watch')) {
$cmd = $this;
$this->watchPHPFile($output, function() use ($cmd, $output) {
$cmd->upload($output);
});
}
}
}
@@ -0,0 +1,73 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\PhpMAE\Commands;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use JsonRpc\Client;
use CloudObjects\PhpMAE\TestEnvironmentManager;
class ClassTestEnvRPCCommand extends AbstractObjectCommand {
private $container;
protected function getContainer() {
if (!isset($this->container)) {
$this->container = TestEnvironmentManager::getContainer();
}
return $this->container;
}
protected function configure() {
$this->setName('class:testenv-rpc')
->setDescription('Executes a JSON-RPC method call on a class in the current test environment.')
->addArgument('coid', InputArgument::REQUIRED, 'The COID of the object.')
->addArgument('method', InputArgument::REQUIRED, 'The method name.')
->addArgument('parameters', InputArgument::IS_ARRAY, 'The parameters for the method.');
}
protected function execute(InputInterface $input, OutputInterface $output) {
$this->requireCloudObjectsCLI();
$container = $this->getContainer();
if (!$container->has('testenv.client'))
throw new \Exception("No test environment configured.");
$this->parse($input->getArgument('coid'));
$this->assertRDF();
if (!in_array('coid://phpmae.dev/Class', $this->rdfTypes)
&& !in_array('coid://phpmae.dev/HTTPInvokableClass', $this->rdfTypes))
throw new \Exception("Object does not have a valid class type.");
$this->assertPHPExists();
// Create JSON-RPC Client
$client = new Client($container->get('testenv.url')
.$this->coid->getHost().$this->coid->getPath());
// Check parameters and load files
$parameters = [];
foreach ($input->getArgument('parameters') as $p) {
if ($p[0] == '@')
$parameters[] = @file_get_contents(substr($p, 1));
else
$parameters[] = $p;
}
// Make RPC Call
if ($client->call($input->getArgument('method'), $parameters)
&& isset($client->result))
$output->writeln(is_string($client->result)
? $client->result
: json_encode($client->result, JSON_PRETTY_PRINT));
else
$output->writeln("<error>RPC has failed!</error>");
}
}
+57
View File
@@ -0,0 +1,57 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\PhpMAE\Commands;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use CloudObjects\PhpMAE\ClassValidator;
class ClassValidateCommand extends AbstractObjectCommand {
protected function configure() {
$this->setName('class:validate')
->setAliases([ 'validate', 'v' ])
->setDescription('Validates a class for the phpMAE.')
->addArgument('coid', InputArgument::REQUIRED, 'The COID of the object.')
->addOption('watch', null, InputOption::VALUE_NONE, 'Keep watching for changes of the file and revalidate automatically.');
}
protected function execute(InputInterface $input, OutputInterface $output) {
$this->parse($input->getArgument('coid'));
$this->assertRDF();
if (!in_array('coid://phpmae.dev/Class', $this->rdfTypes)
&& !in_array('coid://phpmae.dev/HTTPInvokableClass', $this->rdfTypes))
throw new \Exception("Object does not have a valid class type.");
$this->assertPHPExists();
// Running validator
$validator = new ClassValidator;
try {
$validator->validate(file_get_contents($this->phpFileName),
$this->coid, $this->getAdditionalTypes());
$output->writeln("Validated successfully.");
} catch (\Exception $e) {
$output->writeln('<error>'.get_class($e).'</error> '.$e->getMessage());
}
if ($input->getOption('watch')) {
$cmd = $this;
$this->watchPHPFile($output, function() use ($validator, $cmd, $output) {
try {
$validator->validate(file_get_contents($cmd->phpFileName),
$this->coid, $this->getAdditionalTypes());
$output->writeln("Validated successfully.");
} catch (\Exception $e) {
$output->writeln('<error>'.get_class($e).'</error> '.$e->getMessage());
}
});
}
}
}
@@ -0,0 +1,63 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\PhpMAE\Commands;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use CloudObjects\SDK\COIDParser;
class DependenciesAddAttachmentCommand extends AbstractObjectCommand {
protected function configure() {
$this->setName('dependencies:add-attachment')
->setDescription('Adds an attachment to the specification of a class.')
->addArgument('coid-target', InputArgument::REQUIRED, 'The COID of the target class.')
->addArgument('filename', InputArgument::REQUIRED, 'The name of the file that should be attached.')
->addOption('upload', null, InputOption::VALUE_NONE, 'Calls "cloudobjects" to actually upload the file to CloudObjects.');
}
protected function execute(InputInterface $input, OutputInterface $output) {
$this->requireCloudObjectsCLI();
$this->parse($input->getArgument('coid-target'));
$this->assertRDF();
$this->assertPHPExists();
$filename = $input->getArgument('filename');
if (!file_exists($filename))
throw new \Exception("File not found: ".$filename);
$fileUri = "file:///".basename($filename);
// Edit configuration
$found = false;
$object = $this->index[(string)$this->coid];
if (isset($object['coid://phpmae.dev/usesAttachedFile'])) {
foreach ($object['coid://phpmae.dev/usesAttachedFile'] as $o) {
if ($o['type'] != 'uri') continue;
if ($o['value'] == $fileUri) $found = true;
}
if (!$found)
$object['coid://phpmae.dev/usesAttachedFile'][] = [ 'type' => 'uri', 'value' => $fileUri ];
} else
$object['coid://phpmae.dev/usesAttachedFile'] = [[ 'type' => 'uri', 'value' => $fileUri ]];
// Persist configuration
if (!$found) {
$this->index[(string)$this->coid] = $object;
$this->updateRDFLocally($output);
}
if ($input->getOption('upload') !== null) {
$output->writeln("Calling cloudobjects ...");
passthru("cloudobjects attachment:put ".(string)$this->coid." ".$filename);
}
}
}
@@ -0,0 +1,78 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\PhpMAE\Commands;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use CloudObjects\SDK\COIDParser;
class DependenciesAddClassCommand extends AbstractAddDependenciesCommand {
protected function configure() {
$this->setName('dependencies:add-class')
->setDescription('Adds a class dependency to the specification of a class.')
->addArgument('coid-target', InputArgument::REQUIRED, 'The COID of the target class.')
->addOption('key', null, InputArgument::OPTIONAL, 'The key for dependency injection. Randomly generated if not provided.', null)
->addArgument('coid-class', InputArgument::REQUIRED, 'The COID of the dependency class.');
parent::configure();
}
protected function execute(InputInterface $input, OutputInterface $output) {
$this->requireCloudObjectsCLI();
$this->parse($input->getArgument('coid-target'));
$this->dependencyPrecheck();
// Check Class
$coidClass = COIDParser::fromString($input->getArgument('coid-class'));
if (COIDParser::getType($coidClass) != COIDParser::COID_VERSIONED
&& COIDParser::getType($coidClass) != COIDParser::COID_UNVERSIONED)
throw new \Exception("Invalid COID: ".$coid);
// Checking type
$output->writeln("Fetching configuration for ".(string)$coidClass." ...");
$this->getObjectAndAssertType((string)$coidClass, 'coid://phpmae.dev/Class');
// Add dependency
$this->addDependency(
$input->getOption('key') ? $input->getOption('key') : uniqid('class-'),
'coid://phpmae.dev/ClassDependency',
[
'coid://phpmae.dev/hasClass' => [
[ 'type' => 'uri', 'value' => (string)$coidClass ]
]
],
$input, $output
);
// Print documentation
$className = COIDParser::getName($coidClass);
$key = $input->getOption('key') ? $input->getOption('key')
: strtolower($className[0]).substr($className, 1);
$output->writeln("");
$output->writeln("<info>Use your class dependency:</info>");
$output->writeln("");
$output->writeln("1) Add the class ".$className." to your constructor parameters.");
$output->writeln("2) Assign the class to \$this->".$key.".");
$output->writeln("");
$output->writeln(" private \$".$key.";");
$output->writeln("");
$output->writeln(" public function __construct(".$className." \$".$key.") {");
$output->writeln(" \$this->".$key." = \$".$key.";");
$output->writeln(" }");
$output->writeln("");
$output->writeln("3) Use \$this->".$key." wherever required.");
$output->writeln("");
$output->writeln("You can find the documentation for the available class methods on this page:");
$output->writeln("➡️ https://cloudobjects.io/".$coidClass->getHost().$coidClass->getPath());
$output->writeln("");
}
}
@@ -0,0 +1,63 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\PhpMAE\Commands;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use CloudObjects\SDK\COIDParser;
class DependenciesAddStaticTextCommand extends AbstractAddDependenciesCommand {
protected function configure() {
$this->setName('dependencies:add-text')
->setDescription('Adds a static text dependency to the specification of a class.')
->addArgument('coid-target', InputArgument::REQUIRED, 'The COID of the target class.')
->addArgument('key', InputArgument::REQUIRED, 'The key for dependency injection.')
->addArgument('value', InputArgument::REQUIRED, 'The text value.');
parent::configure();
}
protected function execute(InputInterface $input, OutputInterface $output) {
$this->requireCloudObjectsCLI();
$this->parse($input->getArgument('coid-target'));
$this->assertRDF();
$this->dependencyPrecheck();
// Add dependency
$this->addDependency(
$input->getArgument('key'),
'coid://phpmae.dev/StaticTextDependency',
[
'coid://phpmae.dev/hasValue' => [
[ 'type' => 'literal', 'value' => $input->getArgument('value') ]
]
],
$input, $output
);
// Print documentation
$key = $input->getArgument('key');
$output->writeln("");
$output->writeln("<info>Use your static text dependency:</info>");
$output->writeln("");
$output->writeln("1) Make sure you have access to the dependency injection container by adding the container to your class constructor.");
$output->writeln("2) Request the value string from the container using the key \"".$key."\".");
$output->writeln("");
$output->writeln(" private \$".$key.";");
$output->writeln("");
$output->writeln(" public function __construct(\Psr\Container\ContainerInterface \$container) {");
$output->writeln(" \$this->".$key." = \$container->get('".$key."');");
$output->writeln(" }");
$output->writeln("");
$output->writeln("3) Use \$this->".$key." wherever required.");
$output->writeln("");
}
}
@@ -0,0 +1,75 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\PhpMAE\Commands;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use CloudObjects\SDK\COIDParser;
class DependenciesAddTemplateCommand extends AbstractAddDependenciesCommand {
protected function configure() {
$this->setName('dependencies:add-template')
->setDescription('Adds a Twig template dependency to the specification of a class.')
->addArgument('coid-target', InputArgument::REQUIRED, 'The COID of the target class.')
->addArgument('key', InputArgument::REQUIRED, 'The key for dependency injection.')
->addArgument('filename', InputArgument::REQUIRED, 'The filename for the Twig template.')
->addOption('upload', null, InputOption::VALUE_NONE, 'Calls "cloudobjects" to actually upload the template file to CloudObjects.');
parent::configure();
}
protected function execute(InputInterface $input, OutputInterface $output) {
$this->requireCloudObjectsCLI();
$this->parse($input->getArgument('coid-target'));
$this->dependencyPrecheck();
// Check filename
$filename = $input->getArgument('filename');
if (!file_exists($filename))
throw new \Exception("File not found: ".$filename);
// Upload file if requested
if ($input->getOption('upload')) {
$output->writeln("Calling cloudobjects for file upload ...");
passthru("cloudobjects attachment:put ".(string)$this->coid." ".$filename);
}
// Add dependency
$this->addDependency(
$input->getArgument('key'),
'coid://phpmae.dev/TwigTemplateDependency',
[
'coid://phpmae.dev/usesAttachedTwigFile' => [
[ 'type' => 'uri', 'value' => "file:///".basename($filename) ]
]
],
$input, $output
);
// Print documentation
$key = $input->getArgument('key');
$output->writeln("");
$output->writeln("<info>Use your Twig template dependency:</info>");
$output->writeln("");
$output->writeln("1) Make sure you have access to the dependency injection container by adding the container to your class constructor.");
$output->writeln("2) Request the template from the container using the key \"".$key."\".");
$output->writeln("");
$output->writeln(" private \$".$key."Template;");
$output->writeln("");
$output->writeln(" public function __construct(\Psr\Container\ContainerInterface \$container) {");
$output->writeln(" \$this->".$key."Template = \$container->get('".$key."');");
$output->writeln(" }");
$output->writeln("");
$output->writeln("3) Render your template by calling \$this->".$key."Template->render(\$context).");
$output->writeln("");
}
}
@@ -0,0 +1,72 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\PhpMAE\Commands;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use CloudObjects\SDK\COIDParser;
class DependenciesAddWebAPICommand extends AbstractAddDependenciesCommand {
protected function configure() {
$this->setName('dependencies:add-webapi')
->setDescription('Adds a dependency to the specification of a class.')
->addArgument('coid-target', InputArgument::REQUIRED, 'The COID of the target class.')
->addArgument('key', InputArgument::REQUIRED, 'The key for dependency injection.')
->addArgument('coid-webapi', InputArgument::REQUIRED, 'The COID of the Web API.');
parent::configure();
}
protected function execute(InputInterface $input, OutputInterface $output) {
$this->requireCloudObjectsCLI();
$this->parse($input->getArgument('coid-target'));
$this->dependencyPrecheck();
// Check Web API
$coidWebAPI = COIDParser::fromString($input->getArgument('coid-webapi'));
if (COIDParser::getType($coidWebAPI) != COIDParser::COID_VERSIONED
&& COIDParser::getType($coidWebAPI) != COIDParser::COID_UNVERSIONED)
throw new \Exception("Invalid COID: ".$coid);
// Checking type
$output->writeln("Fetching configuration for ".(string)$coidWebAPI." ...");
$this->getObjectAndAssertType((string)$coidWebAPI, 'coid://webapis.co-n.net/HTTPEndpoint');
// Add dependency
$this->addDependency(
$input->getArgument('key'),
'coid://phpmae.dev/WebAPIDependency',
[
'coid://phpmae.dev/hasAPI' => [
[ 'type' => 'uri', 'value' => (string)$coidWebAPI ]
]
],
$input, $output
);
// Print documentation
$key = $input->getArgument('key');
$output->writeln("");
$output->writeln("<info>Use your WebAPI dependency:</info>");
$output->writeln("");
$output->writeln("1) Make sure you have access to the dependency injection container by adding the container to your class constructor.");
$output->writeln("2) Request an API client from the container using the key \"".$key."\".");
$output->writeln("");
$output->writeln(" private \$".$key."Api;");
$output->writeln("");
$output->writeln(" public function __construct(\Psr\Container\ContainerInterface \$container) {");
$output->writeln(" \$this->".$key."Api = \$container->get('".$key."');");
$output->writeln(" }");
$output->writeln("");
$output->writeln("3) Make API requests in your class by calling methods on \$this->".$key."Api.");
$output->writeln("");
}
}
@@ -0,0 +1,84 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\PhpMAE\Commands;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Command\Command;
use CloudObjects\SDK\COIDParser;
use CloudObjects\PhpMAE\CredentialManager, CloudObjects\PhpMAE\ClassValidator;
use CloudObjects\PhpMAE\Exceptions\PhpMAEException;
class InterfaceCreateCommand extends Command {
protected function configure() {
$this->setName('interface:create')
->setDescription('Create a new interface for the phpMAE.')
->addArgument('coid', InputArgument::REQUIRED, 'The COID of the object.')
->addOption('force', 'f', InputOption::VALUE_OPTIONAL, 'Forces new object creation and replaces existing files.', false)
->addOption('confjob', null, InputOption::VALUE_OPTIONAL, 'Calls "cloudobjects" to create a configuration job for the new interface.', false);
}
protected function execute(InputInterface $input, OutputInterface $output) {
if (!CredentialManager::isConfigured())
throw new \Exception("The 'cloudobjects' CLI tool must be installed and authorized.");
$coid = COIDParser::fromString($input->getArgument('coid'));
if (COIDParser::getType($coid)!=COIDParser::COID_VERSIONED
&& COIDParser::getType($coid)!=COIDParser::COID_UNVERSIONED)
throw new \Exception("Invalid COID: ".(string)$coid);
$name = COIDParser::getName($coid);
$version = COIDParser::getVersion($coid);
$fullName = isset($version) ? $name.".".$version : $name;
if (!file_exists($fullName.'.xml') || $input->getOption('force') !== false) {
// Create RDF configuration file
$content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
. "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n"
. " xmlns:co=\"coid://cloudobjects.io/\"\n"
. " xmlns:phpmae=\"coid://phpmae.dev/\">\n"
. "\n"
. " <phpmae:Interface rdf:about=\"".(string)$coid."\">\n"
. " <co:isVisibleTo rdf:resource=\"coid://cloudobjects.io/Vendor\" />\n"
. " </phpmae:Interface>\n"
. "</rdf:RDF>";
file_put_contents($fullName.'.xml', $content);
$output->writeln("Written ".$fullName.".xml.");
} else {
// RDF configuration file already exists
$output->writeln($fullName.".xml already exists.");
}
if (!file_exists($fullName.'.php') || $input->getOption('force') !== false) {
// Create PHP source file
$content = "<?php\n"
. "\n"
. "/**\n"
. " * Definition for ".(string)$coid."\n"
. " */\n"
. "interface ".$name." {\n"
. "\n"
. " // Add methods here ...\n"
. "\n"
. "}";
file_put_contents($fullName.'.php', $content);
$output->writeln("Written ".$fullName.".php.");
} else {
$output->writeln($fullName.".php already exists.");
}
if ($input->getOption('confjob') !== false) {
$output->writeln("Calling cloudobjects ...");
passthru("cloudobjects configuration-job:create ".$fullName.".xml");
}
}
}
@@ -0,0 +1,50 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\PhpMAE\Commands;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use CloudObjects\SDK\COIDParser;
use CloudObjects\PhpMAE\ClassValidator;
class InterfaceDeployCommand extends AbstractObjectCommand {
protected function configure() {
$this->setName('interface:deploy')
->setDescription('Validates an interface for the phpMAE and uploads it into CloudObjects. Updates the configuration if necessary.')
->addArgument('coid', InputArgument::REQUIRED, 'The COID of the object.');
}
protected function execute(InputInterface $input, OutputInterface $output) {
$this->parse($input->getArgument('coid'));
$this->assertRDF();
if (!in_array('coid://phpmae.dev/Interface', $this->rdfTypes))
throw new \Exception("Object does not have athevalid interface type.");
$this->assertPHPExists();
// Running validator
$validator = new ClassValidator();
$validator->validateInterface(file_get_contents($this->fullName.'.php'), $this->coid);
$output->writeln("Validated successfully, calling cloudobjects ...");
passthru("cloudobjects attachment:put ".(string)$this->coid." ".$this->fullName.".php");
// Updates configuration if necessary
if ($this->ensureFilenameInConfig($output, true)) {
$this->createConfigurationJob($output);
}
// Print URL so developer can easily access it
$output->writeln("");
$visibility = isset($object['coid://cloudobjects.io/isVisibleTo'])
? $object['coid://cloudobjects.io/isVisibleTo'][0]['value']
: 'coid://cloudobjects.io/Vendor';
$path = $this->coid->getHost().$this->coid->getPath();
}
}
@@ -0,0 +1,53 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\PhpMAE\Commands;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use CloudObjects\PhpMAE\ClassValidator;
class InterfaceValidateCommand extends AbstractObjectCommand {
protected function configure() {
$this->setName('interface:validate')
->setDescription('Validates an interface for the phpMAE.')
->addArgument('coid', InputArgument::REQUIRED, 'The COID of the object.')
->addOption('watch', null, InputOption::VALUE_OPTIONAL, 'Keep watching for changes of the file and revalidate automatically.', null);
}
protected function execute(InputInterface $input, OutputInterface $output) {
$this->parse($input->getArgument('coid'));
$this->assertRDF();
if (!in_array('coid://phpmae.dev/Interface', $this->rdfTypes))
throw new \Exception("Object does not have the valid interface type.");
$this->assertPHPExists();
// Running validator
$validator = new ClassValidator;
try {
$validator->validateInterface(file_get_contents($this->phpFileName), $this->coid);
$output->writeln("Validated successfully.");
} catch (\Exception $e) {
$output->writeln('<error>'.get_class($e).'</error> '.$e->getMessage());
}
if ($input->getOption('watch') !== null) {
$cmd = $this;
$this->watchPHPFile($output, function() use ($validator, $cmd, $output) {
try {
$validator->validateInterface(file_get_contents($cmd->phpFileName), $this->coid);
$output->writeln("Validated successfully.");
} catch (\Exception $e) {
$output->writeln('<error>'.get_class($e).'</error> '.$e->getMessage());
}
});
}
}
}
@@ -0,0 +1,54 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\PhpMAE\Commands;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Command\Command;
use CloudObjects\PhpMAE\TestEnvironmentManager;
use CloudObjects\PhpMAE\CredentialManager;
class TestEnvironmentStartCommand extends Command {
protected function configure() {
$this->setName('testenv:start')
->setDescription('Starts a local test environment.')
->addOption('port', null, InputOption::VALUE_OPTIONAL, 'Use this port for test environment.', 9000)
->addOption('host', null, InputOption::VALUE_OPTIONAL, 'Bind test environment to this host.', '127.0.0.1');
}
protected function execute(InputInterface $input, OutputInterface $output) {
if (!CredentialManager::isConfigured())
throw new \Exception("The 'cloudobjects' CLI tool must be installed and authorized.");
$port = $input->getOption('port');
$host = $input->getOption('host');
TestEnvironmentManager::setTestEnvironment('http://localhost:'.$port.'/');
$output->writeln('Local webserver started on port '.$port.'.');
$phar = \Phar::running();
if (!$phar || $phar == "") {
// Run extracted version
$dir = realpath(__DIR__."/../../web/");
passthru('cd '.$dir.'; php -S '.$host.':'.$port.' index.php');
} else {
// Run from phar
if (strpos($phar, '.phar') !== false) {
// Run directly
passthru('php -S '.$host.':'.$port.' '.$phar.'/web/index.php');
} else {
// Create copy with .phar extension because PHP might not recognize the file otherwise
$pharCp = sys_get_temp_dir().DIRECTORY_SEPARATOR.'phpmae.phar';
copy(substr($phar, 7), $pharCp);
passthru('php -S '.$host.':'.$port.' phar://'.$pharCp.'/web/index.php');
die("THRU!");
}
}
}
}