433 lines
18 KiB
PHP
433 lines
18 KiB
PHP
<?php
|
|
|
|
/**
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; under version 2
|
|
* of the License (non-upgradable).
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* Copyright (c) 2014-2018 (original work) Open Assessment Technologies SA;
|
|
*
|
|
*
|
|
*/
|
|
|
|
use oat\generis\persistence\PersistenceManager;
|
|
use oat\oatbox\action\Action;
|
|
use oat\oatbox\log\logger\TaoLog;
|
|
use oat\oatbox\log\LoggerService;
|
|
use oat\oatbox\service\ConfigurableService;
|
|
use oat\oatbox\service\ServiceManager;
|
|
use Zend\ServiceManager\ServiceLocatorAwareInterface;
|
|
|
|
class tao_install_Setup implements Action
|
|
{
|
|
// Adding container and logger.
|
|
use \oat\oatbox\log\ContainerLoggerTrait;
|
|
|
|
/**
|
|
* Setup related dependencies will be reached under this offset.
|
|
*/
|
|
const CONTAINER_INDEX = 'taoInstallSetup';
|
|
|
|
/**
|
|
* The setup json content offset in the container.
|
|
*/
|
|
const SETUP_JSON_CONTENT_OFFSET = 'setupJsonContentOffset';
|
|
|
|
/**
|
|
* @param mixed $params The setup params.
|
|
*
|
|
* @throws ErrorException When a module is missing or other kind of general error.
|
|
* @throws common_Exception When the presented config file does not exist
|
|
* @throws common_exception_Error
|
|
* @throws common_ext_ExtensionException When a presented parameter is invalid or malformed.
|
|
* @throws InvalidArgumentException
|
|
* @throws tao_install_utils_Exception
|
|
*/
|
|
public function __invoke($params)
|
|
{
|
|
// Using the container if it's necessary with automatic dependency returning.
|
|
$params = $this->initContainer($params, static::CONTAINER_INDEX);
|
|
|
|
$this->logNotice('Installing TAO...');
|
|
|
|
if ($this->getContainer() !== null && $this->getContainer()->offsetExists(static::SETUP_JSON_CONTENT_OFFSET)) {
|
|
$parameters = json_decode($this->getContainer()->offsetGet(static::SETUP_JSON_CONTENT_OFFSET), true);
|
|
if (is_null($parameters)) {
|
|
throw new InvalidArgumentException('Your Setup JSON seed is malformed');
|
|
}
|
|
} else {
|
|
if (!isset($params[0])) {
|
|
throw new InvalidArgumentException('You should provide a file path');
|
|
}
|
|
|
|
$filePath = $params[0];
|
|
|
|
if (!file_exists($filePath)) {
|
|
throw new \ErrorException('Unable to find ' . $filePath);
|
|
}
|
|
|
|
$info = pathinfo($filePath);
|
|
|
|
switch ($info['extension']) {
|
|
case 'json':
|
|
$parameters = json_decode(file_get_contents($filePath), true);
|
|
if (is_null($parameters)) {
|
|
throw new InvalidArgumentException('Your JSON file is malformed');
|
|
}
|
|
break;
|
|
case 'yml':
|
|
if (extension_loaded('yaml')) {
|
|
$parameters = \yaml_parse_file($filePath);
|
|
if ($parameters === false) {
|
|
throw new InvalidArgumentException('Your YAML file is malformed');
|
|
}
|
|
} else {
|
|
throw new ErrorException('Extension yaml should be installed');
|
|
}
|
|
break;
|
|
default:
|
|
throw new InvalidArgumentException('Please provide a JSON or YAML file');
|
|
}
|
|
}
|
|
|
|
/** @var LoggerService $loggerService */
|
|
$loggerService = $this->getContainer()->offsetGet(LoggerService::SERVICE_ID);
|
|
$loggerService->addLogger(
|
|
new TaoLog([
|
|
'appenders' => [
|
|
[
|
|
'class' => 'SingleFileAppender',
|
|
'threshold' => common_Logger::TRACE_LEVEL,
|
|
'file' => TAO_INSTALL_PATH . 'tao/install/log/install.log'
|
|
]
|
|
]
|
|
])
|
|
);
|
|
|
|
$options = [
|
|
"install_sent" => "1"
|
|
, "module_host" => "tao.local"
|
|
, "module_lang" => "en-US"
|
|
, "module_mode" => "debug"
|
|
, "module_name" => "mytao"
|
|
, "module_namespace" => ""
|
|
, "module_url" => ""
|
|
, "submit" => "Install"
|
|
, "user_email" => ""
|
|
, "user_firstname" => ""
|
|
, "user_lastname" => ""
|
|
, "user_login" => ""
|
|
, "user_pass" => ""
|
|
, "instance_name" => null
|
|
, "extensions" => null
|
|
, 'timezone' => date_default_timezone_get()
|
|
, 'extra_persistences' => []
|
|
];
|
|
|
|
if (!isset($parameters['configuration'])) {
|
|
throw new InvalidArgumentException('Your config should have a \'configuration\' key');
|
|
}
|
|
|
|
if (!isset($parameters['configuration']['generis'])) {
|
|
throw new InvalidArgumentException('Your config should have a \'generis\' key under \'configuration\'');
|
|
}
|
|
|
|
if (!isset($parameters['configuration']['global'])) {
|
|
throw new InvalidArgumentException('Your config should have a \'global\' key under \'configuration\'');
|
|
}
|
|
|
|
$global = $parameters['configuration']['global'];
|
|
$options['module_namespace'] = $global['namespace'];
|
|
$options['instance_name'] = $global['instance_name'];
|
|
$options['module_url'] = $global['url'];
|
|
$options['module_lang'] = $global['lang'];
|
|
$options['module_mode'] = $global['mode'];
|
|
$options['timezone'] = $global['timezone'];
|
|
$options['import_local'] = (isset($global['import_data']) && $global['import_data'] === true);
|
|
|
|
$rootDir = dir(dirname(__FILE__) . '/../../');
|
|
$options['root_path'] = isset($global['root_path'])
|
|
? $global['root_path']
|
|
: realpath($rootDir->path) . DIRECTORY_SEPARATOR;
|
|
|
|
$options['file_path'] = isset($global['file_path'])
|
|
? $global['file_path']
|
|
: $options['root_path'] . 'data' . DIRECTORY_SEPARATOR;
|
|
|
|
if (isset($global['session_name'])) {
|
|
$options['session_name'] = $global['session_name'];
|
|
}
|
|
|
|
if (isset($global['anonymous_lang'])) {
|
|
$options['anonymous_lang'] = $global['anonymous_lang'];
|
|
}
|
|
|
|
//get extensions to install
|
|
if (isset($parameters['extensions'])) {
|
|
$options['extensions'] = $parameters['extensions'];
|
|
}
|
|
|
|
if (!isset($parameters['super-user'])) {
|
|
throw new InvalidArgumentException('Your config should have a \'global\' key under \'generis\'');
|
|
}
|
|
|
|
$superUser = $parameters['super-user'];
|
|
$options['user_login'] = $superUser['login'];
|
|
$options['user_pass1'] = $superUser['password'];
|
|
if (isset($parameters['lastname'])) {
|
|
$options['user_lastname'] = $parameters['lastname'];
|
|
}
|
|
if (isset($parameters['firstname'])) {
|
|
$options['user_firstname'] = $parameters['firstname'];
|
|
}
|
|
if (isset($parameters['email'])) {
|
|
$options['user_email'] = $parameters['email'];
|
|
}
|
|
|
|
|
|
$installOptions = [
|
|
'root_path' => $options['root_path'],
|
|
'install_path' => $options['root_path'] . 'tao/install/',
|
|
];
|
|
|
|
if (isset($global['installation_config_path'])) {
|
|
$installOptions['installation_config_path'] = $global['installation_config_path'];
|
|
}
|
|
|
|
// run the actual install
|
|
if ($this->getContainer() instanceof \Pimple\Container) {
|
|
$this->getContainer()->offsetSet(\tao_install_Installator::CONTAINER_INDEX, $installOptions);
|
|
$installator = new \tao_install_Installator($this->getContainer());
|
|
} else {
|
|
$installator = new \tao_install_Installator($installOptions);
|
|
}
|
|
|
|
$serviceManager = $installator->getServiceManager();
|
|
|
|
if (!isset($parameters['configuration']['generis']['persistences'])) {
|
|
throw new InvalidArgumentException('Your config should have a \'persistence\' key under \'generis\'');
|
|
}
|
|
$persistences = $parameters['configuration']['generis']['persistences'];
|
|
if (isset($persistences['default'])) {
|
|
$parameters['configuration']['generis']['persistences'] = $this->wrapPersistenceConfig($persistences);
|
|
} elseif (!isset($persistences['type'])) {
|
|
throw new InvalidArgumentException('Your config should have a \'default\' key under \'persistences\'');
|
|
}
|
|
|
|
foreach ($parameters['configuration'] as $extension => $configs) {
|
|
foreach ($configs as $key => $config) {
|
|
if (isset($config['type']) && $config['type'] === 'configurableService') {
|
|
$className = $config['class'];
|
|
$params = $config['options'];
|
|
if (is_a($className, \oat\oatbox\service\ConfigurableService::class, true)) {
|
|
if (is_a($className, \oat\tao\model\service\InjectionAwareService::class, true)) {
|
|
$service = new $className(...$this->prepareParameters($className, $params, $serviceManager));
|
|
} else {
|
|
$service = new $className($params);
|
|
}
|
|
$serviceManager->register($extension . '/' . $key, $service);
|
|
} else {
|
|
$this->logWarning('The class : ' . $className . ' can not be set as a Configurable Service');
|
|
$this->logWarning('Make sure your configuration is correct and all required libraries are installed');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// mod rewrite cannot be detected in CLI Mode.
|
|
$installator->escapeCheck('custom_tao_ModRewrite');
|
|
$logger = $this->getLogger();
|
|
|
|
$installator->install($options, function () use ($serviceManager, $parameters, $logger) {
|
|
/** @var common_ext_ExtensionsManager $extensionManager */
|
|
$extensionManager = $serviceManager->get(common_ext_ExtensionsManager::SERVICE_ID);
|
|
foreach ($parameters['configuration'] as $ext => $configs) {
|
|
foreach ($configs as $key => $config) {
|
|
if (! (isset($config['type']) && $config['type'] === 'configurableService')) {
|
|
if (! is_null($extensionManager->getInstalledVersion($ext))) {
|
|
$extension = $extensionManager->getExtensionById($ext);
|
|
if (! $extension->hasConfig($key) || ! $extension->getConfig($key) instanceof ConfigurableService) {
|
|
if (! $extension->setConfig($key, $config)) {
|
|
throw new ErrorException('Your config ' . $ext . '/' . $key . ' cannot be set');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// execute post install scripts
|
|
if (isset($parameters['postInstall'])) {
|
|
foreach ($parameters['postInstall'] as $script) {
|
|
if (isset($script['class']) && is_a($script['class'], Action::class, true)) {
|
|
$object = new $script['class']();
|
|
if (is_a($object, ServiceLocatorAwareInterface::class)) {
|
|
$object->setServiceLocator($serviceManager);
|
|
}
|
|
$params = (isset($script['params']) && is_array($script['params'])) ? $script['params'] : [];
|
|
$report = call_user_func($object, $params);
|
|
|
|
if ($report instanceof common_report_Report) {
|
|
$logger->info(helpers_Report::renderToCommandline($report));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
$logger->notice('Installation completed!');
|
|
});
|
|
|
|
}
|
|
|
|
/**
|
|
* @param string $class
|
|
* @param array $parametersToSort
|
|
* @param ServiceManager $serviceManager
|
|
*
|
|
* @return array
|
|
* @throws ReflectionException
|
|
*/
|
|
private function prepareParameters(string $class, array $parametersToSort, ServiceManager $serviceManager): array
|
|
{
|
|
$reflectionClass = new ReflectionClass($class);
|
|
|
|
$constructParameters = $reflectionClass->getMethod('__construct')->getParameters();
|
|
|
|
$sortedParameters = [];
|
|
|
|
while($constructParameters && $parametersToSort) {
|
|
$parameter = array_shift($constructParameters);
|
|
$parameterName = $parameter->getName();
|
|
|
|
try {
|
|
$paramValue = $parametersToSort[$parameterName] ?? $parameter->getDefaultValue();
|
|
|
|
$sortedParameters[] = $this->resolveParameter($parameter, $paramValue, $serviceManager);
|
|
|
|
unset($parametersToSort[$parameterName]);
|
|
} catch (ReflectionException $exception) {
|
|
throw new RuntimeException(
|
|
sprintf('No default value for `$%s` argument in %s::__construct', $parameterName, $class)
|
|
);
|
|
}
|
|
}
|
|
|
|
if ($parametersToSort) {
|
|
throw new InvalidArgumentException(
|
|
sprintf('Invalid arguments `%s` specified for %s', implode(', ', array_keys($parametersToSort)), $class)
|
|
);
|
|
}
|
|
|
|
return $sortedParameters;
|
|
}
|
|
|
|
private function resolveParameter(ReflectionParameter $parameter, $paramValue, ServiceManager $serviceManager)
|
|
{
|
|
if (
|
|
is_string($paramValue)
|
|
&& $parameter->getClass() !== null
|
|
&& $serviceManager->has($paramValue)
|
|
) {
|
|
$paramValue = $serviceManager->get($paramValue);
|
|
}
|
|
|
|
return $paramValue;
|
|
}
|
|
|
|
/**
|
|
* Transforms the seed persistence configuration into command line parameters
|
|
* and then back into a persistence configuration to ensure backwards compatibility
|
|
* with the previous process
|
|
* @param array $persistences
|
|
* @return array
|
|
*/
|
|
private function wrapPersistenceConfig($persistences)
|
|
{
|
|
$installParams = $this->getCommandLineParameters($persistences['default']);
|
|
|
|
$dbalConfigCreator = new tao_install_utils_DbalConfigCreator();
|
|
$persistences['default'] = $dbalConfigCreator->createDbalConfig($installParams);
|
|
|
|
return [
|
|
'type' => 'configurableService',
|
|
'class' => PersistenceManager::class,
|
|
'options' => [
|
|
'persistences' => $persistences,
|
|
],
|
|
];
|
|
}
|
|
|
|
private function getCommandLineParameters(array $defaultPersistenceConfig): array
|
|
{
|
|
if (isset($defaultPersistenceConfig['connection'])) {
|
|
if ($this->isMasterSlaveConnection($defaultPersistenceConfig)) {
|
|
$options['db_driver'] = $defaultPersistenceConfig['connection']['driver'];
|
|
$options['db_host'] = $defaultPersistenceConfig['connection']['master']['host'];
|
|
$options['db_name'] = $defaultPersistenceConfig['connection']['master']['dbname'];
|
|
|
|
if (isset($defaultPersistenceConfig['connection']['master']['user'])) {
|
|
$options['db_user'] = $defaultPersistenceConfig['connection']['master']['user'];
|
|
}
|
|
|
|
if (isset($defaultPersistenceConfig['connection']['master']['password'])) {
|
|
$options['db_pass'] = $defaultPersistenceConfig['connection']['master']['password'];
|
|
}
|
|
} else {
|
|
$options['db_driver'] = $defaultPersistenceConfig['connection']['driver'];
|
|
|
|
if (isset($defaultPersistenceConfig['connection']['driverClass'])) {
|
|
$options['db_driverClass'] = $defaultPersistenceConfig['connection']['driverClass'];
|
|
}
|
|
|
|
if (isset($defaultPersistenceConfig['connection']['driverOptions'])) {
|
|
$options['db_driverOptions'] = $defaultPersistenceConfig['connection']['driverOptions'];
|
|
}
|
|
|
|
if (isset($defaultPersistenceConfig['connection']['instance'])) {
|
|
$options['db_instance'] = $defaultPersistenceConfig['connection']['instance'];
|
|
}
|
|
|
|
$options['db_host'] = $defaultPersistenceConfig['connection']['host'];
|
|
$options['db_name'] = $defaultPersistenceConfig['connection']['dbname'];
|
|
|
|
if (isset($defaultPersistenceConfig['connection']['user'])) {
|
|
$options['db_user'] = $defaultPersistenceConfig['connection']['user'];
|
|
}
|
|
|
|
if (isset($defaultPersistenceConfig['connection']['password'])) {
|
|
$options['db_pass'] = $defaultPersistenceConfig['connection']['password'];
|
|
}
|
|
}
|
|
} else {
|
|
$options['db_driver'] = $defaultPersistenceConfig['driver'];
|
|
$options['db_host'] = $defaultPersistenceConfig['host'];
|
|
$options['db_name'] = $defaultPersistenceConfig['dbname'];
|
|
|
|
if (isset($defaultPersistenceConfig['user'])) {
|
|
$options['db_user'] = $defaultPersistenceConfig['user'];
|
|
}
|
|
|
|
if (isset($defaultPersistenceConfig['password'])) {
|
|
$options['db_pass'] = $defaultPersistenceConfig['password'];
|
|
}
|
|
}
|
|
|
|
return $options;
|
|
}
|
|
|
|
private function isMasterSlaveConnection(array $defaultPersistenceConfig): bool
|
|
{
|
|
return isset($defaultPersistenceConfig['connection']['wrapperClass'])
|
|
&& $defaultPersistenceConfig['connection']['wrapperClass'] === '\\Doctrine\\DBAL\\Connections\\MasterSlaveConnection';
|
|
}
|
|
}
|