home"; const TEMPLATE_1COL = "OpenTalent.OtTemplating->1Col"; const TEMPLATE_3COL = "OpenTalent.OtTemplating->home"; const TEMPLATE_EVENTS = "OpenTalent.OtTemplating->events"; const TEMPLATE_STRUCTURESEVENTS = "OpenTalent.OtTemplating->structuresEvents"; const TEMPLATE_STRUCTURES = "OpenTalent.OtTemplating->structures"; const TEMPLATE_CONTACT = "OpenTalent.OtTemplating->contact"; const TEMPLATE_NEWS = "OpenTalent.OtTemplating->news"; const TEMPLATE_MEMBERS = "OpenTalent.OtTemplating->members"; const TEMPLATE_MEMBERSCA = "OpenTalent.OtTemplating->membersCa"; const TEMPLATE_E404 = "OpenTalent.OtTemplating->e404"; // Pages dokType values const DOK_PAGE = 1; const DOK_SHORTCUT = 4; const DOK_FOLDER = 116; // Contents CTypes const CTYPE_TEXT = 'text'; const CTYPE_IMAGE = 'image'; const CTYPE_TEXTPIC = 'textpic'; const CTYPE_TEXTMEDIA = 'textmedia'; const CTYPE_HTML = 'html'; const CTYPE_HEADER = 'header'; const CTYPE_UPLOADS = 'uploads'; const CTYPE_LIST = 'list'; const CTYPE_SITEMAP = 'menu_sitemap'; // const DEFAULT_ROOT_PID = 134833; const DEFAULT_ROOT_PID = 11; // Default values const DEFAULT_THEME = 'Classic'; const DEFAULT_COLOR = 'light-blue'; /** * Doctrine connection pool * @var object|LoggerAwareInterface|\TYPO3\CMS\Core\SingletonInterface */ private $cnnPool; /** * Index of the pages created * >> [slug => uid] * @var array */ private $createdPagesIndex; public function __construct() { parent::__construct(); $this->cnnPool = GeneralUtility::makeInstance(ConnectionPool::class); $this->createdPagesIndex = []; } /** * Creates a new website for the given organization, and * returns the root page uid of the newly created site * * @param int $organizationId * @return int Uid of the root page of the newly created website * @throws \RuntimeException */ public function createSiteAction(int $organizationId) { // ** Get the organization object from the Opentalent API $manager = GeneralUtility::makeInstance(ObjectManager::class); $organizationRepository = GeneralUtility::makeInstance( OrganizationRepository::class, $manager ); try { $organization = $organizationRepository->findById($organizationId); } catch (ApiRequestException $e) { throw new \RuntimeException('Unable to fetch the organization with id: ' . $organizationId); } // ** Test the existence of a website with this name and or organization id // Is there a site with this organization's name? $queryBuilder = $this->cnnPool->getQueryBuilderForTable('pages'); $queryBuilder ->select('uid') ->from('pages') ->where($queryBuilder->expr()->eq('title', $queryBuilder->createNamedParameter($organization->getName()))) ->andWhere('is_siteroot=1'); $statement = $queryBuilder->execute(); if ($statement->rowCount() > 0) { throw new \RuntimeException('A website with this name already exists: ' . $organization->getName()); } // Is there a site with this organization's id? $queryBuilder = $this->cnnPool->getQueryBuilderForTable('pages'); $statement = $queryBuilder ->select('uid') ->from('pages') ->where($queryBuilder->expr()->eq('tx_opentalent_structure_id', $queryBuilder->createNamedParameter($organization->getId()))) ->andWhere('is_siteroot=1') ->execute(); if ($statement->rowCount() > 0) { throw new \RuntimeException("A website with this organization's id already exists: " . $organization->getName()); } // ** Create the new website // start transactions $tables = ['be_users', 'pages', 'sys_domain', 'sys_template', 'tt_content']; foreach ($tables as $table) { $this->cnnPool->getConnectionForTable($table)->beginTransaction(); } $pages = []; try { // Create the site pages: // > Root page $rootUid = $this->insertRootPage($organization); // > 'Accueil' shortcut $this->insertPage( $organization, $rootUid, 'Accueil', '/accueil', '', [ 'dokType' => self::DOK_SHORTCUT, 'shortcut' => $rootUid ] ); // > 'Présentation' page $this->insertPage( $organization, $rootUid, 'Présentation', '/presentation' ); // > 'Présentation > Qui sommes nous?' page (hidden by default) $this->insertPage( $organization, $this->createdPagesIndex['/presentation'], 'Qui sommes nous?', '/qui-sommes-nous', '', ['hidden' => 1] ); // > 'Présentation > Les adhérents' page $this->insertPage( $organization, $this->createdPagesIndex['/presentation'], 'Les adhérents', '/les-adherents', self::TEMPLATE_MEMBERS ); // > 'Présentation > Les membres du CA' page $this->insertPage( $organization, $this->createdPagesIndex['/presentation'], 'Les membres du CA', '/les-membres-du-ca', self::TEMPLATE_MEMBERSCA ); // > 'Présentation > Historique' page (hidden by default) $this->insertPage( $organization, $this->createdPagesIndex['/presentation'], 'Historique', '/historique', '', ['hidden' => 1] ); // > 'Actualités' page (hidden by default) $this->insertPage( $organization, $rootUid, 'Actualités', '/actualites', self::TEMPLATE_NEWS ); // > 'Saison en cours' page $this->insertPage( $organization, $rootUid, 'Saison en cours', '/saison-en-cours' ); // > 'Saison en cours > Les évènements' page $this->insertPage( $organization, $this->createdPagesIndex['/saison-en-cours'], 'Les évènements', '/les-evenements', self::TEMPLATE_EVENTS ); // > 'Vie interne' page (restricted, hidden by default) $this->insertPage( $organization, $rootUid, 'Vie interne', '/vie-interne', '', [ 'hidden' => 1, 'fe_group' => -2 ] ); // > 'Footer' page (not in the menu) $this->insertPage( $organization, $rootUid, 'Footer', '/footer', '', [ 'dokType' => self::DOK_FOLDER, 'nav_hide' => 1 ] ); // > 'Footer > Contact' page $this->insertPage( $organization, $this->createdPagesIndex['/footer'], 'Contact', '/contact', self::TEMPLATE_CONTACT ); // > 'Footer > Plan du site' page $this->insertPage( $organization, $this->createdPagesIndex['/footer'], 'Plan du site', '/plan-du-site' ); // > 'Footer > Mentions légales' page $this->insertPage( $organization, $this->createdPagesIndex['/footer'], 'Mentions légales', '/mentions-legales' ); // > 'Page introuvable' page (not in the menu, read-only) $this->insertPage( $organization, $rootUid, 'Page introuvable', '/page-introuvable', self::TEMPLATE_E404, [ 'nav_hide' => 1, 'no_search' => 1 ] ); // Add content to these pages // >> root page content $this->insertContent( $rootUid, self::CTYPE_TEXTPIC, '

Bienvenue sur le site de ' . $organization->getName() . '.

', 0 ); // >> page 'qui sommes nous?' $this->insertContent( $this->createdPagesIndex['/qui-sommes-nous'], self::CTYPE_TEXT, 'Qui sommes nous ...', 0 ); // >> page 'historique' $this->insertContent( $this->createdPagesIndex['/historique'], self::CTYPE_TEXT, "Un peu d'histoire ...", 0 ); // >> page 'plan du site' $this->insertContent( $this->createdPagesIndex['/plan-du-site'], self::CTYPE_SITEMAP ); // >> page 'mentions légales' $this->insertContent( $this->createdPagesIndex['/mentions-legales'], self::CTYPE_TEXT, '

Mentions Légales

', 0 ); // Build and update the domain $domain = $organization->getSubDomain() . '.opentalent.fr'; $queryBuilder = $this->cnnPool->getQueryBuilderForTable('sys_domain'); $queryBuilder->insert('sys_domain') ->values([ 'pid' => $rootUid, 'domainName' => $domain ]) ->execute(); // Create the template $constants = "plugin.tx_ottemplating {" . " settings {" . " organization {" . " id = " . $organization->getId() . " name = " . $organization->getName() . " is_network = " . (1 ? $organization->getIsNetwork() : 0) . " email = " . $organization->getEmail() . " logoid = " . explode('/', $organization->getLogo(), -1)[0] . " twitter = " . $organization->getTwitter() . " facebook = " . $organization->getFacebook() . " }" . " network {" . " logo = " . $organization->getNetworkLogo() . " name = CMF" . $organization->getNetworkName() . " url = " . $organization->getNetworkUrl() . " }" . " }" . "}" . $queryBuilder = $this->cnnPool->getQueryBuilderForTable('sys_template'); $queryBuilder->insert('sys_template') ->values([ 'pid' => $rootUid, 'title' => $organization->getName(), 'sitetitle' => $organization->getName(), 'root' => 1, 'clear' => 3, 'include_static_file' => 'EXT:fluid_styled_content/Configuration/TypoScript/,EXT:fluid_styled_content/Configuration/TypoScript/Styling/,EXT:ot_widgets/Configuration/TypoScript,EXT:form/Configuration/TypoScript/,EXT:news/Configuration/TypoScript,EXT:ot_templating/Configuration/TypoScript', 'constants' => $constants ]) ->execute(); // Create the site config.yaml file $config = ['base'=> 'https://' . $domain, 'baseVariants'=>[], 'errorHandling'=>[ ['errorCode'=>'404', 'errorHandler'=>'Page', 'errorContentSource'=>'t3://page?uid=' . $this->createdPagesIndex['/page-introuvable']], ['errorCode'=>'403', 'errorHandler'=>'Page', 'errorContentSource'=>'t3://page?uid=' . $this->createdPagesIndex['/page-introuvable']] ], 'flux_content_types'=>'', 'flux_page_templates'=>'', 'languages'=>[[ 'title'=>'Fr', 'enabled'=>True, 'base'=>'/', 'typo3Language'=>'fr', 'locale'=>'fr_FR', 'iso-639-1'=>'fr', 'navigationTitle'=>'Fr', 'hreflang'=>'fr-FR', 'direction'=>'ltr', 'flag'=>'fr', 'languageId'=>'0', ]], 'rootPageId'=>$rootUid, 'routes'=>[] ]; $yamlConfig = Yaml::dump($config, 4); // Create the contact form $contscatForm = ""; // Create the BE user // Create the user_upload directory // throw new \Exception('not implemented'); // Try to commit the result foreach ($tables as $table) { $commitSuccess = $this->cnnPool->getConnectionForTable($table)->commit(); if (!$commitSuccess) { throw new \RuntimeException('Something went wrong while commiting the result'); } } return $rootUid; } catch(\Exception $e) { // rollback foreach ($tables as $table) { $this->cnnPool->getConnectionForTable($table)->rollback(); } throw $e; } } /** * Insert a new row in the 'pages' table of the Typo3 DB * * @param Organization $organization * @param int $pid * @param string $title * @param string $slug * @param string $template * @param array $moreValues * @return string */ private function insertPage(Organization $organization, int $pid, string $title, string $slug, string $template = '', array $moreValues = [] ) { $defaultValues = [ 'pid' => $pid, 'perms_groupid' => 3, 'perms_user' => 27, 'cruser_id' => 1, 'dokType' => self::DOK_PAGE, 'title' => $title, 'slug' => $slug, 'backend_layout' => 'flux__grid', 'backend_layout_next_level' => 'flux__grid', 'tx_opentalent_structure_id' => $organization->getId() ]; if ($template) { $defaultValues['tx_fed_page_controller_action'] = $template; $defaultValues['tx_fed_page_controller_action_sub'] = self::TEMPLATE_1COL; } $values = array_merge($defaultValues, $moreValues); $queryBuilder = $this->cnnPool->getQueryBuilderForTable('pages'); $queryBuilder->insert('pages') ->values($values) ->execute(); $uid = $queryBuilder->getConnection()->lastInsertId(); $this->createdPagesIndex[$slug] = $uid; return $uid; } /** * Insert the root page of a new organization's website * * @param Organization $organization * @return string */ private function insertRootPage(Organization $organization) { return $this->insertPage( $organization, self::DEFAULT_ROOT_PID, $organization->getName(), '/', self::TEMPLATE_HOME, [ 'is_siteroot' => 1, 'TSconfig' => 'TCAdefaults.pages.tx_opentalent_structure_id =' . $organization->getId(), 'tx_opentalent_template' => self::DEFAULT_THEME, 'tx_opentalent_template_preferences' => '{"themeColor":"' . self::DEFAULT_COLOR . '","displayCarousel":"1"}' ] ); } /** * Insert a new row in the 'tt_content' table of the Typo3 DB * * @param int $pid * @param string $cType * @param string $bodyText * @param int $colPos * @param array $moreValues */ private function insertContent(int $pid, string $cType=self::CTYPE_TEXT, string $bodyText = '', int $colPos=0, array $moreValues = []) { $defaultValues = [ 'pid' => $pid, 'cruser_id' => 1, 'CType' => $cType, 'colPos' => $colPos, 'bodyText' => $bodyText ]; $values = array_merge($defaultValues, $moreValues); $queryBuilder = $this->cnnPool->getQueryBuilderForTable('tt_content'); $queryBuilder->insert('tt_content') ->values($values) ->execute(); } }