![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/mautic.corals.io/app/bundles/InstallBundle/Install/ |
<?php declare(strict_types=1); namespace Mautic\InstallBundle\Install; use Doctrine\Common\DataFixtures\Executor\ORMExecutor; use Doctrine\Common\DataFixtures\Purger\ORMPurger; use Doctrine\ORM\EntityManager; use Mautic\CoreBundle\Configurator\Configurator; use Mautic\CoreBundle\Configurator\Step\StepInterface; use Mautic\CoreBundle\Doctrine\Loader\FixturesLoaderInterface; use Mautic\CoreBundle\Helper\CacheHelper; use Mautic\CoreBundle\Helper\EncryptionHelper; use Mautic\CoreBundle\Helper\InputHelper; use Mautic\CoreBundle\Helper\PathsHelper; use Mautic\CoreBundle\Loader\ParameterLoader; use Mautic\CoreBundle\Release\ThisRelease; use Mautic\InstallBundle\Configurator\Step\DoctrineStep; use Mautic\InstallBundle\Exception\AlreadyInstalledException; use Mautic\InstallBundle\Exception\DatabaseVersionTooOldException; use Mautic\InstallBundle\Helper\SchemaHelper; use Mautic\UserBundle\Entity\Role; use Mautic\UserBundle\Entity\User; use Symfony\Bundle\FrameworkBundle\Console\Application; use Symfony\Component\Console\Input\ArgvInput; use Symfony\Component\Console\Output\BufferedOutput; use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasher; use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Contracts\Translation\TranslatorInterface; class InstallService { public const CHECK_STEP = 0; public const DOCTRINE_STEP = 1; public const USER_STEP = 2; public const FINAL_STEP = 3; public function __construct( private Configurator $configurator, private CacheHelper $cacheHelper, protected PathsHelper $pathsHelper, private EntityManager $entityManager, private TranslatorInterface $translator, private KernelInterface $kernel, private ValidatorInterface $validator, private UserPasswordHasher $hasher, private FixturesLoaderInterface $fixturesLoader ) { } /** * Get step object for given index or appropriate step index. * * @param int $index The step number to retrieve * * @return StepInterface the valid step given installation status * * @throws \InvalidArgumentException|AlreadyInstalledException */ public function getStep(int $index = 0): StepInterface { // We're going to assume a bit here; if the config file exists already and DB info is provided, assume the app // is installed and redirect if ($this->checkIfInstalled()) { throw new AlreadyInstalledException(); } $params = $this->configurator->getParameters(); // Check to ensure the installer is in the right place if ((empty($params) || !isset($params['db_driver']) || empty($params['db_driver'])) && $index > 1) { return $this->configurator->getStep(self::DOCTRINE_STEP)[0]; } return $this->configurator->getStep($index)[0]; } /** * Get local config file location. */ private function localConfig(): string { return ParameterLoader::getLocalConfigFile($this->pathsHelper->getSystemPath('root').'/app'); } /** * Get local config parameters. */ public function localConfigParameters(): array { $localConfigFile = $this->localConfig(); if (file_exists($localConfigFile)) { /** @var array $parameters */ $parameters = []; // Load local config to override parameters include $localConfigFile; $localParameters = $parameters; } else { $localParameters = []; } return $localParameters; } /** * Checks if the application has been installed and redirects if so. */ public function checkIfInstalled(): bool { // If the config file doesn't even exist, no point in checking further $localConfigFile = $this->localConfig(); if (!file_exists($localConfigFile)) { return false; } $params = $this->configurator->getParameters(); // if db_driver and site_url are present then it is assumed all the steps of the installation have been // performed; manually deleting these values or deleting the config file will be required to re-enter // installation. if (empty($params['db_driver']) || empty($params['site_url'])) { return false; } return true; } /** * Translation messages array. */ private function translateMessages(array $messages): array { if (empty($messages)) { return $messages; } foreach ($messages as $key => $value) { $messages[$key] = $this->translator->trans($value); } return $messages; } /** * Checks for step's requirements. */ public function checkRequirements(StepInterface $step): array { $messages = $step->checkRequirements(); return $this->translateMessages($messages); } /** * Checks for step's optional settings. */ public function checkOptionalSettings(StepInterface $step): array { $messages = $step->checkOptionalSettings(); return $this->translateMessages($messages); } public function saveConfiguration($params, StepInterface $step = null, $clearCache = false): array { if ($step instanceof StepInterface) { $params = $step->update($step); } $this->configurator->mergeParameters($params); $messages = []; try { $this->configurator->write(); } catch (\RuntimeException) { $messages = [ 'error' => $this->translator->trans( 'mautic.installer.error.writing.configuration', [], 'flashes' ), ]; } if ($clearCache) { $this->cacheHelper->refreshConfig(); } return $messages; } /** * @return array Validation errors */ public function validateDatabaseParams(array $dbParams): array { $required = [ 'driver', 'host', 'name', 'user', ]; $messages = []; foreach ($required as $r) { if (!isset($dbParams[$r]) || empty($dbParams[$r])) { $messages[$r] = $this->translator->trans( 'mautic.core.value.required', [], 'validators' ); } } if (!isset($dbParams['port']) || (int) $dbParams['port'] <= 0) { $messages['port'] = $this->translator->trans( 'mautic.install.database.port.invalid', [], 'validators' ); } if (!empty($dbParams['driver']) && !in_array($dbParams['driver'], DoctrineStep::getDriverKeys())) { $messages['driver'] = $this->translator->trans( 'mautic.install.database.driver.invalid', ['%drivers%' => implode(', ', DoctrineStep::getDriverKeys())], 'validators' ); } return $messages; } /** * Create the database. */ public function createDatabaseStep(StepInterface $step, array $dbParams): array { $messages = $this->validateDatabaseParams($dbParams); if (!empty($messages)) { return $messages; } // Check if connection works and/or create database if applicable $schemaHelper = new SchemaHelper($dbParams); try { $schemaHelper->testConnection(); $schemaHelper->validateDatabaseVersion(); if ($schemaHelper->createDatabase()) { $messages = $this->saveConfiguration($dbParams, $step, true); if (empty($messages)) { return $messages; } } $messages['error'] = $this->translator->trans( 'mautic.installer.error.creating.database', ['%name%' => $dbParams['name']], 'flashes' ); } catch (DatabaseVersionTooOldException $e) { $metadata = ThisRelease::getMetadata(); $messages['error'] = $this->translator->trans( 'mautic.installer.error.database.version', [ '%currentversion%' => $e->getCurrentVersion(), '%mysqlminversion%' => $metadata->getMinSupportedMySqlVersion(), '%mariadbminversion%' => $metadata->getMinSupportedMariaDbVersion(), ], 'flashes' ); } catch (\Exception $exception) { $messages['error'] = $this->translator->trans( 'mautic.installer.error.connecting.database', ['%exception%' => $exception->getMessage()], 'flashes' ); } return $messages; } /** * Create the database schema. */ public function createSchemaStep(array $dbParams): array { $schemaHelper = new SchemaHelper($dbParams); $schemaHelper->setEntityManager($this->entityManager); $messages = []; try { if (!$schemaHelper->installSchema()) { $messages['error'] = $this->translator->trans( 'mautic.installer.error.no.metadata', [], 'flashes' ); } } catch (\Exception $exception) { $messages['error'] = $this->translator->trans( 'mautic.installer.error.installing.data', ['%exception%' => $exception->getMessage()], 'flashes' ); } return $messages; } /** * Load the database fixtures in the database. */ public function createFixturesStep(): array { $messages = []; try { $this->installDatabaseFixtures(); } catch (\Exception $exception) { $messages['error'] = $this->translator->trans( 'mautic.installer.error.adding.fixtures', ['%exception%' => $exception->getMessage()], 'flashes' ); } return $messages; } /** * Installs data fixtures for the application. * * @throws \InvalidArgumentException */ public function installDatabaseFixtures(): void { $fixtures = $this->fixturesLoader->getFixtures(['group_install']); if (!$fixtures) { throw new \InvalidArgumentException('Could not find any fixtures to load with the "group_install" group.'); } $purger = new ORMPurger($this->entityManager); $purger->setPurgeMode(ORMPurger::PURGE_MODE_DELETE); $executor = new ORMExecutor($this->entityManager, $purger); /* * FIXME entity manager does not load configuration if local.php just created by CLI install * [error] An error occurred while attempting to add default data * An exception occured in driver: * SQLSTATE[HY000] [1045] Access refused for user: ''@'@localhost' (mot de passe: NON) */ $executor->execute($fixtures, true); } /** * Create the administrator user. */ public function createAdminUserStep(array $data): array { $entityManager = $this->entityManager; // ensure the username and email are unique try { /** @var User $existingUser */ $existingUser = $entityManager->getRepository(User::class)->find(1); } catch (\Exception) { $existingUser = null; } if (null !== $existingUser) { $user = $existingUser; } else { $user = new User(); } $required = [ 'firstname', 'lastname', 'username', 'email', 'password', ]; $messages = []; foreach ($required as $r) { if (!isset($data[$r])) { $messages[$r] = $this->translator->trans( 'mautic.core.value.required', [], 'validators' ); } } if (!empty($messages)) { return $messages; } $validations = []; $emailConstraint = new Assert\Email(); $emailConstraint->message = $this->translator->trans('mautic.core.email.required', [], 'validators'); $passwordConstraint = new Assert\Length(['min' => 6]); $passwordConstraint->minMessage = $this->translator->trans('mautic.install.password.minlength', [], 'validators'); $validations[] = $this->validator->validate($data['email'], $emailConstraint); $validations[] = $this->validator->validate($data['password'], $passwordConstraint); $messages = []; foreach ($validations as $errors) { foreach ($errors as $error) { $messages[] = $error->getMessage(); } } if (!empty($messages)) { return $messages; } $hasher = $this->hasher; $user->setFirstName(InputHelper::clean($data['firstname'])); $user->setLastName(InputHelper::clean($data['lastname'])); $user->setUsername(InputHelper::clean($data['username'])); $user->setEmail(InputHelper::email($data['email'])); $user->setPassword($hasher->hashPassword($user, $data['password'])); $adminRole = null; try { $adminRole = $entityManager->getReference(Role::class, 1); } catch (\Exception $exception) { $messages['error'] = $this->translator->trans( 'mautic.installer.error.getting.role', ['%exception%' => $exception->getMessage()], 'flashes' ); } if (!empty($adminRole)) { $user->setRole($adminRole); try { $entityManager->persist($user); $entityManager->flush(); } catch (\Exception $exception) { $messages['error'] = $this->translator->trans( 'mautic.installer.error.creating.user', ['%exception%' => $exception->getMessage()], 'flashes' ); } } return $messages; } /** * Create the final configuration. */ public function createFinalConfigStep(string $siteUrl): array { // Merge final things into the config, wipe the container, and we're done! $finalConfigVars = [ 'secret_key' => EncryptionHelper::generateKey(), 'site_url' => $siteUrl, ]; return $this->saveConfiguration($finalConfigVars, null, true); } /** * Final migration step for install. */ public function finalMigrationStep(): void { // Add database migrations up to this point since this is a fresh install (must be done at this point // after the cache has been rebuilt $input = new ArgvInput(['console', 'doctrine:migrations:version', '--add', '--all', '--no-interaction']); $output = new BufferedOutput(); $application = new Application($this->kernel); $application->setAutoExit(false); $application->run($input, $output); } }