aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/console
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-08-03 01:30:26 +0900
committernsfisis <nsfisis@gmail.com>2026-08-03 01:30:26 +0900
commit20f7a7826ae048d249e0d837ca6393a5f09c9ba6 (patch)
treee35b541857c47543b54afcacf58b82ef3a7cce70 /crates/shirabe/src/console
parentbf7ec47524a068c7fa7658f03f4dd44957f492a6 (diff)
downloadphp-shirabe-20f7a7826ae048d249e0d837ca6393a5f09c9ba6.tar.gz
php-shirabe-20f7a7826ae048d249e0d837ca6393a5f09c9ba6.tar.zst
php-shirabe-20f7a7826ae048d249e0d837ca6393a5f09c9ba6.zip
feat(event-dispatcher): run composer.json PHP scripts through the RPC worker
Implement the two script execution paths that previously stopped at todo!(): a Class::method listener is invoked as CallStaticMethod with the event crossing the boundary as a proxy-stub handle, and a Command-class listener runs inside a throwaway bare Symfony Application hosted by the worker via a generated snippet, its BufferedOutput written back through the dispatcher's IO. makeAutoloader is ported for real (canonical-package hash, setDevMode, buildPackageMap/parseAutoloads/createLoader), and the class_exists/is_callable/is_a/defined guards now query the worker, whose script autoloader resolves classes by asking the Rust-side ClassLoader over the reverse channel. EventInterface gains as_any (the IOInterface downcast pattern) so the concrete event type is reachable behind the trait object. Application::do_run now registers ScriptAliasCommand entries as typed commands, unblocking the run-script --list/alias tests; the dev-mode-to-generator test is ported with local mockall mocks. The remaining ignored tests carry re-verified reasons: the listener methods live on the PHPUnit test class itself (unloadable in the worker), or the test needs live import of a user PHP Command class into the Application. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/console')
-rw-r--r--crates/shirabe/src/console/application.rs98
1 files changed, 43 insertions, 55 deletions
diff --git a/crates/shirabe/src/console/application.rs b/crates/shirabe/src/console/application.rs
index 56718164..af18cd04 100644
--- a/crates/shirabe/src/console/application.rs
+++ b/crates/shirabe/src/console/application.rs
@@ -2372,63 +2372,51 @@ impl ApplicationHandle {
// if the command is not an array of commands, and points to a valid SymfonyCommand subclass, import its details directly
let dummy_str = dummy.as_string().unwrap_or("").to_string();
- let cmd: PhpMixed = if is_string(dummy)
- && shirabe_php_shim::class_exists(&dummy_str)
- && is_subclass_of(
- &PhpMixed::String(dummy_str.clone()),
- "Symfony\\Component\\Console\\Command\\Command",
- true,
- ) {
- if is_subclass_of(
- &PhpMixed::String(dummy_str.clone()),
- "Symfony\\Component\\Console\\SingleCommandApplication",
- true,
- ) {
- io.write_error(&format!("<warning>The script named {} extends SingleCommandApplication which is not compatible with Composer 2.9+, make sure you extend Symfony\\Component\\Console\\Command instead.</warning>", script));
- }
- let mut cmd = shirabe_php_shim::instantiate_class(
- &dummy_str,
- vec![PhpMixed::String(script.clone())],
- );
- // TODO(phase-c): the script's command class is built by
- // reflection (instantiate_class) and stays PhpMixed; the
- // SingleCommandApplication / SymfonyCommand typed registry it
- // belongs to is an external-package todo!() stub.
- // let _ = SingleCommandApplication::new;
-
- // makes sure the command is find()'able by the name defined in composer.json, and the name isn't overridden in its configure()
- // TODO(phase-c): cmd is the PhpMixed result of reflection
- // instantiation; reading/overriding its
- // name/description requires the typed SymfonyCommand model that
- // the Symfony stub does not yet provide.
- let _ = description;
- let _ = &mut cmd;
- cmd
- } else {
- // fallback to usual aliasing behavior
- // TODO(phase-c): ScriptAliasCommand is a typed BaseCommand
- // but this code path stores commands as PhpMixed; it can
- // only be carried as a typed trait object once the Symfony
- // command registry is modelled.
- let _ = ScriptAliasCommand::new(
- script.clone(),
- Some(description),
- aliases,
- );
- PhpMixed::Null
- };
+ let cmd: std::rc::Rc<std::cell::RefCell<dyn SymfonyCommand>> =
+ if is_string(dummy)
+ && shirabe_php_shim::class_exists(&dummy_str)
+ && is_subclass_of(
+ &PhpMixed::String(dummy_str.clone()),
+ "Symfony\\Component\\Console\\Command\\Command",
+ true,
+ )
+ {
+ if is_subclass_of(
+ &PhpMixed::String(dummy_str.clone()),
+ "Symfony\\Component\\Console\\SingleCommandApplication",
+ true,
+ ) {
+ io.write_error(&format!("<warning>The script named {} extends SingleCommandApplication which is not compatible with Composer 2.9+, make sure you extend Symfony\\Component\\Console\\Command instead.</warning>", script));
+ }
+ // TODO(plugin): `new $dummy($script)` instantiates the
+ // user's PHP command class in-process and registers the
+ // live object on this Application; hosting a PHP-owned
+ // command here needs the PHP-side Application / command
+ // proxying of the plugin milestones. The shim
+ // class_exists above never recognizes user classes, so
+ // this arm is currently unreachable.
+ let _ = shirabe_php_shim::instantiate_class(
+ &dummy_str,
+ vec![PhpMixed::String(script.clone())],
+ );
+ todo!(
+ "plugin: import a user Command class as a live application command"
+ );
+ } else {
+ // fallback to usual aliasing behavior
+ std::rc::Rc::new(std::cell::RefCell::new(
+ ScriptAliasCommand::new(
+ script.clone(),
+ Some(description),
+ aliases,
+ )?,
+ ))
+ };
// Compatibility layer for symfony/console <7.4
- // TODO(phase-c): Application::add() takes Rc<RefCell<dyn
- // SymfonyCommand>>
- // but `cmd` here is the PhpMixed result of reflection-based
- // plugin command instantiation; registering it as a typed
- // command instance is blocked on the Symfony command-registry
- // model (external-package todo!() stub).
- let _ = &cmd;
- todo!(
- "plugin: register reflection-instantiated command on Application::add"
- );
+ // (addCommand does not exist in the ported Application; add()
+ // is the only registration entry point.)
+ self.add(cmd)?;
}
}
}