Layers   A
last analyzed

Complexity

Total Complexity 8

Size/Duplication

Total Lines 79
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 31
dl 0
loc 79
rs 10
c 0
b 0
f 0
wmc 8

3 Methods

Rating   Name   Duplication   Size   Complexity  
A processing() 0 39 5
A handler() 0 7 2
A __construct() 0 3 1
1
<?php
2
/**
3
 * Layers handler
4
 * User: moyo
5
 * Date: 06/08/2017
6
 * Time: 6:33 PM
7
 */
8
9
namespace Carno\Chain;
10
11
use Carno\Chain\Chips\Extensions;
12
use Carno\Coroutine\Context;
13
use Carno\Promise\Promise;
14
use Carno\Promise\Promised;
15
use Closure;
16
use Throwable;
17
18
final class Layers
19
{
20
    use Extensions;
21
22
    /**
23
     * processed layer idx
24
     */
25
    private const XID = 'chain-lax-id';
26
27
    /**
28
     * @var Layered[]
29
     */
30
    private $layers = [];
31
32
    /**
33
     * Layers constructor.
34
     * @param Layered ...$layers
35
     */
36
    public function __construct(Layered ...$layers)
37
    {
38
        $this->layers = $layers;
39
    }
40
41
    /**
42
     * @param Context $ctx
43
     * @param mixed $initial
44
     * @return Promised
45
     */
46
    private function processing(Context $ctx, $initial) : Promised
47
    {
48
        $seed = $chain = Promise::deferred();
49
50
        foreach ($this->layers as $idx => $layer) {
51
            $chain = $chain->then(static function ($data) use ($ctx, $layer, $idx) {
52
                return $layer->inbound($data, $ctx->set(self::XID, $idx));
53
            }, static function (Throwable $e) use ($ctx, $layer, $idx) {
54
                if (($ctx->get(self::XID) ?? 999) >= $idx) {
55
                    $layer->exception($e, $ctx);
56
                } else {
57
                    throw $e;
58
                }
59
            });
60
        }
61
62
        $size = count($this->layers);
63
64
        /**
65
         * @var Layered[] $replies
66
         */
67
68
        $replies = array_reverse($this->layers);
69
70
        foreach ($replies as $idx => $layer) {
71
            $chain = $chain->then(static function ($data) use ($ctx, $layer) {
72
                return $layer->outbound($data, $ctx);
73
            }, static function (Throwable $e) use ($ctx, $layer, $idx, $size) {
74
                if (($ctx->get(self::XID) ?? 999) >= ($size - $idx - 1)) {
75
                    $layer->exception($e, $ctx);
76
                } else {
77
                    throw $e;
78
                }
79
            });
80
        }
81
82
        $seed->resolve($initial, $ctx);
83
84
        return $chain;
85
    }
86
87
    /**
88
     * @return Closure
89
     */
90
    public function handler() : Closure
91
    {
92
        return function ($initial, Context $ctx = null) {
93
            try {
94
                return $this->processing($ctx ?? new Context, $initial);
95
            } catch (Throwable $e) {
96
                return Promise::rejected($e);
97
            }
98
        };
99
    }
100
}
101