[CORE][EXTENSIONS] Added extension (modules, plugins) loading and test plugin, which is able to handle events

This commit is contained in:
Hugo Sales 2020-03-20 22:10:01 +00:00 committed by Hugo Sales
parent 2f5bdeed62
commit d8d2ad3e10
12 changed files with 274 additions and 42 deletions

2
.gitignore vendored
View File

@ -19,3 +19,5 @@
!.php_cs
/.php_cs.cache
###< friendsofphp/php-cs-fixer ###
plugins/available

View File

@ -7,6 +7,7 @@
"php": "^7.4",
"ext-ctype": "*",
"ext-iconv": "*",
"lstrojny/functional-php": "^1.11",
"sensio/framework-extra-bundle": "^5.1",
"symfony/asset": "5.0.*",
"symfony/console": "5.0.*",
@ -47,7 +48,8 @@
},
"autoload": {
"psr-4": {
"App\\": "src/"
"App\\": "src/",
"Plugin\\": "plugins/enabled/"
}
},
"autoload-dev": {

144
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "29d2cd792b5bb1a62925c27414e0a448",
"content-hash": "0c92d597e3a31937bac9663d686a42eb",
"packages": [
{
"name": "doctrine/annotations",
@ -1428,6 +1428,148 @@
],
"time": "2020-01-07T22:58:31+00:00"
},
{
"name": "lstrojny/functional-php",
"version": "1.11.0",
"source": {
"type": "git",
"url": "https://github.com/lstrojny/functional-php.git",
"reference": "df0e516eb44cd0579eeaff57023ef41ffa11947f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/lstrojny/functional-php/zipball/df0e516eb44cd0579eeaff57023ef41ffa11947f",
"reference": "df0e516eb44cd0579eeaff57023ef41ffa11947f",
"shasum": ""
},
"require": {
"php": "~7"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.14",
"phpunit/phpunit": "~7",
"squizlabs/php_codesniffer": "~3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Functional\\": "src/Functional"
},
"files": [
"src/Functional/Average.php",
"src/Functional/ButLast.php",
"src/Functional/Capture.php",
"src/Functional/ConstFunction.php",
"src/Functional/CompareOn.php",
"src/Functional/CompareObjectHashOn.php",
"src/Functional/Compose.php",
"src/Functional/Concat.php",
"src/Functional/Contains.php",
"src/Functional/Converge.php",
"src/Functional/Curry.php",
"src/Functional/CurryN.php",
"src/Functional/Difference.php",
"src/Functional/DropFirst.php",
"src/Functional/DropLast.php",
"src/Functional/Each.php",
"src/Functional/Equal.php",
"src/Functional/ErrorToException.php",
"src/Functional/Every.php",
"src/Functional/False.php",
"src/Functional/Falsy.php",
"src/Functional/Filter.php",
"src/Functional/First.php",
"src/Functional/FirstIndexOf.php",
"src/Functional/FlatMap.php",
"src/Functional/Flatten.php",
"src/Functional/Flip.php",
"src/Functional/GreaterThan.php",
"src/Functional/GreaterThanOrEqual.php",
"src/Functional/Group.php",
"src/Functional/Head.php",
"src/Functional/Id.php",
"src/Functional/IfElse.php",
"src/Functional/Identical.php",
"src/Functional/IndexesOf.php",
"src/Functional/Intersperse.php",
"src/Functional/Invoke.php",
"src/Functional/InvokeFirst.php",
"src/Functional/InvokeIf.php",
"src/Functional/InvokeLast.php",
"src/Functional/Invoker.php",
"src/Functional/Last.php",
"src/Functional/LastIndexOf.php",
"src/Functional/LessThan.php",
"src/Functional/LessThanOrEqual.php",
"src/Functional/LexicographicCompare.php",
"src/Functional/Map.php",
"src/Functional/Match.php",
"src/Functional/Maximum.php",
"src/Functional/Memoize.php",
"src/Functional/Minimum.php",
"src/Functional/None.php",
"src/Functional/Noop.php",
"src/Functional/Not.php",
"src/Functional/OmitKeys.php",
"src/Functional/PartialAny.php",
"src/Functional/PartialLeft.php",
"src/Functional/PartialMethod.php",
"src/Functional/PartialRight.php",
"src/Functional/Partition.php",
"src/Functional/Pick.php",
"src/Functional/Pluck.php",
"src/Functional/Poll.php",
"src/Functional/Product.php",
"src/Functional/Ratio.php",
"src/Functional/ReduceLeft.php",
"src/Functional/ReduceRight.php",
"src/Functional/Reindex.php",
"src/Functional/Reject.php",
"src/Functional/Repeat.php",
"src/Functional/Retry.php",
"src/Functional/Select.php",
"src/Functional/SelectKeys.php",
"src/Functional/SequenceConstant.php",
"src/Functional/SequenceExponential.php",
"src/Functional/SequenceLinear.php",
"src/Functional/Some.php",
"src/Functional/Sort.php",
"src/Functional/Sum.php",
"src/Functional/SuppressError.php",
"src/Functional/Tap.php",
"src/Functional/Tail.php",
"src/Functional/TailRecursion.php",
"src/Functional/TakeLeft.php",
"src/Functional/TakeRight.php",
"src/Functional/True.php",
"src/Functional/Truthy.php",
"src/Functional/Unique.php",
"src/Functional/With.php",
"src/Functional/Zip.php",
"src/Functional/ZipAll.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Lars Strojny",
"email": "lstrojny@php.net",
"homepage": "http://usrportage.de"
},
{
"name": "Max Beutel",
"email": "nash12@gmail.com"
}
],
"description": "Functional primitives for PHP",
"keywords": [
"functional"
],
"time": "2019-12-19T16:01:40+00:00"
},
{
"name": "monolog/monolog",
"version": "2.0.2",

View File

@ -0,0 +1,11 @@
<?php
namespace Plugin\Test;
class Test
{
public function onTest(string $foo)
{
dump('Event handled: ' . $foo);
}
}

1
plugins/enabled/Test Symbolic link
View File

@ -0,0 +1 @@
../available/Test/

View File

@ -2,15 +2,15 @@
namespace App\Controller;
use App\Util\GSEvent;
use App\Util\GSEvent as Event;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class NetworkPublic extends AbstractController
{
public function __invoke()
{
GSEvent::handle('test', ['foobar']);
Event::handle('Test', ['foobar']);
return $this->render('network/public.html.twig', []);
}
}

View File

@ -17,6 +17,34 @@ class Kernel extends BaseKernel
private const CONFIG_EXTS = '.{php,xml,yaml,yml}';
public function __construct(string $environment, bool $debug)
{
parent::__construct($environment, $debug);
if (!\defined('INSTALLDIR')) {
define('INSTALLDIR', dirname(__DIR__));
define('SRCDIR', INSTALLDIR . '/src');
define('PUBLICDIR', INSTALLDIR . '/public');
define('GNUSOCIAL_ENGINE', 'GNU social');
// MERGE Change to https://gnu.io/social/
define('GNUSOCIAL_ENGINE_URL', 'https://gnusocial.network/');
// MERGE Change to https://git.gnu.io/gnu/gnu-social
define('GNUSOCIAL_ENGINE_REPO_URL', 'https://notabug.org/diogo/gnu-social/');
// Current base version, major.minor.patch
define('GNUSOCIAL_BASE_VERSION', '3.0.0');
// 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release'
define('GNUSOCIAL_LIFECYCLE', 'dev');
define('GNUSOCIAL_VERSION', GNUSOCIAL_BASE_VERSION . '-' . GNUSOCIAL_LIFECYCLE);
define('GNUSOCIAL_CODENAME', 'Big bang');
// Work internally in UTC
date_default_timezone_set('UTC');
// Work internally with UTF-8
mb_internal_encoding('UTF-8');
}
}
public function registerBundles(): iterable
{
$contents = require $this->getProjectDir() . '/config/bundles.php';
@ -37,6 +65,7 @@ class Kernel extends BaseKernel
$container->addResource(new FileResource($this->getProjectDir() . '/config/bundles.php'));
$container->setParameter('container.dumper.inline_class_loader', PHP_VERSION_ID < 70400 || $this->debug);
$container->setParameter('container.dumper.inline_factories', true);
$confDir = $this->getProjectDir() . '/config';
$loader->load($confDir . '/{packages}/*' . self::CONFIG_EXTS, 'glob');

View File

@ -17,6 +17,9 @@
namespace App\Util;
use Functional as F;
use Symfony\Component\Config\Definition\Exception\Exception;
abstract class Common
{
public static function config(string $section, string $field)
@ -44,10 +47,40 @@ abstract class Common
} else {
// We might be running directly from the plugins dir?
// If so, there's no place to store locale info.
Log::error('The GNU social install dir seems to contain a piece named plugin');
return false;
throw new Exception('The GNU social install dir seems to contain a piece named plugin');
}
return $final;
}
public static function swapArgs($call, $arg)
{
return function ($v) use ($call, $arg) { return self::$call($v, $arg); };
}
public static function startsWith($haystack, string $needle): bool
{
if (is_string($haystack)) {
$length = strlen($needle);
return substr($haystack, 0, $length) === $needle;
}
return F\every($haystack,
function ($haystack) use ($needle) {
return self::startsWith($haystack, $needle);
});
}
public static function endsWith($haystack, string $needle)
{
if (is_string($haystack)) {
$length = strlen($needle);
if ($length == 0) {
return true;
}
return substr($haystack, -$length) === $needle;
}
return F\every($haystack,
function ($haystack) use ($needle) {
return self::endsWith($haystack, $needle);
});
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\Util;
use App\Util\GSEvent as Event;
use Functional as F;
abstract class ExtensionManager
{
public static array $extensions = [];
public static function loadExtensions()
{
$plugins_paths = glob(INSTALLDIR . '/plugins/enabled/*');
foreach ($plugins_paths as $plugin_path) {
$class_name = basename($plugin_path);
$qualified = 'Plugin\\' . $class_name . '\\' . $class_name;
require_once $plugin_path . '/' . $class_name . '.php';
$class = new $qualified;
self::$extensions[] = $class;
// Register event handlers
$methods = get_class_methods($class);
$events = F\select($methods, Common::swapArgs('startsWith', 'on'));
F\map($events,
function (string $m) use ($class) {
Event::addHandler(substr($m, 2), [$class, $m]);
});
}
}
}

View File

@ -63,9 +63,7 @@ use Symfony\Contracts\Translation\TranslatorInterface;
class GNUsocial implements EventSubscriberInterface
{
protected ContainerInterface $container;
protected LoggerInterface $logger;
protected TranslatorInterface $translator;
public function __construct(ContainerInterface $container,
@ -75,40 +73,17 @@ class GNUsocial implements EventSubscriberInterface
$this->container = $container;
$this->logger = $logger;
$this->translator = $translator;
if (!\defined('INSTALLDIR')) {
define('INSTALLDIR', dirname(__DIR__));
define('SRCDIR', INSTALLDIR . '/src');
define('PUBLICDIR', INSTALLDIR . '/public');
define('GNUSOCIAL_ENGINE', 'GNU social');
// MERGE Change to https://gnu.io/social/
define('GNUSOCIAL_ENGINE_URL', 'https://gnusocial.network/');
// MERGE Change to https://git.gnu.io/gnu/gnu-social
define('GNUSOCIAL_ENGINE_REPO_URL', 'https://notabug.org/diogo/gnu-social/');
// Current base version, major.minor.patch
define('GNUSOCIAL_BASE_VERSION', '3.0.0');
// 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release'
define('GNUSOCIAL_LIFECYCLE', 'dev');
define('GNUSOCIAL_VERSION', GNUSOCIAL_BASE_VERSION . '-' . GNUSOCIAL_LIFECYCLE);
define('GNUSOCIAL_CODENAME', 'Big bang');
// Work internally in UTC
date_default_timezone_set('UTC');
// Work internally with UTF-8
mb_internal_encoding('UTF-8');
}
}
public function onKernelRequest(RequestEvent $event,
string $event_name,
$event_dispatcher): RequestEvent
{
if (!\defined('INSTALLDIR')) {
Log::setLogger($this->logger);
GSEvent::setDispatcher($event_dispatcher);
I18n::setTranslator($this->translator);
}
ExtensionManager::loadExtensions();
return $event;
}

View File

@ -66,10 +66,11 @@ abstract class GSEvent
self::$dispatcher->addListener(
$name,
function ($event, $event_name, $dispatcher) use ($handler) {
if ($event instanceof GenericEvent
// Old style of events (preferred)
&& call_user_func_array($handler, $event->getArguments()) == self::stop) {
if ($event instanceof GenericEvent) {
if (call_user_func_array($handler, $event->getArguments()) == self::stop) {
$event->stopPropagation();
}
return $event;
}
// Symfony style of events

View File

@ -120,6 +120,9 @@
"laminas/laminas-zendframework-bridge": {
"version": "1.0.1"
},
"lstrojny/functional-php": {
"version": "1.11.0"
},
"monolog/monolog": {
"version": "2.0.2"
},