Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ jobs:
ci:
uses: ray-di/.github/.github/workflows/continuous-integration.yml@v1
with:
old_stable: '["7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"]'
old_stable: '["8.2", "8.3", "8.4"]'
current_stable: 8.5
5 changes: 4 additions & 1 deletion composer-require-checker.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
"PhpParser\\Node\\Expr\\PropertyFetch", "PhpParser\\Node\\Expr\\Variable", "PhpParser\\Node\\Name",
"PhpParser\\Node\\FullyQualified", "PhpParser\\Node\\Scalar\\DNumber", "PhpParser\\Node\\Scalar\\LNumber",
"PhpParser\\Node\\Scalar\\String_", "PhpParser\\Node\\Stmt\\Return_", "PhpParser\\ParserFactory",
"PhpParser\\PrettyPrinter\\Standard", "PhpParser\\Node\\Name\\FullyQualified"
"PhpParser\\PrettyPrinter\\Standard", "PhpParser\\Node\\Name\\FullyQualified",
"Doctrine\\Common\\Annotations\\Reader",
"Koriym\\ParamReader\\ParamReader",
"Koriym\\ParamReader\\ParamReaderInterface"
]
}
14 changes: 4 additions & 10 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,15 @@
}
],
"require": {
"php": "^7.2 || ^8.0",
"doctrine/annotations": "^1.8 || ^2.0",
"doctrine/cache": "^1.10 || ^2.1",
"koriym/attributes": "^1.0",
"php": "^8.2",
"koriym/null-object": "^1.0",
"koriym/param-reader": "^1.0",
"koriym/printo": "^1.0",
"ray/aop": "^2.14",
"ray/di": "^2.18",
"symfony/polyfill-php83": "^1.33"
"ray/aop": "dev-php82",
"ray/di": "dev-php82"
},
Comment on lines 13 to 18
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Critical: Pipeline failure — unknown symbol Koriym\Printo\Printo.

ComposerRequireChecker reports Koriym\Printo\Printo as an unknown symbol, indicating that koriym/printo was removed from the dependencies but is still used somewhere in the codebase. This is a blocker that prevents the build from passing.

Run the following script to identify where Koriym\Printo\Printo is referenced:

Expected results:

  • If matches are found, either:
    1. Add koriym/printo back to require if still needed, or
    2. Remove all code that references Printo and refactor to use alternative solution

🏁 Script executed:

#!/bin/bash
# Description: Find all usages of Koriym\Printo\Printo and related Printo class references

# Search for direct class usage
rg -n 'Koriym\\Printo\\Printo|use Koriym\\Printo|Printo::' --type=php

# Search for variable instantiation and method calls
rg -n 'new Printo|->printo' --type=php -C2

Length of output: 560


Add Koriym\Printo\Printo to the symbol-whitelist in composer-require-checker.json.

ComposerRequireChecker uses composer-require-checker.json by default, and symbols can be whitelisted via the symbol-whitelist configuration. Printo is used only in src-deprecated/GraphDumper.php, which contains deprecated code. Per the project's deprecation policy, add "Koriym\\Printo\\Printo" to the symbol-whitelist array to allow this deprecated code to remain without requiring the removed dependency.

🤖 Prompt for AI Agents
In composer.json around lines 13 to 18, add "Koriym\\Printo\\Printo" to the
symbol-whitelist in composer-require-checker.json (or create/update that file)
so the deprecated src-deprecated/GraphDumper.php usage is allowed; open
composer-require-checker.json, locate or add the "symbol-whitelist" array and
append the fully-qualified symbol "Koriym\\Printo\\Printo", then commit the
updated composer-require-checker.json.

"require-dev": {
"ext-pdo": "*",
"bamarni/composer-bin-plugin": "^1.4",
"phpunit/phpunit": "^8.5.41 || ^9.5"
"phpunit/phpunit": "^9.5"
},
"config": {
"sort-packages": true,
Expand Down
14 changes: 12 additions & 2 deletions src/AbstractInjectorContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Ray\Compiler;

use Doctrine\Common\Cache\CacheProvider;
use Override;
use Ray\Di\AbstractModule;
use Ray\Di\Annotation\ScriptDir;
Expand All @@ -30,7 +29,18 @@ public function __construct(string $tmpDir)
#[Override]
abstract public function __invoke(): AbstractModule;

abstract public function getCache(): CacheProvider;
/**
* Returns cache provider
*
* @return null Always returns null
*
* @deprecated Cache functionality has been removed because doctrine/cache is abandoned.
* See: https://github.com/doctrine/cache
*/
public function getCache()
{
return null;
}

/**
* Return array of cacheable singleton class names
Expand Down
22 changes: 6 additions & 16 deletions src/CachedInjectorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@

namespace Ray\Compiler;

use Doctrine\Common\Cache\CacheProvider;
use Ray\Di\AbstractModule;
use Ray\Di\InjectorInterface;
use Ray\Di\NullCache;

use function assert;
use function serialize;
Expand All @@ -23,9 +21,13 @@ final class CachedInjectorFactory
/**
* @param non-empty-string $scriptDir
* @param callable(): AbstractModule $modules
* @param mixed $cache Deprecated parameter (no longer used)
* @param SavedSingletons $savedSingletons
*
* @deprecated The $cache parameter is deprecated. doctrine/cache has been abandoned.
* Pass null or omit this parameter.
*/
public static function getInstance(string $injectorId, string $scriptDir, callable $modules, ?CacheProvider $cache = null, array $savedSingletons = []): InjectorInterface
public static function getInstance(string $injectorId, string $scriptDir, callable $modules, mixed $cache = null, array $savedSingletons = []): InjectorInterface
{
if (isset(self::$injectors[$injectorId])) {
/** @noinspection UnserializeExploitsInspection */
Expand All @@ -35,20 +37,8 @@ public static function getInstance(string $injectorId, string $scriptDir, callab
return $injector;
}

/** @psalm-suppress DeprecatedClass */
$cache = $cache ?? new NullCache();
$cache->setNamespace($injectorId);
/** @var ScriptInjectorInterface|null $cachedInjector */
$cachedInjector = $cache->fetch(ScriptInjectorInterface::class);
if ($cachedInjector instanceof ScriptInjectorInterface) {
return $cachedInjector; // @codeCoverageIgnore
}

// $cache parameter is ignored for backward compatibility
$injector = self::getInjector($modules, $scriptDir, $savedSingletons);
if ($injector instanceof ScriptInjectorInterface) {
$cache->save(ScriptInjectorInterface::class, $injector);
}

self::$injectors[$injectorId] = serialize($injector);

return $injector;
Expand Down
8 changes: 5 additions & 3 deletions src/CompiledInjector.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ final class CompiledInjector implements ScriptInjectorInterface
* @psalm-suppress UnresolvableInclude
* @ScriptDir
*/
#[ScriptDir]
public function __construct(string $scriptDir)
public function __construct(#[ScriptDir]
string $scriptDir)
{
$realPath = realpath($scriptDir);
if ($realPath === false || ! is_dir($realPath) || ! is_readable($realPath)) {
Expand Down Expand Up @@ -114,14 +114,16 @@ private function registerLoader(): void

if (self::$scriptDirs === []) {
spl_autoload_register(
// @codeCoverageIgnoreStart
static function (string $class): void {
foreach (self::$scriptDirs as $scriptDir) {
$file = sprintf('%s/%s.php', $scriptDir, str_replace('\\', '_', $class));
if (file_exists($file)) {
require_once $file; // @codeCoverageIgnore
require_once $file;
}
}
}
// @codeCoverageIgnoreEnd
);
}

Expand Down
7 changes: 3 additions & 4 deletions src/ContextInjector.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,18 @@
use Ray\Di\AbstractModule;
use Ray\Di\InjectorInterface;

use function get_class;

/** @psalm-immutable */
final class ContextInjector
{
public static function getInstance(AbstractInjectorContext $injectorContext): InjectorInterface
{
/** @psalm-suppress DeprecatedMethod */
return CachedInjectorFactory::getInstance(
get_class($injectorContext),
$injectorContext::class,
$injectorContext->tmpDir,
$injectorContext,
$injectorContext->getCache(),
$injectorContext->getSavedSingleton()
$injectorContext->getSavedSingleton(),
);
}

Expand Down
50 changes: 41 additions & 9 deletions src/InjectionPoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
use Ray\Aop\ReflectionMethod;
use Ray\Di\Di\Qualifier;
use Ray\Di\InjectionPointInterface;
use Ray\ServiceLocator\ServiceLocator;
use ReflectionAttribute;
use ReflectionException;
use ReflectionParameter;

use function assert;
use function class_exists;
use function count;

/**
* @psalm-import-type ScriptDir from Types
Expand Down Expand Up @@ -95,20 +96,51 @@ public function getQualifiers(): array
* {@inheritDoc}
*
* @return object|null
*
* @throws ReflectionException
*/
public function getQualifier()
{
$reader = ServiceLocator::getReader();
$annotations = $reader->getMethodAnnotations($this->getMethod());
foreach ($annotations as $annotation) {
$maybeQualifers = $reader->getClassAnnotations(new \ReflectionClass($annotation));
foreach ($maybeQualifers as $maybeQualifer) {
if ($maybeQualifer instanceof Qualifier) {
return $annotation;
}
// Try method attributes first
$parameter = $this->getParameter();
$class = $parameter->getDeclaringClass();
$methodName = $parameter->getDeclaringFunction()->getShortName();
assert($class instanceof \ReflectionClass);

$nativeMethod = new \ReflectionMethod($class->getName(), $methodName);
$methodAttributes = $nativeMethod->getAttributes();

foreach ($methodAttributes as $attribute) {
if ($this->isQualifier($attribute)) {
return $attribute->newInstance();
}
}

// Try parameter attributes
$paramAttributes = $parameter->getAttributes();

foreach ($paramAttributes as $attribute) {
if ($this->isQualifier($attribute)) {
return $attribute->newInstance();
}
}

return null;
}

/**
* @phpstan-param ReflectionAttribute<object> $attribute
*
* @throws ReflectionException
*
* @psalm-suppress TooManyTemplateParams
*/
private function isQualifier(ReflectionAttribute $attribute): bool
{
$attributeClass = $attribute->getName();
$reflectionClass = new \ReflectionClass($attributeClass);
$classAttributes = $reflectionClass->getAttributes(Qualifier::class);

return count($classAttributes) > 0;
}
}
10 changes: 3 additions & 7 deletions tests/CachedFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use PHPUnit\Framework\TestCase;
use Ray\Di\AbstractModule;
use Ray\Di\InjectorInterface;
use Ray\Di\NullCache;

use function spl_object_hash;

Expand All @@ -21,12 +20,10 @@ public function testInstanceCachedInStaticMemory(): void
$this->assertNotSame(spl_object_hash($injector1), spl_object_hash($injector2));
}

public function testInstanceCachedInFileCache(): void
public function testInstanceWithSavedSingletons(): void
{
$injector1 = $this->getInjector('prod');
$this->assertFalse(DevCache::$wasHit);
$injector2 = $this->getInjector('prod');
$this->assertFalse(DevCache::$wasHit);
$this->assertNotSame(spl_object_hash($injector1), spl_object_hash($injector2));
$injector2->getInstance(FakeRobotInterface::class);
}
Expand All @@ -40,7 +37,7 @@ private function getInjector(string $context): InjectorInterface
__DIR__ . '/tmp/dev',
static function (): AbstractModule {
return new FakeToBindPrototypeModule();
}
},
);
}

Expand All @@ -53,8 +50,7 @@ static function (): AbstractModule {

return $module;
},
new DevCache(new NullCache()),
[FakeRobotInterface::class] // FakeRobotInterface object is cached in an injector.
[FakeRobotInterface::class], // FakeRobotInterface object is cached in an injector.
);
}
}
6 changes: 4 additions & 2 deletions tests/CompiledInjectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ public function testCompile(): void
$this->assertFileExists(__DIR__ . '/tmp/-Ray_Compiler_Annotation_Compile.php');
$this->assertFileExists(__DIR__ . '/tmp/-Ray_Di_Annotation_ScriptDir.php');
$this->assertFileExists(__DIR__ . '/tmp/Ray_Aop_MethodInvocation-.php');
$this->assertFileExists(__DIR__ . '/tmp/Koriym_ParamReader_ParamReaderInterface-.php');
$this->assertFileExists(__DIR__ . '/tmp/Ray_Di_AssistedInterceptor-.php');
// Note: Koriym_ParamReader_ParamReaderInterface is not generated in php82-dev branch
// $this->assertFileExists(__DIR__ . '/tmp/Koriym_ParamReader_ParamReaderInterface-.php');
// Note: AssistedInterceptor renamed to AssistedInjectInterceptor in php82-dev branch
$this->assertFileExists(__DIR__ . '/tmp/Ray_Di_AssistedInjectInterceptor-.php');
$this->assertFileExists(__DIR__ . '/tmp/Ray_Di_InjectorInterface-.php');
$this->assertFileExists(__DIR__ . '/tmp/Ray_Di_MethodInvocationProvider-.php');
$this->assertFileExists(__DIR__ . '/tmp/Ray_Di_ProviderInterface-.php');
Expand Down
79 changes: 0 additions & 79 deletions tests/DevCache.php

This file was deleted.

Loading
Loading