PHPackages                             dotink/affinity - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. dotink/affinity

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

dotink/affinity
===============

A bootstrapper that loves you

1.3.1(9y ago)11.4kAGPL-3.0PHPPHP &gt;=5.4.0

Since Feb 10Pushed 9y ago1 watchersCompare

[ Source](https://github.com/dotink/affinity)[ Packagist](https://packagist.org/packages/dotink/affinity)[ RSS](/packages/dotink-affinity/feed)WikiDiscussions master Synced 2w ago

READMEChangelogDependencies (1)Versions (12)Used By (0)

Affinity - A Bootstrapper for PHP Projects
==========================================

[](#affinity---a-bootstrapper-for-php-projects)

Affinity is a bootstrapper for PHP projects which allows you to create modular configurations and actions that can be dropped into place for added functionality without additional work.

It provides mechanisms for running bootstrap operations and logic as well as creating and accessing well organized configuration data.

Affinity is a key component of the inKWell framework, you can read more about the integration of it at:

Or... continue reading below for standalone use.

Basic Usage
-----------

[](#basic-usage)

```
$engine = new Affinity\Engine(
	new Affinity\NativeDriver('/path/to/configs'),
	new Affinity\NativeDriver('/path/to/actions')
);

$engine->start('production', ['app' => $app, 'di' => $di]);
```

This example shows the most basic setup of affinity. Using the native driver we can scan directories recursively for configurations or actions to load then call `start()` in order to execute bootstrapping.

Configuration / Action Directory Structure
------------------------------------------

[](#configuration--action-directory-structure)

The native driver assumes that your configuration and action directory structure looks like the following:

```
--- config_root [this is what you pass to the __construct() call]
 |
 |- default
 |
 |- environment1
 |
 |- environment2
 |
 |- ...

```

All configs and actions from `default` will be included no matter what and will be extended based on the environment provided to the `start()` call.

You can extend by multiple environments by passing a comma separated list:

```
$engine->start('production, europe', $context);
```

This allows you to only override the necessary config data or logic for the specific environment requirements whether they be the execution mode, deployment stability, location, whatever.

The directory structure inside each environment folder is up to you, although it is suggested you use additional sub directories for namespacing purposes.

The relative path to a given config file or action is used by affinity as a means to identify the configuration or action. So, for example `config/default/core.php` is identified by the simple string `'core'` while a file such as `include/default/routes/main.php` is identified by `'routes/main'`.

Configurations
--------------

[](#configurations)

You can create a configuration by returning it from any PHP file located in an environment directory. For example, let's imagine adding the following to `config/default/test.php`:

```
return Affinity\Config::create([

	'key' => 'value',

	'parent' => [
		'child' => 'value'
	]
]);
```

### Accessing Configuration Data

[](#accessing-configuration-data)

Once a config is created, you can access configuration data by using the `fetch()` method on the affinity engine.

```
$engine->fetch('test', 'key', 'default');
```

The parameters for the `fetch()` method are the configuration id, the parameter within that configuration, and the default value if it's not found, respectively. You can access deeply nested data using a javascript style object notation for the second parameter:

```
$engine->fetch('test', 'parent.child', 'default');
```

### Aggregate IDs

[](#aggregate-ids)

In addition to identifying a specific configuration to fetch data from, it is also possible to specify types of information which may be provided by multiple configurations using an aggregate ID. All aggregate IDs must begin with `@`:

```
$engine->fetch('@providers', 'mapping', array());
```

In order to provide information for aggregate ID fetches, you need to pass an optional first parameter to the `Affinity\Config::create()` method containing a list of aggregates you provide. The data is then keyed initially under the aggregate ID within the config itself.

```
return Affinity\Config::create(['providers'], [
	'@providers' => [
		'mapping' => [
			'Dotink\Package\UsefulInterface' => 'My\Concrete\ProviderClass'
		]
	]
]);
```

When fetching information from an aggregate ID, the returned array consists of one entry for every configuration file which provides that aggregate data keyed by the specific configuration id. In the case of the above mappings, this means we have to first loop over the individual configuration data, and *then* over the mapping themselves.

You can fetch a list of specific IDs which provide aggregate data by fetching the aggregate ID alone, without specifying a parameter:

```
foreach ($engine->fetch('@providers') as $id) {
	$provider_mapping = $engine->fetch($id, '@providers.mapping', []);
	$provider_params  = $engine->fetch($id, '@providers.params',  []);

	foreach ($provider_mapping as $interface => $provider) {
		$injector->alias($interface, $provider);
	}

	foreach ($provider_params as $provider => $params) {
		$injector->define($provider, $params);
	}
}
```

Actions
-------

[](#actions)

Actions are pieces of modularized and pluggable logic which use the configuration data in order to prepare your application for running. Some of their main functions include:

- Setting up dependency wiring
- Running static class methods for config or setting static class properties for config
- Registering providers in the application container

Unlike configs which are just arrays of information, actions represent callable logic.

#### Creating an Action

[](#creating-an-action)

Add a file to the appropriate environment and return `Affinity\Action::create()`:

```
return Affinity\Action::create(function($app, $di) {
	//
	// Your bootstrap logic here
	//
});
```

### Action Ordering (Dependencies)

[](#action-ordering-dependencies)

If you need to make sure your actions run in order, you can add an array of dependencies as an optional first argument. The below action will not run until the action identified by the `core` ID has run:

```
return Affinity\Action::create(['core'], function($app, $di) {
	//
	// Your bootstrap logic here
	//
});
```

Context
-------

[](#context)

In our first example you may have noted the addition of an array which was passed to the `start()` method on the engine:

```
$engine->start('production', ['app' => $app, 'di' => $di]);
```

This is the context. If you didn't pick up on it before, it is provided to the action operations and is also available in the configuration as normal variables. The context can be whatever you want, but is usually used to provide your application instance and dependency injector for use in configs and actions respectively.

###  Health Score

30

—

LowBetter than 62% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity16

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity65

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~64 days

Recently: every ~93 days

Total

11

Last Release

3512d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/4ab2b91daf2aa6e4c7f98f785a3135daa3e9998bd7021d89df05a374e28ecde5?d=identicon)[mattsah](/maintainers/mattsah)

---

Top Contributors

[![mattsah](https://avatars.githubusercontent.com/u/586346?v=4)](https://github.com/mattsah "mattsah (3 commits)")

---

Tags

bootstrap

### Embed Badge

![Health badge](/badges/dotink-affinity/health.svg)

```
[![Health](https://phpackages.com/badges/dotink-affinity/health.svg)](https://phpackages.com/packages/dotink-affinity)
```

###  Alternatives

[fortawesome/font-awesome

The iconic font, CSS, and SVG framework

76.7k7.6M143](/packages/fortawesome-font-awesome)[kartik-v/yii2-editable

An enhanced editable widget for Yii 2.0 that allows easy editing of displayed data with numerous configuration possibilities.

1173.4M60](/packages/kartik-v-yii2-editable)[kartik-v/yii2-date-range

An advanced Yii 2 date range picker input for based on bootstrap-daterangepicker plugin.

924.6M42](/packages/kartik-v-yii2-date-range)[kartik-v/yii2-dialog

An asset bundle for bootstrap3-dialog for Yii 2.0 framework.

526.5M19](/packages/kartik-v-yii2-dialog)[kartik-v/yii2-widget-timepicker

Enhanced Yii2 wrapper for the bootstrap timepicker plugin (sub repo split from yii2-widgets)

445.2M14](/packages/kartik-v-yii2-widget-timepicker)[kartik-v/yii2-widget-rating

A Yii2 widget for the simple yet powerful bootstrap-star-rating plugin with fractional rating support (sub repo split from yii2-widgets)

474.3M8](/packages/kartik-v-yii2-widget-rating)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
