File tree 3 files changed +138
-2
lines changed
spec/drupol/phptree/Builder
3 files changed +138
-2
lines changed Original file line number Diff line number Diff line change
1
+ <?php
2
+
3
+ declare (strict_types=1 );
4
+
5
+ namespace spec \drupol \phptree \Builder ;
6
+
7
+ use drupol \phptree \Builder \Random ;
8
+ use drupol \phptree \Node \Node ;
9
+ use drupol \phptree \Node \NodeInterface ;
10
+ use PhpSpec \ObjectBehavior ;
11
+
12
+ class RandomSpec extends ObjectBehavior
13
+ {
14
+ public function it_can_build_a_random_tree ()
15
+ {
16
+ $ parameters = [Node::class];
17
+ $ nodes = [
18
+ 'foo ' => $ parameters ,
19
+ 'bar ' => $ parameters ,
20
+ ];
21
+
22
+ $ this ::create ($ nodes )
23
+ ->shouldReturn (null );
24
+
25
+ $ nodes = array_values ($ nodes );
26
+
27
+ $ this ::create ($ nodes )
28
+ ->shouldBeAnInstanceOf (NodeInterface::class);
29
+
30
+ $ this ::create ($ nodes )
31
+ ->count ()
32
+ ->shouldReturn (1 );
33
+
34
+ $ parameters = [static function () {
35
+ return Node::class;
36
+ }];
37
+
38
+ $ nodes = [
39
+ $ parameters ,
40
+ $ parameters ,
41
+ ];
42
+
43
+ $ this ::create ($ nodes )
44
+ ->shouldBeAnInstanceOf (NodeInterface::class);
45
+
46
+ $ nodes = array_pad ([], 20 , $ parameters );
47
+ $ this ::create ($ nodes )
48
+ ->shouldBeAnInstanceOf (NodeInterface::class);
49
+ }
50
+
51
+ public function it_is_initializable ()
52
+ {
53
+ $ this ->shouldHaveType (Random::class);
54
+ }
55
+ }
Original file line number Diff line number Diff line change @@ -14,7 +14,7 @@ interface BuilderInterface
14
14
/**
15
15
* @param iterable<NodeInterface> $nodes
16
16
*
17
- * @return \drupol\phptree\Node\NodeInterface
17
+ * @return \drupol\phptree\Node\NodeInterface|null
18
18
*/
19
- public static function create (iterable $ nodes ): NodeInterface ;
19
+ public static function create (iterable $ nodes ): ? NodeInterface ;
20
20
}
Original file line number Diff line number Diff line change
1
+ <?php
2
+
3
+ declare (strict_types=1 );
4
+
5
+ namespace drupol \phptree \Builder ;
6
+
7
+ use drupol \phptree \Node \NodeInterface ;
8
+ use function is_callable ;
9
+
10
+ /**
11
+ * Class Random.
12
+ */
13
+ class Random implements BuilderInterface
14
+ {
15
+ /**
16
+ * {@inheritdoc}
17
+ */
18
+ public static function create (iterable $ nodes ): ?NodeInterface
19
+ {
20
+ $ root = null ;
21
+
22
+ foreach ($ nodes as $ key => $ value ) {
23
+ if (0 === $ key ) {
24
+ $ root = self ::createNode ($ value );
25
+
26
+ continue ;
27
+ }
28
+
29
+ if (false === ($ root instanceof NodeInterface)) {
30
+ continue ;
31
+ }
32
+
33
+ self ::pickRandomNode ($ root )->add (self ::createNode ($ value ));
34
+ }
35
+
36
+ return $ root ;
37
+ }
38
+
39
+ /**
40
+ * @param array<mixed> $parameters
41
+ *
42
+ * @return \drupol\phptree\Node\NodeInterface
43
+ */
44
+ private static function createNode (array $ parameters = []): NodeInterface
45
+ {
46
+ $ parameters = array_map (
47
+ static function ($ parameter ) {
48
+ if (is_callable ($ parameter )) {
49
+ return $ parameter ();
50
+ }
51
+
52
+ return $ parameter ;
53
+ },
54
+ $ parameters
55
+ );
56
+
57
+ $ class = array_shift ($ parameters );
58
+
59
+ return new $ class (...$ parameters );
60
+ }
61
+
62
+ /**
63
+ * @param \drupol\phptree\Node\NodeInterface $node
64
+ *
65
+ * @return \drupol\phptree\Node\NodeInterface
66
+ */
67
+ private static function pickRandomNode (NodeInterface $ node ): NodeInterface
68
+ {
69
+ $ pick = (int ) random_int (0 , $ node ->count ());
70
+
71
+ $ i = 0 ;
72
+
73
+ foreach ($ node ->all () as $ child ) {
74
+ if (++$ i === $ pick ) {
75
+ return $ child ;
76
+ }
77
+ }
78
+
79
+ return $ node ;
80
+ }
81
+ }
You can’t perform that action at this time.
0 commit comments