Initial commit: CloudOps infrastructure platform

This commit is contained in:
root
2026-04-09 19:58:57 +02:00
commit 1166a52f26
7762 changed files with 839452 additions and 0 deletions

View File

@@ -0,0 +1,52 @@
<?php
namespace Mautic\InstallBundle\Configurator\Form;
use Mautic\CoreBundle\Form\Type\FormButtonsType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
/**
* @extends AbstractType<mixed>
*/
class CheckStepType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add(
'buttons',
FormButtonsType::class,
[
'pre_extra_buttons' => [
[
'name' => 'next',
'label' => 'mautic.install.next.step',
'type' => 'submit',
'attr' => [
'class' => 'btn btn-success pull-right btn-next',
'icon' => 'ri-arrow-right-circle-line',
'onclick' => 'MauticInstaller.showWaitMessage(event);',
],
],
],
'apply_text' => '',
'save_text' => '',
'cancel_text' => '',
]
);
$builder->add('site_url', HiddenType::class);
$builder->add('cache_path', HiddenType::class);
$builder->add('log_path', HiddenType::class);
if (!empty($options['action'])) {
$builder->setAction($options['action']);
}
}
public function getBlockPrefix(): string
{
return 'install_check_step';
}
}

View File

@@ -0,0 +1,177 @@
<?php
namespace Mautic\InstallBundle\Configurator\Form;
use Mautic\CoreBundle\Form\Type\FormButtonsType;
use Mautic\CoreBundle\Form\Type\YesNoButtonGroupType;
use Mautic\InstallBundle\Configurator\Step\DoctrineStep;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\Choice;
/**
* Doctrine Form Type.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @note This class is based on Sensio\Bundle\DistributionBundle\Configurator\Form\DoctrineStepType
*
* @extends AbstractType<mixed>
*/
class DoctrineStepType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add(
'driver',
ChoiceType::class,
[
'choices' => array_flip(DoctrineStep::getDrivers()),
'expanded' => false,
'multiple' => false,
'label' => 'mautic.install.form.database.driver',
'label_attr' => ['class' => 'control-label'],
'placeholder' => false,
'required' => true,
'attr' => [
'class' => 'form-control',
],
'constraints' => [
new Choice(
[
'callback' => '\Mautic\InstallBundle\Configurator\Step\DoctrineStep::getDriverKeys',
]
),
],
]
);
$builder->add(
'host',
TextType::class,
[
'label' => 'mautic.install.form.database.host',
'label_attr' => ['class' => 'control-label'],
'attr' => ['class' => 'form-control'],
'required' => true,
]
);
$builder->add(
'port',
TextType::class,
[
'label' => 'mautic.install.form.database.port',
'label_attr' => ['class' => 'control-label'],
'attr' => ['class' => 'form-control'],
'required' => false,
]
);
$builder->add(
'name',
TextType::class,
[
'label' => 'mautic.install.form.database.name',
'label_attr' => ['class' => 'control-label'],
'attr' => ['class' => 'form-control'],
'required' => true,
]
);
$builder->add(
'table_prefix',
TextType::class,
[
'label' => 'mautic.install.form.database.table.prefix',
'label_attr' => ['class' => 'control-label'],
'attr' => ['class' => 'form-control'],
'required' => false,
]
);
$builder->add(
'user',
TextType::class,
[
'label' => 'mautic.install.form.database.user',
'label_attr' => ['class' => 'control-label'],
'attr' => ['class' => 'form-control'],
'required' => true,
]
);
$builder->add(
'password',
PasswordType::class,
[
'label' => 'mautic.install.form.database.password',
'label_attr' => ['class' => 'control-label'],
'attr' => [
'class' => 'form-control',
'preaddon' => 'ri-lock-fill',
],
'required' => false,
]
);
$builder->add(
'backup_tables',
YesNoButtonGroupType::class,
[
'label' => 'mautic.install.form.existing_tables',
'attr' => [
'tooltip' => 'mautic.install.form.existing_tables_descr',
'onchange' => 'MauticInstaller.toggleBackupPrefix();',
],
]
);
$builder->add(
'backup_prefix',
TextType::class,
[
'label' => 'mautic.install.form.backup_prefix',
'label_attr' => ['class' => 'control-label'],
'attr' => [
'class' => 'form-control',
],
'required' => false,
]
);
$builder->add(
'buttons',
FormButtonsType::class,
[
'pre_extra_buttons' => [
[
'name' => 'next',
'label' => 'mautic.install.next.step',
'type' => 'submit',
'attr' => [
'class' => 'btn btn-success pull-right btn-next',
'icon' => 'ri-arrow-right-circle-line',
'onclick' => 'MauticInstaller.showWaitMessage(event);',
],
],
],
'apply_text' => '',
'save_text' => '',
'cancel_text' => '',
]
);
if (!empty($options['action'])) {
$builder->setAction($options['action']);
}
}
public function getBlockPrefix(): string
{
return 'install_doctrine_step';
}
}

View File

@@ -0,0 +1,177 @@
<?php
namespace Mautic\InstallBundle\Configurator\Form;
use Mautic\CoreBundle\Form\Type\FormButtonsType;
use Mautic\UserBundle\Form\Validator\Constraints\NotWeak;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @extends AbstractType<mixed>
*/
class UserStepType extends AbstractType
{
public function __construct(
private RequestStack $requestStack,
) {
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$storedData = $this->requestStack->getSession()->get('mautic.installer.user', new \stdClass());
$builder->add(
'firstname',
TextType::class,
[
'label' => 'mautic.core.firstname',
'label_attr' => ['class' => 'control-label'],
'attr' => ['class' => 'form-control'],
'required' => true,
'data' => (!empty($storedData->firstname)) ? $storedData->firstname : '',
'constraints' => [
new Assert\NotBlank(
[
'message' => 'mautic.core.value.required',
]
),
],
]
);
$builder->add(
'lastname',
TextType::class,
[
'label' => 'mautic.core.lastname',
'label_attr' => ['class' => 'control-label'],
'attr' => ['class' => 'form-control'],
'required' => true,
'data' => (!empty($storedData->lastname)) ? $storedData->lastname : '',
'constraints' => [
new Assert\NotBlank(
[
'message' => 'mautic.core.value.required',
]
),
],
]
);
$builder->add(
'email',
EmailType::class,
[
'label' => 'mautic.install.form.user.email',
'label_attr' => ['class' => 'control-label'],
'attr' => [
'class' => 'form-control',
'preaddon' => 'ri-mail-line',
],
'required' => true,
'data' => (!empty($storedData->email)) ? $storedData->email : '',
'constraints' => [
new Assert\NotBlank(
[
'message' => 'mautic.core.value.required',
]
),
new Assert\Email(
[
'message' => 'mautic.core.email.required',
]
),
],
]
);
$builder->add(
'username',
TextType::class,
[
'label' => 'mautic.install.form.user.username',
'label_attr' => ['class' => 'control-label'],
'attr' => [
'class' => 'form-control',
],
'required' => true,
'data' => (!empty($storedData->username)) ? $storedData->username : '',
'constraints' => [
new Assert\NotBlank(
[
'message' => 'mautic.core.value.required',
]
),
],
]
);
$builder->add(
'password',
PasswordType::class,
[
'label' => 'mautic.install.form.user.password',
'label_attr' => ['class' => 'control-label'],
'attr' => [
'class' => 'form-control',
'tooltip' => 'mautic.user.user.form.help.passwordrequirements',
'preaddon' => 'ri-lock-fill',
],
'required' => true,
'constraints' => [
new Assert\NotBlank(
[
'message' => 'mautic.core.value.required',
]
),
new Assert\Length(
[
'min' => 6,
'minMessage' => 'mautic.install.password.minlength',
]
),
new NotWeak([
'message' => 'mautic.user.user.password.weak',
]),
],
]
);
$builder->add(
'buttons',
FormButtonsType::class,
[
'pre_extra_buttons' => [
[
'name' => 'next',
'label' => 'mautic.install.next.step',
'type' => 'submit',
'attr' => [
'class' => 'btn btn-success pull-right btn-next',
'icon' => 'ri-arrow-right-circle-line',
'onclick' => 'MauticInstaller.showWaitMessage(event);',
],
],
],
'apply_text' => '',
'save_text' => '',
'cancel_text' => '',
]
);
if (!empty($options['action'])) {
$builder->setAction($options['action']);
}
}
public function getBlockPrefix(): string
{
return 'install_user_step';
}
}

View File

@@ -0,0 +1,249 @@
<?php
namespace Mautic\InstallBundle\Configurator\Step;
use Mautic\CoreBundle\Configurator\Configurator;
use Mautic\CoreBundle\Configurator\Step\StepInterface;
use Mautic\CoreBundle\Helper\FileHelper;
use Mautic\CoreBundle\Security\Cryptography\Cipher\Symmetric\OpenSSLCipher;
use Mautic\InstallBundle\Configurator\Form\CheckStepType;
use Symfony\Component\HttpFoundation\RequestStack;
class CheckStep implements StepInterface
{
/**
* Flag if the configuration file is writable.
*/
private bool $configIsWritable;
/**
* Absolute path to cache directory.
* Required in step.
*
* @var string
*/
public $cache_path = '%kernel.project_dir%/var/cache';
/**
* Absolute path to log directory.
* Required in step.
*
* @var string
*/
public $log_path = '%kernel.project_dir%/var/logs';
/**
* Set the domain URL for use in getting the absolute URL for cli/cronjob generated URLs.
*
* @var string
*/
public $site_url = '';
/**
* Recommended minimum memory limit for Mautic.
*
* @var string
*/
public const RECOMMENDED_MEMORY_LIMIT = '512M';
/**
* @param Configurator $configurator Configurator service
* @param string $projectDir Kernel root path
* @param RequestStack $requestStack Request stack
*/
public function __construct(
Configurator $configurator,
private string $projectDir,
RequestStack $requestStack,
private OpenSSLCipher $openSSLCipher,
) {
$request = $requestStack->getCurrentRequest();
$this->configIsWritable = $configurator->isFileWritable();
if (!empty($request)) {
$this->site_url = $request->getSchemeAndHttpHost().$request->getBasePath();
}
}
public function getFormType(): string
{
return CheckStepType::class;
}
public function checkRequirements(): array
{
$messages = [];
if (!is_dir($this->projectDir.'/vendor/composer')) {
$messages[] = 'mautic.install.composer.dependencies';
}
if (!$this->configIsWritable) {
$messages[] = 'mautic.install.config.unwritable';
}
if (!is_writable(str_replace('%kernel.project_dir%', $this->projectDir, $this->cache_path))) {
$messages[] = 'mautic.install.cache.unwritable';
}
if (!is_writable(str_replace('%kernel.project_dir%', $this->projectDir, $this->log_path))) {
$messages[] = 'mautic.install.logs.unwritable';
}
$timezones = [];
foreach (\DateTimeZone::listAbbreviations() as $abbreviations) {
foreach ($abbreviations as $abbreviation) {
$timezones[$abbreviation['timezone_id']] = true;
}
}
if (!isset($timezones[date_default_timezone_get()])) {
$messages[] = 'mautic.install.timezone.not.supported';
}
if (!function_exists('json_encode')) {
$messages[] = 'mautic.install.function.jsonencode';
}
if (!function_exists('session_start')) {
$messages[] = 'mautic.install.function.sessionstart';
}
if (!function_exists('ctype_alpha')) {
$messages[] = 'mautic.install.function.ctypealpha';
}
if (!function_exists('token_get_all')) {
$messages[] = 'mautic.install.function.tokengetall';
}
if (!function_exists('simplexml_import_dom')) {
$messages[] = 'mautic.install.function.simplexml';
}
if (false === $this->openSSLCipher->isSupported()) {
$messages[] = 'mautic.install.extension.openssl';
}
if (!function_exists('curl_init')) {
$messages[] = 'mautic.install.extension.curl';
}
if (!function_exists('finfo_open')) {
$messages[] = 'mautic.install.extension.fileinfo';
}
if (!function_exists('mb_strtolower')) {
$messages[] = 'mautic.install.extension.mbstring';
}
if (extension_loaded('xdebug')) {
if (ini_get('xdebug.show_exception_trace')) {
$messages[] = 'mautic.install.xdebug.exception.trace';
}
if (ini_get('xdebug.scream')) {
$messages[] = 'mautic.install.xdebug.scream';
}
}
return $messages;
}
public function checkOptionalSettings(): array
{
$messages = [];
if (extension_loaded('xdebug')) {
$cfgValue = ini_get('xdebug.max_nesting_level');
if ($cfgValue <= 100) {
$messages[] = 'mautic.install.xdebug.nesting';
}
}
if (!extension_loaded('zip')) {
$messages[] = 'mautic.install.extension.zip';
}
// We set a default timezone in the app bootstrap, but advise the user if their PHP config is missing it
if (!ini_get('date.timezone')) {
$messages[] = 'mautic.install.date.timezone.not.set';
}
if (!class_exists('\\DomDocument')) {
$messages[] = 'mautic.install.module.phpxml';
}
if (!function_exists('iconv')) {
$messages[] = 'mautic.install.function.iconv';
}
if (!extension_loaded('xml')) {
$messages[] = 'mautic.install.function.xml';
}
if (!function_exists('imap_open')) {
$messages[] = 'mautic.install.extension.imap';
}
if (!$this->site_url || !str_starts_with($this->site_url, 'https')) {
$messages[] = 'mautic.install.ssl.certificate';
}
if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
if (!function_exists('posix_isatty')) {
$messages[] = 'mautic.install.function.posix.enable';
}
}
$memoryLimit = FileHelper::convertPHPSizeToBytes(ini_get('memory_limit'));
$suggestedLimit = FileHelper::convertPHPSizeToBytes(self::RECOMMENDED_MEMORY_LIMIT);
if ($memoryLimit > -1 && $memoryLimit < $suggestedLimit) {
$messages[] = 'mautic.install.memory.limit';
}
if (!class_exists('\\Locale')) {
$messages[] = 'mautic.install.module.intl';
}
if (class_exists('\\Collator')) {
try {
if (is_null(new \Collator('fr_FR'))) {
$messages[] = 'mautic.install.intl.config';
}
} catch (\Exception) {
$messages[] = 'mautic.install.intl.config';
}
}
if (-1 !== (int) ini_get('zend.assertions')) {
$messages[] = 'mautic.install.zend_assertions';
}
return $messages;
}
public function getTemplate(): string
{
return '@MauticInstall/Install/check.html.twig';
}
/**
* @return mixed[]
*/
public function update(StepInterface $data): array
{
$parameters = [];
foreach ($data as $key => $value) {
// Exclude keys from the config
if (!in_array($key, ['configIsWritable', 'projectDir'])) {
$parameters[$key] = $value;
}
}
return $parameters;
}
}

View File

@@ -0,0 +1,169 @@
<?php
namespace Mautic\InstallBundle\Configurator\Step;
use Mautic\CoreBundle\Configurator\Configurator;
use Mautic\CoreBundle\Configurator\Step\StepInterface;
use Mautic\InstallBundle\Configurator\Form\DoctrineStepType;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
class DoctrineStep implements StepInterface
{
/**
* Database driver.
*/
public $driver = 'pdo_mysql';
/**
* Database host.
*/
public $host = 'localhost';
/**
* Database host. Read Only Replica.
*/
public ?string $host_ro = null;
/**
* Database table prefix.
* Required in step.
*
* @var string
*/
public $table_prefix;
/**
* Database connection port.
*/
public $port = 3306;
/**
* Database name.
*/
public $name;
/**
* Database user.
*/
public $user;
/**
* Database user's password.
*
* @var string
*/
public $password;
/**
* Backup tables if they exist; otherwise drop them.
* Required in step.
*
* @var bool
*/
public $backup_tables = true;
/**
* Prefix for backup tables.
* Required in step.
*
* @var string
*/
public $backup_prefix = 'bak_';
public ?string $server_version;
public function __construct(Configurator $configurator)
{
$parameters = $configurator->getParameters();
foreach ($parameters as $key => $value) {
if (str_starts_with($key, 'db_')) {
$parameters[substr($key, 3)] = $value;
$key = substr($key, 3);
$this->$key = $value;
}
}
}
public function getFormType(): string
{
return DoctrineStepType::class;
}
public function checkRequirements(): array
{
$messages = [];
if (!class_exists('\PDO')) {
$messages[] = 'mautic.install.pdo.mandatory';
} else {
if (!in_array('mysql', \PDO::getAvailableDrivers(), true)) {
$messages[] = 'mautic.install.pdo.drivers';
}
}
return $messages;
}
public function checkOptionalSettings(): array
{
return [];
}
/**
* @return mixed[]
*/
public function update(StepInterface $data): array
{
$parameters = [];
foreach ($data as $key => $value) {
$parameters['db_'.$key] = $value;
}
return $parameters;
}
public function getTemplate(): string
{
return '@MauticInstall/Install/doctrine.html.twig';
}
/**
* Return the key values of the available driver array.
* Required in step.
*
* @see \Mautic\InstallBundle\Configurator\Form\DoctrineStepType::buildForm()
*/
public static function getDriverKeys(): array
{
return array_keys(static::getDrivers());
}
/**
* Fetches the available database drivers for the environment.
*/
public static function getDrivers(): array
{
$mauticSupported = [
'pdo_mysql' => 'MySQL PDO (Recommended)',
];
$supported = [];
// Add PDO drivers if supported
if (class_exists('\PDO')) {
$pdoDrivers = \PDO::getAvailableDrivers();
foreach ($pdoDrivers as $driver) {
if (array_key_exists('pdo_'.$driver, $mauticSupported)) {
$supported['pdo_'.$driver] = $mauticSupported['pdo_'.$driver];
}
}
}
return $supported;
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace Mautic\InstallBundle\Configurator\Step;
use Mautic\CoreBundle\Configurator\Step\StepInterface;
use Mautic\InstallBundle\Configurator\Form\UserStepType;
class UserStep implements StepInterface
{
/**
* User's first name.
*/
public $firstname;
/**
* User's last name.
*/
public $lastname;
/**
* User's e-mail address.
*/
public $email;
/**
* User's username.
*/
public $username;
/**
* User's password.
*/
public $password;
public function getFormType(): string
{
return UserStepType::class;
}
public function checkRequirements(): array
{
return [];
}
public function checkOptionalSettings(): array
{
return [];
}
public function getTemplate(): string
{
return '@MauticInstall/Install/user.html.twig';
}
public function update(StepInterface $data): array
{
return [];
}
}