nucleardog/discovery

Dynamically discover PHP objects

v1.0.0 2024-11-24 18:38 UTC

This package is auto-updated.

Last update: 2024-12-24 23:46:19 UTC


README

Provide dynamic discovery of PHP objects.

Usage

[!note] Laravel

This documentation focuses on use of this package within Laravel. While it should work outside of Laravel, you will be responsible for setting up all the scaffolding currently managed by the included Laravel service provider.

This package provides a system for declaring interfaces, attributes, and other things which you are interested in and dynamically discovery all classes that are annotated with the attribute, implement the interface, etc.

Register Things to Discover

You can either register things directly in your configuration or at runtime.

Config

Publish the default configuration:

$ artisan vendor:publish --provider='Nucleardog\Discovery\Laravel\Providers\DiscoveryServiceProvider'

Edit the new config/discovery.php class to list any interfaces or attributes you want discovered. For example:

<?php

declare(strict_types=1);

return [

	'discover' => [

		// For any interface listed here, all classes implementing this interface
		// will be discovered and available through the discovery class.
		'interfaces' => [
			\App\Contracts\ProvidesFoo::class,
		],

		// For any attributes listed here, all classes tagged with this attribute
		// will be discovered and available through the discovery class.
		'attributes' => [
			//
		],

	],

	// List the namespaces you want the discovery package to look in to find
	// implementations.
	'namespaces' => [
		'App',
	],

];

Runtime

In a service provider's register() method, extend the Discovery class and register any additional interfaces, attributes, or namespaces you are interested in:

<?php

use Nucleardog\Discovery\Discovery;

class MyServiceProvider
{

	public function register(): void
	{
		$this->app->extend(
			Discovery::class,
			function(Discovery $discovery) {
				$discovery->addNamespace('My\\Module');
				$discovery->addAttribute(\My\Module\Frobulates::class);
			},
		);
	}

}

Fetched Discovered Things

At runtime, you can fetch things that have been discovered:

<?php

$discovery = app()->make(Discovery::class);

// Fetch all classes that implement an interface
$classes = $discovery->classes(\App\Contracts\ProvidesFoo::class);
foreach ($classes as $class) {
	// $class is the class path (string) for the class implementing the interface
	$instance = new $class();
	$instance->getFoo();
}

// Fetch all classes that have an attribute attached
$attributes = $discovery->attributes(\My\Module\Frobulates::class);
foreach ($attributes as $class => $attribute) {
	// $class is the class path (string) for the class with the attribute attached
	//        to it
	// $attribute is an instantiated instance of the attribute class
}

// Fetch all classes that have an attribute attached, and fetch all instances
// of that attribute that are attached (if the attribute is declared more than
// once).
$attributes = $discovery->attributes(\My\Module\Frobulates::class, all: true);
foreach ($attributes as $class => $attributes) {
	// $class is the class path (string) for the class with the attribute attached
	//        to it
	// $attributes is an array of instantiated attribute classes.
}

Artisan Commands

This package register a few artisan commands:

discovery:list

Syntax:
artisan discovery:list

Lists all registered interfaces and attributes and the implementing classes that have been discovered.

discovery:cache

Syntax:
artisan discovery:cache

Caches all discovered classes in bootstrap/cache/discovery.php so discovery doesn't have to happen on every request.

discovery:clear

Syntax:
artisan discovery:clear

Clears the discovery cache.

Tests

Phpunit is included in a separate composer file and must be explicitly installed:

$ cd tools/phpunit/
$ composer install

Once installed, the tests can be run from the root package folder with:

$ composer test

Notes

The discovery process currently uses the composer class map to find all classes in your project. During development, as files are added or removed from your project, you may need to re-run composer dump-autoload to regenerate the class map for the discovery system to detect the changes.

Legal

Copyright 2024 Adam Pippin hello@adampippin.ca

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.