Change format of module configuration to make them implement their events on a single calss.
This commit is contained in:
+48
-24
@@ -3,12 +3,13 @@ declare (strict_types=1);
|
||||
|
||||
namespace LotGD\Core;
|
||||
|
||||
use Composer\Package\PackageInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use LotGD\Core\Models\Module;
|
||||
use LotGD\Core\Exceptions\KeyNotFoundException;
|
||||
use LotGD\Core\Exceptions\ModuleAlreadyExistsException;
|
||||
use LotGD\Core\Exceptions\ModuleDoesNotExistException;
|
||||
use Composer\Package\PackageInterface;
|
||||
use LotGD\Core\Models\Module as ModuleModel;
|
||||
|
||||
/**
|
||||
* Handles the adding and removing of modules to the game.
|
||||
@@ -27,18 +28,16 @@ class ModuleManager
|
||||
|
||||
private static function getPackageSubscriptions(PackageInterface $package): array
|
||||
{
|
||||
$name = $package->getName();
|
||||
$extra = $package->getExtra();
|
||||
if (!empty($extra['subscriptions'])) {
|
||||
$subscriptions = array();
|
||||
|
||||
// Minimal scrub to the subscriptions list.
|
||||
foreach ($extra['subscriptions'] as $s) {
|
||||
if (!isset($s['pattern']) ||
|
||||
!isset($s['class']) ||
|
||||
!is_string($s['pattern']) ||
|
||||
!is_string($s['class']))
|
||||
if (!is_string($s))
|
||||
{
|
||||
// TODO: log this but continue on.
|
||||
$this->g->getLogger()->error("Module {$name} has invalid event subscription: {$s}.");
|
||||
continue;
|
||||
}
|
||||
array_push($subscriptions, $s);
|
||||
@@ -57,27 +56,49 @@ class ModuleManager
|
||||
* @param PackageInterface $package Composer package containing this module.
|
||||
* @throws ModuleAlreadyExistsException if the module is already installed.
|
||||
* @throws ClassNotFoundException if an event subscription class cannot be resolved.
|
||||
* @throws WrongTypeException if an event subscription class does not implement the EventHandler
|
||||
* @throws WrongTypeException if an event subscription class does not implement the Module
|
||||
* interface or the pattern is not a valid regular expression.
|
||||
*/
|
||||
public function register(string $library, PackageInterface $package)
|
||||
{
|
||||
$m = $this->g->getEntityManager()->getRepository(Module::class)->find($library);
|
||||
$m = $this->g->getEntityManager()->getRepository(ModuleModel::class)->find($library);
|
||||
if ($m) {
|
||||
throw new ModuleAlreadyExistsException($library);
|
||||
} else {
|
||||
// TODO: handle error cases here.
|
||||
$m = new Module($library);
|
||||
$m = new ModuleModel($library);
|
||||
$m->save($this->g->getEntityManager());
|
||||
|
||||
$name = $package->getName();
|
||||
|
||||
$class = $package->getExtra()['class'];
|
||||
if (!isset($package->getExtra()['class']) ||
|
||||
!is_string($class))
|
||||
{
|
||||
throw new KeyNotFoundException("Module {$name} is missing a valid 'class' entry in its extra field.");
|
||||
}
|
||||
try {
|
||||
$klass = new \ReflectionClass($class);
|
||||
} catch (\LogicException $e) {
|
||||
throw new ClassNotFoundException("Could not load class ${class} while registering module {$name}.");
|
||||
} catch (\ReflectionException $e) {
|
||||
throw new ClassNotFoundException("Could not find class ${class} while registering module {$name}.");
|
||||
}
|
||||
|
||||
// Verify that the class is a module class.
|
||||
$interface = Module::class;
|
||||
if (!$klass->implementsInterface($interface)) {
|
||||
throw new WrongTypeException("Class {$class} does not implement {$interface} while registering module {$name}.");
|
||||
}
|
||||
|
||||
// Subscribe to the module's events.
|
||||
$subscriptions = ModuleManager::getPackageSubscriptions($package);
|
||||
foreach ($subscriptions as $s) {
|
||||
$pattern = $s['pattern'];
|
||||
$class = $s['class'];
|
||||
|
||||
$this->g->getEventManager()->subscribe($pattern, $class, $library);
|
||||
$this->g->getEventManager()->subscribe($s, $class, $library);
|
||||
}
|
||||
|
||||
// Run the module's onRegister handler.
|
||||
$class::onRegister($this->g);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,25 +112,27 @@ class ModuleManager
|
||||
*/
|
||||
public function unregister(string $library, PackageInterface $package)
|
||||
{
|
||||
$m = $this->g->getEntityManager()->getRepository(Module::class)->find($library);
|
||||
$m = $this->g->getEntityManager()->getRepository(ModuleModel::class)->find($library);
|
||||
if (!$m) {
|
||||
throw new ModuleDoesNotExistException($library);
|
||||
} else {
|
||||
// TODO: handle error cases here.
|
||||
$m->delete($this->g->getEntityManager());
|
||||
|
||||
$class = $package->getExtra()['class'];
|
||||
|
||||
// Unsubscribe the module's events.
|
||||
$subscriptions = ModuleManager::getPackageSubscriptions($package);
|
||||
foreach ($subscriptions as $s) {
|
||||
$pattern = $s['pattern'];
|
||||
$class = $s['class'];
|
||||
|
||||
try {
|
||||
$this->g->getEventManager()->unsubscribe($pattern, $class, $library);
|
||||
$this->g->getEventManager()->unsubscribe($s, $class, $library);
|
||||
} catch (SubscriptionNotFoundException $e) {
|
||||
// TODO: log this but continue on.
|
||||
}
|
||||
}
|
||||
|
||||
// Run the module's onUnregister handler.
|
||||
$class::onUnregister($this->g);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +141,7 @@ class ModuleManager
|
||||
* @return array<Module> Array of modules.
|
||||
*/
|
||||
public function getModules(): array {
|
||||
return $this->g->getEntityManager()->getRepository(Module::class)->findAll();
|
||||
return $this->g->getEntityManager()->getRepository(ModuleModel::class)->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,6 +172,7 @@ class ModuleManager
|
||||
$currentSubscriptions = $this->g->getEventManager()->getSubscriptions();
|
||||
foreach ($packages as $p) {
|
||||
$name = $p->getName();
|
||||
$class = $p->getExtra()['class'];
|
||||
|
||||
$expectedSubscriptions = ModuleManager::getPackageSubscriptions($p);
|
||||
$currentSubscriptionsForThisPackage = array_filter($currentSubscriptions, function($s) use ($name) {
|
||||
@@ -162,8 +186,8 @@ class ModuleManager
|
||||
$found = false;
|
||||
foreach ($currentSubscriptionsForThisPackage as $c) {
|
||||
// Count the subscriptions for this
|
||||
if ($c->getPattern() === $e['pattern'] &&
|
||||
$c->getClass() === $e['class'] &&
|
||||
if ($c->getPattern() === $e &&
|
||||
$c->getClass() === $class &&
|
||||
$c->getLibrary() === $p->getName())
|
||||
{
|
||||
$found = true;
|
||||
@@ -171,8 +195,8 @@ class ModuleManager
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
$pattern = $e['pattern'];
|
||||
$class = $e['class'];
|
||||
$pattern = $e;
|
||||
$class = $class;
|
||||
array_push($result, "Error: Couldn't find subscription ({$pattern} => ${class}) for module {$name}.");
|
||||
}
|
||||
}
|
||||
|
||||
+34
-132
@@ -9,21 +9,18 @@ use LotGD\Core\EventHandler;
|
||||
use LotGD\Core\EventManager;
|
||||
use LotGD\Core\EventSubscription;
|
||||
use LotGD\Core\ModuleManager;
|
||||
use LotGD\Core\Models\Module;
|
||||
use LotGD\Core\Module;
|
||||
use LotGD\Core\Exceptions\ModuleAlreadyExistsException;
|
||||
use LotGD\Core\Exceptions\ModuleDoesNotExistException;
|
||||
use LotGD\Core\Tests\ModelTestCase;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Composer;
|
||||
|
||||
class ModuleManagerTestSubscriber implements EventHandler
|
||||
{
|
||||
public static function handleEvent(string $event, array $context) {}
|
||||
}
|
||||
|
||||
class ModuleManagerTestAnotherSubscriber implements EventHandler
|
||||
class ModuleManagerTestModule implements Module
|
||||
{
|
||||
public static function handleEvent(string $event, array $context) {}
|
||||
public static function onRegister(Game $g) {}
|
||||
public static function onUnregister(Game $g) {}
|
||||
}
|
||||
|
||||
class ModuleManagerTest extends ModelTestCase
|
||||
@@ -57,7 +54,7 @@ class ModuleManagerTest extends ModelTestCase
|
||||
public function testGetModules()
|
||||
{
|
||||
$modules = $this->mm->getModules();
|
||||
$this->assertContainsOnlyInstancesOf(Module::class, $modules);
|
||||
$this->assertContainsOnlyInstancesOf(\LotGD\Core\Models\Module::class, $modules);
|
||||
|
||||
// This is a little fragile, but assertContains() doesn't seem to work.
|
||||
$this->assertEquals(new \DateTime('2016-05-01'), $modules[0]->getCreatedAt());
|
||||
@@ -75,7 +72,9 @@ class ModuleManagerTest extends ModelTestCase
|
||||
public function testUnregisterWithNoEvents()
|
||||
{
|
||||
$package = $this->getMockForAbstractClass(PackageInterface::class);
|
||||
$package->method('getExtra')->willReturn(array());
|
||||
$package->method('getExtra')->willReturn(array(
|
||||
'class' => ModuleManagerTestModule::class
|
||||
));
|
||||
|
||||
$eventManager = $this->getMockBuilder(EventManager::class)
|
||||
->disableOriginalConstructor()
|
||||
@@ -92,20 +91,16 @@ class ModuleManagerTest extends ModelTestCase
|
||||
public function testUnregisterWithEvents()
|
||||
{
|
||||
$subscriptions = array(
|
||||
array(
|
||||
'pattern' => '/pattern1/',
|
||||
'class' => 'SomeClass1'
|
||||
),
|
||||
array(
|
||||
'pattern' => '/pattern2/',
|
||||
'class' => 'SomeClass2'
|
||||
),
|
||||
'/pattern1/',
|
||||
'/pattern2/'
|
||||
);
|
||||
$class = ModuleManagerTestModule::class;
|
||||
|
||||
$library = 'lotgd/tests';
|
||||
|
||||
$package = $this->getMockForAbstractClass(PackageInterface::class);
|
||||
$package->method('getExtra')->willReturn(array(
|
||||
'class' => $class,
|
||||
'subscriptions' => $subscriptions
|
||||
));
|
||||
|
||||
@@ -116,46 +111,8 @@ class ModuleManagerTest extends ModelTestCase
|
||||
$eventManager->expects($this->exactly(2))
|
||||
->method('unsubscribe')
|
||||
->withConsecutive(
|
||||
array($this->equalTo($subscriptions[0]['pattern']), $this->equalTo($subscriptions[0]['class']), $library),
|
||||
array($this->equalTo($subscriptions[1]['pattern']), $this->equalTo($subscriptions[1]['class']), $library)
|
||||
);
|
||||
|
||||
$this->game->method('getEventManager')->willReturn($eventManager);
|
||||
|
||||
$this->mm->unregister($library, $package);
|
||||
|
||||
$modules = $this->mm->getModules();
|
||||
$this->assertEmpty($modules);
|
||||
}
|
||||
|
||||
public function testUnregisterWithInvalidEvents()
|
||||
{
|
||||
$subscriptions = array(
|
||||
array(
|
||||
'pattern' => '/pattern1/',
|
||||
'class' => 'SomeClass1'
|
||||
),
|
||||
array(
|
||||
// Invalid subscription.
|
||||
'crazy' => 'making'
|
||||
),
|
||||
);
|
||||
|
||||
$library = 'lotgd/tests';
|
||||
|
||||
$package = $this->getMockForAbstractClass(PackageInterface::class);
|
||||
$package->method('getExtra')->willReturn(array(
|
||||
'subscriptions' => $subscriptions
|
||||
));
|
||||
|
||||
$eventManager = $this->getMockBuilder(EventManager::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('unsubscribe'))
|
||||
->getMock();
|
||||
$eventManager->expects($this->exactly(1))
|
||||
->method('unsubscribe')
|
||||
->withConsecutive(
|
||||
array($this->equalTo($subscriptions[0]['pattern']), $this->equalTo($subscriptions[0]['class']), $library)
|
||||
array($this->equalTo($subscriptions[0]), $this->equalTo($class), $library),
|
||||
array($this->equalTo($subscriptions[1]), $this->equalTo($class), $library)
|
||||
);
|
||||
|
||||
$this->game->method('getEventManager')->willReturn($eventManager);
|
||||
@@ -169,7 +126,9 @@ class ModuleManagerTest extends ModelTestCase
|
||||
public function testRegisterWithNoEvents()
|
||||
{
|
||||
$package = $this->getMockForAbstractClass(PackageInterface::class);
|
||||
$package->method('getExtra')->willReturn(array());
|
||||
$package->method('getExtra')->willReturn(array(
|
||||
'class' => ModuleManagerTestModule::class
|
||||
));
|
||||
|
||||
$library = 'lotgd/tests2';
|
||||
|
||||
@@ -193,20 +152,16 @@ class ModuleManagerTest extends ModelTestCase
|
||||
public function testRegisterWithEvents()
|
||||
{
|
||||
$subscriptions = array(
|
||||
array(
|
||||
'pattern' => '/pattern1/',
|
||||
'class' => ModuleManagerTestSubscriber::class
|
||||
),
|
||||
array(
|
||||
'pattern' => '/pattern2/',
|
||||
'class' => ModuleManagerTestAnotherSubscriber::class
|
||||
),
|
||||
'/pattern1/',
|
||||
'/pattern2/',
|
||||
);
|
||||
$class = ModuleManagerTestModule::class;
|
||||
|
||||
$library = 'lotgd/tests2';
|
||||
|
||||
$package = $this->getMockForAbstractClass(PackageInterface::class);
|
||||
$package->method('getExtra')->willReturn(array(
|
||||
'class' => $class,
|
||||
'subscriptions' => $subscriptions
|
||||
));
|
||||
|
||||
@@ -217,51 +172,8 @@ class ModuleManagerTest extends ModelTestCase
|
||||
$eventManager->expects($this->exactly(2))
|
||||
->method('subscribe')
|
||||
->withConsecutive(
|
||||
array($this->equalTo($subscriptions[0]['pattern']), $this->equalTo($subscriptions[0]['class']), $library),
|
||||
array($this->equalTo($subscriptions[1]['pattern']), $this->equalTo($subscriptions[1]['class']), $library)
|
||||
);
|
||||
|
||||
$this->game->method('getEventManager')->willReturn($eventManager);
|
||||
|
||||
$this->mm->register($library, $package);
|
||||
|
||||
$modules = $this->mm->getModules();
|
||||
|
||||
// Timestamps should be within 5 seconds :)
|
||||
$timeDiff = (new \DateTime())->getTimestamp() - $modules[1]->getCreatedAt()->getTimestamp();
|
||||
$this->assertLessThanOrEqual(5, $timeDiff);
|
||||
$this->assertGreaterThanOrEqual(-5, $timeDiff);
|
||||
$this->assertEquals($library, $modules[1]->getLibrary());
|
||||
}
|
||||
|
||||
public function testRegisterWithInvalidEvents()
|
||||
{
|
||||
$subscriptions = array(
|
||||
array(
|
||||
'pattern' => '/pattern1/',
|
||||
'class' => ModuleManagerTestSubscriber::class
|
||||
),
|
||||
array(
|
||||
// Invalid subscription.
|
||||
'crazy' => 'making'
|
||||
),
|
||||
);
|
||||
|
||||
$library = 'lotgd/tests2';
|
||||
|
||||
$package = $this->getMockForAbstractClass(PackageInterface::class);
|
||||
$package->method('getExtra')->willReturn(array(
|
||||
'subscriptions' => $subscriptions
|
||||
));
|
||||
|
||||
$eventManager = $this->getMockBuilder(EventManager::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('subscribe'))
|
||||
->getMock();
|
||||
$eventManager->expects($this->exactly(1))
|
||||
->method('subscribe')
|
||||
->withConsecutive(
|
||||
array($this->equalTo($subscriptions[0]['pattern']), $this->equalTo($subscriptions[0]['class']), $library)
|
||||
array($this->equalTo($subscriptions[0]), $this->equalTo($class), $library),
|
||||
array($this->equalTo($subscriptions[1]), $this->equalTo($class), $library)
|
||||
);
|
||||
|
||||
$this->game->method('getEventManager')->willReturn($eventManager);
|
||||
@@ -283,16 +195,14 @@ class ModuleManagerTest extends ModelTestCase
|
||||
$class = "LotGD\\Core\\Tests\\EventManagerTestInstalledSubscriber";
|
||||
$library = 'lotgd/tests';
|
||||
$subscriptions = array(
|
||||
array(
|
||||
'pattern' => $pattern,
|
||||
'class' => $class
|
||||
),
|
||||
$pattern,
|
||||
);
|
||||
|
||||
$p1 = $this->getMockBuilder(PackageInterface::class)
|
||||
->getMock();
|
||||
$p1->method('getName')->willReturn($library);
|
||||
$p1->method('getExtra')->willReturn(array(
|
||||
'class' => $class,
|
||||
'subscriptions' => $subscriptions
|
||||
));
|
||||
|
||||
@@ -331,20 +241,15 @@ class ModuleManagerTest extends ModelTestCase
|
||||
$class = "LotGD\\Core\\Tests\\EventManagerTestInstalledSubscriber";
|
||||
$library = 'lotgd/tests';
|
||||
$subscriptions = array(
|
||||
array(
|
||||
'pattern' => $pattern,
|
||||
'class' => $class
|
||||
),
|
||||
array(
|
||||
'pattern' => '/another pattern/',
|
||||
'class' => $class
|
||||
)
|
||||
$pattern,
|
||||
'/another pattern/',
|
||||
);
|
||||
|
||||
$p1 = $this->getMockBuilder(PackageInterface::class)
|
||||
->getMock();
|
||||
$p1->method('getName')->willReturn($library);
|
||||
$p1->method('getExtra')->willReturn(array(
|
||||
'class' => $class,
|
||||
'subscriptions' => $subscriptions
|
||||
));
|
||||
|
||||
@@ -419,16 +324,14 @@ class ModuleManagerTest extends ModelTestCase
|
||||
$library = 'lotgd/tests';
|
||||
|
||||
$subscriptions = array(
|
||||
array(
|
||||
'pattern' => $pattern,
|
||||
'class' => $class
|
||||
),
|
||||
$pattern
|
||||
);
|
||||
|
||||
$p1 = $this->getMockBuilder(PackageInterface::class)
|
||||
->getMock();
|
||||
$p1->method('getName')->willReturn($library);
|
||||
$p1->method('getExtra')->willReturn(array(
|
||||
'class' => $class,
|
||||
'subscriptions' => $subscriptions
|
||||
));
|
||||
|
||||
@@ -436,6 +339,7 @@ class ModuleManagerTest extends ModelTestCase
|
||||
->getMock();
|
||||
$p2->method('getName')->willReturn('lotgd/tests-another');
|
||||
$p2->method('getExtra')->willReturn(array(
|
||||
'class' => $class,
|
||||
'subscriptions' => $subscriptions
|
||||
));
|
||||
|
||||
@@ -475,16 +379,14 @@ class ModuleManagerTest extends ModelTestCase
|
||||
$library = 'lotgd/tests';
|
||||
|
||||
$subscriptions = array(
|
||||
array(
|
||||
'pattern' => $pattern,
|
||||
'class' => $class
|
||||
),
|
||||
$pattern
|
||||
);
|
||||
|
||||
$p1 = $this->getMockBuilder(PackageInterface::class)
|
||||
->getMock();
|
||||
$p1->method('getName')->willReturn($library);
|
||||
$p1->method('getExtra')->willReturn(array(
|
||||
'class' => $class,
|
||||
'subscriptions' => $subscriptions
|
||||
));
|
||||
|
||||
@@ -509,7 +411,7 @@ class ModuleManagerTest extends ModelTestCase
|
||||
->setMethods(array('getPattern', 'getClass', 'getLibrary'))
|
||||
->getMock();
|
||||
$s2->method('getPattern')->willReturn('/some pattern/');
|
||||
$s2->method('getClass')->willReturn('SomeClass');
|
||||
$s2->method('getClass')->willReturn(ModuleManagerTestModule::class);
|
||||
$s2->method('getLibrary')->willReturn($library);
|
||||
|
||||
$installedSubscriptions = array($s1, $s2);
|
||||
|
||||
Reference in New Issue
Block a user