public function fix_fluent_menu() { if (!class_exists('Fluent')) { return; } $conf = SiteConfig::current_site_config(); $localesNames = Fluent::locale_names(); if ($conf->hasExtension('ActiveLocalesExtension') && $conf->ActiveLocales) { $localesNames = $conf->ActiveLocalesNames(); } $locales = json_encode($localesNames); $locale = json_encode(Fluent::current_locale()); // If we have only one locale, set this one as default if (count($localesNames) === 1) { $locale = json_encode(key($localesNames)); } $param = json_encode(Fluent::config()->query_param); $buttonTitle = json_encode(_t('Fluent.ChangeLocale', 'Change Locale')); Requirements::block('FluentHeadScript'); Requirements::insertHeadTags(<<<EOT <script type="text/javascript"> //<![CDATA[ \tvar fluentLocales = {$locales}; \tvar fluentLocale = {$locale}; \tvar fluentParam = {$param}; \tvar fluentButtonTitle = {$buttonTitle}; //]]> </script> EOT , 'FluentHeadScriptSubsite'); }
public function augmentSQL(SQLQuery &$query, DataQuery &$dataQuery = null) { // When filtering my menu, swap out condition for locale specific condition $locale = Fluent::current_locale(); $field = Fluent::db_field_for_locale("ShowInMenus", $locale); $query->replaceText("\"{$this->ownerBaseClass}\".\"ShowInMenus\"", "\"{$this->ownerBaseClass}\".\"{$field}\""); }
/** * Retrieves information about this object in the CURRENT locale * * @param string $locale The locale information to request, or null to use the default locale * @return ArrayData Mapped list of locale properties */ public function CurrentLocaleInformation() { $locale = Fluent::current_locale(); // Store basic locale information $data = array('Locale' => $locale, 'LocaleRFC1766' => i18n::convert_rfc1766($locale), 'Alias' => Fluent::alias($locale), 'Title' => i18n::get_locale_name($locale), 'LanguageNative' => i18n::get_language_name(i18n::get_lang_from_locale($locale), true)); return new ArrayData($data); }
public function preRequest(SS_HTTPRequest $request, Session $session, DataModel $model) { // Ensures routes etc are setup // We need to inject the presented session temporarily, as there is no current controller set FluentSession::with_session($session, function () { Fluent::init(); }); }
public function updateCMSFields(FieldList $fields) { parent::updateCMSFields($fields); // Fix URLSegment field issue for root pages if (!SiteTree::config()->nested_urls || empty($this->owner->ParentID)) { $baseLink = Director::absoluteURL(Controller::join_links(Director::baseURL(), Fluent::alias(Fluent::current_locale()), '/')); $urlsegment = $fields->dataFieldByName('URLSegment'); $urlsegment->setURLPrefix($baseLink); } }
public function init() { $dirName = basename(dirname(dirname(dirname(__FILE__)))); $locales = json_encode(Fluent::locale_names()); $locale = json_encode(Fluent::current_locale()); $param = json_encode(Fluent::config()->query_param); $buttonTitle = json_encode(_t('Fluent.ChangeLocale', 'Change Locale')); // Force the variables to be written to the head, to ensure these are available for other scripts to pick up. Requirements::insertHeadTags(<<<EOT <script type="text/javascript"> //<![CDATA[ \tvar fluentLocales = {$locales}; \tvar fluentLocale = {$locale}; \tvar fluentParam = {$param}; \tvar fluentButtonTitle = {$buttonTitle}; //]]> </script> EOT , 'FluentHeadScript'); Requirements::javascript("{$dirName}/javascript/fluent.js"); Requirements::css("{$dirName}/css/fluent.css"); }
public function handleRequest(SS_HTTPRequest $request, DataModel $model = null) { self::$is_at_root = true; $this->setDataModel($model); $this->pushCurrent(); $this->init(); $this->setRequest($request); // Check for existing routing parameters, redirecting to another locale automatically if necessary $locale = Fluent::get_request_locale(); if (empty($locale)) { // Determine if this user should be redirected $locale = $this->getRedirectLocale(); $this->extend('updateRedirectLocale', $locale); // Check if the user should be redirected $domainDefault = Fluent::default_locale(true); if (Fluent::is_locale($locale) && $locale !== $domainDefault) { // Check new traffic with detected locale return $this->redirect(Fluent::locale_baseurl($locale)); } // Reset parameters to act in the default locale $locale = $domainDefault; Fluent::set_persist_locale($locale); $params = $request->routeParams(); $params[Fluent::config()->query_param] = $locale; $request->setRouteParams($params); } if (!DB::isActive() || !ClassInfo::hasTable('SiteTree')) { $this->response = new SS_HTTPResponse(); $this->response->redirect(Director::absoluteBaseURL() . 'dev/build?returnURL=' . (isset($_GET['url']) ? urlencode($_GET['url']) : null)); return $this->response; } $localeURL = Fluent::alias($locale); $request->setUrl(self::fluent_homepage_link($localeURL)); $request->match($localeURL . '/$URLSegment//$Action', true); $controller = new ModelAsController(); $result = $controller->handleRequest($request, $model); $this->popCurrent(); return $result; }
function get_silverstripe_language() { $locale = i18n::get_locale(); if (class_exists('Fluent')) { $locale = Fluent::get_persist_locale(); } $lang = i18n::get_lang_from_locale($locale); if ($lang == 'en') { return 'en_EN'; } if ($lang == 'fr') { return 'fr_FR'; } // Otherwise look in lang folder $ulocale = str_replace('-', '_', $locale); $lang_folder = dirname(__DIR__) . '/lang/'; if (is_file($lang_folder . $lang . '.php')) { return $lang; } if (is_file($lang_folder . $ulocale . '.php')) { return $ulocale; } return 'en_EN'; }
/** * Set/Install the given locale. * This does set the i18n locale as well as the Translatable or Fluent locale (if any of these modules is installed) * @param string $locale the locale to install * @throws Zend_Locale_Exception @see Zend_Locale_Format::getDateFormat and @see Zend_Locale_Format::getTimeFormat */ public static function install_locale($locale) { // If the locale isn't given, silently fail (there might be carts that still have locale set to null) if (empty($locale)) { return; } if (class_exists('Translatable')) { Translatable::set_current_locale($locale); } else { if (class_exists('Fluent')) { Fluent::set_persist_locale($locale); } } // Do something like Fluent does to install the locale i18n::set_locale($locale); // LC_NUMERIC causes SQL errors for some locales (comma as decimal indicator) so skip foreach (array(LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_TIME) as $category) { setlocale($category, "{$locale}.UTF-8", $locale); } // Get date/time formats from Zend require_once 'Zend/Date.php'; i18n::config()->date_format = Zend_Locale_Format::getDateFormat($locale); i18n::config()->time_format = Zend_Locale_Format::getTimeFormat($locale); }
/** * 系统错误,可直接将Exception对象传给$msg * @param string/Exception $msg */ public static function show_500($msg = null) { Core::close_buffers(false); # 避免输出的CSS头试抛出页面无法显示 @header('Content-Type: text/html;charset=' . Core::config('charset'), true); HttpIO::$status = 500; HttpIO::send_headers(); if (null === $msg) { $msg = __('Internal Server Error'); } if (IS_DEBUG && class_exists('DevException', false)) { if ($msg instanceof Exception) { $e = $msg; } else { $e = new Exception($msg); } echo DevException::exception_handler($e, true); exit; } if (IS_CLI) { echo "[31m", $msg, CRLF, "[39m", CRLF; exit; } try { if ($msg instanceof Exception) { $error = $msg->getMessage(); $trace_obj = $msg; } else { $error = $msg; $trace_obj = new Exception($msg); } $error_config = Core::config('error500'); $view = new View('error/500'); if ($error_config && isset($error_config['close']) && $error_config['close'] == true) { # 不记录 $view->error_saved = false; $error_no = ''; } else { $trace_array = array('project' => Core::$project, 'admin_mode' => IS_ADMIN_MODE, 'uri' => HttpIO::$uri, 'url' => HttpIO::PROTOCOL . $_SERVER['HTTP_HOST'] . $_SERVER["REQUEST_URI"], 'post' => HttpIO::POST(null, HttpIO::PARAM_TYPE_OLDDATA), 'get' => $_SERVER['QUERY_STRING'], 'cookie' => HttpIO::COOKIE(null, HttpIO::PARAM_TYPE_OLDDATA), 'client_ip' => HttpIO::IP, 'user_agent' => HttpIO::USER_AGENT, 'referrer' => HttpIO::REFERRER, 'server_ip' => $_SERVER["SERVER_ADDR"]); $date = @date('Y-m-d'); $no = strtoupper(substr(md5(serialize($trace_array)), 10, 10)); $error_no = $date . '-' . $no; # 其它数据 $trace_array['server_name'] = function_exists('php_uname') ? php_uname('a') : 'unknown'; $trace_array['time'] = TIME; $trace_array['use_time'] = microtime(1) - START_TIME; $trace_array['trace'] = (string) $trace_obj; $trace_string = Core::json_encode($trace_array); $view->error_saved = true; # 记录错误日志 try { if (isset($error_config['save_type']) && $error_config['save_type']) { $save_type = $error_config['save_type']; } else { $save_type = 'file'; } if ($save_type === 'file') { # 文件模式 $write_mode = Core::config('file_write_mode'); if (preg_match('#^(db|cache|fluent)://(([a-z0-9\\.\\-_]+)(?:\\:|/)([a-z0-9_]+))$#i', $write_mode, $m)) { $save_type = $m[1]; $error_config['server'] = $m[2]; $error_config['type_config'] = $m[3]; } } switch ($save_type) { case 'database': $obj = $error_config['type_config'] ? new Database($error_config['type_config']) : new Database(); $data = array('time' => strtotime($date . ' 00:00:00'), 'no' => $no, 'log' => $obj->is_support_object_value() ? $trace_array : $trace_string, 'expire_time' => TIME + 7 * 86400); $obj->insert('error500_log', $data); break; case 'cache': $obj = $error_config['type_config'] ? new Cache($error_config['type_config']) : new Cache(); if (!$obj->get($error_no)) { $obj->set($error_no, $trace_string, 7 * 86400); } break; case 'fluent': if (strpos($error_config['server'], ':') !== false) { $fd_server = 'tcp://' . $error_config['server']; } else { $fd_server = 'udp://' . $error_config['server']; } $obj = Fluent::instance($fd_server); $obj->push('system.error500', $trace_array); break; default: $file = DIR_LOG . 'error500' . DS . str_replace('-', DS, $date) . DS . $no . '.log'; if (!is_file($file)) { File::create_file($file, date('Y-m-d\\TH:i:s') . ' - ' . $trace_string, null, null, $error_config['type_config'] ? $error_config['type_config'] : 'default'); } break; } } catch (Exception $e) { } } $view->error_no = $error_no; $view->error = $error; $view->render(true); } catch (Exception $e) { list($REQUEST_URI) = explode('?', $_SERVER['REQUEST_URI'], 2); $REQUEST_URI = htmlspecialchars(rawurldecode($REQUEST_URI)); echo '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">' . CRLF . '<html>' . CRLF . '<head>' . CRLF . '<title>Internal Server Error</title>' . CRLF . '</head>' . CRLF . '<body>' . CRLF . '<h1>Internal Server Error</h1>' . CRLF . '<p>The requested URL ' . $REQUEST_URI . ' was error on this server.</p>' . CRLF . '<hr />' . CRLF . $_SERVER['SERVER_SIGNATURE'] . '<br/><br/><br/>' . CRLF . 'Powered by MyQEE V' . Core::VERSION . CRLF . '</body>' . CRLF . '</html>'; } exit; }
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>"; } } }
public function updateCMSFields(FieldList $fields) { // get all fields to translate and remove $translated = $this->getTranslatedTables(); foreach ($translated as $table => $translatedFields) { foreach ($translatedFields as $translatedField) { // Find field matching this translated field // If the translated field has an ID suffix also check for the non-suffixed version // E.g. UploadField() $field = $fields->dataFieldByName($translatedField); if (!$field && preg_match('/^(?<field>\\w+)ID$/', $translatedField, $matches)) { $field = $fields->dataFieldByName($matches['field']); } // Highlight any translated field if ($field && !$field->hasClass('LocalisedField')) { // Add a language indicator next to the fluent icon $locale = Fluent::current_locale(); $title = $field->Title(); $field->setTitle('<span class="fluent-locale-label">' . strtok($locale, '_') . '</span>' . $title); $field->addExtraClass('LocalisedField'); } // Remove translation DBField from automatic scaffolded fields foreach (Fluent::locales() as $locale) { $fieldName = Fluent::db_field_for_locale($translatedField, $locale); $fields->removeByName($fieldName, true); } } } }
/** * Determine the baseurl within a specified $locale. * * @param string $locale Locale, or null to use current locale * @return string */ public static function locale_baseurl($locale = null) { if (empty($locale)) { $locale = Fluent::current_locale(); } // Build domain-specific base url $base = Director::baseURL(); if ($domain = Fluent::domain_for_locale($locale)) { $base = Controller::join_links(Director::protocol() . $domain, $base); } // Don't append locale to home page for default locale if ($locale === self::default_locale()) { return $base; } // Append locale otherwise return Controller::join_links($base, self::alias($locale), '/'); }
/** * Add 'Hidden' flag to the SiteTree object if the page is not present in this locale * * @param array $flags */ public function updateStatusFlags(&$flags) { if (!$this->owner->{Fluent::db_field_for_locale("LocaleFilter", Fluent::current_locale())}) { $flags['fluenthidden'] = array('text' => _t('Fluent.BadgeHiddenShort', 'Hidden'), 'title' => _t('Fluent.BadgeHiddenHelp', 'Page is hidden in this locale')); } }
/** * * Return a MenuTitle depending on if we have the Fluent module enabled, and the * current selected locale. * * It is also obviously contingent on each of the MenuTitle_<locale> fields * having been configured correctly. * * This method obviously _only_ deals with the MenuTitle_<locale> field. It is * therefore not at all DRY in the sense that there is no answer to the following * question: What do we do for other properties-as-fields, configured and * translated via Fluent? * * @return string */ public function MenuTitle() { if ($this->hasFluent()) { $localeCurrent = Fluent::current_locale(); $fieldCurrent = 'MenuTitle_' . $localeCurrent; if (isset($this->{$fieldCurrent}) && ($title = $this->{$fieldCurrent})) { return $title; } } return $this->MenuTitle; }
/** * Adds a UI message to indicate whether you're editing in the default locale or not * * @param FieldList $fields * @return $this */ protected function addLocaleIndicatorMessage(FieldList $fields) { if (Fluent::config()->disable_current_locale_message) { return $this; } // If the field is already present, don't add it a second time if ($fields->fieldByName('CurrentLocaleMessage')) { return $this; } $localeNames = Fluent::locale_names(); $isDefaultLocale = Fluent::default_locale() === Fluent::current_locale(); $messageClass = $isDefaultLocale ? 'good' : 'notice'; $message = $isDefaultLocale ? _t('Fluent.DefaultLocale', 'This is the default locale') : _t('Fluent.DefaultLocaleIs', 'The default locale is') . ' ' . $localeNames[Fluent::default_locale()]; $fields->unshift(LiteralField::create('CurrentLocaleMessage', sprintf('<p class="message %s">' . _t('Fluent.EditingIn', 'Please note: You are editing in') . ' %s. %s.</p>', $messageClass, $localeNames[Fluent::current_locale()], $message))); return $this; }
public function updateCMSFields(FieldList $fields) { // get all fields to translate and remove $translated = $this->getTranslatedTables(); foreach ($translated as $table => $translatedFields) { foreach ($translatedFields as $translatedField) { // Find field matching this translated field // If the translated field has an ID suffix also check for the non-suffixed version // E.g. UploadField() $field = $fields->dataFieldByName($translatedField); if (!$field && preg_match('/^(?<field>\\w+)ID$/', $translatedField, $matches)) { $field = $fields->dataFieldByName($matches['field']); } // Highlight any translated field if ($field) { $field->addExtraClass('LocalisedField'); } // Remove translation DBField from automatic scaffolded fields foreach (Fluent::locales() as $locale) { $fieldName = Fluent::db_field_for_locale($translatedField, $locale); $fields->removeByName($fieldName, true); } } } }
public function onBeforeInit() { Fluent::install_locale(); }
/** * Resets all translated fields to their value in the default locale */ public function resetTranslations() { $translated = $this->getTranslatedTables(); foreach ($translated as $table => $fields) { foreach ($fields as $field) { $defaultField = Fluent::db_field_for_locale($field, Fluent::default_locale()); $defaultValue = $this->owner->{$defaultField}; foreach (Fluent::locales() as $locale) { if ($locale === Fluent::default_locale()) { continue; } $localeField = Fluent::db_field_for_locale($field, $locale); $originalValue = $this->owner->{$localeField}; $this->owner->{$localeField} = $defaultValue; // If these values differ, but a change isn't detected, then force a change if ($this->owner->exists() && $originalValue != $defaultValue && !$this->owner->isChanged($field)) { $this->owner->forceChange(); } $this->owner->write(); } } } }
/** * Tests adding an invalid validator. */ public function testAddInvalidValidator() { $this->expectException(\Jyxo\Input\Exception::class); $input = new Fluent(); $input->validate('foo'); }
/** * Test fluent setters. */ public function testFluentSetters() { $config = new Config(array('inputFile' => null, 'outputDir' => null)); $complexType = new ComplexType($config, 'Fluent'); $complexType->addMember('string', 'attribute', true); $this->generateClass($complexType); // When calling a setter the returned value should be the same as the // object where the setter was called. $object = new \Fluent(); $returnValue = $object->setAttribute('value'); $this->assertEquals($object, $returnValue); // The setter should also have its own class as its return type. $class = new \ReflectionClass($object); $this->assertMethodHasReturnType($class->getMethod('setAttribute'), $class->getName()); }
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"); } } }
/** * Sets whether to force "is_frontend" to return true or false. This can be used for situations where the * frontend controllers are not involved, e.g. API modules, unit testing or retrieving data programmatically. * * @param boolean $force */ public static function set_force_is_frontend($force = true) { self::$force_is_frontend = $force; }
/** * Rewrites the WHERE fragment of a query * * @param string $class * @param array $translatedColumns Translated columns * @param SQLQUery $query * @param string $keywords SQL escaped keywords * @param string $keywordsHTML HTML escaped keywords */ public function augmentFilter($class, $translatedColumns, SQLQuery $query, $keywords, $keywordsHTML, $booleanMode) { // Augment the search section $locale = Fluent::current_locale(); $wherePattern = self::$where_replacements[$class]; $translatedPattern = $wherePattern; $searchColumns = self::$search_columns[$class]; foreach (array_intersect($searchColumns, $translatedColumns) as $column) { $replacement = Fluent::db_field_for_locale($column, $locale); $translatedPattern = preg_replace('/\\b' . preg_quote($column) . '\\b/', $replacement, $translatedPattern); } // If no fields were translated, then don't modify if ($translatedPattern === $wherePattern) { return; } // Inject keywords into patterns $search = array('/\\$keywords/i', '/\\$htmlEntityKeywords/i', '/\\$boolean/i'); $replace = array($keywords, $keywordsHTML, $booleanMode ? 'IN BOOLEAN MODE' : ''); $whereOriginal = preg_replace($search, $replace, $wherePattern); $whereTranslated = preg_replace($search, $replace, $translatedPattern); $where = $query->getWhere(); $newWhere = array(); foreach ($query->getWhere() as $where) { // Remove excessive whitespace which breaks string replacement $where = preg_replace('/\\s+/im', ' ', $where); $whereOriginal = preg_replace('/\\s+/im', ' ', $whereOriginal); $newWhere[] = str_replace($whereOriginal, "{$whereOriginal} + {$whereTranslated}", $where); } $query->setWhere($newWhere); }
/** * Tests adding an invalid validator. */ public function testAddInvalidValidator() { $this->setExpectedException('\\Jyxo\\Input\\Exception'); $input = new Fluent(); $input->validate('foo'); }
public function run($request) { // Extend time limit set_time_limit(100000); // we may need some proivileges for this to work // without this, running under sake is a problem // maybe sake could take care of it ... Security::findAnAdministrator()->login(); $this->checkInstalled(); $this->withTransaction(function ($task) { Versioned::reading_stage('Stage'); $classes = $task->fluentClasses(); $tables = DB::tableList(); $deleteQueue = array(); foreach ($classes as $class) { // Ensure that a translationgroup table exists for this class $groupTable = strtolower($class . "_translationgroups"); if (isset($tables[$groupTable])) { $groupTable = $tables[$groupTable]; } else { Debug::message("Ignoring class without _translationgroups table {$class}", false); continue; } // Disable filter if ($class::has_extension('FluentFilteredExtension')) { $class::remove_extension('FluentFilteredExtension'); } // Select all instances of this class in the default locale $instances = DataObject::get($class, sprintf('"Locale" = \'%s\'', Convert::raw2sql(Fluent::default_locale()))); foreach ($instances as $instance) { $isPublished = false; if ($instance->hasMethod('isPublished')) { $isPublished = $instance->isPublished(); } if ($instance->ObsoleteClassName) { Debug::message("Skipping {$instance->ClassName} with ID {$instanceID} because it from an obsolete class", false); continue; } $instanceID = $instance->ID; $translatedFields = $task->getTranslatedFields($instance->ClassName); Debug::message("Updating {$instance->ClassName} {$instance->MenuTitle} ({$instanceID})", false); $changed = false; // Select all translations for this $translatedItems = DataObject::get($class, sprintf('"Locale" != \'%1$s\' AND "ID" IN ( SELECT "OriginalID" FROM "%2$s" WHERE "TranslationGroupID" IN ( SELECT "TranslationGroupID" FROM "%2$s" WHERE "OriginalID" = %3$d ) )', Convert::raw2sql(Fluent::default_locale()), $groupTable, $instanceID)); foreach ($translatedItems as $translatedItem) { $locale = DB::query(sprintf('SELECT "Locale" FROM "%s" WHERE "ID" = %d', $class, $translatedItem->ID))->value(); // since we are going to delete the stuff // anyway, no need bothering validating it DataObject::config()->validation_enabled = false; // Unpublish and delete translated record if ($translatedItem->hasMethod('doUnpublish')) { Debug::message(" -- Unpublishing {$locale}", false); if ($translatedItem->doUnpublish() === false) { throw new ConvertTranslatableException("Failed to unpublish"); } } Debug::message(" -- Adding {$translatedItem->ID} ({$locale})", false); foreach ($translatedFields as $field) { $trField = Fluent::db_field_for_locale($field, $locale); if ($translatedItem->{$field}) { Debug::message(" -- Adding {$trField}", false); $instance->{$trField} = $translatedItem->{$field}; $changed = true; } } // for some reason, deleting items here has disruptive effects // as too much stuff gets removed, so lets wait with this until the end of the migration $deleteQueue[] = $translatedItem; } if ($changed) { if (!$isPublished) { $instance->write(); } elseif ($instance->doPublish() === false) { Debug::message(" -- Publishing FAILED", false); throw new ConvertTranslatableException("Failed to publish"); } else { Debug::message(" -- Published", false); } } } } foreach ($deleteQueue as $delItem) { Debug::message(" -- Removing {$delItem->ID}", false); $delItem->delete(); } }); }
/** * If only one locale is active * * @return string|boolean The active locale or false */ public function HasOnlyOneLocale() { $list = $this->owner->ActiveLocales; if (!$list) { $list = implode(',', array_keys(Fluent::locale_names())); } $list = trim($list, ','); if ($list && strpos($list, ',') === false) { return $list; } return false; }
public function Link() { return Controller::join_links(Director::baseURL(), Fluent::current_locale(), 'link', '/'); }
/** * Compile a primary key command. * * @param Schema_Blueprint $blueprint * @param Fluent $command * @return string */ public function compile_primary(Schema_Blueprint $blueprint, Fluent $command) { $command->name(NULL); return $this->_compile_key($blueprint, $command, 'primary key'); }
public function __construct(array $attributes = []) { parent::__construct($attributes); $this->syncOriginal(); }