findSupportingModelFactoryForObject()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 3
nc 3
nop 1
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Xsolve\ModelFactory\ModelFactoryCollection;
4
5
use Traversable;
6
use Xsolve\ModelFactory\ModelFactory\ModelFactoryInterface;
7
use Xsolve\ModelFactory\ModelFactoryCollection\Exception\ModelFactoryCollectionException;
8
9
class ModelFactoryCollection implements ModelFactoryCollectionInterface
10
{
11
    /** @var ModelFactoryInterface[] */
12
    protected $modelFactories = [];
13
14
    /**
15
     * {@inheritdoc}
16
     */
17
    public function addModelFactory(ModelFactoryInterface $modelFactory)
18
    {
19
        $this->modelFactories[] = $modelFactory;
20
21
        return $this;
22
    }
23
24
    /**
25
     * {@inheritdoc}
26
     */
27
    public function supportsObject($object)
28
    {
29
        return $this->findSupportingModelFactoryForObject($object) instanceof ModelFactoryInterface;
30
    }
31
32
    /**
33
     * {@inheritdoc}
34
     */
35
    public function supportsObjects($objects)
36
    {
37
        if ($objects instanceof Traversable) {
38
            $objects = iterator_to_array($objects);
39
        } elseif (!is_array($objects)) {
40
            throw new ModelFactoryCollectionException('An array or an instance of Traversable expected.');
41
        }
42
43
        if ($this->findSupportingModelFactoryForObjects($objects) instanceof ModelFactoryInterface) {
44
            return true;
45
        }
46
47
        foreach ($objects as $object) {
48
            if (!$this->supportsObject($object)) {
49
                return false;
50
            }
51
        }
52
53
        return true;
54
    }
55
56
    /**
57
     * {@inheritdoc}
58
     */
59
    public function createModels($objects)
60
    {
61
        if (!$objects instanceof Traversable && !is_array($objects)) {
62
            throw new ModelFactoryCollectionException('An array or an instance of Traversable expected.');
63
        }
64
65
        // First try to find a single model factory supporting all items.
66
        $modelFactory = $this->findSupportingModelFactoryForObjects($objects);
67
        if ($modelFactory instanceof ModelFactoryInterface) {
68
            return $this->createModelsAndSetDependencies($modelFactory, $objects);
69
        }
70
71
        // If that fails, try to find model factory for each item individually.
72
        $models = [];
73
        foreach ($objects as $key => $object) {
74
            $modelFactory = $this->findSupportingModelFactoryForObject($object);
75
            if (!$modelFactory instanceof ModelFactoryInterface) {
76
                if (is_object($object)) {
77
                    throw new ModelFactoryCollectionException(sprintf(
78
                        'Model factory for class %s not found.',
79
                        get_class($object)
80
                    ));
81
                }
82
                
83
                throw new ModelFactoryCollectionException(sprintf(
84
                    'Model factory for type %s not found.',
85
                    gettype($object)
86
                ));
87
            }
88
            $models[$key] = $this->createModelAndSetDependencies($modelFactory, $object);
89
        }
90
91
        return $models;
92
    }
93
94
    /**
95
     * {@inheritdoc}
96
     */
97
    public function createModel($object)
98
    {
99
        $models = $this->createModels([$object]);
100
101
        return reset($models);
102
    }
103
104
    /**
105
     * @param ModelFactoryInterface $modelFactory
106
     * @param array|Traversable     $objects
107
     *
108
     * @return array
109
     */
110
    protected function createModelsAndSetDependencies(ModelFactoryInterface $modelFactory, $objects)
111
    {
112
        $models = $modelFactory->createModels($objects);
113
        foreach ($models as $model) {
114
            if ($model instanceof ModelFactoryCollectionAwareModelInterface) {
115
                $model->setModelFactoryCollection($this);
116
            }
117
        }
118
119
        return $models;
120
    }
121
122
    /**
123
     * @param ModelFactoryInterface $modelFactory
124
     * @param mixed                 $object
125
     *
126
     * @return mixed
127
     */
128
    protected function createModelAndSetDependencies(ModelFactoryInterface $modelFactory, $object)
129
    {
130
        $models = $this->createModelsAndSetDependencies($modelFactory, [$object]);
131
132
        return reset($models);
133
    }
134
135
    /**
136
     * @param array|Traversable $objects
137
     *
138
     * @return ModelFactoryInterface|null
139
     */
140
    protected function findSupportingModelFactoryForObjects($objects)
141
    {
142
        foreach ($this->modelFactories as $modelFactory) {
143
            if ($modelFactory->supportsObjects($objects)) {
144
                return $modelFactory;
145
            }
146
        }
147
    }
148
149
    /**
150
     * @param mixed $object
151
     *
152
     * @return ModelFactoryInterface|null
153
     */
154
    protected function findSupportingModelFactoryForObject($object)
155
    {
156
        foreach ($this->modelFactories as $modelFactory) {
157
            if ($modelFactory->supportsObject($object)) {
158
                return $modelFactory;
159
            }
160
        }
161
    }
162
}
163