| Age | Commit message (Collapse) | Author |
|
A proxy stub declares none of the real class's instance properties, and the
`__get`/`__set` forwarders were emitted only for classes that declare a public
one. Every other property access therefore got PHP's own answer for an
undeclared property — null on a read, a dynamic property on a write — so plugin
code reading state the entity holds ran on with null and failed somewhere else
entirely, or not at all.
Emit the forwarders on every root stub, add `__isset`/`__unset` alongside them
so `isset()` cannot answer false silently either, and serve all four from one
dispatcher that answers the state the Rust-side entity exposes and rejects every
other name.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
AliasPackage, CompleteAliasPackage and RootAliasPackage now have generated
proxy stubs, so a package handed to a plugin no longer has to be a real
package: it crosses as the stub matching its concrete variant, answers
getAliasOf / setRootPackageAlias / isRootPackageAlias /
hasSelfVersionRequires, and can be constructed from plugin code.
The setters RootPackageInterface declares are routed through that interface
for every root package instead of through the base Package state. Only the
alias variant needs it -- RootAliasPackage overrides all nine to write
through to the package it aliases -- but a real RootPackage delegates to the
same base state either way, so both take one path.
An alias of an alias has no representation here, so narrowing the
constructor argument to a real package is an explicit error rather than a
silent demotion.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
An installer that extends LibraryInstaller reaches for the Composer object
graph in ways the proxy did not answer: the download manager and the config,
the writable repository methods, a React promise as its own return value, and
`new Package(...)` from its supports() path.
* `Composer::getConfig`/`getDownloadManager` are dispatched, and both classes
become generated proxy stubs. Their reads and mutators answer from the Rust
entity; the surfaces needing stubs of their own (ConfigSourceInterface,
DownloaderInterface) stay explicit errors.
* The download manager's futures are driven to completion and handed back as
already-settled React promises, since PHP declares a non-nullable
PromiseInterface there. A promise a plugin returns is drained the same way:
settled yields its value, rejected re-raises, pending is an explicit error.
* Proxy stubs now carry the real class's constructor and ask the Rust side to
allocate the entity; reviving a stub for an existing entity binds the handle
without running it. Classes Rust cannot build name themselves in the error.
* The package proxy covers `Package`'s own setters, `CompletePackage`'s
metadata, `RootPackage`'s root-only state, and `BasePackage::$id`.
Link values and release dates still have no wire image, so the methods
carrying them remain explicit errors.
|
|
A plugin can now hand an InstallerInterface implementation to
InstallationManager::addInstaller across the wire, and a legacy
composer-installer package is loaded as one; both are backed by a
PhpInstallerProxy forwarding the whole installer contract to the entity in
the PHP worker. An installer returning a real promise is an explicit error
until promises can cross the boundary.
InstallationManager takes installers as shared handles instead of boxes, so
the object identity removeInstaller and PluginManager's registeredPlugins
compare against survives registration, and holds them in a RefCell:
Installer::run keeps a shared borrow of the manager for the whole run, and a
plugin activated inside it registers its installer from there. The type
cache keys on the installer itself, like upstream, so re-entrant
registration cannot leave a stale index behind. InstallerInterface::supports
is fallible for the same reason getCapabilities and getCommands are: it
answers over RPC.
Cloning a proxy stub clones the Rust-side entity and rebinds the copy to the
fresh handle. Previously only the classes declaring __clone got a throwing
body, and the rest let two stubs share (and twice release) one handle.
Package entities answer with AnyPackage::dup, which already carries
BasePackage::__clone and the RootAliasPackage override; the others are an
explicit error.
The package proxy covers the whole PackageInterface surface; only the link
maps and the release date still lack a wire image for their value objects.
PluginManager gains a test-only seam for the reported Plugin API version,
and the three PluginInstallerTest cases that need it are ported.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Emit the eleven stubs a subscriber plugin's object-graph calls reach
(BasePackage through RootPackage, the installed-repository hierarchy,
RepositoryManager, InstallationManager). The generator learns the member
kinds these classes need: builtin interfaces contribute no closure entries,
public static properties are materialized, public instance properties
forward through __get/__set, __toString forwards like a plain method,
__clone throws (proxy clone semantics are still an open design question),
and a subclass stub may add interfaces to its inherited surface.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|