Merge pull request #1335 from flarum/next-back-extenders

Start of PHP extenders API
This commit is contained in:
Toby Zerner 2018-01-06 09:17:27 +10:30 committed by GitHub
commit 6df4e63910
14 changed files with 341 additions and 21 deletions

View File

@ -14,6 +14,9 @@ namespace Flarum\Event;
use Flarum\Http\RouteCollection;
use Flarum\Http\RouteHandlerFactory;
/**
* @deprecated
*/
abstract class AbstractConfigureRoutes
{
/**

View File

@ -12,9 +12,7 @@
namespace Flarum\Event;
/**
* Configure API routes.
*
* This event is fired when API routes are being registered.
* @deprecated
*/
class ConfigureApiRoutes extends AbstractConfigureRoutes
{

View File

@ -14,9 +14,7 @@ namespace Flarum\Event;
use Flarum\Forum\Controller\FrontendController;
/**
* Configure forum routes.
*
* This event is fired when routes for the forum client are being registered.
* @deprecated
*/
class ConfigureForumRoutes extends AbstractConfigureRoutes
{

View File

@ -15,6 +15,9 @@ use DirectoryIterator;
use Flarum\Locale\LocaleManager;
use RuntimeException;
/**
* @deprecated
*/
class ConfigureLocales
{
/**

View File

@ -13,6 +13,9 @@ namespace Flarum\Event;
use Zend\Stratigility\MiddlewarePipe;
/**
* @deprecated
*/
class ConfigureMiddleware
{
/**

View File

@ -0,0 +1,81 @@
<?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\Extend;
use Flarum\Frontend\Event\Rendering;
use Illuminate\Contracts\Container\Container;
use Illuminate\Events\Dispatcher;
class Assets implements Extender
{
protected $appName;
protected $assets = [];
protected $bootstrapper;
public function __construct($appName)
{
$this->appName = $appName;
}
public function defaultAssets($baseDir)
{
$this->asset("$baseDir/js/{$this->appName}/dist/extension.js");
$this->asset("$baseDir/less/{$this->appName}/extension.less");
return $this;
}
public function asset($path)
{
$this->assets[] = $path;
return $this;
}
public function bootstrapper($name)
{
$this->bootstrapper = $name;
return $this;
}
public function apply(Container $container)
{
$container->make(Dispatcher::class)->listen(
Rendering::class,
function (Rendering $event) {
if (! $this->matches($event)) {
return;
}
$event->addAssets($this->assets);
if ($this->bootstrapper) {
$event->addBootstrapper($this->bootstrapper);
}
}
);
}
private function matches(Rendering $event)
{
switch ($this->appName) {
case 'admin':
return $event->isAdmin();
case 'forum':
return $event->isForum();
default:
return false;
}
}
}

View File

@ -0,0 +1,38 @@
<?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\Extend;
use Illuminate\Contracts\Container\Container;
/**
* This class is used to wrap old bootstrap.php closures (as used in versions up
* to 0.1.0-beta7) in the new Extender format.
*
* This gives extensions the chance to work with the new API without making any
* changes, and have some time to convert to the pure usage of extenders.
*
* @deprecated
*/
class Compat implements Extender
{
protected $callback;
public function __construct($callback)
{
$this->callback = $callback;
}
public function apply(Container $container)
{
$container->call($this->callback);
}
}

View File

@ -0,0 +1,19 @@
<?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\Extend;
use Illuminate\Contracts\Container\Container;
interface Extender
{
public function apply(Container $container);
}

View File

@ -0,0 +1,36 @@
<?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\Extend;
use Flarum\Formatter\Event\Configuring;
use Illuminate\Contracts\Container\Container;
use Illuminate\Events\Dispatcher;
class FormatterConfiguration implements Extender
{
protected $callback;
public function __construct(callable $callback)
{
$this->callback = $callback;
}
public function apply(Container $container)
{
$container->make(Dispatcher::class)->listen(
Configuring::class,
function (Configuring $event) {
call_user_func($this->callback, $event->configurator);
}
);
}
}

View File

@ -0,0 +1,75 @@
<?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\Extend;
use DirectoryIterator;
use Flarum\Locale\LocaleManager;
use Illuminate\Contracts\Container\Container;
use RuntimeException;
class Locale implements Extender
{
protected $directory;
public function __construct($directory)
{
$this->directory = $directory;
}
public function apply(Container $container)
{
$this->loadLanguagePackFrom(
$this->directory,
$container->make(LocaleManager::class)
);
}
private function loadLanguagePackFrom($directory, LocaleManager $locales)
{
$name = $title = basename($directory);
if (file_exists($manifest = $directory.'/composer.json')) {
$json = json_decode(file_get_contents($manifest), true);
if (empty($json)) {
throw new RuntimeException("Error parsing composer.json in $name: ".json_last_error_msg());
}
$locale = array_get($json, 'extra.flarum-locale.code');
$title = array_get($json, 'extra.flarum-locale.title', $title);
}
if (! isset($locale)) {
throw new RuntimeException("Language pack $name must define \"extra.flarum-locale.code\" in composer.json.");
}
$locales->addLocale($locale, $title);
if (! is_dir($localeDir = $directory.'/locale')) {
throw new RuntimeException("Language pack $name must have a \"locale\" subdirectory.");
}
if (file_exists($file = $localeDir.'/config.js')) {
$locales->addJsFile($locale, $file);
}
if (file_exists($file = $localeDir.'/config.css')) {
$locales->addCssFile($locale, $file);
}
foreach (new DirectoryIterator($localeDir) as $file) {
if ($file->isFile() && in_array($file->getExtension(), ['yml', 'yaml'])) {
$locales->addTranslations($locale, $file->getPathname());
}
}
}
}

View File

@ -0,0 +1,49 @@
<?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\Extend;
use Flarum\Http\RouteCollection;
use Flarum\Http\RouteHandlerFactory;
use Illuminate\Contracts\Container\Container;
class Route implements Extender
{
protected $appName;
protected $name;
protected $httpMethod;
protected $path;
protected $handler;
public function __construct($appName, $name, $httpMethod, $path, $handler)
{
$this->appName = $appName;
$this->name = $name;
$this->httpMethod = $httpMethod;
$this->path = $path;
$this->handler = $handler;
}
public function apply(Container $container)
{
/** @var RouteCollection $routes */
$collection = $container->make("flarum.{$this->appName}.routes");
/** @var RouteHandlerFactory $factory */
$factory = $container->make(RouteHandlerFactory::class);
$collection->{$this->httpMethod}(
$this->path,
$this->name,
$factory->toController($this->handler)
);
}
}

View File

@ -231,6 +231,11 @@ class Extension implements Arrayable
return $this->path;
}
public function getBootstrapperPath()
{
return "{$this->path}/bootstrap.php";
}
/**
* Tests whether the extension has assets.
*

View File

@ -12,6 +12,7 @@
namespace Flarum\Extension;
use Flarum\Database\Migrator;
use Flarum\Extend\Compat;
use Flarum\Extension\Event\Disabled;
use Flarum\Extension\Event\Disabling;
use Flarum\Extension\Event\Enabled;
@ -273,21 +274,30 @@ class ExtensionManager
}
/**
* Loads all bootstrap.php files of the enabled extensions.
* Retrieve all extender instances of all enabled extensions.
*
* @return Collection
*/
public function getEnabledBootstrappers()
public function getActiveExtenders()
{
$bootstrappers = new Collection;
return $this->getEnabledExtensions()
->flatMap(function (Extension $extension) {
$bootstrapper = $extension->getBootstrapperPath();
if ($this->filesystem->exists($bootstrapper)) {
$extenders = require $bootstrapper;
foreach ($this->getEnabledExtensions() as $extension) {
if ($this->filesystem->exists($file = $extension->getPath().'/bootstrap.php')) {
$bootstrappers->push($file);
}
}
if (is_array($extenders)) {
return $extenders;
}
return $bootstrappers;
// Assume that the extension has not yet switched to the new
// bootstrap.php format, and wrap the callback in a Compat
// extender.
return [new Compat($extenders)];
} else {
return [];
}
});
}
/**

View File

@ -12,6 +12,7 @@
namespace Flarum\Extension;
use Flarum\Foundation\AbstractServiceProvider;
use Illuminate\Contracts\Container\Container;
class ExtensionServiceProvider extends AbstractServiceProvider
{
@ -22,13 +23,14 @@ class ExtensionServiceProvider extends AbstractServiceProvider
{
$this->app->bind('flarum.extensions', ExtensionManager::class);
$bootstrappers = $this->app->make('flarum.extensions')->getEnabledBootstrappers();
$this->app->booting(function (Container $app) {
/** @var \Flarum\Extend\Extender[] $extenders */
$extenders = $app->make('flarum.extensions')->getActiveExtenders();
foreach ($bootstrappers as $file) {
$bootstrapper = require $file;
$this->app->call($bootstrapper);
}
foreach ($extenders as $extender) {
$extender->apply($app);
}
});
}
/**