Skip to content

Commit

Permalink
Add ConfigBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
olvlvl committed Apr 23, 2022
1 parent ae84fae commit 0e63091
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 168 deletions.
39 changes: 39 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Migration

## v5.x to v6.x

### Breaking changes

- `Prototype::bind()` requires a `Config` objects instead of an array.

```php
<?php

namespace ICanBoogie;

Prototype::bind([
Cat::class => [
'meow' => fn(Cat $cat) => 'Meow'
],

FierceCat::class => [
'meow' => fn(FierceCat $cat) => 'MEOOOW !'
]
]);

```

```php
<?php

namespace ICanBoogie;

use ICanBoogie\Prototype\ConfigBuilder;use ICanBoogie\PrototypeTest\FierceCat;

$config = (new ConfigBuilder())
->bind(Cat::class, 'meom', fn(Cat $cat) => 'Meow')
->bind(FierceCat::class, 'meow', fn(FierceCat $cat) => 'MEOOOW !')
->build();

ICanBoogie\Prototype::bind($config);
```
118 changes: 20 additions & 98 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ getters and setters.



#### Installation

```bash
composer require icanboogie/prototype
```



## Defining methods at runtime
Expand All @@ -35,18 +41,10 @@ $fierce_cat = new FierceCat;
$second_fierce_cat = new FierceCat;

// define the 'meow' prototype method for Cat class
Prototype::from(Cat::class)['meow'] = function(Cat $cat) {

return 'Meow';

};
Prototype::from(Cat::class)['meow'] = fn(Cat $cat) => 'Meow';

// override the 'meow' prototype method for FierceCat class
Prototype::from(FierceCat::class)['meow'] = function(Cat $cat) {

return 'MEOOOW !';

};
Prototype::from(FierceCat::class)['meow'] = fn(Cat $cat) => 'MEOOOW !';

echo $cat->meow(); // Meow
echo $other_cat->meow(); // Meow
Expand Down Expand Up @@ -123,13 +121,8 @@ class Article

// …

Prototype::from(Article::class)['get_image'] = function(Article $target) use ($image_model) {

return $target->image_id
? $image_model[$target->image_id]
: null;

};
Prototype::from(Article::class)['get_image']
= fn(Article $target) => $image_model[$target->image_id] ?? null;

$article = new Article;
$article->image_id = 12;
Expand Down Expand Up @@ -166,11 +159,7 @@ class News extends Node
}
}

Prototype::from(Node::class)['url'] = function($node, $type) {

return "/path/to/$type.html";

};
Prototype::from(Node::class)['url'] = fn(Node $node, string $type) => "/path/to/$type.html";

$node = new Node;
$news = new News;
Expand Down Expand Up @@ -205,27 +194,16 @@ defined using any callable such as `"App\Hooks::cat_meow"`.
```php
<?php

ICanBoogie\Prototype::bind([
namespace ICanBoogie;

Cat::class => [
use ICanBoogie\Prototype\ConfigBuilder;use ICanBoogie\PrototypeTest\FierceCat;

'meow' => function(Cat $cat) {
$config = (new ConfigBuilder())
->bind(Cat::class, 'meom', fn(Cat $cat) => 'Meow')
->bind(FierceCat::class, 'meow', fn(FierceCat $cat) => 'MEOOOW !')
->build();

return 'Meow';

}
],

FierceCat::class => [

'meow' => function(FierceCat $cat) {

return 'MEOOOW !';

}
]

]);
ICanBoogie\Prototype::bind($config);
```


Expand All @@ -248,11 +226,7 @@ class Cat

$cat = new Cat;

$cat->prototype['meow'] = function(Cat $cat) {

return 'Meow';

};
$cat->prototype['meow'] = fn(Cat $cat) => 'Meow';

echo $cat->meow();
```
Expand All @@ -270,35 +244,7 @@ Prototype methods may be defined using the `Prototype` instance of a class:

use ICanBoogie\Prototype;

Prototype::from(Cat::class)['meow'] = function(Cat $cat) {

return 'Meow';

};
```





### Defining prototypes methods using config fragments

If the package is bound to [ICanBoogie][] using [icanboogie/bind-prototype][], prototype methods may be defined
using `prototype` configuration fragments:

```php
<?php

use Article;

// config/prototype.php

return [

Article::class . '::url' => 'App\Hooks::article_url',
Article::class . '::get_url' => 'App\Hooks::article_get_url'

];
Prototype::from(Cat::class)['meow'] = fn(Cat $cat) => 'Meow';
```


Expand Down Expand Up @@ -420,26 +366,6 @@ The following exceptions are defined:



## Requirements

The package requires PHP 7.2 or later.





## Installation

The recommended way to install this package is through [Composer](http://getcomposer.org/):

```bash
$ composer require icanboogie/prototype
```





## Documentation

The package is documented as part of the [ICanBoogie][] framework [documentation][]. You can
Expand Down Expand Up @@ -471,16 +397,12 @@ The package is continuously tested by [Travis CI](http://about.travis-ci.org/).





## License

**icanboogie/prototype** is licensed under the New BSD License - See the [LICENSE](LICENSE) file for details.





[PropertyNotWritable]: https://icanboogie.org/api/common/1.2/class-ICanBoogie.PropertyNotWritable.html
[PropertyNotReadable]: https://icanboogie.org/api/common/1.2/class-ICanBoogie.PropertyNotReadable.html
[ToArray]: https://icanboogie.org/api/common/1.2/class-ICanBoogie.ToArray.html
Expand Down
37 changes: 14 additions & 23 deletions lib/Prototype.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use ArrayAccess;
use ArrayIterator;
use ICanBoogie\Prototype\Config;
use ICanBoogie\Prototype\MethodNotDefined;
use IteratorAggregate;
use Traversable;
Expand Down Expand Up @@ -61,13 +62,12 @@ static public function from(object|string $class_or_object): Prototype

/**
* Defines prototype methods.
*
* @param array<class-string, array<string, callable>> $bindings
*/
static public function bind(array $bindings): void
static public function bind(Config $config): void
{
if (!$bindings)
{
$bindings = $config->bindings;

if (!$bindings) {
return;
}

Expand All @@ -84,16 +84,14 @@ static private function update_bindings(array $bindings): void
{
$current = &self::$bindings;

if (!$current)
{
if (!$current) {
$current = $bindings;
}

$intersect = array_intersect_key($bindings, $current);
$current += array_diff_key($bindings, $current);

foreach ($intersect as $class => $methods)
{
foreach ($intersect as $class => $methods) {
$current[$class] = array_merge($current[$class], $methods);
}
}
Expand All @@ -105,12 +103,10 @@ static private function update_bindings(array $bindings): void
*/
static private function update_instances(array $bindings): void
{
foreach (self::$prototypes as $class => $prototype)
{
foreach (self::$prototypes as $class => $prototype) {
$prototype->consolidated_methods = null;

if (empty($bindings[$class]))
{
if (empty($bindings[$class])) {
continue;
}

Expand Down Expand Up @@ -150,8 +146,7 @@ private function __construct(
$parent_class = get_parent_class($class);
$this->parent = $parent_class ? self::from($parent_class) : null;

if (isset(self::$bindings[$class]))
{
if (isset(self::$bindings[$class])) {
$this->methods = self::$bindings[$class];
}
}
Expand All @@ -177,8 +172,7 @@ private function consolidate_methods(): array
{
$methods = $this->methods;

if ($this->parent)
{
if ($this->parent) {
$methods += $this->parent->get_consolidated_methods();
}

Expand All @@ -194,10 +188,8 @@ private function revoke_consolidated_methods(): void
{
$class = $this->class;

foreach (self::$prototypes as $prototype)
{
if (!is_subclass_of($prototype->class, $class))
{
foreach (self::$prototypes as $prototype) {
if (!is_subclass_of($prototype->class, $class)) {
continue;
}

Expand Down Expand Up @@ -258,8 +250,7 @@ public function offsetGet(mixed $offset): mixed
{
$methods = $this->consolidated_methods ??= $this->consolidate_methods();

if (!isset($methods[$offset]))
{
if (!isset($methods[$offset])) {
throw new MethodNotDefined($offset, $this->class);
}

Expand Down
25 changes: 25 additions & 0 deletions lib/Prototype/Config.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

/*
* This file is part of the ICanBoogie package.
*
* (c) Olivier Laviale <olivier.laviale@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace ICanBoogie\Prototype;

final class Config
{
/**
* @param array<class-string, array<string, callable>> $bindings
* Where _key_ is a target class and _value_ is an array of method bindings,
* where _key_ is a method and _value_ a callable.
*/
public function __construct(
public readonly array $bindings = []
) {
}
}
Loading

0 comments on commit 0e63091

Please sign in to comment.