diff --git a/examples/jobExecute.php b/examples/jobExecute.php new file mode 100644 index 0000000..9815ec7 --- /dev/null +++ b/examples/jobExecute.php @@ -0,0 +1,87 @@ +theQuestion = $theQuestion; + } + + /** + * Note the required service in parameters: + */ + public function __invoke(Oracle $oracle): ?string + { + return $oracle->answer($this->theQuestion); + } +} + +class Queue +{ + public function getNextJob() + { + // This would be fetched from the message queue or a database or wherever you store async jobs in. + $message = ' + { + "class": "AnswerQuestionJob", + "args": ["Will there be a storm tomorrow?"] + } + '; + return json_decode($message); + } +} + +class Oracle +{ + public function answer(string $question): ?string + { + $seed = rand(-10, 10); + return $seed > 0 ? 'yes' : ($seed < 0 ? 'no' : null); + } +} + +// The service container has its services registered by their class name: +$container = new Sleeve([ + Oracle::class => fn() => new Oracle(), +]); + +if (!$container->get(Oracle::class) instanceof Oracle) { + // this won't happen + throw new Exception('WTF.'); +} + +// Fetch the next job from the job queue: +[$className, $args] = (new Queue())->getNextJob(); + +// Instantiate the job: +$job = new $className(...$args); + +if (!is_callable($job)) { + throw new Exception('The job is not callable.'); +} + +// Since we have no idea what services the job needs to be executed +// and there may be multiple jobs with different signatures, +// we utilize dynamic dependency resolution: +$g = new Genie($container); +$g->invoke($job); + +// That's it! +// Our job is called and the Oracle class is fetched from the container and delivered as an argument. + diff --git a/readme.md b/readme.md index a6a7e1a..6502fef 100644 --- a/readme.md +++ b/readme.md @@ -12,22 +12,6 @@ Wire with genie powers. > - - - - ## What? A superpowered `call_user_func`? Yup! And more. @@ -72,21 +56,35 @@ For each parameter it is possible to: ```php // override type-hint(s) -$callable = function (#[Wire(MyService::class)] ServiceInterface $service, #[Wire(Thing::class)] $thing){ ... }; +$callable = function ( + #[Wire(MyService::class)] AnInterface $service, + #[Wire(Thing::class)] $thing +){ ... }; $value = $g->invoke($callable); // construct object(s) if not present in the container -$callable = function (#[Hot] Something $some, #[Make(Thing::class)] $thing){ ... }; +$callable = function ( + #[Hot] Something $some, + #[Make(Thing::class)] $thing +){ ... }; $value = $g->invoke($callable); // provide arguments for scalar-type, no-type and otherwise unresolvable parameters $callable = function (string $question, MyService $service, int $answer){ ... }; -$g->invoke($callable, 'The Ultimate Question of Life, the Universe, and Everything.', 42); -$g->invoke($callable, answer: 42, question: 'The Ultimate Question of Life, the Universe, and Everything.',); +$g->invoke( + $callable, + 'The Ultimate Question of Life, the Universe, and Everything.', + 42, +); +$g->invoke( + $callable, + answer: 42, + question: 'The Ultimate Question of Life, the Universe, and Everything.', +); -// skip wiring for a parameter +// skip wiring for a parameter... $callable = function (#[Skip] MyService $service){ ... }; -$g->invoke($callable, new MyService(...)); // provide your own argument(s) +$g->invoke($callable, new MyService(...)); // ...and provide your own argument(s) ``` @@ -137,8 +135,10 @@ their constructor dependencies will be resolved from the container or created on - for controllers, where dependencies are wired at runtime +**Examples** +- [asynchronous job execution](examples/jobExecute.php) + @@ -202,7 +202,7 @@ $object = $g->provide( Dependency::class, OtherDependency::class )->invoke($fact You can limit the services accessible through `Genie` by using a filtering proxy `Limiter`: ```php -$repoGenie = new Genie( +$repoGenie = new Dakujem\Wire\Genie( new Dakujem\Wire\Limiter($container, [ RepositoryInterface::class, // you may whitelist multiple classes or interfaces