Skip to content

Commit

Permalink
The annotation reader is activated by config.
Browse files Browse the repository at this point in the history
  • Loading branch information
feuzeu committed Apr 27, 2022
1 parent 8964010 commit 417a35d
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 55 deletions.
3 changes: 3 additions & 0 deletions src/Di/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class Container extends PimpleContainer implements LoggerAwareInterface
use Traits\RegisterTrait;
use Traits\ViewTrait;
use Traits\UtilTrait;
use Traits\AnnotationTrait;

/**
* The Dependency Injection Container
Expand All @@ -67,9 +68,11 @@ public function __construct(Ajax $jaxon)
// Save the Ajax and Container instances
$this->val(Ajax::class, $jaxon);
$this->val(Container::class, $this);

// Template directory
$sTemplateDir = realpath(__DIR__ . '/../../templates');
$this->val('jaxon.core.dir.template', $sTemplateDir);

// Translation directory
$sTranslationDir = realpath(__DIR__ . '/../../translations');
$this->val('jaxon.core.dir.translation', $sTranslationDir);
Expand Down
64 changes: 64 additions & 0 deletions src/Di/Traits/AnnotationTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

namespace Jaxon\Di\Traits;

use Jaxon\Annotations\AnnotationReader;
use Jaxon\App\Config\ConfigEventManager;
use Jaxon\App\Config\ConfigListenerInterface;
use Jaxon\Plugin\AnnotationReaderInterface;
use Jaxon\Utils\Config\Config;

use function class_exists;

trait AnnotationTrait
{
/**
* Register the values into the container
*
* @return void
*/
private function registerAnnotations()
{
// By default, register a fake annotation reader.
$this->set(AnnotationReaderInterface::class, function() {
return new class implements AnnotationReaderInterface
{
public function getAttributes(string $sClass, array $aMethods): array
{
return [false, [], []];
}
};
});

if(class_exists(AnnotationReader::class))
{
$sEventListenerKey = AnnotationReader::class . '\\ConfigListener';
// The annotation package is installed, register the real annotation reader,
// but only if the feature is activated in the config.
$this->set($sEventListenerKey, function() {
return new class implements ConfigListenerInterface
{
public function onChanges(Config $xConfig)
{
if($xConfig->getOption('core.annotations.on'))
{
AnnotationReader::register(jaxon()->di());
}
}

public function onChange(Config $xConfig, string $sName)
{
if($sName === 'core.annotations.on' && $xConfig->getOption('core.annotations.on'))
{
AnnotationReader::register(jaxon()->di());
}
}
};
});

// Register the event listener
$xEventManager = $this->g(ConfigEventManager::class);
$xEventManager->addListener($sEventListenerKey);
}
}
}
18 changes: 0 additions & 18 deletions src/Di/Traits/RegisterTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,6 @@

trait RegisterTrait
{
/**
* Register the values into the container
*
* @return void
*/
private function registerAnnotations()
{
$this->set(AnnotationReaderInterface::class, function($c) {
return new class implements AnnotationReaderInterface
{
public function getAttributes(string $sClass, array $aMethods): array
{
return [false, [], []];
}
};
});
}

/**
* @param array $aConfigOptions
* @param array $aAnnotationOptions
Expand Down
41 changes: 13 additions & 28 deletions src/Plugin/Request/CallableClass/CallableObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
namespace Jaxon\Plugin\Request\CallableClass;

use Jaxon\Di\Container;
use Jaxon\Exception\SetupException;
use Jaxon\Response\ResponseInterface;

use ReflectionClass;
Expand Down Expand Up @@ -251,6 +252,7 @@ public function getPublicMethods(array $aProtectedMethods = []): array
$aMethods = array_map(function($xMethod) {
return $xMethod->getShortName();
}, $this->xReflectionClass->getMethods(ReflectionMethod::IS_PUBLIC));

return array_filter($aMethods, function($sMethodName) use($aProtectedMethods) {
// Don't take magic __call, __construct, __destruct methods
// Don't take protected methods
Expand Down Expand Up @@ -293,11 +295,7 @@ public function getCallableMethods(array $aProtectedMethods): array
*/
public function getRegisteredObject()
{
if($this->xRegisteredObject === null)
{
$this->xRegisteredObject = $this->di->g($this->xReflectionClass->getName());
}
return $this->xRegisteredObject;
return $this->di->g($this->xReflectionClass->getName());
}

/**
Expand Down Expand Up @@ -332,24 +330,15 @@ private function callMethod(string $sMethod, array $aArgs, bool $bAccessible)
/**
* Call the specified method of the registered callable object using the specified array of arguments
*
* @param array $aClassMethods The method config options
* @param array $aHookMethods The method config options
* @param string $sMethod The method called by the request
*
* @return void
* @throws ReflectionException
*/
private function callHookMethods(array $aClassMethods, string $sMethod)
private function callHookMethods(array $aHookMethods, string $sMethod)
{
$aMethods = [];
if(isset($aClassMethods[$sMethod]))
{
$aMethods = $aClassMethods[$sMethod];
}
elseif(isset($aClassMethods['*']))
{
$aMethods = $aClassMethods['*'];
}

$aMethods = $aHookMethods[$sMethod] ?? $aHookMethods['*'] ?? [];
foreach($aMethods as $xKey => $xValue)
{
$sMethodName = $xValue;
Expand All @@ -371,22 +360,18 @@ private function callHookMethods(array $aClassMethods, string $sMethod)
*
* @return null|ResponseInterface
* @throws ReflectionException
* @throws SetupException
*/
public function call(string $sMethod, array $aArgs): ?ResponseInterface
{
$this->getRegisteredObject();
$this->xRegisteredObject = $this->getRegisteredObject();

// Set dynamic attributes
foreach($this->aAttributes as $sKey => $aAttributes)
// Set attributes from the DI container
$aAttributes = $this->aAttributes[$sMethod] ?? $this->aAttributes['*'] ?? [];
foreach($aAttributes as $sName => $sClass)
{
if($sKey === $sMethod || $sKey === '*')
{
foreach($aAttributes as $sName => $sClass)
{
// Warning: dynamic properties will be deprecated in PHP8.2.
$this->xRegisteredObject->$sName = $this->di->get($sClass);
}
}
// Warning: dynamic properties will be deprecated in PHP8.2.
$this->xRegisteredObject->$sName = $this->di->get($sClass);
}

// Methods to call before processing the request
Expand Down
6 changes: 1 addition & 5 deletions tests/TestRegistration/AnnotationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,7 @@ class AnnotationTest extends TestCase
*/
public function setUp(): void
{
jaxon()->setOption('core.prefix.class', '');
jaxon()->setOption('core.request.uri', 'http://example.test/path');

// Register the annotation reader
AnnotationReader::register();
jaxon()->config(__DIR__ . '/../config/annotations.php');

jaxon()->register(Jaxon::CALLABLE_CLASS, Annotated::class);
jaxon()->register(Jaxon::CALLABLE_CLASS, Excluded::class);
Expand Down
21 changes: 20 additions & 1 deletion tests/TestRegistrationApp/RegistrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,25 @@ public function testSetupIncorrectConfig()
jaxon()->app()->setup(__DIR__ . '/../config/app/app-error.php');
}

/**
* @throws RequestException
*/
public function testJaxonClassAnnotations()
{
jaxon()->setOption('core.annotations.on', true);
// The server request
jaxon()->di()->set(ServerRequestInterface::class, function($c) {
return $c->g(ServerRequestCreator::class)->fromGlobals()->withParsedBody([
'jxncls' => 'Jaxon.NsTests.DirB.ClassB',
'jxnmthd' => 'methodBa',
'jxnargs' => [],
])->withMethod('POST');
});

$this->assertTrue(jaxon()->app()->canProcessRequest());
$this->assertNotNull(jaxon()->di()->getCallableClassPlugin()->processRequest());
}

/**
* @throws RequestException
*/
Expand All @@ -128,7 +147,7 @@ public function testRequestToJaxonClass()
'jxncls' => 'Jaxon.NsTests.DirB.ClassB',
'jxnmthd' => 'methodBb',
'jxnargs' => [],
]);
])->withMethod('POST');
});

$this->assertTrue(jaxon()->app()->canProcessRequest());
Expand Down
6 changes: 3 additions & 3 deletions tests/TestRequestHandler/NamespaceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public function testGetRequestToJaxonClass()
'jxncls' => 'Jaxon.NsTests.DirA.ClassA',
'jxnmthd' => 'methodAa',
'jxnargs' => [],
]);
])->withMethod('GET');
});

$this->assertTrue(jaxon()->di()->getRequestHandler()->canProcessRequest());
Expand All @@ -64,7 +64,7 @@ public function testPostRequestToJaxonClass()
'jxncls' => 'Jaxon.NsTests.DirB.ClassB',
'jxnmthd' => 'methodBb',
'jxnargs' => [],
]);
])->withMethod('POST');
});

$this->assertTrue(jaxon()->di()->getRequestHandler()->canProcessRequest());
Expand All @@ -84,7 +84,7 @@ public function testRequestToJaxonClass()
'jxncls' => 'Jaxon.NsTests.DirC.ClassC',
'jxnmthd' => 'methodCa',
'jxnargs' => [],
]);
])->withMethod('POST');
});

$this->assertTrue(jaxon()->di()->getRequestHandler()->canProcessRequest());
Expand Down
15 changes: 15 additions & 0 deletions tests/config/annotations.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

return [
'core' => [
'prefix' => [
'class' => '',
],
'request' => [
'uri' => 'http://example.test/path',
],
'annotations' => [
'on' => true,
],
],
];
5 changes: 5 additions & 0 deletions tests/src/dir_ns/DirB/ClassB.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@
namespace Jaxon\NsTests\DirB;

use Jaxon\Response\ResponseInterface;
use Jaxon\Tests\Ns\Lib\ServiceInterface;

class ClassB
{
/**
* @di('attr' => 'service', 'class' => 'ServiceInterface')
* @return ResponseInterface
*/
public function methodBa(): ResponseInterface
{
$xResponse = jaxon()->getResponse();
Expand Down

0 comments on commit 417a35d

Please sign in to comment.