Completed
Push — develop-3.0 ( 5ab583...f20237 )
by Mohamed
06:33
created

ModelAbstract::factoryRepository()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 14
rs 8.8571
cc 5
eloc 8
nc 4
nop 1
1
<?php
2
3
/*
4
 * This file is part of the Tinyissue package.
5
 *
6
 * (c) Mohamed Alsharaf <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Tinyissue\Model;
13
14
use Illuminate\Database\Eloquent\Model;
15
use Tinyissue\Repository\Repository;
16
use Tinyissue\Repository\RepositoryUpdater;
17
18
/**
19
 * Class ModelAbstract
20
 *
21
 * @method \Illuminate\Support\Collection get()
22
 * @method int count()
23
 * @method \Illuminate\Support\Collection pluck($name, $key)
24
 * @method static orderBy($column, $direction = 'asc')
25
 * @method static select($columns = ['*'])
26
 * @method static where($key, $operator, $value = null)
27
 * @method static dropdown($text = 'name', $value = 'id')
28
 * @method static find($id, $columns = ['*'])
29
 * @method static whereIn($column, $values, $boolean = 'and', $not = false)
30
 */
31
abstract class ModelAbstract extends Model
32
{
33
    /**
34
     * @var RepositoryUpdater
35
     */
36
    protected $updater;
37
38
    /**
39
     * @var Repository
40
     */
41
    protected $counter;
42
43
    /**
44
     * @var Repository
45
     */
46
    protected $fetcher;
47
48
    /**
49
     * Factory method to instantiate a repository class based on a type.
50
     *
51
     * @param string $type
52
     *
53
     * @return Repository|RepositoryUpdater
54
     */
55
    protected function factoryRepository($type)
56
    {
57
        if (is_null($this->$type)) {
58
            $class = $this->getRepositoryClassName($type);
59
            if (class_exists($class)) {
60
                $this->$type = new $class($this);
61
                if (!$this->$type instanceof RepositoryUpdater && !$this->$type instanceof Repository) {
62
                    throw new \DomainException(sprintf('Unable to find the repository class "%s"', $class));
63
                }
64
            }
65
        }
66
67
        return $this->$type;
68
    }
69
70
    /**
71
     * Construct the repository class name for current model.
72
     *
73
     * @param string $type
74
     *
75
     * @return string
76
     */
77
    protected function getRepositoryClassName($type)
78
    {
79
        return str_replace(__NAMESPACE__, 'Tinyissue\\Repository', static::class) . '\\' . ucfirst($type);
80
    }
81
82
    /**
83
     * Get repository for updating / modifying data.
84
     *
85
     * @param User|null $user
86
     *
87
     * @return RepositoryUpdater
88
     */
89
    public function updater(User $user = null)
90
    {
91
        $this->factoryRepository('updater');
92
93
        if ($this->updater instanceof RepositoryUpdater) {
94
            $this->updater->setUser($user);
95
        }
96
97
        return $this->updater;
98
    }
99
100
    /**
101
     * get repository class for counting records.
102
     *
103
     * @return Repository
104
     */
105
    public function counter()
106
    {
107
        $this->factoryRepository('counter');
108
109
        return $this->counter;
110
    }
111
112
    /**
113
     * Get repository class for fetching data.
114
     *
115
     * @return Repository
116
     */
117
    public function fetcher()
118
    {
119
        $this->factoryRepository('fetcher');
120
121
        return $this->fetcher;
122
    }
123
124
    /**
125
     * Attempt to proxy the method call to other related classes if possible.
126
     *
127
     * @param string $name
128
     * @param array  $arguments
129
     *
130
     * @return mixed
131
     */
132
    public function __call($name, $arguments)
133
    {
134
        $collection = collect(['counter', 'fetcher', 'updater']);
135
136
        $caller = $collection->first(function ($type) use ($name) {
137
            $related = $this->$type();
138
139
            return !is_null($related) && method_exists($this->$type, $name);
140
        });
141
142
        if ($caller) {
143
            return $this->{$caller}->{$name}(...$arguments);
144
        }
145
146
        return parent::__call($name, $arguments);
147
    }
148
149
    /**
150
     * Return instance of the current class.
151
     *
152
     * @param array $attributes
153
     *
154
     * @return static
155
     */
156
    public static function instance(array $attributes = [])
157
    {
158
        $model = new static($attributes);
159
        $model->exists = false;
160
161
        return $model;
162
    }
163
164
    /**
165
     * Returns the aggregate value of a field.
166
     *
167
     * @param string $field
168
     *
169
     * @return int
170
     */
171
    protected function getCountAttribute($field)
172
    {
173
        // if relation is not loaded already, let's do it first
174
        if (!array_key_exists($field, $this->relations)) {
175
            $this->load($field);
176
        }
177
178
        $related = $this->getRelation($field);
179
180
        // then return the count directly
181
        return ($related) ? (int)$related->aggregate : 0;
182
    }
183
}
184