/** * Returns [route name, route params] for url generation, or null for various reasons. * * @return array|null */ public function getRouteNameAndParams() { if (empty($this->app)) { $this->app = ResourceManager::getApp(); } if (empty($this->id)) { return null; } // No links for records that are 'viewless' if (isset($this->contenttype['viewless']) && $this->contenttype['viewless'] == true) { return null; } list($name, $config) = $this->getRouteConfig(); if (!$config) { return null; } $slug = $this->getLinkSlug(); $availableParams = array_filter(array_merge($config['defaults'] ?: [], $this->getRouteRequirementParams($config), ['contenttypeslug' => $this->contenttype['singular_slug'], 'id' => $this->id, 'slug' => $slug])); /** @var Route|null $route */ $route = $this->app['routes']->get($name); if (!$route) { return null; } // Needed params as array keys $pathVars = $route->compile()->getPathVariables(); $neededKeys = array_flip($pathVars); // Set the values of neededKeys from the availableParams. // This removes extra parameters that are not needed for url generation. $params = array_replace($neededKeys, array_intersect_key($availableParams, $neededKeys)); return [$name, $params]; }
/** * Creates a URL for the content record. * * @return string */ public function link() { if (empty($this->app)) { $this->app = ResourceManager::getApp(); } if (empty($this->id)) { return null; } // No links for records that are 'viewless' if (isset($this->contenttype['viewless']) && $this->contenttype['viewless'] == true) { return null; } list($binding, $route) = $this->getRoute(); if (!$route) { return null; } $slug = $this->values['slug']; if (empty($slug)) { $slug = $this->id; } $link = $this->app['url_generator']->generate($binding, array_filter(array_merge($route['defaults'] ?: [], $this->getRouteRequirementParams($route), ['contenttypeslug' => $this->contenttype['singular_slug'], 'id' => $this->id, 'slug' => $slug]))); // Strip the query string generated by supplementary parameters. // since our $params contained all possible arguments and the ->generate() // added all $params which it didn't need in the query-string we can // safely strip the query-string. // NB. this does mean we don't support routes with query strings return preg_replace('/^([^?]*).*$/', '\\1', $link); }
private static function getValidityTimestampFilename() { // If 'invalidate()' was called statically, we don't have the // $integrityCachePath yet, so we set it here. if (empty(self::$integrityCachePath)) { $app = \Bolt\Configuration\ResourceManager::getApp(); self::$integrityCachePath = $app['resources']->getPath('cache'); } return self::$integrityCachePath . '/' . self::INTEGRITY_CHECK_TS_FILENAME; }
/** * @runInSeparateProcess */ public function testEarlyStaticFails() { $this->setExpectedException('RuntimeException'); $app = ResourceManager::getApp(); }
public function testStaticApp() { $config = new Standard(PHPUNIT_WEBROOT); $app = new Application(['resources' => $config]); $app2 = ResourceManager::getApp(); $this->assertEquals($app, $app2); }
/** * Returns translated contenttype name with fallback to name/slug from 'contenttypes.yml'. * * @param string $contenttype The contentype * @param bool $singular Singular or plural requested? * @param string $locale Translate to this locale * * @return string */ private static function transContenttypeName($contenttype, $singular, $locale) { $key = 'contenttypes.' . $contenttype . '.name.' . ($singular ? 'singular' : 'plural'); $name = self::trans($key, [], 'contenttypes', $locale); if ($name === $key) { $app = ResourceManager::getApp(); $name = $app['config']->get('contenttypes/' . $contenttype . ($singular ? '/singular_name' : '/name')); if (empty($name)) { $name = ucfirst($app['config']->get('contenttypes/' . $contenttype . ($singular ? '/singular_slug' : '/slug'), $contenttype)); } // Escape names coming from 'contenttypes.yml' $name = htmlspecialchars($name, ENT_QUOTES); } return $name; }
/** * Create a simple redirect to a page / path. * * @param string $path * @param bool $abort * * @return string */ public static function simpleredirect($path, $abort = false) { $app = ResourceManager::getApp(); if (empty($path)) { $path = '/'; } header("location: {$path}"); echo "<p>Redirecting to <a href='{$path}'>{$path}</a>.</p>"; echo "<script>window.setTimeout(function () { window.location='{$path}'; }, 500);</script>"; if (!$abort) { return $path; } $app->abort(Response::HTTP_SEE_OTHER, "Redirecting to '{$path}'."); }
static function enqueueScript($handle, $src = false, $deps = array(), $ver = false, $in_footer = false) { if (!is_array(self::$scriptQueue)) { self::$scriptQueue = ['head' => [], 'footer' => []]; } if ($in_footer) { $location = 'footer'; } else { $location = 'head'; } if ($src != false) { $script = sprintf("<script type='text/javascript' src='%s%s' type='text/css'></script>\n", $src, !empty($ver) ? '?ver=' . $ver : ''); self::$scriptQueue[$location][$handle] = $script; } if (in_array('jquery', $deps)) { $app = ResourceManager::getApp(); $jqueryfile = sprintf('%s%s/%s/wordpress-theme/assets/jquery-2.2.3.min.js', $app['paths']['extensions'], basename(dirname(dirname(dirname(__DIR__)))), basename(dirname(dirname(__DIR__)))); self::enqueueScript('jquery', $jqueryfile); } }
/** * Translates contentype specific messages and falls back to building generic message or fallback locale. * * @param string $genericKey * @param array $params * @param string $id * @param boolean $singular * @param mixed $locale * * @return boolean */ private static function transContenttype($genericKey, array $params, $id, $singular, $locale) { $contenttype = $params[$id]; $encParams = self::htmlencodeParams($params, $id); $key = 'contenttypes.' . $contenttype . '.text.' . substr($genericKey, 21); // Try to get a real translation from contenttypes.xx_XX.yml $trans = self::trans($key, $encParams, 'contenttypes', $locale, false); $app = ResourceManager::getApp(); $localeFallbacks = $app['locale_fallbacks']; $transFallback = self::trans($key, $encParams, 'contenttypes', reset($localeFallbacks), false); // We don't want fallback translation here if ($trans === $transFallback) { $trans = false; } // No translation found, build string from generic translation pattern if ($trans === false) { // Get generic translation with name replaced $encParams[$id] = self::transContenttypeName($contenttype, $singular, $locale); $transGeneric = self::trans($genericKey, $encParams, 'messages', $locale, false); } else { $transGeneric = false; } // Return: translation => generic translation => fallback translation => key if ($trans !== false) { return $trans; } elseif ($transGeneric !== false) { return $transGeneric; } elseif ($transFallback !== false) { return $transFallback; } else { return $genericKey; } }
/** * i18n made right, second attempt... * * Instead of calling directly $app['translator']->trans(), we check * for the presence of a placeholder named '%contentype%'. * * If one is found, we replace it with the contenttype.name parameter, * and try to get a translated string. If there is not, we revert to * the generic (%contenttype%) string, which must have a translation. */ function __() { $app = ResourceManager::getApp(); $num_args = func_num_args(); if (0 == $num_args) { return null; } $args = func_get_args(); if ($num_args > 4) { $fn = 'transChoice'; } elseif ($num_args == 1 || is_array($args[1])) { // If only 1 arg or 2nd arg is an array call trans $fn = 'trans'; } else { $fn = 'transChoice'; } $tr_args = null; if ($fn == 'trans' && $num_args > 1) { $tr_args = $args[1]; } elseif ($fn == 'transChoice' && $num_args > 2) { $tr_args = $args[2]; } // Check for contenttype(s) placeholder if ($tr_args) { $keytype = '%contenttype%'; $keytypes = '%contenttypes%'; $have_singular = array_key_exists($keytype, $tr_args); $have_plural = array_key_exists($keytypes, $tr_args); if ($have_singular || $have_plural) { // have a %contenttype% placeholder, try to find a specialized translation if ($have_singular) { $text = str_replace($keytype, $tr_args[$keytype], $args[0]); unset($tr_args[$keytype]); } else { $text = str_replace($keytypes, $tr_args[$keytypes], $args[0]); unset($tr_args[$keytypes]); } //echo "\n" . '<!-- contenttype replaced: '.htmlentities($text)." -->\n"; if ($fn == 'transChoice') { $trans = $app['translator']->transChoice($text, $args[1], htmlencode_params($tr_args), isset($args[3]) ? $args[3] : 'contenttypes', isset($args[4]) ? $args[4] : $app['request']->getLocale()); } else { $trans = $app['translator']->trans($text, htmlencode_params($tr_args), isset($args[2]) ? $args[2] : 'contenttypes', isset($args[3]) ? $args[3] : $app['request']->getLocale()); } //echo '<!-- translation : '.htmlentities($trans)." -->\n"; if ($text != $trans) { return $trans; } } } //try { if (isset($args[1])) { $args[1] = htmlencode_params($args[1]); } switch ($num_args) { case 5: return $app['translator']->transChoice($args[0], $args[1], $args[2], $args[3], $args[4]); case 4: //echo "<!-- 4. call: $fn($args[0], $args[1], $args[2], $args[3]) -->\n"; return $app['translator']->{$fn}($args[0], $args[1], $args[2], $args[3]); case 3: //echo "<!-- 3. call: $fn($args[0], $args[1], $args[2]) -->\n"; return $app['translator']->{$fn}($args[0], $args[1], $args[2]); case 2: //echo "<!-- 2. call: $fn($args[0],$args[1] -->\n"; return $app['translator']->{$fn}($args[0], $args[1]); case 1: //echo "<!-- 1. call: $fn($args[0]) -->\n"; return $app['translator']->{$fn}($args[0]); } /*} catch (\Exception $e) { echo "<!-- ARGHH !!! -->\n"; //return $args[0]; die($e->getMessage()); }*/ }
/** * Shortcut for {@see UrlGeneratorInterface::generate} * * @param string $name The name of the route * @param array $params An array of parameters * @param int $referenceType The type of reference to be generated (one of the constants) * * @return string */ protected function generateUrl($name, $params = [], $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH) { $app = ResourceManager::getApp(); /** @var UrlGeneratorInterface $generator */ $generator = $app['url_generator']; return $generator->generate($name, $params, $referenceType); }
public static function catchFatalErrors() { // Get last error, if any $error = error_get_last(); if ($error['type'] == E_ERROR || $error['type'] == E_PARSE) { $html = self::$html; // Get the application object $app = \Bolt\Configuration\ResourceManager::getApp(); // Detect if we're being called from a core, an extension or vendor $isBoltCoreError = strpos($error['file'], $app['resources']->getPath('rootpath') . 'src'); $isVendorError = strpos($error['file'], $app['resources']->getPath('rootpath') . 'vendor'); $isExtensionError = strpos($error['file'], $app['resources']->getPath('extensions')); // Assemble error trace $errorblock = '<code>Error: ' . $error['message'] . '</code><br>'; $errorblock .= '<code>File: ' . $error['file'] . '</code><br>'; $errorblock .= '<code>Line: ' . $error['line'] . '</code><br><br>'; if ($isBoltCoreError === 0) { $html = str_replace('%error_title%', 'PHP Fatal Error: Bolt Core', $html); $html = str_replace('%info%', '', $html); $message = $errorblock; } elseif ($isVendorError === 0) { $html = str_replace('%error_title%', 'PHP Fatal Error: Vendor Library', $html); $html = str_replace('%info%', '', $html); $message = $errorblock; } elseif ($isExtensionError === 0) { $vendor = $app['resources']->getPath('extensions') . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR; $base = str_replace($vendor, '', $error['file']); $parts = explode(DIRECTORY_SEPARATOR, $base); $package = $parts[0] . '/' . $parts[1]; $delete = 'extensions' . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $parts[0] . DIRECTORY_SEPARATOR . $parts[1]; $html = str_replace('%error_title%', 'PHP Fatal Error: Bolt Extensions', $html); $html = str_replace('%info%', '<p>You will only be able to continue by manually deleting the extension that is installed at:</p>' . '<code>' . $delete . '</code><br><br>', $html); $message = '<h4>There is a fatal error in the \'' . $package . '\' extension ' . 'loaded on your Bolt Installation.<h4>'; $message .= $errorblock; } else { // Unknown $html = str_replace('%error_title%', 'PHP Fatal Error: Bolt Generic', $html); $html = str_replace('%info%', '', $html); $message = $errorblock; } $message = nl2br($message); $html = str_replace('%error%', $message, $html); echo str_replace($app['resources']->getPath('rootpath'), '', $html); } }
/** * Callback for register_shutdown_function() to handle fatal errors. * * @param \Silex\Application $app */ public static function catchFatalErrors($app = null) { // Get last error, if any $error = error_get_last(); // Let Whoops handle AJAX requested fatal errors if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') { return; } if ($error['type'] == E_ERROR || $error['type'] == E_PARSE) { $html = self::$html; // Get the application object if ($app === null) { $app = ResourceManager::getApp(); } // Detect if we're being called from a core, an extension or vendor $isBoltCoreError = strpos($error['file'], $app['resources']->getPath('rootpath/src')); $isVendorError = strpos($error['file'], $app['resources']->getPath('rootpath/vendor')); $isExtensionError = strpos($error['file'], $app['resources']->getPath('extensions')); // Assemble error trace $errorblock = '<code>Error: ' . $error['message'] . '</code><br>'; $errorblock .= '<code>File: ' . $error['file'] . '</code><br>'; $errorblock .= '<code>Line: ' . $error['line'] . '</code><br><br>'; if ($isBoltCoreError === 0) { $html = str_replace('%error_title%', 'PHP Fatal Error: Bolt Core', $html); $html = str_replace('%info%', '', $html); $message = $errorblock; } elseif ($isVendorError === 0) { $html = str_replace('%error_title%', 'PHP Fatal Error: Vendor Library', $html); $html = str_replace('%info%', '', $html); $message = $errorblock; } elseif ($isExtensionError === 0) { $base = str_replace($app['resources']->getPath('extensions'), '', $error['file']); $parts = explode(DIRECTORY_SEPARATOR, ltrim($base, '/')); $package = $parts[1] . '/' . $parts[2]; $delete = 'extensions' . DIRECTORY_SEPARATOR . $parts[0] . DIRECTORY_SEPARATOR . $parts[1] . DIRECTORY_SEPARATOR . $parts[2]; $html = str_replace('%error_title%', 'PHP Fatal Error: Bolt Extensions', $html); $html = str_replace('%info%', '<p>You will only be able to continue by manually deleting the extension that is installed at:</p>' . '<code>' . $delete . '</code><br><br>', $html); $message = '<h4>There is a fatal error in the \'' . $package . '\' extension ' . 'loaded on your Bolt Installation.<h4>'; $message .= $errorblock; } else { // Unknown $html = str_replace('%error_title%', 'PHP Fatal Error: Bolt Generic', $html); $html = str_replace('%info%', '', $html); $message = $errorblock; } $message = nl2br($message); $html = str_replace('%error%', $message, $html); // Determine if we're on the command line. If so, don't output HTML. if (php_sapi_name() == 'cli') { $html = self::cleanHTML($html); } echo str_replace($app['resources']->getPath('rootpath'), '', $html); } }
public function __construct() { $this->app = ResourceManager::getApp(); }
/** * Find all twig templates and bolt php code, extract translatables * strings, merge with existing translations, return */ function gatherTranslatableStrings($locale = null, $translated = array()) { $app = ResourceManager::getApp(); $isPhp = function ($fname) { return pathinfo(strtolower($fname), PATHINFO_EXTENSION) == 'php'; }; $isTwig = function ($fname) { return pathinfo(strtolower($fname), PATHINFO_EXTENSION) == 'twig'; }; $ctypes = $app['config']->get('contenttypes'); // function that generates a string for each variation of contenttype/contenttypes $genContentTypes = function ($txt) use($ctypes) { $stypes = array(); if (strpos($txt, '%contenttypes%') !== false) { foreach ($ctypes as $key => $ctype) { $stypes[] = str_replace('%contenttypes%', $ctype['name'], $txt); } } if (strpos($txt, '%contenttype%') !== false) { foreach ($ctypes as $key => $ctype) { $stypes[] = str_replace('%contenttype%', $ctype['singular_name'], $txt); } } return $stypes; }; // Step one: gather all translatable strings $finder = new Finder(); $finder->files()->ignoreVCS(true)->name('*.twig')->name('*.php')->notName('*~')->exclude(array('cache', 'config', 'database', 'resources', 'tests'))->in(dirname($app['paths']['themepath']))->in($app['paths']['apppath']); // regex from: stackoverflow.com/questions/5695240/php-regex-to-ignore-escaped-quotes-within-quotes $re_dq = '/"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"/s'; $re_sq = "/'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'/s"; $nstr = 0; $strings = array(); foreach ($finder as $file) { $s = file_get_contents($file); // Scan twig templates for __('...' and __("..." if ($isTwig($file)) { // __('single_quoted_string'... if (preg_match_all("/\\b__\\(\\s*'([^'\\\\]*(?:\\\\.[^'\\\\]*)*)'(?U).*\\)/s", $s, $matches)) { //print_r($matches[1]); foreach ($matches[1] as $t) { $nstr++; if (!in_array($t, $strings) && strlen($t) > 1) { $strings[] = $t; sort($strings); } } } // __("double_quoted_string"... if (preg_match_all('/\\b__\\(\\s*"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"(?U).*\\)/s', $s, $matches)) { //print_r($matches[1]); foreach ($matches[1] as $t) { $nstr++; if (!in_array($t, $strings) && strlen($t) > 1) { $strings[] = $t; sort($strings); } } } } // php : /** all translatables strings have to be called with: * __("text", $params=array(), $domain='messages', locale=null) // $app['translator']->trans() * __("text", count, $params=array(), $domain='messages', locale=null) // $app['translator']->transChoice() */ if ($isPhp($file)) { $tokens = token_get_all($s); $num_tokens = count($tokens); for ($x = 0; $x < $num_tokens; $x++) { $token = $tokens[$x]; if (is_array($token) && $token[0] == T_STRING && $token[1] == '__') { $token = $tokens[++$x]; if ($x < $num_tokens && is_array($token) && $token[0] == T_WHITESPACE) { $token = $tokens[++$x]; } if ($x < $num_tokens && !is_array($token) && $token == '(') { // in our func args... $token = $tokens[++$x]; if ($x < $num_tokens && is_array($token) && $token[0] == T_WHITESPACE) { $token = $tokens[++$x]; } if (!is_array($token)) { // give up continue; } if ($token[0] == T_CONSTANT_ENCAPSED_STRING) { $t = substr($token[1], 1, strlen($token[1]) - 2); $nstr++; if (!in_array($t, $strings) && strlen($t) > 1) { $strings[] = $t; sort($strings); } // TODO: retrieve domain? } } } } // end for $x } } // Add fields name|label for contenttype (forms) foreach ($ctypes as $ckey => $contenttype) { foreach ($contenttype['fields'] as $fkey => $field) { if (isset($field['label'])) { $t = $field['label']; } else { $t = ucfirst($fkey); } if (!in_array($t, $strings) && strlen($t) > 1) { $strings[] = $t; } } // Relation name|label if exists if (array_key_exists('relations', $contenttype)) { foreach ($contenttype['relations'] as $fkey => $field) { if (isset($field['label'])) { $t = $field['label']; } else { $t = ucfirst($fkey); } if (!in_array($t, $strings) && strlen($t) > 1) { $strings[] = $t; } } } } // Add name + singular_name for taxonomies foreach ($app['config']->get('taxonomy') as $txkey => $value) { foreach (array('name', 'singular_name') as $key) { $t = $value[$key]; if (!in_array($t, $strings)) { $strings[] = $t; } } } // Return the previously translated string if exists, // Return an empty string otherwise $getTranslated = function ($key) use($app, $translated) { if (($trans = $app['translator']->trans($key)) == $key) { if (is_array($translated) && array_key_exists($key, $translated) && !empty($translated[$key])) { return $translated[$key]; } return ''; } return $trans; }; // Step 2: find already translated strings sort($strings); if (!$locale) { $locale = $app['request']->getLocale(); } $msg_domain = array('translated' => array(), 'not_translated' => array()); $ctype_domain = array('translated' => array(), 'not_translated' => array()); foreach ($strings as $idx => $key) { $key = stripslashes($key); $raw_key = $key; $key = Escaper::escapeWithDoubleQuotes($key); if (($trans = $getTranslated($raw_key)) == '' && ($trans = $getTranslated($key)) == '') { $msg_domain['not_translated'][] = $key; } else { $trans = Escaper::escapeWithDoubleQuotes($trans); $msg_domain['translated'][$key] = $trans; } // Step 3: generate additionals strings for contenttypes if (strpos($raw_key, '%contenttype%') !== false || strpos($raw_key, '%contenttypes%') !== false) { foreach ($genContentTypes($raw_key) as $ctypekey) { $key = Escaper::escapeWithDoubleQuotes($ctypekey); if (($trans = $getTranslated($ctypekey)) == '' && ($trans = $getTranslated($key)) == '') { // Not translated $ctype_domain['not_translated'][] = $key; } else { $trans = Escaper::escapeWithDoubleQuotes($trans); $ctype_domain['translated'][$key] = $trans; } } } } sort($msg_domain['not_translated']); ksort($msg_domain['translated']); sort($ctype_domain['not_translated']); ksort($ctype_domain['translated']); return array($msg_domain, $ctype_domain); }
/** * Clear the cache. Both the doctrine FilesystemCache, as well as twig and thumbnail temp files. * * @see clearCacheHelper */ public function clearCache() { $result = array('successfiles' => 0, 'failedfiles' => 0, 'failed' => array(), 'successfolders' => 0, 'failedfolders' => 0, 'log' => ''); // Clear Doctrine's folder. $this->flushAll(); // Clear our own cache folder. $this->clearCacheHelper($this->getDirectory(), '', $result); // Clear the thumbs folder. $app = ResourceManager::getApp(); $this->clearCacheHelper($app['resources']->getPath('web') . '/thumbs', '', $result); return $result; }