mirror of
https://github.com/flarum/core.git
synced 2025-07-24 02:01:19 +02:00
Create new Flarum\Frontend namespace
It replaces the old Http\WebApp namespace and swallows other namespaces and files, such as Flarum\Asset.
This commit is contained in:
188
framework/core/src/Frontend/AbstractFrontend.php
Normal file
188
framework/core/src/Frontend/AbstractFrontend.php
Normal file
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Frontend;
|
||||
|
||||
use Flarum\Locale\LocaleManager;
|
||||
use Flarum\Settings\SettingsRepositoryInterface;
|
||||
|
||||
abstract class AbstractFrontend
|
||||
{
|
||||
/**
|
||||
* @var FrontendAssetsFactory
|
||||
*/
|
||||
protected $assets;
|
||||
|
||||
/**
|
||||
* @var FrontendViewFactory
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* @var SettingsRepositoryInterface
|
||||
*/
|
||||
protected $settings;
|
||||
|
||||
/**
|
||||
* @var LocaleManager
|
||||
*/
|
||||
protected $locales;
|
||||
|
||||
/**
|
||||
* @param FrontendAssetsFactory $assets
|
||||
* @param FrontendViewFactory $view
|
||||
* @param SettingsRepositoryInterface $settings
|
||||
* @param LocaleManager $locales
|
||||
*/
|
||||
public function __construct(FrontendAssetsFactory $assets, FrontendViewFactory $view, SettingsRepositoryInterface $settings, LocaleManager $locales)
|
||||
{
|
||||
$this->assets = $assets;
|
||||
$this->view = $view;
|
||||
$this->settings = $settings;
|
||||
$this->locales = $locales;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FrontendView
|
||||
*/
|
||||
public function getView()
|
||||
{
|
||||
$view = $this->view->make($this->getLayout(), $this->getAssets());
|
||||
|
||||
$this->addDefaultAssets($view);
|
||||
$this->addCustomLess($view);
|
||||
$this->addTranslations($view);
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FrontendAssets
|
||||
*/
|
||||
public function getAssets()
|
||||
{
|
||||
return $this->assets->make($this->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the client.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getName();
|
||||
|
||||
/**
|
||||
* Get the path to the client layout view.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getLayout()
|
||||
{
|
||||
return __DIR__.'/../../../views/'.$this->getName().'.blade.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a regular expression to match against translation keys.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTranslationFilter()
|
||||
{
|
||||
return '/^.+(?:\.|::)(?:'.$this->getName().'|lib)\./';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FrontendView $view
|
||||
*/
|
||||
private function addDefaultAssets(FrontendView $view)
|
||||
{
|
||||
$root = __DIR__.'/../../..';
|
||||
$name = $this->getName();
|
||||
|
||||
$view->getJs()->addFile("$root/js/$name/dist/app.js");
|
||||
$view->getCss()->addFile("$root/less/$name/app.less");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FrontendView $view
|
||||
*/
|
||||
private function addCustomLess(FrontendView $view)
|
||||
{
|
||||
$css = $view->getCss();
|
||||
$localeCss = $view->getLocaleCss();
|
||||
|
||||
$lessVariables = function () {
|
||||
$less = '';
|
||||
|
||||
foreach ($this->getLessVariables() as $name => $value) {
|
||||
$less .= "@$name: $value;";
|
||||
}
|
||||
|
||||
return $less;
|
||||
};
|
||||
|
||||
$css->addString($lessVariables);
|
||||
$localeCss->addString($lessVariables);
|
||||
|
||||
$css->addString(function () {
|
||||
return $this->settings->get('custom_less');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the values of any LESS variables to compile into the CSS, based on
|
||||
* the forum's configuration.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getLessVariables()
|
||||
{
|
||||
return [
|
||||
'config-primary-color' => $this->settings->get('theme_primary_color') ?: '#000',
|
||||
'config-secondary-color' => $this->settings->get('theme_secondary_color') ?: '#000',
|
||||
'config-dark-mode' => $this->settings->get('theme_dark_mode') ? 'true' : 'false',
|
||||
'config-colored-header' => $this->settings->get('theme_colored_header') ? 'true' : 'false'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FrontendView $view
|
||||
*/
|
||||
private function addTranslations(FrontendView $view)
|
||||
{
|
||||
$translations = array_get($this->locales->getTranslator()->getMessages(), 'messages', []);
|
||||
|
||||
$translations = $this->filterTranslations($translations);
|
||||
|
||||
$view->getLocaleJs()->setTranslations($translations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a selection of keys from a collection of translations.
|
||||
*
|
||||
* @param array $translations
|
||||
* @return array
|
||||
*/
|
||||
private function filterTranslations(array $translations)
|
||||
{
|
||||
$filter = $this->getTranslationFilter();
|
||||
|
||||
if (! $filter) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$filtered = array_filter(array_keys($translations), function ($id) use ($filter) {
|
||||
return preg_match($filter, $id);
|
||||
});
|
||||
|
||||
return array_only($translations, $filtered);
|
||||
}
|
||||
}
|
57
framework/core/src/Frontend/AbstractFrontendController.php
Normal file
57
framework/core/src/Frontend/AbstractFrontendController.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Frontend;
|
||||
|
||||
use Flarum\Event\ConfigureClientView;
|
||||
use Flarum\Event\ConfigureWebApp;
|
||||
use Flarum\Http\Controller\AbstractHtmlController;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
|
||||
abstract class AbstractFrontendController extends AbstractHtmlController
|
||||
{
|
||||
/**
|
||||
* @var AbstractFrontend
|
||||
*/
|
||||
protected $webApp;
|
||||
|
||||
/**
|
||||
* @var Dispatcher
|
||||
*/
|
||||
protected $events;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(Request $request)
|
||||
{
|
||||
$view = $this->getView($request);
|
||||
|
||||
$this->events->fire(
|
||||
new ConfigureClientView($this, $view, $request)
|
||||
);
|
||||
$this->events->fire(
|
||||
new ConfigureWebApp($this, $view, $request)
|
||||
);
|
||||
|
||||
return $view->render($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return \Flarum\Frontend\FrontendView
|
||||
*/
|
||||
protected function getView(Request $request)
|
||||
{
|
||||
return $this->webApp->getView();
|
||||
}
|
||||
}
|
42
framework/core/src/Frontend/Asset/CompilerInterface.php
Normal file
42
framework/core/src/Frontend/Asset/CompilerInterface.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Frontend\Asset;
|
||||
|
||||
interface CompilerInterface
|
||||
{
|
||||
/**
|
||||
* @param string $filename
|
||||
*/
|
||||
public function setFilename($filename);
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
*/
|
||||
public function addFile($file);
|
||||
|
||||
/**
|
||||
* @param callable $callback
|
||||
*/
|
||||
public function addString(callable $callback);
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFile();
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function compile();
|
||||
|
||||
public function flush();
|
||||
}
|
118
framework/core/src/Frontend/Asset/JsCompiler.php
Normal file
118
framework/core/src/Frontend/Asset/JsCompiler.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Frontend\Asset;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Cache\Repository;
|
||||
use MatthiasMullie\Minify;
|
||||
use s9e\TextFormatter\Configurator;
|
||||
use s9e\TextFormatter\Configurator\JavaScript\Minifiers\FirstAvailable;
|
||||
|
||||
class JsCompiler extends RevisionCompiler
|
||||
{
|
||||
/**
|
||||
* @var Repository
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param string $filename
|
||||
* @param bool $watch
|
||||
* @param Repository $cache
|
||||
*/
|
||||
public function __construct($path, $filename, $watch = false, Repository $cache = null)
|
||||
{
|
||||
parent::__construct($path, $filename, $watch);
|
||||
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function format($string)
|
||||
{
|
||||
if (! $this->watch) {
|
||||
$key = 'js.'.sha1($string);
|
||||
|
||||
$string = $this->cache->rememberForever($key, function () use ($string) {
|
||||
return $this->minify($string);
|
||||
});
|
||||
}
|
||||
|
||||
return $string.";\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getCacheDifferentiator()
|
||||
{
|
||||
return $this->watch;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $source
|
||||
* @return string
|
||||
*/
|
||||
protected function minify($source)
|
||||
{
|
||||
set_time_limit(60);
|
||||
|
||||
try {
|
||||
$source = $this->minifyWithClosureCompilerService($source);
|
||||
} catch (Exception $e) {
|
||||
$source = $this->minifyWithFallback($source);
|
||||
}
|
||||
|
||||
return $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $source
|
||||
* @return string
|
||||
*/
|
||||
protected function minifyWithClosureCompilerService($source)
|
||||
{
|
||||
// The minifier may need some classes bundled with the Configurator so we autoload it
|
||||
class_exists(Configurator::class);
|
||||
|
||||
$minifier = new FirstAvailable;
|
||||
|
||||
$remoteCache = $minifier->add('RemoteCache');
|
||||
$remoteCache->url = 'http://s9e-textformatter.rhcloud.com/flarum-minifier/';
|
||||
|
||||
$hostedMinifer = $minifier->add('HostedMinifier');
|
||||
$hostedMinifer->url = 'http://s9e-textformatter.rhcloud.com/flarum-minifier/';
|
||||
$hostedMinifer->httpClient->timeout = 30;
|
||||
|
||||
$ccs = $minifier->add('ClosureCompilerService');
|
||||
$ccs->compilationLevel = 'SIMPLE_OPTIMIZATIONS';
|
||||
$ccs->httpClient->timeout = 30;
|
||||
|
||||
$minifier->add('MatthiasMullieMinify');
|
||||
|
||||
return $minifier->minify($source);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $source
|
||||
* @return string
|
||||
*/
|
||||
protected function minifyWithFallback($source)
|
||||
{
|
||||
$minifier = new Minify\JS($source);
|
||||
|
||||
return $minifier->minify();
|
||||
}
|
||||
}
|
70
framework/core/src/Frontend/Asset/LessCompiler.php
Normal file
70
framework/core/src/Frontend/Asset/LessCompiler.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Frontend\Asset;
|
||||
|
||||
use Less_Exception_Parser;
|
||||
use Less_Parser;
|
||||
|
||||
class LessCompiler extends RevisionCompiler
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $cachePath;
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param string $filename
|
||||
* @param bool $watch
|
||||
* @param string $cachePath
|
||||
*/
|
||||
public function __construct($path, $filename, $watch, $cachePath)
|
||||
{
|
||||
parent::__construct($path, $filename, $watch);
|
||||
|
||||
$this->cachePath = $cachePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function compile()
|
||||
{
|
||||
if (! count($this->files) || ! count($this->strings)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ini_set('xdebug.max_nesting_level', 200);
|
||||
|
||||
$parser = new Less_Parser([
|
||||
'compress' => true,
|
||||
'cache_dir' => $this->cachePath,
|
||||
'import_dirs' => [
|
||||
base_path().'/vendor/components/font-awesome/less' => '',
|
||||
],
|
||||
]);
|
||||
|
||||
try {
|
||||
foreach ($this->files as $file) {
|
||||
$parser->parseFile($file);
|
||||
}
|
||||
|
||||
foreach ($this->strings as $callback) {
|
||||
$parser->parse($callback());
|
||||
}
|
||||
|
||||
return $parser->getCss();
|
||||
} catch (Less_Exception_Parser $e) {
|
||||
// TODO: log an error somewhere?
|
||||
}
|
||||
}
|
||||
}
|
44
framework/core/src/Frontend/Asset/LocaleJsCompiler.php
Normal file
44
framework/core/src/Frontend/Asset/LocaleJsCompiler.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Frontend\Asset;
|
||||
|
||||
class LocaleJsCompiler extends JsCompiler
|
||||
{
|
||||
protected $translations = [];
|
||||
|
||||
public function setTranslations(array $translations)
|
||||
{
|
||||
$this->translations = $translations;
|
||||
}
|
||||
|
||||
public function compile()
|
||||
{
|
||||
$output = "
|
||||
System.register('locale', [], function(_export) {
|
||||
return {
|
||||
execute: function() {
|
||||
_export('default', function(app) {
|
||||
app.translator.translations = ".json_encode($this->translations).";\n";
|
||||
|
||||
foreach ($this->files as $filename) {
|
||||
$output .= file_get_contents($filename);
|
||||
}
|
||||
|
||||
$output .= '
|
||||
});
|
||||
}
|
||||
};
|
||||
});';
|
||||
|
||||
return $this->format($output);
|
||||
}
|
||||
}
|
203
framework/core/src/Frontend/Asset/RevisionCompiler.php
Normal file
203
framework/core/src/Frontend/Asset/RevisionCompiler.php
Normal file
@@ -0,0 +1,203 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Frontend\Asset;
|
||||
|
||||
class RevisionCompiler implements CompilerInterface
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $files = [];
|
||||
|
||||
/**
|
||||
* @var callable[]
|
||||
*/
|
||||
protected $strings = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $watch;
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param string $filename
|
||||
* @param bool $watch
|
||||
*/
|
||||
public function __construct($path, $filename, $watch = false)
|
||||
{
|
||||
$this->path = $path;
|
||||
$this->filename = $filename;
|
||||
$this->watch = $watch;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setFilename($filename)
|
||||
{
|
||||
$this->filename = $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addFile($file)
|
||||
{
|
||||
$this->files[] = $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addString(callable $callback)
|
||||
{
|
||||
$this->strings[] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFile()
|
||||
{
|
||||
$old = $current = $this->getRevision();
|
||||
|
||||
$ext = pathinfo($this->filename, PATHINFO_EXTENSION);
|
||||
$file = $this->path.'/'.substr_replace($this->filename, '-'.$old, -strlen($ext) - 1, 0);
|
||||
|
||||
if ($this->watch || ! $old) {
|
||||
$cacheDifferentiator = [$this->getCacheDifferentiator()];
|
||||
|
||||
foreach ($this->files as $source) {
|
||||
$cacheDifferentiator[] = [$source, filemtime($source)];
|
||||
}
|
||||
|
||||
$current = hash('crc32b', serialize($cacheDifferentiator));
|
||||
}
|
||||
|
||||
$exists = file_exists($file);
|
||||
|
||||
if (! $exists || $old !== $current) {
|
||||
if ($exists) {
|
||||
unlink($file);
|
||||
}
|
||||
|
||||
$file = $this->path.'/'.substr_replace($this->filename, '-'.$current, -strlen($ext) - 1, 0);
|
||||
|
||||
if ($content = $this->compile()) {
|
||||
$this->putRevision($current);
|
||||
|
||||
file_put_contents($file, $content);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getCacheDifferentiator()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
* @return string
|
||||
*/
|
||||
protected function format($string)
|
||||
{
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function compile()
|
||||
{
|
||||
$output = '';
|
||||
|
||||
foreach ($this->files as $file) {
|
||||
$output .= $this->formatFile($file);
|
||||
}
|
||||
|
||||
foreach ($this->strings as $callback) {
|
||||
$output .= $this->format($callback());
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @return string
|
||||
*/
|
||||
protected function formatFile($file)
|
||||
{
|
||||
return $this->format(file_get_contents($file));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getRevisionFile()
|
||||
{
|
||||
return $this->path.'/rev-manifest.json';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
protected function getRevision()
|
||||
{
|
||||
if (file_exists($file = $this->getRevisionFile())) {
|
||||
$manifest = json_decode(file_get_contents($file), true);
|
||||
|
||||
return array_get($manifest, $this->filename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $revision
|
||||
* @return int
|
||||
*/
|
||||
protected function putRevision($revision)
|
||||
{
|
||||
if (file_exists($file = $this->getRevisionFile())) {
|
||||
$manifest = json_decode(file_get_contents($file), true);
|
||||
} else {
|
||||
$manifest = [];
|
||||
}
|
||||
|
||||
$manifest[$this->filename] = $revision;
|
||||
|
||||
return file_put_contents($this->getRevisionFile(), json_encode($manifest));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function flush()
|
||||
{
|
||||
$revision = $this->getRevision();
|
||||
|
||||
$ext = pathinfo($this->filename, PATHINFO_EXTENSION);
|
||||
|
||||
$file = $this->path.'/'.substr_replace($this->filename, '-'.$revision, -strlen($ext) - 1, 0);
|
||||
|
||||
if (file_exists($file)) {
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
}
|
165
framework/core/src/Frontend/FrontendAssets.php
Normal file
165
framework/core/src/Frontend/FrontendAssets.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Frontend;
|
||||
|
||||
use Flarum\Frontend\Asset\JsCompiler;
|
||||
use Flarum\Frontend\Asset\LessCompiler;
|
||||
use Flarum\Foundation\Application;
|
||||
use Flarum\Frontend\Asset\LocaleJsCompiler as LocaleJsCompiler;
|
||||
use Flarum\Locale\LocaleManager;
|
||||
use Illuminate\Contracts\Cache\Repository;
|
||||
|
||||
class FrontendAssets
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var Application
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* @var Repository
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* @var LocaleManager
|
||||
*/
|
||||
protected $locales;
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param Application $app
|
||||
* @param Repository $cache
|
||||
* @param LocaleManager $locales
|
||||
*/
|
||||
public function __construct($name, Application $app, Repository $cache, LocaleManager $locales)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->app = $app;
|
||||
$this->cache = $cache;
|
||||
$this->locales = $locales;
|
||||
}
|
||||
|
||||
public function flush()
|
||||
{
|
||||
$this->flushJs();
|
||||
$this->flushCss();
|
||||
}
|
||||
|
||||
public function flushJs()
|
||||
{
|
||||
$this->getJs()->flush();
|
||||
$this->flushLocaleJs();
|
||||
}
|
||||
|
||||
public function flushLocaleJs()
|
||||
{
|
||||
foreach ($this->locales->getLocales() as $locale => $info) {
|
||||
$this->getLocaleJs($locale)->flush();
|
||||
}
|
||||
}
|
||||
|
||||
public function flushCss()
|
||||
{
|
||||
$this->getCss()->flush();
|
||||
$this->flushLocaleCss();
|
||||
}
|
||||
|
||||
public function flushLocaleCss()
|
||||
{
|
||||
foreach ($this->locales->getLocales() as $locale => $info) {
|
||||
$this->getLocaleCss($locale)->flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JsCompiler
|
||||
*/
|
||||
public function getJs()
|
||||
{
|
||||
return new JsCompiler(
|
||||
$this->getDestination(),
|
||||
"$this->name.js",
|
||||
$this->shouldWatch(),
|
||||
$this->cache
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LessCompiler
|
||||
*/
|
||||
public function getCss()
|
||||
{
|
||||
return new LessCompiler(
|
||||
$this->getDestination(),
|
||||
"$this->name.css",
|
||||
$this->shouldWatch(),
|
||||
$this->getLessStorage()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $locale
|
||||
* @return LocaleJsCompiler
|
||||
*/
|
||||
public function getLocaleJs($locale)
|
||||
{
|
||||
return new LocaleJsCompiler(
|
||||
$this->getDestination(),
|
||||
"$this->name-$locale.js",
|
||||
$this->shouldWatch(),
|
||||
$this->cache
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $locale
|
||||
* @return LessCompiler
|
||||
*/
|
||||
public function getLocaleCss($locale)
|
||||
{
|
||||
return new LessCompiler(
|
||||
$this->getDestination(),
|
||||
"$this->name-$locale.css",
|
||||
$this->shouldWatch(),
|
||||
$this->getLessStorage()
|
||||
);
|
||||
}
|
||||
|
||||
protected function getDestination()
|
||||
{
|
||||
return $this->app->publicPath().'/assets';
|
||||
}
|
||||
|
||||
protected function shouldWatch()
|
||||
{
|
||||
return $this->app->config('debug');
|
||||
}
|
||||
|
||||
protected function getLessStorage()
|
||||
{
|
||||
return $this->app->storagePath().'/less';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
55
framework/core/src/Frontend/FrontendAssetsFactory.php
Normal file
55
framework/core/src/Frontend/FrontendAssetsFactory.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Frontend;
|
||||
|
||||
use Flarum\Foundation\Application;
|
||||
use Flarum\Locale\LocaleManager;
|
||||
use Illuminate\Contracts\Cache\Repository;
|
||||
|
||||
class FrontendAssetsFactory
|
||||
{
|
||||
/**
|
||||
* @var Application
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* @var Repository
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* @var LocaleManager
|
||||
*/
|
||||
protected $locales;
|
||||
|
||||
/**
|
||||
* @param Application $app
|
||||
* @param Repository $cache
|
||||
* @param LocaleManager $locales
|
||||
*/
|
||||
public function __construct(Application $app, Repository $cache, LocaleManager $locales)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->cache = $cache;
|
||||
$this->locales = $locales;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return FrontendAssets
|
||||
*/
|
||||
public function make($name)
|
||||
{
|
||||
return new FrontendAssets($name, $this->app, $this->cache, $this->locales);
|
||||
}
|
||||
}
|
483
framework/core/src/Frontend/FrontendView.php
Normal file
483
framework/core/src/Frontend/FrontendView.php
Normal file
@@ -0,0 +1,483 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Frontend;
|
||||
|
||||
use Flarum\Api\Client;
|
||||
use Flarum\Api\Serializer\AbstractSerializer;
|
||||
use Flarum\Frontend\Asset\CompilerInterface;
|
||||
use Flarum\Foundation\Application;
|
||||
use Flarum\Frontend\Asset\LocaleJsCompiler;
|
||||
use Flarum\Locale\LocaleManager;
|
||||
use Illuminate\View\Factory;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Tobscure\JsonApi\Document;
|
||||
use Tobscure\JsonApi\Resource;
|
||||
|
||||
/**
|
||||
* This class represents a view which boots up Flarum's client.
|
||||
*/
|
||||
class FrontendView
|
||||
{
|
||||
/**
|
||||
* The title of the document, displayed in the <title> tag.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
public $title;
|
||||
|
||||
/**
|
||||
* The description of the document, displayed in a <meta> tag.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
public $description;
|
||||
|
||||
/**
|
||||
* The language of the document, displayed as the value of the attribute `dir` in the <html> tag.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
public $language;
|
||||
|
||||
/**
|
||||
* The text direction of the document, displayed as the value of the attribute `dir` in the <html> tag.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
public $direction;
|
||||
|
||||
/**
|
||||
* The path to the client layout view to display.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $layout;
|
||||
|
||||
/**
|
||||
* The SEO content of the page, displayed within the layout in <noscript>
|
||||
* tags.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $content;
|
||||
|
||||
/**
|
||||
* An API response to be preloaded into the page.
|
||||
*
|
||||
* This should be a JSON-API document.
|
||||
*
|
||||
* @var null|array|object
|
||||
*/
|
||||
public $document;
|
||||
|
||||
/**
|
||||
* Other variables to preload into the page.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $variables = [];
|
||||
|
||||
/**
|
||||
* An array of JS modules to load before booting the app.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $modules = ['locale'];
|
||||
|
||||
/**
|
||||
* An array of strings to append to the page's <head>.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $head = [];
|
||||
|
||||
/**
|
||||
* An array of strings to prepend before the page's </body>.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $foot = [];
|
||||
|
||||
/**
|
||||
* A map of <link> tags to be generated.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $links = [];
|
||||
|
||||
/**
|
||||
* @var CompilerInterface
|
||||
*/
|
||||
protected $js;
|
||||
|
||||
/**
|
||||
* @var CompilerInterface
|
||||
*/
|
||||
protected $css;
|
||||
|
||||
/**
|
||||
* @var CompilerInterface
|
||||
*/
|
||||
protected $localeJs;
|
||||
|
||||
/**
|
||||
* @var CompilerInterface
|
||||
*/
|
||||
protected $localeCss;
|
||||
|
||||
/**
|
||||
* @var FrontendAssets
|
||||
*/
|
||||
protected $assets;
|
||||
|
||||
/**
|
||||
* @var Client
|
||||
*/
|
||||
protected $api;
|
||||
|
||||
/**
|
||||
* @var Factory
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* @var LocaleManager
|
||||
*/
|
||||
protected $locales;
|
||||
|
||||
/**
|
||||
* @var AbstractSerializer
|
||||
*/
|
||||
protected $userSerializer;
|
||||
|
||||
/**
|
||||
* @var Application
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* @param string $layout
|
||||
* @param FrontendAssets $assets
|
||||
* @param Client $api
|
||||
* @param Factory $view
|
||||
* @param LocaleManager $locales
|
||||
* @param AbstractSerializer $userSerializer
|
||||
* @param Application $app
|
||||
*/
|
||||
public function __construct($layout, FrontendAssets $assets, Client $api, Factory $view, LocaleManager $locales, AbstractSerializer $userSerializer, Application $app)
|
||||
{
|
||||
$this->layout = $layout;
|
||||
$this->api = $api;
|
||||
$this->assets = $assets;
|
||||
$this->view = $view;
|
||||
$this->locales = $locales;
|
||||
$this->userSerializer = $userSerializer;
|
||||
$this->app = $app;
|
||||
|
||||
$this->addHeadString('<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700,600">', 'font');
|
||||
|
||||
$this->js = $this->assets->getJs();
|
||||
$this->css = $this->assets->getCss();
|
||||
|
||||
$locale = $this->locales->getLocale();
|
||||
$this->localeJs = $this->assets->getLocaleJs($locale);
|
||||
$this->localeCss = $this->assets->getLocaleCss($locale);
|
||||
|
||||
foreach ($this->locales->getJsFiles($locale) as $file) {
|
||||
$this->localeJs->addFile($file);
|
||||
}
|
||||
|
||||
foreach ($this->locales->getCssFiles($locale) as $file) {
|
||||
$this->localeCss->addFile($file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a string to be appended to the page's <head>.
|
||||
*
|
||||
* @param string $string
|
||||
* @param null|string $name
|
||||
*/
|
||||
public function addHeadString($string, $name = null)
|
||||
{
|
||||
if ($name) {
|
||||
$this->head[$name] = $string;
|
||||
} else {
|
||||
$this->head[] = $string;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a string to be prepended before the page's </body>.
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
public function addFootString($string)
|
||||
{
|
||||
$this->foot[] = $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a <link> tag.
|
||||
*
|
||||
* @param string $relation
|
||||
* @param string $target
|
||||
*/
|
||||
public function link($relation, $target)
|
||||
{
|
||||
$this->links[$relation] = $target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the canonical URL for this page.
|
||||
*
|
||||
* This will signal to search engines what URL should be used for this
|
||||
* content, if it can be found under multiple addresses. This is an
|
||||
* important tool to tackle duplicate content.
|
||||
*
|
||||
* @param string $url
|
||||
*/
|
||||
public function setCanonicalUrl($url)
|
||||
{
|
||||
$this->link('canonical', $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a variable to be preloaded into the app.
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setVariable($name, $value)
|
||||
{
|
||||
$this->variables[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a JavaScript module to be imported before the app is booted.
|
||||
*
|
||||
* @param string $module
|
||||
*/
|
||||
public function loadModule($module)
|
||||
{
|
||||
$this->modules[] = $module;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string contents of the view.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return string
|
||||
*/
|
||||
public function render(Request $request)
|
||||
{
|
||||
$forum = $this->getForumDocument($request);
|
||||
|
||||
$this->view->share('translator', $this->locales->getTranslator());
|
||||
$this->view->share('allowJs', ! array_get($request->getQueryParams(), 'nojs'));
|
||||
$this->view->share('forum', array_get($forum, 'data'));
|
||||
$this->view->share('debug', $this->app->inDebugMode());
|
||||
|
||||
$view = $this->view->file(__DIR__.'/../../../views/app.blade.php');
|
||||
|
||||
$view->title = $this->buildTitle(array_get($forum, 'data.attributes.title'));
|
||||
$view->description = $this->description ?: array_get($forum, 'data.attributes.description');
|
||||
$view->language = $this->language ?: $this->locales->getLocale();
|
||||
$view->direction = $this->direction ?: 'ltr';
|
||||
|
||||
$view->modules = $this->modules;
|
||||
$view->payload = $this->buildPayload($request, $forum);
|
||||
|
||||
$view->layout = $this->buildLayout();
|
||||
|
||||
$baseUrl = array_get($forum, 'data.attributes.baseUrl');
|
||||
$view->cssUrls = $this->buildCssUrls($baseUrl);
|
||||
$view->jsUrls = $this->buildJsUrls($baseUrl);
|
||||
|
||||
$view->head = $this->buildHeadContent();
|
||||
$view->foot = implode("\n", $this->foot);
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
protected function buildTitle($forumTitle)
|
||||
{
|
||||
return ($this->title ? $this->title.' - ' : '').$forumTitle;
|
||||
}
|
||||
|
||||
protected function buildPayload(Request $request, $forum)
|
||||
{
|
||||
$data = $this->getDataFromDocument($forum);
|
||||
|
||||
if ($request->getAttribute('actor')->exists) {
|
||||
$user = $this->getUserDocument($request);
|
||||
$data = array_merge($data, $this->getDataFromDocument($user));
|
||||
}
|
||||
|
||||
$payload = [
|
||||
'resources' => $data,
|
||||
'session' => $this->buildSession($request),
|
||||
'document' => $this->document,
|
||||
'locales' => $this->locales->getLocales(),
|
||||
'locale' => $this->locales->getLocale()
|
||||
];
|
||||
|
||||
return array_merge($payload, $this->variables);
|
||||
}
|
||||
|
||||
protected function buildLayout()
|
||||
{
|
||||
$view = $this->view->file($this->layout);
|
||||
|
||||
$view->content = $this->buildContent();
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
protected function buildContent()
|
||||
{
|
||||
$view = $this->view->file(__DIR__.'/../../../views/content.blade.php');
|
||||
|
||||
$view->content = $this->content;
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
protected function buildCssUrls($baseUrl)
|
||||
{
|
||||
return $this->buildAssetUrls($baseUrl, [$this->css->getFile(), $this->localeCss->getFile()]);
|
||||
}
|
||||
|
||||
protected function buildJsUrls($baseUrl)
|
||||
{
|
||||
return $this->buildAssetUrls($baseUrl, [$this->js->getFile(), $this->localeJs->getFile()]);
|
||||
}
|
||||
|
||||
protected function buildAssetUrls($baseUrl, $files)
|
||||
{
|
||||
return array_map(function ($file) use ($baseUrl) {
|
||||
return $baseUrl.str_replace(public_path(), '', $file);
|
||||
}, array_filter($files));
|
||||
}
|
||||
|
||||
protected function buildHeadContent()
|
||||
{
|
||||
$html = implode("\n", $this->head);
|
||||
|
||||
foreach ($this->links as $rel => $href) {
|
||||
$html .= "\n<link rel=\"$rel\" href=\"$href\" />";
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CompilerInterface
|
||||
*/
|
||||
public function getJs()
|
||||
{
|
||||
return $this->js;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CompilerInterface
|
||||
*/
|
||||
public function getCss()
|
||||
{
|
||||
return $this->css;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LocaleJsCompiler
|
||||
*/
|
||||
public function getLocaleJs()
|
||||
{
|
||||
return $this->localeJs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CompilerInterface
|
||||
*/
|
||||
public function getLocaleCss()
|
||||
{
|
||||
return $this->localeCss;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the result of an API request to show the forum.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
protected function getForumDocument(Request $request)
|
||||
{
|
||||
$actor = $request->getAttribute('actor');
|
||||
|
||||
$response = $this->api->send('Flarum\Api\Controller\ShowForumController', $actor);
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the result of an API request to show the current user.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
protected function getUserDocument(Request $request)
|
||||
{
|
||||
$actor = $request->getAttribute('actor');
|
||||
|
||||
$this->userSerializer->setActor($actor);
|
||||
|
||||
$resource = new Resource($actor, $this->userSerializer);
|
||||
|
||||
$document = new Document($resource->with('groups'));
|
||||
|
||||
return $document->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about the current session.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
protected function buildSession(Request $request)
|
||||
{
|
||||
$actor = $request->getAttribute('actor');
|
||||
$session = $request->getAttribute('session');
|
||||
|
||||
return [
|
||||
'userId' => $actor->id,
|
||||
'csrfToken' => $session->get('csrf_token')
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of data by merging the 'data' and 'included' keys of a
|
||||
* JSON-API document.
|
||||
*
|
||||
* @param array $document
|
||||
* @return array
|
||||
*/
|
||||
private function getDataFromDocument(array $document)
|
||||
{
|
||||
$data[] = $document['data'];
|
||||
|
||||
if (isset($document['included'])) {
|
||||
$data = array_merge($data, $document['included']);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
72
framework/core/src/Frontend/FrontendViewFactory.php
Normal file
72
framework/core/src/Frontend/FrontendViewFactory.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Frontend;
|
||||
|
||||
use Flarum\Api\Client;
|
||||
use Flarum\Api\Serializer\CurrentUserSerializer;
|
||||
use Flarum\Foundation\Application;
|
||||
use Flarum\Locale\LocaleManager;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
|
||||
class FrontendViewFactory
|
||||
{
|
||||
/**
|
||||
* @var Client
|
||||
*/
|
||||
protected $api;
|
||||
|
||||
/**
|
||||
* @var Factory
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* @var LocaleManager
|
||||
*/
|
||||
protected $locales;
|
||||
|
||||
/**
|
||||
* @var CurrentUserSerializer
|
||||
*/
|
||||
protected $userSerializer;
|
||||
|
||||
/**
|
||||
* @var Application
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* @param Client $api
|
||||
* @param Factory $view
|
||||
* @param LocaleManager $locales
|
||||
* @param CurrentUserSerializer $userSerializer
|
||||
* @param Application $app
|
||||
*/
|
||||
public function __construct(Client $api, Factory $view, LocaleManager $locales, CurrentUserSerializer $userSerializer, Application $app)
|
||||
{
|
||||
$this->api = $api;
|
||||
$this->view = $view;
|
||||
$this->locales = $locales;
|
||||
$this->userSerializer = $userSerializer;
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $layout
|
||||
* @param FrontendAssets $assets
|
||||
* @return FrontendView
|
||||
*/
|
||||
public function make($layout, FrontendAssets $assets)
|
||||
{
|
||||
return new FrontendView($layout, $assets, $this->api, $this->view, $this->locales, $this->userSerializer, $this->app);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user