baraja-core / service-method-invoker
Invoke method by service, name and arguments.
Installs: 230 731
Dependents: 4
Suggesters: 0
Security: 0
Stars: 2
Watchers: 1
Forks: 2
Open Issues: 0
pkg:composer/baraja-core/service-method-invoker
Requires
- php: ^8.1
Requires (Dev)
- phpstan/extension-installer: ^1.1
- phpstan/phpstan: ^1.0
- phpstan/phpstan-deprecation-rules: ^1.0
- phpstan/phpstan-nette: ^1.0
- phpstan/phpstan-strict-rules: ^1.0
- roave/security-advisories: dev-master
- spaze/phpstan-disallowed-calls: ^2.0
- tracy/tracy: ^2.8
- dev-master
- v2.4.0
- v2.3.1
- v2.3.0
- v2.2.6
- v2.2.5
- v2.2.4
- v2.2.3
- v2.2.2
- v2.2.1
- v2.2.0
- v2.1.1
- v2.1.0
- v2.0.1
- v2.0.0
- v1.2.5
- v1.2.4
- v1.2.3
- v1.2.2
- v1.2.1
- v1.2.0
- v1.1.3
- v1.1.2
- v1.1.1
- v1.1.0
- v1.0.6
- v1.0.5
- v1.0.4
- v1.0.3
- v1.0.2
- v1.0.1
- v1.0.0
- dev-renovate/configure
- dev-restyled/renovate/configure
- dev-dependabot/add-v2-config-file
- dev-property-resolve-type
This package is auto-updated.
Last update: 2026-01-04 11:18:38 UTC
README
A robust PHP library for safely invoking methods on services with automatic parameter validation, type coercion, and entity hydration. Perfect for API endpoints, command handlers, and any scenario where you need to dynamically call methods with user-provided data.
π― Key Features
- Safe method invocation with automatic parameter validation and type checking
- Automatic type coercion for scalar types (bool, int, float, string, array)
- Entity hydration - automatically converts array data to typed objects/DTOs
- PHP 8.1+ enum support with case-insensitive matching
- Nullable parameter handling with proper default value support
- Tracy Debugger integration with custom BlueScreen panels for debugging
- Circular reference detection in nested entity hydration
- Custom entity repository support for resolving entities by ID
- Detailed exception messages with context about the failing service and method
ποΈ Architecture
The package consists of several components working together to provide safe method invocation:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ServiceMethodInvoker β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β invoke(service, method, params) β β
β β getInvokeArgs(service, method, params) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β β β
β βΌ βΌ βΌ β
β βββββββββββββββ βββββββββββββββββββ ββββββββββββββββ β
β βType Coercionβ βEntity Hydration β βEnum Handling β β
β β fixType() β βhydrateDataTo..()β βprocessEnum..()β β
β βββββββββββββββ βββββββββββββββββββ ββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
βΌ βΌ
βββββββββββββββββββ βββββββββββββββββββββββββββ
β Helpers β β ProjectEntityRepository β
β - Type parsing β β - Find entities by ID β
β - Annotations β β (optional interface) β
β - Use statementsβ βββββββββββββββββββββββββββ
βββββββββββββββββββ
β
βΌ
βββββββββββββββββββ βββββββββββββββββββββββββββ
β BlueScreen β β RuntimeInvokeException β
β Tracy panel β β Contextual exceptions β
βββββββββββββββββββ βββββββββββββββββββββββββββ
π§ Components
| Component | Description |
|---|---|
ServiceMethodInvoker |
Main class responsible for invoking methods with validated and hydrated parameters |
Service |
Interface for services that extends Stringable for user-friendly error messages |
RuntimeInvokeException |
Exception class that carries service context, method name, and parameters for debugging |
BlueScreen |
Tracy Debugger integration that renders detailed error panels with source code |
Helpers |
Utility class for type resolution, annotation parsing, and use statement extraction |
ProjectEntityRepository |
Interface for custom entity resolution by ID (e.g., Doctrine integration) |
π¦ Installation
It's best to use Composer for installation, and you can also find the package on Packagist and GitHub.
To install, simply use the command:
$ composer require baraja-core/service-method-invoker
You can use the package manually by creating an instance of the internal classes, or register a DIC extension to link the services directly to the Nette Framework.
Requirements: PHP 8.1 or higher
π Basic Usage
Simple Method Invocation
Think of a simple service as an API endpoint with a public method for hydrating your data:
$invoker = new \Baraja\ServiceMethodInvoker; $apiEndpoint = new \Baraja\MyApiEndpoint; $data = $invoker->invoke($apiEndpoint, 'actionDetail', ['id' => 42]); var_dump($data); // return "My id is: 42"
And your endpoint can be:
class MyApiEndpoint { public function actionDetail(int $id): string { return 'My id is: ' . $id; } }
Getting Invoke Arguments Without Execution
If you need to prepare the arguments without actually invoking the method:
$invoker = new \Baraja\ServiceMethodInvoker; $args = $invoker->getInvokeArgs($service, 'methodName', $params); // $args is now a validated and hydrated array ready for method invocation
π Type Coercion
The invoker automatically handles type conversion based on method parameter types:
Scalar Types
class MyService { public function process( int $count, // "42" -> 42, "null" -> null (if nullable) float $price, // "19.99" -> 19.99 bool $active, // "true", "1", "yes" -> true; others -> false string $name, // kept as-is array $items, // kept as-is ): void { // ... } } $invoker->invoke($service, 'process', [ 'count' => '42', 'price' => '19.99', 'active' => 'yes', 'name' => 'Test', 'items' => ['a', 'b'], ]);
Nullable Parameters
When a parameter is nullable and receives an empty or falsy value, it's converted to null:
public function find(?int $id): void { // '' or '0' with nullable type -> null // '0' with non-nullable int -> 0 }
Boolean Conversion
The following string values are treated as true: "1", "true", "yes" (case-insensitive).
All other values are converted to false.
π Entity Hydration
One of the most powerful features is automatic entity/DTO hydration from array data:
Simple Entity
class CreateUserRequest { public function __construct( public string $email, public string $name, public ?int $age = null, ) {} } class UserController { public function create(CreateUserRequest $request): User { // $request is automatically hydrated from the params array return new User($request->email, $request->name); } } $invoker->invoke($controller, 'create', [ 'email' => 'john@example.com', 'name' => 'John Doe', 'age' => 25, ]);
Nested Entities
The invoker supports nested entity hydration:
class Address { public function __construct( public string $street, public string $city, ) {} } class Order { public function __construct( public string $product, public Address $shippingAddress, ) {} } $invoker->invoke($service, 'createOrder', [ 'product' => 'Widget', 'shippingAddress' => [ 'street' => '123 Main St', 'city' => 'Prague', ], ]);
Property Hydration via Setters
If an entity has setter methods, they will be used for hydration:
class UserEntity { private string $email; public function setEmail(string $email): void { $this->email = strtolower($email); } }
Circular Reference Detection
The invoker detects and prevents circular references in entity hydration:
class NodeA { public NodeB $child; } class NodeB { public NodeA $parent; // This would cause a circular reference } // RuntimeInvokeException: Circular reference detected...
π’ PHP 8.1+ Enum Support
The invoker fully supports PHP enums with case-insensitive matching:
enum Status: string { case Active = 'active'; case Inactive = 'inactive'; case Pending = 'pending'; } class OrderService { public function updateStatus(int $orderId, Status $status): void { // ... } } // All of these work: $invoker->invoke($service, 'updateStatus', ['orderId' => 1, 'status' => 'active']); $invoker->invoke($service, 'updateStatus', ['orderId' => 1, 'status' => 'ACTIVE']); $invoker->invoke($service, 'updateStatus', ['orderId' => 1, 'status' => 'Active']);
If an invalid enum value is provided, a helpful error message is shown:
Value "unknown" is not possible option of enum "Status". Did you mean "active", "inactive", "pending"?
π Custom Entity Repository
For integrating with ORMs like Doctrine, implement the ProjectEntityRepository interface:
use Baraja\ServiceMethodInvoker\ProjectEntityRepository; class DoctrineEntityRepository implements ProjectEntityRepository { public function __construct( private EntityManagerInterface $em, ) {} public function find(string $className, int|string $id): ?object { return $this->em->find($className, $id); } } $invoker = new ServiceMethodInvoker( projectEntityRepository: new DoctrineEntityRepository($entityManager), );
This allows automatic entity resolution from IDs:
class ArticleController { public function show(Article $article): Response { // $article is automatically loaded from the database using the ID } } $invoker->invoke($controller, 'show', ['article' => 42]); // Article with ID 42 is automatically loaded via the repository
π The Data Parameter
When dataMustBeArray is true, a parameter named data must be typed as array and will receive all input parameters:
class BatchProcessor { public function process(array $data): void { // $data contains all the input parameters } } $invoker->invoke($processor, 'process', [ 'item1' => 'value1', 'item2' => 'value2', ], dataMustBeArray: true); // $data = ['item1' => 'value1', 'item2' => 'value2']
π Tracy Debugger Integration
When Tracy Debugger is available, the package automatically registers a custom BlueScreen panel that provides:
- Service class name and the exact method being called
- Source code highlighting of the failing method
- Input parameters table showing all passed values
- Direct editor link to open the file at the exact line
This integration is automatic when Tracy is installed - no configuration needed.
β οΈ Exception Handling
The RuntimeInvokeException provides rich context for debugging:
try { $invoker->invoke($service, 'method', $params); } catch (RuntimeInvokeException $e) { $e->getService(); // The service object that failed $e->getMethod(); // The method name that was being called $e->getParams(); // The parameters that were passed $e->getMessage(); // Detailed error message }
Common Exceptions
| Scenario | Exception Type |
|---|---|
| Method doesn't exist | InvalidArgumentException |
| Method is not callable | InvalidArgumentException |
| Required parameter missing | RuntimeInvokeException |
| Invalid enum value | RuntimeInvokeException |
| Type incompatibility | RuntimeInvokeException |
| Circular reference in entities | RuntimeInvokeException |
| Entity class doesn't exist | RuntimeInvokeException |
π¨ Service Interface
Implement the Service interface on your services for better error messages:
use Baraja\Service; class UserApiEndpoint implements Service { public function __toString(): string { return 'User API Endpoint'; } public function getUser(int $id): array { // ... } } // Error messages will now show "User API Endpoint" instead of the class name
π DateTime Handling
DateTimeInterface implementations are automatically instantiated:
class EventService { public function schedule( string $name, \DateTimeImmutable $startDate, ): void { // $startDate is automatically created from the string value } } $invoker->invoke($service, 'schedule', [ 'name' => 'Conference', 'startDate' => '2024-06-15 10:00:00', ]);
π Default Values for Empty Inputs
When a non-nullable parameter receives an empty value, appropriate defaults are used:
| Type | Default Value |
|---|---|
string |
"" (empty string) |
int |
0 |
float |
0.0 |
bool |
false |
array |
[] |
π€ Author
Jan Barasek - https://baraja.cz
π License
baraja-core/service-method-invoker is licensed under the MIT license. See the LICENSE file for more details.