public function testFindTemplates() { $base = dirname(__FILE__) . '/fixtures/templatemanifest'; $manifest = new SS_TemplateManifest($base, false, true); $loader = new SS_TemplateLoader(); $manifest->regenerate(false); $loader->pushManifest($manifest); $expectPage = array( 'main' => "$base/module/templates/Page.ss", 'Layout' => "$base/module/templates/Layout/Page.ss" ); $expectPageThemed = array( 'main' => "$base/themes/theme/templates/Page.ss", 'Layout' => "$base/themes/theme/templates/Layout/Page.ss" ); $this->assertEquals($expectPage, $loader->findTemplates('Page')); $this->assertEquals($expectPage, $loader->findTemplates(array('Foo', 'Page'))); $this->assertEquals($expectPage, $loader->findTemplates('PAGE')); $this->assertEquals($expectPageThemed, $loader->findTemplates('Page', 'theme')); $expectPageLayout = array('main' => "$base/module/templates/Layout/Page.ss"); $expectPageLayoutThemed = array('main' => "$base/themes/theme/templates/Layout/Page.ss"); $this->assertEquals($expectPageLayout, $loader->findTemplates('Layout/Page')); $this->assertEquals($expectPageLayout, $loader->findTemplates('Layout/PAGE')); $this->assertEquals($expectPageLayoutThemed, $loader->findTemplates('Layout/Page', 'theme')); $expectCustomPage = array( 'main' => "$base/module/templates/Page.ss", 'Layout' => "$base/module/templates/Layout/CustomPage.ss" ); $this->assertEquals($expectCustomPage, $loader->findTemplates(array('CustomPage', 'Page'))); }
/** * Pushes a class and template manifest instance that include tests onto the * top of the loader stacks. */ public static function use_test_manifest() { $classManifest = new SS_ClassManifest(BASE_PATH, true, isset($_GET['flush'])); SS_ClassLoader::instance()->pushManifest($classManifest); SapphireTest::set_test_class_manifest($classManifest); SS_TemplateLoader::instance()->pushManifest(new SS_TemplateManifest(BASE_PATH, true, isset($_GET['flush']))); }
function beforeCallActionHandler($request, $action) { if (!$this->owner->response->isFinished() && $action == 'build' && $request->getVar('flush')) { SS_TemplateLoader::instance()->getManifest()->regenerate(true); SSViewer::flush_template_cache(); } }
/** * Override to check if there is a custom template for this panel, otherwise fall back. * * @return string */ protected function getTemplate() { $templateName = get_class($this) . '_' . $this->SubjectPage()->ClassName . '_' . $this->GridFieldName; if (SS_TemplateLoader::instance()->findTemplates($templateName)) { return $templateName; } return parent::getTemplate(); }
/** * Override to check if there is a custom template for this panel, otherwise fall back * * @return string */ protected function getTemplate() { $templateName = get_class($this) . '_' . $this->ModelAdminClass . '_' . $this->ModelAdminModel; if (SS_TemplateLoader::instance()->findTemplates($templateName)) { return $templateName; } return parent::getTemplate(); }
public function tearDown() { SS_TemplateLoader::instance()->popManifest(); i18n::set_locale($this->originalLocale); Config::inst()->update('Director', 'alternate_base_folder', null); Config::inst()->update('SSViewer', 'theme', $this->_oldTheme); i18n::register_translator($this->origAdapter, 'core'); parent::tearDown(); }
public function tearDown() { SS_TemplateLoader::instance()->popManifest(); i18n::set_locale($this->originalLocale); Director::setBaseFolder(null); SSViewer::set_theme($this->_oldTheme); i18n::register_translator($this->origAdapter, 'core'); parent::tearDown(); }
/** * Pushes a class and template manifest instance that include tests onto the * top of the loader stacks. */ public static function use_test_manifest() { $classManifest = new SS_ClassManifest(BASE_PATH, true, isset($_GET['flush'])); SS_ClassLoader::instance()->pushManifest($classManifest, false); SapphireTest::set_test_class_manifest($classManifest); SS_TemplateLoader::instance()->pushManifest(new SS_TemplateManifest(BASE_PATH, project(), true, isset($_GET['flush']))); Config::inst()->pushConfigStaticManifest(new SS_ConfigStaticManifest(BASE_PATH, true, isset($_GET['flush']))); // Invalidate classname spec since the test manifest will now pull out new subclasses for each internal class // (e.g. Member will now have various subclasses of DataObjects that implement TestOnly) DataObject::clear_classname_spec_cache(); }
public function detectTemplate($templates) { $manifest = SS_TemplateLoader::instance()->getManifest(); if (Config::inst()->get('SSViewer', 'theme_enabled')) { $theme = Config::inst()->get('SSViewer', 'theme'); } else { $theme = null; } foreach ((array) $templates as $template) { if ($manifest->getCandidateTemplate($template, $theme)) { return $template; } } return false; }
public function updateCMSFields(FieldList $fields) { Requirements::css(SEO_DIR . '/css/seo.css'); // check for Google Sitemaps module & notification; $GSMactive = Config::inst()->get('GoogleSitemap', 'enabled', Config::INHERITED); $GSMping = Config::inst()->get('GoogleSitemap', 'google_notification_enabled', Config::INHERITED); // check for Redirectmanager $RedirActive = Object::has_extension("ContentController", "RedirectedURLHandler"); //$template = new SSViewer('AdminSiteConfigSeoTips'); //$seotips = $template->process($this->owner->customise(new ArrayData(array( $seotips = $this->owner->customise(new ArrayData(array('GSMactive' => $GSMactive, 'GSMping' => $GSMping, 'RedirActive' => $RedirActive)))->renderWith('AdminSiteConfigSeoTips'); $fields->addFieldToTab("Root.Main", LiteralField::create('SEOtips', $seotips)); // SEOTITLE // parse out the title tag as used by the theme; $loader = SS_TemplateLoader::instance(); $theme = Config::inst()->get('SSViewer', 'theme'); $foundpath = $loader->findTemplates("main/Page", $theme); // TODO: this is a guess... $path = $foundpath['main']; if (file_exists($path)) { $templatecode = file_get_contents($path); } else { throw new Exception('Failed to identify path'); } if ($templatecode && strpos($templatecode, '<title>')) { $templatetag = explode('<title>', $templatecode); $templatetag = array_pop($templatetag); $templatetag = explode('</title>', $templatetag); $templatetag = array_shift($templatetag); } else { $templatetag = false; } // $template = SSViewer::fromString($titlehtml); // $fulltitle = $template->process($this->owner); if ($templatetag) { $templatetag = "<br />Current template title tag: " . $templatetag; } else { $templatetag = ""; } // FIXME - not sure of the intention of this value, but set it to avoid site config breaking $titlehtml = ''; $fields->addFieldToTab("Root.Main", $seotitlefield = TextField::create('SEOTitleTemplate')->SetRightTitle("For SEO preview (valid js expression, available vars: page_title, page_menutitle, '.\n\t\t\t\t\t'page_metadata_title), eg:<br /> page_title + ' » ' +\n\t\t\t\tsiteconfig_title [OR] (page_metadata_title ? page_metadata_title : page_title)" . $titlehtml)); // set default/initial value if (!$this->owner->SEOTitleTemplate) { $seotitlefield->setValue("page_title + ' » ' + siteconfig_title"); } }
public function getStyles() { $config = SiteConfig::current_site_config(); if ($config->Theme) { Config::inst()->update('SSViewer', 'theme_enabled', true); Config::inst()->update('SSViewer', 'theme', $config->Theme); } $theme = $config->Theme; $manifest = SS_TemplateLoader::instance()->getManifest(); $templates = array(); // Debug::dump($manifest->getTemplates()); foreach ($manifest->getTemplates() as $templateName => $templateInfo) { $themeexists = $theme && isset($templateInfo['themes'][$theme]) && isset($templateInfo['themes'][$theme]['Styles']); if ((isset($templateInfo['Styles']) || $themeexists) && !isset($templates[$templateName])) { $templates[$templateName] = array('ID' => trim($templateName), 'Name' => trim(str_replace('_', ' ', $templateName)), 'Layout' => $this->renderWith(array($templateName))); } } return new ArrayList($templates); }
public function __construct($templateList) { // flush template manifest cache if requested if (isset($_GET['flush']) && $_GET['flush'] == 'all') { if (Director::isDev() || Director::is_cli() || Permission::check('ADMIN')) { self::flush_template_cache(); } else { return Security::permissionFailure(null, 'Please log in as an administrator to flush the template cache.'); } } if (!is_array($templateList) && substr((string) $templateList, -3) == '.ss') { $this->chosenTemplates['main'] = $templateList; } else { $this->chosenTemplates = SS_TemplateLoader::instance()->findTemplates($templateList, self::current_theme()); //Debug::show($this->chosenTemplates); } if (!$this->chosenTemplates) { $templateList = is_array($templateList) ? $templateList : array($templateList); user_error("None of these templates can be found in theme '" . self::current_theme() . "': " . implode(".ss, ", $templateList) . ".ss", E_USER_WARNING); } }
protected function templateArray() { global $project; $config = SiteConfig::current_site_config(); if ($config->Theme) { Config::inst()->update('SSViewer', 'theme_enabled', true); Config::inst()->update('SSViewer', 'theme', $config->Theme); } $theme = $config->Theme; $manifest = SS_TemplateLoader::instance()->getManifest(); $templateList = array(); foreach ($manifest->getTemplates() as $template_name => $templateInfo) { $projectexists = isset($templateInfo[$project]) && isset($templateInfo[$project]['Patterns']); $themeexists = $theme && isset($templateInfo['themes'][$theme]) && isset($templateInfo['themes'][$theme]['Patterns']); //always use project template files, and grab template files if not already used if ($projectexists || $themeexists && !isset($templateList[$template_name])) { $templateList[$template_name] = array('Link' => Controller::join_links(Director::absoluteBaseUrl(), 'patterns', 'index', $template_name), 'Name' => $this->stripeTemplateName($template_name), 'Template' => $template_name); } } ksort($templateList); return $templateList; }
/** * @param string $identifier A template name without '.ss' extension or path * @param string $type The template type, either "main", "Includes" or "Layout" * @return string Full system path to a template file */ public static function getTemplateFileByType($identifier, $type) { $loader = SS_TemplateLoader::instance(); $found = $loader->findTemplates("{$type}/{$identifier}", self::current_theme()); if ($found) { return $found['main']; } }
/** * Tests that {@link ContentController::getViewer()} chooses the correct templates. * * @covers ContentController::getViewer() **/ public function testGetViewer() { $self = $this; $this->useTestTheme(dirname(__FILE__), 'controllertest', function () use($self) { // Test a page without a controller (ContentControllerTest_PageWithoutController.ss) $page = new ContentControllerTestPageWithoutController(); $page->URLSegment = "test"; $page->write(); $page->publish("Stage", "Live"); $response = $self->get($page->RelativeLink()); $self->assertEquals("ContentControllerTestPageWithoutController", trim($response->getBody())); // // This should fall over to user Page.ss $page = new ContentControllerTestPage(); $page->URLSegment = "test"; $page->write(); $page->publish("Stage", "Live"); $response = $self->get($page->RelativeLink()); $self->assertEquals("Page", trim($response->getBody())); // Test that the action template is rendered. $page = new ContentControllerTestPage(); $page->URLSegment = "page-without-controller"; $page->write(); $page->publish("Stage", "Live"); $response = $self->get($page->RelativeLink("test")); $self->assertEquals("ContentControllerTestPage_test", trim($response->getBody())); // Test that an action without a template will default to the index template, which is // to say the default Page.ss template $response = $self->get($page->RelativeLink("testwithouttemplate")); $self->assertEquals("Page", trim($response->getBody())); // Test that an action with a template will render the both action template *and* the // correct parent template $controller = new ContentController($page); $viewer = $controller->getViewer('test'); $templateList = array('ContentControllerTestPage_test', 'Page'); $expected = SS_TemplateLoader::instance()->findTemplates($templateList, 'controllertest'); $self->assertEquals($expected, $viewer->templates()); }); }
/** * @param string $identifier A template name without '.ss' extension or path * @param string $type The template type, either "main", "Includes" or "Layout" * * @return string Full system path to a template file */ public static function getTemplateFileByType($identifier, $type) { $loader = SS_TemplateLoader::instance(); if (Config::inst()->get('SSViewer', 'theme_enabled')) { $theme = Config::inst()->get('SSViewer', 'theme'); } else { $theme = null; } $found = $loader->findTemplates("{$type}/{$identifier}", $theme); if (isset($found['main'])) { return $found['main']; } else { if (!empty($found)) { $founds = array_values($found); return $founds[0]; } } }
// The coupling is a hack, but it removes an annoying bug where new classes // referenced in _config.php files can be referenced during the build process. $flush = (isset($_GET['flush']) || isset($_REQUEST['url']) && ( $_REQUEST['url'] == 'dev/build' || $_REQUEST['url'] == BASE_URL . '/dev/build' )); $manifest = new SS_ClassManifest(BASE_PATH, false, $flush); $loader = SS_ClassLoader::instance(); $loader->registerAutoloader(); $loader->pushManifest($manifest); // Now that the class manifest is up, load the configuration $configManifest = new SS_ConfigManifest(BASE_PATH, false, $flush); Config::inst()->pushConfigManifest($configManifest); SS_TemplateLoader::instance()->pushManifest(new SS_TemplateManifest( BASE_PATH, false, isset($_GET['flush']) )); // If in live mode, ensure deprecation, strict and notices are not reported if(Director::isLive()) { error_reporting(E_ALL & ~(E_DEPRECATED | E_STRICT | E_NOTICE)); } /////////////////////////////////////////////////////////////////////////////// // POST-MANIFEST COMMANDS /** * Load error handlers */ Debug::loadErrorHandlers();
public function run($request) { echo 'Run with ?clear=1 to clear empty database before running the task<br/>'; echo 'Run with ?overwrite=1 to overwrite templates that exists in the cms<br/>'; echo 'Run with ?templates=xxx,yyy to specify which template should be imported<br/>'; echo 'Run with ?subsite=1 to create email templates in all subsites as well. Overwriting is based on main site.<br/>'; echo '<hr/>'; $overwrite = $request->getVar('overwrite'); $clear = $request->getVar('clear'); $templatesToImport = $request->getVar('templates'); $importToSubsite = $request->getVar('subsite'); $subsites = array(); if ($importToSubsite) { $subsites = Subsite::get()->map(); } if ($templatesToImport) { $templatesToImport = explode(',', $templatesToImport); } if ($clear == 1) { echo '<strong>Clear all email templates</strong><br/>'; $emailTemplates = EmailTemplate::get(); foreach ($emailTemplates as $emailTemplate) { $emailTemplate->delete(); } } $o = singleton('EmailTemplate'); $ignoredModules = self::config()->ignored_modules; if (!is_array($ignoredModules)) { $ignoredModules = array(); } $locales = null; if (class_exists('Fluent') && Fluent::locale_names()) { if ($o->hasExtension('FluentExtension')) { $locales = array_keys(Fluent::locale_names()); } } $defaultLocale = i18n::get_locale(); $templates = SS_TemplateLoader::instance()->getManifest()->getTemplates(); foreach ($templates as $t) { $isOverwritten = false; // Emails in mysite/email are not properly marked as emails if (isset($t['mysite']) && isset($t['mysite']['email'])) { $t['email'] = $t['mysite']['email']; } // Should be in the /email folder if (!isset($t['email'])) { continue; } $filePath = $t['email']; $fileName = basename($filePath, '.ss'); // Should end with *Email if (!preg_match('/Email$/', $fileName)) { continue; } $relativeFilePath = str_replace(Director::baseFolder(), '', $filePath); $relativeFilePathParts = explode('/', trim($relativeFilePath, '/')); // Group by module $module = array_shift($relativeFilePathParts); // Ignore some modules if (in_array($module, $ignoredModules)) { continue; } array_shift($relativeFilePathParts); // remove /templates part $templateName = str_replace('.ss', '', implode('/', $relativeFilePathParts)); $templateTitle = basename($templateName); // Create a default code from template name $code = strtolower(preg_replace('/([a-zA-Z])(?=[A-Z])/', '$1-', $fileName)); $code = preg_replace('/-email$/', '', $code); if (!empty($templatesToImport) && !in_array($code, $templatesToImport)) { echo "<div style='color:blue'>Template with code '{$code}' was ignored.</div>"; continue; } $emailTemplate = EmailTemplate::get()->filter('Code', $code)->first(); if (!$overwrite && $emailTemplate) { echo "<div style='color:blue'>Template with code '{$code}' already exists.</div>"; continue; } // Create a default title from code $title = explode('-', $code); $title = array_map(function ($item) { return ucfirst($item); }, $title); $title = implode(' ', $title); // Get content of the email $content = file_get_contents($filePath); // Analyze content to find incompatibilities $errors = array(); if (strpos($content, '<% with') !== false) { $errors[] = 'Replace "with" blocks by plain calls to the variable'; } if (strpos($content, '<% if') !== false) { $errors[] = 'If/else logic is not supported. Please create one template by use case or abstract logic into the model'; } if (strpos($content, '<% loop') !== false) { $errors[] = 'Loops are not supported. Please create a helper method on the model to render the loop'; } if (strpos($content, '<% sprintf') !== false) { $errors[] = 'You should not use sprintf to escape content, please use plain _t calls'; } if (!empty($errors)) { echo "<div style='color:red'>Invalid syntax was found in '{$relativeFilePath}'. Please fix these errors before importing the template<ul>"; foreach ($errors as $error) { echo '<li>' . $error . '</li>'; } echo '</ul></div>'; continue; } // Parse language $collector = new i18nTextCollector(); $entities = $collector->collectFromTemplate($content, $fileName, $module); $translationTable = array(); foreach ($entities as $entity => $data) { if ($locales) { foreach ($locales as $locale) { i18n::set_locale($locale); if (!isset($translationTable[$entity])) { $translationTable[$entity] = array(); } $translationTable[$entity][$locale] = i18n::_t($entity); } i18n::set_locale($defaultLocale); } else { $translationTable[$entity] = array($defaultLocale => i18n::_t($entity)); } } $contentLocale = array(); foreach ($locales as $locale) { $contentLocale[$locale] = $content; } foreach ($translationTable as $entity => $translationData) { $escapedEntity = str_replace('.', '\\.', $entity); $baseTranslation = null; foreach ($translationData as $locale => $translation) { if (!$baseTranslation && $translation) { $baseTranslation = $translation; } if (!$translation) { $translation = $baseTranslation; } // This regex should match old and new style $count = 0; $contentLocale[$locale] = preg_replace("/<%(t | _t\\(')" . $escapedEntity . "( |').*?%>/ums", $translation, $contentLocale[$locale], -1, $count); if (!$count) { throw new Exception("Failed to replace {$escapedEntity} with translation {$translation}"); } } } if (!$emailTemplate) { $emailTemplate = new EmailTemplate(); } else { $isOverwritten = true; } // Scan for extra models based on convention preg_match_all('/\\$([a-zA-Z]+)\\./ms', $contentLocale[$defaultLocale], $matches); $extraModels = array(); if (!empty($matches) && !empty($matches[1])) { $arr = array_unique($matches[1]); foreach ($arr as $n) { if (strtolower($n) === 'siteconfig') { continue; } if (class_exists($n)) { $extraModels[$n] = $n; } } } // Apply content to email $this->assignContent($emailTemplate, $contentLocale[$defaultLocale]); if (!empty($locales)) { foreach ($locales as $locale) { $this->assignContent($emailTemplate, $contentLocale[$locale], $locale); } } // Title $emailTemplate->Title = $title; if (!empty($locales)) { // By convention, we store the translation under NameOfTheTemplateEmail.SUBJECT foreach ($locales as $locale) { i18n::set_locale($locale); $localeField = 'Title_' . $locale; $entity = $templateTitle . '.SUBJECT'; $translation = i18n::_t($entity); if (!$translation) { $translation = $title; } $emailTemplate->{$localeField} = $translation; if (strpos($translation, '%s') !== false) { echo '<div style="color:red">There is a %s in the title that should be replaced in locale ' . $locale . '!</div>'; } if ($locale == $defaultLocale) { $emailTemplate->Title = $translation; } } i18n::set_locale($defaultLocale); } // Other properties $emailTemplate->Code = $code; $emailTemplate->Category = $module; $emailTemplate->setExtraModelsAsArray($extraModels); $emailTemplate->write(); $subsiteImport = ''; // Loop through subsites if ($importToSubsite) { $subsiteImport .= ' => Main site and subsites'; Subsite::$disable_subsite_filter = true; foreach ($subsites as $subsiteID => $subsiteTitle) { $subsiteEmailTemplate = EmailTemplate::get()->filter(array('Code' => $code, 'SubsiteID' => $subsiteID))->first(); $emailTemplateCopy = $emailTemplate; $emailTemplateCopy->SubsiteID = $subsiteID; if ($subsiteEmailTemplate) { $emailTemplateCopy->ID = $subsiteEmailTemplate->ID; } else { $emailTemplateCopy->ID = 0; // New } $emailTemplateCopy->write(); } } if ($isOverwritten) { echo "<div style='color:orange'>Overwrote {$emailTemplate->Code}{$subsiteImport}</div>"; } else { echo "<div style='color:green'>Imported {$emailTemplate->Code}{$subsiteImport}</div>"; } } }
/** * Test against a theme. * * @param $themeBaseDir string - themes directory * @param $theme string - theme name * @param $callback Closure */ protected function useTestTheme($themeBaseDir, $theme, $callback) { Config::nest(); global $project; $manifest = new SS_TemplateManifest($themeBaseDir, $project, true, true); SS_TemplateLoader::instance()->pushManifest($manifest); Config::inst()->update('SSViewer', 'theme', $theme); $e = null; try { $callback(); } catch (Exception $e) { /* NOP for now, just save $e */ } // Remove all the test themes we created SS_TemplateLoader::instance()->popManifest(); Config::unnest(); if ($e) { throw $e; } }
require_once 'core/manifest/TemplateManifest.php'; require_once 'core/manifest/TokenisedRegularExpression.php'; /////////////////////////////////////////////////////////////////////////////// // MANIFEST // Regenerate the manifest if ?flush is set, or if the database is being built. // The coupling is a hack, but it removes an annoying bug where new classes // referenced in _config.php files can be referenced during the build process. $flush = isset($_GET['flush']) || isset($_REQUEST['url']) && ($_REQUEST['url'] == 'dev/build' || $_REQUEST['url'] == BASE_URL . '/dev/build'); $manifest = new SS_ClassManifest(BASE_PATH, false, $flush); $loader = SS_ClassLoader::instance(); $loader->registerAutoloader(); $loader->pushManifest($manifest); // Now that the class manifest is up, load the configuration $configManifest = new SS_ConfigManifest(BASE_PATH, false, $flush); Config::inst()->pushConfigManifest($configManifest); SS_TemplateLoader::instance()->pushManifest(new SS_TemplateManifest(BASE_PATH, false, isset($_GET['flush']))); // If in live mode, ensure deprecation, strict and notices are not reported if (Director::isLive()) { error_reporting(E_ALL & ~(E_DEPRECATED | E_STRICT | E_NOTICE)); } /////////////////////////////////////////////////////////////////////////////// // POST-MANIFEST COMMANDS /** * Load error handlers */ Debug::loadErrorHandlers(); // initialise the dependency injector $default_options = array('locator' => 'SilverStripeServiceConfigurationLocator'); Injector::inst($default_options); /////////////////////////////////////////////////////////////////////////////// // HELPER FUNCTIONS
public function run($request) { echo 'Run with ?clear=1 to clear empty database before running the task<br/>'; echo 'Run with ?overwrite=soft|hard to overwrite templates that exists in the cms. Soft will replace template if not modified by the user, hard will replace template even if modified by user.<br/>'; echo 'Run with ?templates=xxx,yyy to specify which template should be imported<br/>'; echo 'Run with ?subsite=all|subsiteID to create email templates in all subsites (including main site) or only in the chosen subsite (if a subsite is active, it will be used by default).<br/>'; echo 'Run with ?locales=fr,en to choose which locale to import.<br/>'; echo '<strong>Remember to flush the templates/translations if needed</strong><br/>'; echo '<hr/>'; $overwrite = $request->getVar('overwrite'); $clear = $request->getVar('clear'); $templatesToImport = $request->getVar('templates'); $importToSubsite = $request->getVar('subsite'); $chosenLocales = $request->getVar('locales'); // Normalize argument if ($overwrite && $overwrite != 'soft' && $overwrite != 'hard') { $overwrite = 'soft'; } $subsites = array(); if ($importToSubsite == 'all') { $subsites = Subsite::get()->map(); } else { if (is_numeric($importToSubsite)) { $subsites = array($importToSubsite => Subsite::get()->byID($importToSubsite)->Title); } } if (class_exists('Subsite') && Subsite::currentSubsiteID()) { DB::alteration_message("Importing to current subsite. Run from main site to import other subsites at once.", "created"); $subsites = array(); } if (!empty($subsites)) { DB::alteration_message("Importing to subsites : " . implode(',', array_values($subsites)), "created"); } if ($templatesToImport) { $templatesToImport = explode(',', $templatesToImport); } if ($clear == 1) { DB::alteration_message("Clear all email templates", "created"); $emailTemplates = EmailTemplate::get(); foreach ($emailTemplates as $emailTemplate) { $emailTemplate->delete(); } } $emailTemplateSingl = singleton('EmailTemplate'); $ignoredModules = self::config()->ignored_modules; if (!is_array($ignoredModules)) { $ignoredModules = array(); } $locales = null; if (class_exists('Fluent') && Fluent::locale_names()) { if ($emailTemplateSingl->hasExtension('FluentExtension')) { $locales = array_keys(Fluent::locale_names()); if ($chosenLocales) { $arr = explode(',', $chosenLocales); $locales = array(); foreach ($arr as $a) { if (strlen($a) == 2) { $a = i18n::get_locale_from_lang($a); } $locales[] = $a; } } } } $defaultLocale = i18n::get_locale(); $templates = SS_TemplateLoader::instance()->getManifest()->getTemplates(); foreach ($templates as $t) { $isOverwritten = false; // Emails in mysite/email are not properly marked as emails if (isset($t['mysite']) && isset($t['mysite']['email'])) { $t['email'] = $t['mysite']['email']; } // Should be in the /email folder if (!isset($t['email'])) { continue; } $filePath = $t['email']; $fileName = basename($filePath, '.ss'); // Should end with *Email if (!preg_match('/Email$/', $fileName)) { continue; } $relativeFilePath = str_replace(Director::baseFolder(), '', $filePath); $relativeFilePathParts = explode('/', trim($relativeFilePath, '/')); // Group by module $module = array_shift($relativeFilePathParts); // Ignore some modules if (in_array($module, $ignoredModules)) { continue; } array_shift($relativeFilePathParts); // remove /templates part $templateName = str_replace('.ss', '', implode('/', $relativeFilePathParts)); $templateTitle = basename($templateName); // Create a default code from template name $code = strtolower(preg_replace('/([a-zA-Z])(?=[A-Z])/', '$1-', $fileName)); $code = preg_replace('/-email$/', '', $code); if (!empty($templatesToImport) && !in_array($code, $templatesToImport)) { DB::alteration_message("Template with code <b>{$code}</b> was ignored.", "repaired"); continue; } $whereCode = array('Code' => $code); $emailTemplate = EmailTemplate::get()->filter($whereCode)->first(); // Check if it has been modified or not $templateModified = false; if ($emailTemplate) { $templateModified = $emailTemplate->Created != $emailTemplate->LastEdited; } if (!$overwrite && $emailTemplate) { DB::alteration_message("Template with code <b>{$code}</b> already exists. Choose overwrite if you want to import again.", "repaired"); continue; } if ($overwrite == 'soft' && $templateModified) { DB::alteration_message("Template with code <b>{$code}</b> has been modified by the user. Choose overwrite=hard to change.", "repaired"); continue; } // Create a default title from code $title = explode('-', $code); $title = array_map(function ($item) { return ucfirst($item); }, $title); $title = implode(' ', $title); // Get content of the email $content = file_get_contents($filePath); // Analyze content to find incompatibilities $errors = array(); if (strpos($content, '<% with') !== false) { $errors[] = 'Replace "with" blocks by plain calls to the variable'; } if (strpos($content, '<% if') !== false) { $errors[] = 'If/else logic is not supported. Please create one template by use case or abstract logic into the model'; } if (strpos($content, '<% loop') !== false) { $errors[] = 'Loops are not supported. Please create a helper method on the model to render the loop'; } if (strpos($content, '<% sprintf') !== false) { $errors[] = 'You should not use sprintf to escape content, please use plain _t calls'; } if (!empty($errors)) { echo "<div style='color:red'>Invalid syntax was found in '{$relativeFilePath}'. Please fix these errors before importing the template<ul>"; foreach ($errors as $error) { echo '<li>' . $error . '</li>'; } echo '</ul></div>'; continue; } // Parse language $collector = new i18nTextCollector(); $entities = $collector->collectFromTemplate($content, $fileName, $module); $translationTable = array(); foreach ($entities as $entity => $data) { if ($locales) { foreach ($locales as $locale) { i18n::set_locale($locale); if (!isset($translationTable[$entity])) { $translationTable[$entity] = array(); } $translationTable[$entity][$locale] = i18n::_t($entity); } i18n::set_locale($defaultLocale); } else { $translationTable[$entity] = array($defaultLocale => i18n::_t($entity)); } } $contentLocale = array(); foreach ($locales as $locale) { $contentLocale[$locale] = $content; } foreach ($translationTable as $entity => $translationData) { $escapedEntity = str_replace('.', '\\.', $entity); $baseTranslation = null; foreach ($translationData as $locale => $translation) { if (!$baseTranslation && $translation) { $baseTranslation = $translation; } if (!$translation) { $translation = $baseTranslation; } // This regex should match old and new style $count = 0; $contentLocale[$locale] = preg_replace("/<%(t | _t\\(')" . $escapedEntity . "( |').*?%>/ums", $translation, $contentLocale[$locale], -1, $count); if (!$count) { throw new Exception("Failed to replace {$escapedEntity} with translation {$translation}"); } } } if (!$emailTemplate) { $emailTemplate = new EmailTemplate(); } else { $isOverwritten = true; } // Scan for extra models based on convention preg_match_all('/\\$([a-zA-Z]+)\\./ms', $contentLocale[$defaultLocale], $matches); $extraModels = array(); if (!empty($matches) && !empty($matches[1])) { $arr = array_unique($matches[1]); foreach ($arr as $n) { if (strtolower($n) === 'siteconfig') { continue; } if (class_exists($n)) { $extraModels[$n] = $n; } } } // Apply content to email $this->assignContent($emailTemplate, $contentLocale[$defaultLocale]); if (!empty($locales)) { foreach ($locales as $locale) { $this->assignContent($emailTemplate, $contentLocale[$locale], $locale); } } // Title $emailTemplate->Title = $title; if (!empty($locales)) { // By convention, we store the translation under NameOfTheTemplateEmail.SUBJECT foreach ($locales as $locale) { i18n::set_locale($locale); $localeField = 'Title_' . $locale; $entity = $templateTitle . '.SUBJECT'; $translation = i18n::_t($entity); if (!$translation) { $translation = $title; DB::alteration_message("No title found in {$locale} for {$title}. You should define {$templateTitle}.SUBJECT", "error"); } $emailTemplate->{$localeField} = $translation; if (strpos($translation, '%s') !== false) { echo '<div style="color:red">There is a %s in the title that should be replaced in locale ' . $locale . '!</div>'; } if ($locale == $defaultLocale) { $emailTemplate->Title = $translation; } } i18n::set_locale($defaultLocale); } // Other properties $emailTemplate->Code = $code; $emailTemplate->Category = $module; if (class_exists('Subsite') && Subsite::currentSubsiteID()) { $emailTemplate->SubsiteID = Subsite::currentSubsiteID(); } $emailTemplate->setExtraModelsAsArray($extraModels); // Write to main site or current subsite $emailTemplate->write(); $this->resetLastEditedDate($emailTemplate->ID); // Loop through subsites if (!empty($importToSubsite)) { Subsite::$disable_subsite_filter = true; foreach ($subsites as $subsiteID => $subsiteTitle) { $whereCode['SubsiteID'] = $subsiteID; $subsiteEmailTemplate = EmailTemplate::get()->filter($whereCode)->first(); $emailTemplateCopy = $emailTemplate; $emailTemplateCopy->SubsiteID = $subsiteID; if ($subsiteEmailTemplate) { $emailTemplateCopy->ID = $subsiteEmailTemplate->ID; } else { $emailTemplateCopy->ID = 0; // New } $emailTemplateCopy->write(); $this->resetLastEditedDate($emailTemplateCopy->ID); } } if ($isOverwritten) { DB::alteration_message("Overwrote <b>{$emailTemplate->Code}</b>", "created"); } else { DB::alteration_message("Imported <b>{$emailTemplate->Code}</b>", "created"); } } }
// Register SilverStripe's class map autoload $loader = SS_ClassLoader::instance(); $loader->registerAutoloader(); $loader->pushManifest($manifest); // Fall back to Composer's autoloader (e.g. for PHPUnit), if composer is used if (file_exists(BASE_PATH . '/vendor/autoload.php')) { require_once BASE_PATH . '/vendor/autoload.php'; } // Now that the class manifest is up, load the static configuration $configManifest = new SS_ConfigStaticManifest(BASE_PATH, false, $flush); Config::inst()->pushConfigStaticManifest($configManifest); // And then the yaml configuration $configManifest = new SS_ConfigManifest(BASE_PATH, false, $flush); Config::inst()->pushConfigYamlManifest($configManifest); // Load template manifest SS_TemplateLoader::instance()->pushManifest(new SS_TemplateManifest(BASE_PATH, project(), false, $flush)); // If in live mode, ensure deprecation, strict and notices are not reported if (Director::isLive()) { error_reporting(E_ALL & ~(E_DEPRECATED | E_STRICT | E_NOTICE)); } /////////////////////////////////////////////////////////////////////////////// // POST-MANIFEST COMMANDS /** * Load error handlers */ Debug::loadErrorHandlers(); /////////////////////////////////////////////////////////////////////////////// // HELPER FUNCTIONS /** * Creates a class instance by the "singleton" design pattern. * It will always return the same instance for this class,
/** * Find an alternative template for the current page in a separate theme * * @param type $inTheme */ protected function findAlternate($inTheme, $templates = array(), $action = null) { if (is_array($templates)) { if (count($templates) == 0) { // duplicated from Controller::getViewer $parentClass = $this->owner->class; if ($action && $action != 'index') { $parentClass = $this->owner->class; while ($parentClass != "Controller" && $parentClass != 'DataObject') { $templates[] = strtok($parentClass, '_') . '_' . $action; $parentClass = get_parent_class($parentClass); } } // Add controller templates for inheritance chain $parentClass = $this->owner->class; // This is slightly different from Controller::getViewer to prevent // picking up the cms/controller template in the findTemplates call while ($parentClass != "ContentController" && $parentClass != 'DataObject') { $templates[] = strtok($parentClass, '_'); $parentClass = get_parent_class($parentClass); } } // remove duplicates $templates = array_unique($templates); } $other = SS_TemplateLoader::instance()->findTemplates($templates, $inTheme); // check that the theme's path is actually in the returned paths foreach ($other as $key => $path) { if (strpos($path, 'themes/' . $inTheme) === false) { unset($other[$key]); } } if (count($other)) { return $other; } }
/** * @return SS_TemplateLoader */ public static function instance() { return self::$instance ? self::$instance : (self::$instance = new self()); }
/** * Find the appropriate "$Layout" template for this class * @throws Exception * @return string */ protected function findLayout() { $theme = Config::inst()->get('SSViewer', 'theme'); $templateList = array(); $parentClass = $this->getOwner()->class; while ($parentClass !== 'SiteTree') { $templateList[] = $parentClass; $parentClass = get_parent_class($parentClass); } $templates = SS_TemplateLoader::instance()->findTemplates($templateList, $theme); if (!isset($templates['Layout'])) { throw new Exception('No layout found for class: ' . get_class($this->getOwner())); } return $templates['Layout']; }
/** * @return mixed * @throws Exception */ public function getTemplate() { $templates = SS_TemplateLoader::instance()->findTemplates($tryTemplates = $this->getTemplates(), Config::inst()->get('SSViewer', 'theme')); if (!$templates) { throw new Exception('Can\'t find a template from list: "' . implode('", "', $tryTemplates) . '"'); } return reset($templates); }
/** * Loads all the static .ss templates as HTML into memory */ protected function loadTemplates() { $manifest = SS_TemplateLoader::instance()->getManifest(); $templates = $manifest->getTemplates(); $total = sizeof($templates); $count = 0; $this->output->clearProgress(); foreach ($templates as $name => $data) { foreach ($manifest->getCandidateTemplate($name, $this->theme) as $template) { $this->samples[] = $template; } $count++; $this->output->updateProgressPercent($count, $total); } $this->output->writeln(); }
function tearDown() { SS_TemplateLoader::instance()->popManifest(); i18n::set_locale($this->originalLocale); parent::tearDown(); }
function tearDown() { SS_TemplateLoader::instance()->popManifest(); parent::tearDown(); }