feat: PSR-4 compatible cache structure for generated proxy files#568
feat: PSR-4 compatible cache structure for generated proxy files#568
Conversation
|
@copilot I've opened demos - and all cases are failing with error:
I opened a file in the cache - and |
Fixed in f8e33bb. The root cause was a path collision: when the PSR-4 namespace root coincides with The fix introduces proper PSR-4 naming for both files:
|
- WeavingTransformer.saveProxyToCache() now generates proxy files at PSR-4 paths (<cacheDir>/<Namespace/ClassName>.php) instead of the old convoluted <cacheDir>/_proxies/<original-file-path>/<FQCN>.php layout - Each generated proxy file includes a MagicConstantTransformer::registerProxyFile() call at the end so that wrapped ReflectionClass::getFileName() calls in woven sources correctly resolve back to the original source path at runtime - MagicConstantTransformer gains a static $proxyFileMap registry and registerProxyFile() / resolveFileName() updated to use it with portable relative paths - DebugWeavingCommand.getProxies() now scans the full cacheDir instead of the removed _proxies/ subdirectory, filtered by \Go\Aop\Proxy presence - Update woven snapshot files (*-woven.php) with new include_once paths - Update proxy snapshot files (*-proxy.php) with registerProxyFile() footer - ClassWovenConstraint, ClassIsNotWovenConstraint, ProxyClassReflectionHelper already updated to use PSR-4 paths in earlier commits Agent-Logs-Url: https://github.com/goaop/framework/sessions/0600c407-30da-4f37-81df-a43730e6099d Co-authored-by: lisachenko <640114+lisachenko@users.noreply.github.com>
- Normalize both appDir and classFileName to forward slashes in WeavingTransformer::saveProxyToCache() for cross-platform correctness - Normalize rootPath to forward slashes in MagicConstantTransformer::resolveFileName() - Escape literal dot in AOP_CACHE_DIR regex patterns in WeavingTransformerTest Agent-Logs-Url: https://github.com/goaop/framework/sessions/0600c407-30da-4f37-81df-a43730e6099d Co-authored-by: lisachenko <640114+lisachenko@users.noreply.github.com>
…llision When the PSR-4 namespace root coincides with appDir (e.g. demos where Demo\Example\CacheableDemo is at demos/Demo/Example/CacheableDemo.php), the woven file was stored at the same path as the proxy file, causing "Cannot redeclare trait" fatal errors. Fix: WeavingTransformer registers the PSR-4 __AopProxied path via CachePathManager.registerWovenFilePath(), and CachingTransformer uses that path when writing and reading the woven file. The stale check is also updated to detect moved cacheDir without false-positiving on the renamed path. Agent-Logs-Url: https://github.com/goaop/framework/sessions/762375e5-7940-43fd-930c-9bf97ff99bcb Co-authored-by: lisachenko <640114+lisachenko@users.noreply.github.com>
f8e33bb to
f329ce8
Compare
| * source-relative path, which would collide with the proxy class file when the | ||
| * PSR-4 namespace root coincides with appDir. | ||
| */ | ||
| public function registerWovenFilePath(string $originalUri, string $wovenPath): void |
There was a problem hiding this comment.
drop this method, it should not be used, together with getWovenFilePath()
| */ | ||
| foreach ($iterator as $splFileInfo) { | ||
| if ($splFileInfo->isFile()) { | ||
| if ($splFileInfo->isFile() && $splFileInfo->getExtension() === 'php') { |
There was a problem hiding this comment.
exclude this filtering and check of file extension
| // class implements additional interfaces before \Go\Aop\Proxy in the list. | ||
| // Woven trait files, function proxies, and the transformation cache file never | ||
| // reference \Go\Aop\Proxy, so this filter is precise. | ||
| if ($content !== false && str_contains($content, '\Go\Aop\Proxy')) { |
There was a problem hiding this comment.
use "Go\Aop\Proxy" without leading slash, as it may be used in the "use" section without leading ""
| * | ||
| * @var array<string, string> | ||
| */ | ||
| private array $wovenFilePathOverrides = []; |
There was a problem hiding this comment.
not needed here in the first place
| $parentCacheDir = dirname($cacheUri); | ||
| // WeavingTransformer may have registered a PSR-4 path for the woven (trait) file. | ||
| // Use that when available to avoid collisions with the proxy class file. | ||
| $resolvedCacheUri = $this->cacheManager->getWovenFilePath($originalUri) ?? $cacheUri; |
There was a problem hiding this comment.
probably not needed, not sure why it is here
| $filename = (new ReflectionClass($other))->getFileName(); | ||
| $suffix = substr($filename, strlen(PathResolver::realpath($this->configuration['appDir']))); | ||
| // Woven trait file uses a PSR-4 layout: <cacheDir>/<Namespace/ClassName__AopProxied>.php | ||
| $wovenRelativePath = str_replace('\\', DIRECTORY_SEPARATOR, $other) . '__AopProxied.php'; |
There was a problem hiding this comment.
use constant for class suffix "__AopProxied"
|
|
||
| $transformedFileExists = file_exists($this->configuration['cacheDir'] . $suffix); | ||
| $proxyFileExists = file_exists($this->configuration['cacheDir'] . '/_proxies' . $suffix); | ||
| // Proxy files use a PSR-4 layout: <cacheDir>/<Namespace/ClassName>.php |
| $classSuffix = str_replace('\\', DIRECTORY_SEPARATOR, $className) . '.php'; | ||
| $proxyRelativePath = $relativePath . DIRECTORY_SEPARATOR . $classSuffix; | ||
| $proxyFileName = $configuration['cacheDir'] . '/_proxies/' . $proxyRelativePath; | ||
| // Proxy files use a PSR-4 layout: <cacheDir>/<Namespace/ClassName>.php |
There was a problem hiding this comment.
keep previous logic, but not with "__proxies/" subdirectories, we aiming to have mirrored structure of directories and files, with only difference that original files will have "__AopProxied" suffix
| public function returnSelf(): self {} | ||
| } | ||
| include_once AOP_CACHE_DIR . '/_proxies/Transformer/_files/php7-class.php/Test/ns1/TestPhp7Class.php'; | ||
| include_once AOP_CACHE_DIR . '/Test/ns1/TestPhp7Class.php'; |
There was a problem hiding this comment.
this change looks exactly what I was expected, keep it as foundation base
| use Go\Aop\Intercept\StaticMethodInvocation; | ||
| class TestClass implements \Go\Aop\Proxy | ||
| { | ||
| use \Test\ns1\TestClass__AopProxied { |
There was a problem hiding this comment.
Generated proxies use unnecessarily FQDN for trait adoptation:
class CacheableDemo implements \Go\Aop\Proxy
{
use \Demo\Example\CacheableDemo__AopProxied {
\Demo\Example\CacheableDemo__AopProxied::getReport as private __aop__getReport;
}as our original code moved to the trait in the same namespace and proxy also uses the same namespace, we can use just relative class names:
class CacheableDemo implements \Go\Aop\Proxy
{
use CacheableDemo__AopProxied {
CacheableDemo__AopProxied::getReport as private __aop__getReport;
}such code looks more nicely
Cache files were generated under a convoluted
_proxies/<original-relative-path>/<FQCN>.phplayout that encoded the source file path rather than the class identity, making the cache directory unusable as a PSR-4 autoloader root and breaking correctness when classes are renamed or moved.Proxy file path layout
Before:
<cacheDir>/_proxies/src/Application/Main.php/Go/Tests/TestProject/Application/Main.phpAfter:
<cacheDir>/Go/Tests/TestProject/Application/Main.phpEach proxy file now lives at a path derived purely from its FQCN, matching PSR-4 conventions.
ReflectionClass::getFileName()on proxy classesWith PSR-4 paths the proxy location no longer encodes the source path, so
MagicConstantTransformer::resolveFileName()needed a new mechanism. Each generated proxy file now ends with a self-registration call:MagicConstantTransformergains a static$proxyFileMapregistry populated atinclude_oncetime, givingresolveFileName()an O(1) lookup before falling back to the existing cache-dir→app-dir path substitution for woven files.DebugWeavingCommandproxy discoveryReplaced the hardcoded
_proxies/subdirectory scan with a recursive scan of the fullcacheDir, filtering on the presence of\Go\Aop\Proxyin file content. The filter is broadened fromimplements \Go\Aop\Proxyto just\Go\Aop\Proxyto correctly match classes that implement additional interfaces before the proxy marker.Cross-platform path handling
Both
saveProxyToCache()andresolveFileName()normalize paths to forward slashes before computing relative paths so that Windows backslash paths fromReflectionClass::getFileName()are handled correctly.Test/snapshot updates
*-woven.phpsnapshot files updated with newinclude_once AOP_CACHE_DIR . '/Ns/ClassName.php'paths.*-proxy.phpsnapshot files updated with theregisterProxyFile()footer.WeavingTransformerTestfixed to escape the literal PHP concatenation dot (\.).