Skip to content

Commit

Permalink
Check if a class is registrable before it is registered.
Browse files Browse the repository at this point in the history
  • Loading branch information
feuzeu committed Dec 26, 2024
1 parent e8ae3a2 commit cc0bc50
Show file tree
Hide file tree
Showing 13 changed files with 103 additions and 57 deletions.
2 changes: 1 addition & 1 deletion src/App/Ajax/Lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public static function getInstance(): Lib
// First call: create and initialize the instances.
self::$xInstance = new Lib();
$xContainer = new Container(self::$xInstance);
$xClassContainer = new ClassContainer($xContainer);
$xClassContainer = new ClassContainer($xContainer, $xContainer->g(Translator::class));
$xContainer->val(ClassContainer::class, $xClassContainer);

self::$xInstance->init($xContainer, $xClassContainer);
Expand Down
57 changes: 32 additions & 25 deletions src/Di/ClassContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Jaxon\App\AbstractCallable;
use Jaxon\App\Config\ConfigManager;
use Jaxon\App\I18n\Translator;
use Jaxon\App\Pagination;
use Jaxon\Exception\SetupException;
use Jaxon\Plugin\Request\CallableClass\CallableClassHelper;
use Jaxon\Plugin\Request\CallableClass\CallableObject;
Expand Down Expand Up @@ -63,8 +64,11 @@ class ClassContainer

/**
* The class constructor
*
* @param Container $di
* @param Translator $xTranslator
*/
public function __construct(private Container $di)
public function __construct(private Container $di, private Translator $xTranslator)
{
$this->xContainer = new PimpleContainer();
$this->val(ClassContainer::class, $this);
Expand Down Expand Up @@ -145,39 +149,54 @@ public function val(string $sKey, $xValue)
*/
public function registerClass(string $sClassName, array $aOptions = [])
{
$this->aClasses[$sClassName] = $aOptions;
try
{
// Make sure the registered class exists
isset($aOptions['include']) && require_once($aOptions['include']);
$xReflectionClass = new ReflectionClass($sClassName);
// Check if the class is registrable
if($xReflectionClass->isInstantiable() &&
!$xReflectionClass->isSubclassOf(Pagination::class))
{
$this->aClasses[$sClassName] = $aOptions;
$this->val($this->getReflectionClassKey($sClassName), $xReflectionClass);
}
}
catch(ReflectionException $e)
{
throw new SetupException($this->xTranslator->trans('errors.class.invalid',
['name' => $sClassName]));
}
}

/**
* Find the options associated with a registered class name
*
* @param string $sClassName The class name
*
* @return array
* @return void
* @throws SetupException
*/
private function getClassOptions(string $sClassName): array
private function registerClassOptions(string $sClassName)
{
// Find options for a class registered with namespace.
if(!isset($this->aClasses[$sClassName]))
{
// Find options for a class registered with namespace.
/** @var CallableRegistry */
$xRegistry = $this->di->g(CallableRegistry::class);
$xRegistry->registerClassFromNamespace($sClassName);
if(!isset($this->aClasses[$sClassName]))
{
// Find options for a class registered without namespace.
// We then need to parse all classes to be able to find one.
// We need to parse all the classes to be able to find one.
$xRegistry->parseDirectories();
}
}
if(isset($this->aClasses[$sClassName]))
if(!isset($this->aClasses[$sClassName]))
{
return $this->aClasses[$sClassName];
throw new SetupException($this->xTranslator->trans('errors.class.invalid',
['name' => $sClassName]));
}

$xTranslator = $this->di->g(Translator::class);
throw new SetupException($xTranslator->trans('errors.class.invalid', ['name' => $sClassName]));
}

/**
Expand Down Expand Up @@ -326,20 +345,8 @@ private function registerCallableClass(string $sClassName)
$this->di->getCache(), $this->di->getUploadHandler());
});

$aOptions = $this->getClassOptions($sClassName);

// Register the reflection class
try
{
// Make sure the registered class exists
isset($aOptions['include']) && require_once($aOptions['include']);
$this->val($this->getReflectionClassKey($sClassName), new ReflectionClass($sClassName));
}
catch(ReflectionException $e)
{
$xTranslator = $this->di->g(Translator::class);
throw new SetupException($xTranslator->trans('errors.class.invalid', ['name' => $sClassName]));
}
$this->registerClassOptions($sClassName);
$aOptions = $this->aClasses[$sClassName];

// Register the callable object
$this->set($sCallableObject, function() use($sClassName, $aOptions) {
Expand Down
4 changes: 1 addition & 3 deletions src/Plugin/Request/CallableClass/CallableObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
namespace Jaxon\Plugin\Request\CallableClass;

use Jaxon\App\AbstractCallable;
use Jaxon\App\Pagination;
use Jaxon\Di\ClassContainer;
use Jaxon\Di\Container;
use Jaxon\Exception\SetupException;
Expand Down Expand Up @@ -180,8 +179,7 @@ public function getPublicMethods(bool $bTakeAll): array
*/
public function excluded(): bool
{
return $this->xOptions->excluded() || $this->xReflectionClass->isAbstract() ||
$this->xReflectionClass->isSubclassOf(Pagination::class);
return $this->xOptions->excluded();
}

/**
Expand Down
11 changes: 3 additions & 8 deletions src/Plugin/Request/CallableClass/CallableRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -406,19 +406,14 @@ public function parseDirectories()

$sClassName = $xFile->getBasename('.php');
$aClassOptions = ['timestamp' => $xFile->getMTime()];
// No more custom classmap autoloading. The file will be included when needed.
if(($aDirectoryOptions['autoload']))
if(($aDirectoryOptions['autoload']) && $this->xAutoloader !== null)
{
$aClassMap[$sClassName] = $xFile->getPathname();
// Set classmap autoloading. Must be done before registering the class.
$this->xAutoloader->addClassMap([$sClassName => $xFile->getPathname()]);
}
$this->_registerClass($sClassName, $aClassOptions, $aDirectoryOptions);
}
}
// Set classmap autoloading
if(($aClassMap) && $this->xAutoloader !== null)
{
$this->xAutoloader->addClassMap($aClassMap);
}
}

/**
Expand Down
5 changes: 3 additions & 2 deletions tests/TestRegistration/FunctionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,12 @@ public function testLibraryJsCodeWithPlugins()
// This URI will be parsed by the URI detector
$_SERVER['REQUEST_URI'] = 'http://example.test/path';
$sJsCode = jaxon()->getScript(true, true);
$this->assertEquals(1527, strlen(trim($sJsCode)));
// file_put_contents(__DIR__ . '/../src/js/plugin.js', $sJsCode);
$this->assertEquals(file_get_contents(__DIR__ . '/../src/js/plugin.js'), $sJsCode);
$this->assertEquals(32, strlen(jaxon()->di()->getCodeGenerator()->getHash()));

$sJsCode = trim(jaxon()->getCss() . "\n" . jaxon()->getJs()) . jaxon()->getScript();
$this->assertEquals(1527, strlen(trim($sJsCode)));
$this->assertEquals(file_get_contents(__DIR__ . '/../src/js/plugin.js'), $sJsCode);

unset($_SERVER['REQUEST_URI']);
}
Expand Down
20 changes: 14 additions & 6 deletions tests/TestRegistration/NamespaceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Jaxon\Tests\TestRegistration;

use Jaxon\App\Pagination;
use Jaxon\Jaxon;
use Jaxon\Exception\SetupException;
use Jaxon\Plugin\Request\CallableClass\CallableClassPlugin;
Expand Down Expand Up @@ -58,6 +59,16 @@ public function testPluginName()
$this->assertEquals(Jaxon::CALLABLE_DIR, $this->xDirPlugin->getName());
}

/**
* @throws SetupException
*/
public function testPaginationCallable()
{
$xPaginationCallable = $this->xClassPlugin->getCallable(Pagination::class);
$this->assertEquals(CallableObject::class, get_class($xPaginationCallable));
$this->assertTrue($xPaginationCallable->excluded());
}

/**
* @throws SetupException
*/
Expand Down Expand Up @@ -86,8 +97,7 @@ public function testCallableDirJsCode()
$this->assertEquals(32, strlen($this->xClassPlugin->getHash()));
$sJsCode = $this->xClassPlugin->getScript();
// file_put_contents(__DIR__ . '/../src/js/nss.js', $sJsCode);
// $this->assertEquals(file_get_contents(__DIR__ . '/../src/js/nss.js'), $sJsCode);
$this->assertEquals(2880, strlen($sJsCode));
$this->assertEquals(file_get_contents(__DIR__ . '/../src/js/nss.js'), $sJsCode);
}

/**
Expand All @@ -103,8 +113,7 @@ public function testRegisterWithIncorrectSeparator()
$this->assertEquals(32, strlen($this->xClassPlugin->getHash()));
$sJsCode = $this->xClassPlugin->getScript();
// file_put_contents(__DIR__ . '/../src/js/nsi.js', $sJsCode);
// $this->assertEquals(file_get_contents(__DIR__ . '/../src/js/nsi.js'), $sJsCode);
$this->assertEquals(2880, strlen($sJsCode));
$this->assertEquals(file_get_contents(__DIR__ . '/../src/js/nsi.js'), $sJsCode);
}

/**
Expand All @@ -122,8 +131,7 @@ public function testRegisterWithUnderscoreAsSeparator()
$this->assertEquals(32, strlen($this->xClassPlugin->getHash()));
$sJsCode = $this->xClassPlugin->getScript();
// file_put_contents(__DIR__ . '/../src/js/nsu.js', $sJsCode);
// $this->assertEquals(file_get_contents(__DIR__ . '/../src/js/nsu.js'), $sJsCode);
$this->assertEquals(2724, strlen($sJsCode));
$this->assertEquals(file_get_contents(__DIR__ . '/../src/js/nsu.js'), $sJsCode);

$xCallable = $this->xClassPlugin->getCallable('Jaxon_Tests_Ns_Ajax_ClassA');
$this->assertEquals(CallableObject::class, get_class($xCallable));
Expand Down
1 change: 1 addition & 0 deletions tests/TestRegistration/RegistrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ public function testInvalidPluginId()
public function testUnknownCallableClass()
{
// Register a class that does not exist.
$this->expectException(SetupException::class);
jaxon()->register(Jaxon::CALLABLE_CLASS, 'UnknownClass');
$this->expectException(SetupException::class);
$this->xPlugin->getCallable('UnknownClass');
Expand Down
2 changes: 1 addition & 1 deletion tests/TestRequestHandler/CallbackTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public function setUp(): void
jaxon()->register(Jaxon::CALLABLE_FUNCTION, 'my_first_function',
__DIR__ . '/../src/first.php');
jaxon()->setOption('core.prefix.class', '');
jaxon()->register(Jaxon::CALLABLE_DIR, __DIR__ . '/../src/response');
jaxon()->register(Jaxon::CALLABLE_DIR, __DIR__ . '/../src/response', ['autoload' => true]);
}

/**
Expand Down
9 changes: 7 additions & 2 deletions tests/src/js/lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
cursor: pointer;
}
</style>
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/jaxon-php/[email protected].3/dist/libs/chibi/chibi.js" charset="UTF-8"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/jaxon-php/[email protected].3/dist/jaxon.core.js" charset="UTF-8"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/jaxon-php/[email protected].6/dist/libs/chibi/chibi.js" charset="UTF-8"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/jaxon-php/[email protected].6/dist/jaxon.core.js" charset="UTF-8"></script>

<script type="text/javascript" charset="UTF-8">
/* <![CDATA[ */
Expand All @@ -16,6 +16,11 @@ jaxon.config.defaultMode = "asynchronous";
jaxon.config.defaultMethod = "POST";
jaxon.config.responseType = "JSON";

JaxonSamplePackageClass = {};
JaxonSamplePackageClass.home = function() {
return jaxon.request({ jxncls: 'SamplePackageClass', jxnmthd: 'home' }, { parameters: arguments });
};

jxn_my_first_function = function() {
return jaxon.request({ jxnfun: 'my_first_function' }, { parameters: arguments });
};
Expand Down
3 changes: 0 additions & 3 deletions tests/src/js/nsi.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ Jaxon.NsTests.DirC.ClassC.methodCa = function() {
Jaxon.NsTests.DirC.ClassC.methodCb = function() {
return jaxon.request({ jxncls: 'Jaxon.NsTests.DirC.ClassC', jxnmthd: 'methodCb' }, { parameters: arguments });
};
Jaxon.NsTests.DirC.ClassC.paginator = function() {
return jaxon.request({ jxncls: 'Jaxon.NsTests.DirC.ClassC', jxnmthd: 'paginator' }, { parameters: arguments });
};
if(Jaxon.Tests.Ns.Ajax.ClassA === undefined) {
Jaxon.Tests.Ns.Ajax.ClassA = {};
}
Expand Down
3 changes: 0 additions & 3 deletions tests/src/js/nss.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ Jaxon.NsTests.DirC.ClassC.methodCa = function() {
Jaxon.NsTests.DirC.ClassC.methodCb = function() {
return jaxon.request({ jxncls: 'Jaxon.NsTests.DirC.ClassC', jxnmthd: 'methodCb' }, { parameters: arguments });
};
Jaxon.NsTests.DirC.ClassC.paginator = function() {
return jaxon.request({ jxncls: 'Jaxon.NsTests.DirC.ClassC', jxnmthd: 'paginator' }, { parameters: arguments });
};
if(Jaxon.Tests.Ns.Ajax.ClassA === undefined) {
Jaxon.Tests.Ns.Ajax.ClassA = {};
}
Expand Down
3 changes: 0 additions & 3 deletions tests/src/js/nsu.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@ Jaxon_NsTests_DirC_ClassC.methodCa = function() {
Jaxon_NsTests_DirC_ClassC.methodCb = function() {
return jaxon.request({ jxncls: 'Jaxon_NsTests_DirC_ClassC', jxnmthd: 'methodCb' }, { parameters: arguments });
};
Jaxon_NsTests_DirC_ClassC.paginator = function() {
return jaxon.request({ jxncls: 'Jaxon_NsTests_DirC_ClassC', jxnmthd: 'paginator' }, { parameters: arguments });
};
if(Jaxon.Tests.Ns.Ajax.ClassA === undefined) {
Jaxon.Tests.Ns.Ajax.ClassA = {};
}
Expand Down
40 changes: 40 additions & 0 deletions tests/src/js/plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<style>
.pagination li a {
cursor: pointer;
}
</style>
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/jaxon-php/[email protected]/dist/libs/chibi/chibi.js" charset="UTF-8"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/jaxon-php/[email protected]/dist/jaxon.core.js" charset="UTF-8"></script>

<script type="text/javascript" charset="UTF-8">
/* <![CDATA[ */
jaxon.config.requestURI = "http://example.test/path";
jaxon.config.statusMessages = false;
jaxon.config.waitCursor = true;
jaxon.config.version = "Jaxon 5.x";
jaxon.config.defaultMode = "asynchronous";
jaxon.config.defaultMethod = "POST";
jaxon.config.responseType = "JSON";

JaxonSamplePackageClass = {};
JaxonSamplePackageClass.home = function() {
return jaxon.request({ jxncls: 'SamplePackageClass', jxnmthd: 'home' }, { parameters: arguments });
};

jxn_my_first_function = function() {
return jaxon.request({ jxnfun: 'my_first_function' }, { parameters: arguments });
};
jxn_my_alias_function = function() {
return jaxon.request({ jxnfun: 'my_alias_function' }, { parameters: arguments, upload: 'html_field_id' });
};
jxn_my_third_function = function() {
return jaxon.request({ jxnfun: 'my_third_function' }, { parameters: arguments });
};

jaxon.dom.ready(function() {

jaxon.processCustomAttrs();
});

/* ]]> */
</script>

0 comments on commit cc0bc50

Please sign in to comment.