Completed
Branch develop-3.0 (3cc72c)
by Mohamed
03:32
created

ModelAbstract   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 157
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
wmc 21
c 0
b 0
f 0
lcom 1
cbo 2
dl 0
loc 157
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
B factoryRepository() 0 14 5
A getRepositoryClassName() 0 4 1
A updater() 0 10 2
A counter() 0 6 1
A fetcher() 0 6 1
C __call() 0 22 7
A instance() 0 7 1
A getCountAttribute() 0 12 3
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
     * @param string $type
72
     *
73
     * @return string
74
     */
75
    protected function getRepositoryClassName($type)
76
    {
77
        return str_replace(__NAMESPACE__, 'Tinyissue\\Repository', static::class) . '\\' . ucfirst($type);
78
    }
79
80
    /**
81
     * Get repository for updating / modifying data.
82
     *
83
     * @param User|null $user
84
     *
85
     * @return RepositoryUpdater
86
     */
87
    public function updater(User $user = null)
88
    {
89
        $this->factoryRepository('updater');
90
91
        if ($this->updater instanceof RepositoryUpdater) {
92
            $this->updater->setUser($user);
93
        }
94
95
        return $this->updater;
96
    }
97
98
    /**
99
     * get repository class for counting records.
100
     *
101
     * @return Repository
102
     */
103
    public function counter()
104
    {
105
        $this->factoryRepository('counter');
106
107
        return $this->counter;
108
    }
109
110
    /**
111
     * Get repository class for fetching data.
112
     *
113
     * @return Repository
114
     */
115
    public function fetcher()
116
    {
117
        $this->factoryRepository('fetcher');
118
119
        return $this->fetcher;
120
    }
121
122
    /**
123
     * Attempt to proxy the method call to other related classes if possible.
124
     *
125
     * @param string $name
126
     * @param array  $arguments
127
     *
128
     * @return mixed
129
     */
130
    public function __call($name, $arguments)
131
    {
132
        $caller = false;
133
134
        if (strpos($name, 'count') === 0) {
135
            $caller = $this->counter();
136
        }
137
138
        if (strpos($name, 'get') === 0) {
139
            $caller = $this->fetcher();
140
        }
141
142
        if (!is_null($this->updater()) && method_exists($this->updater, $name)) {
143
            $caller = $this->updater();
144
        }
145
146
        if (false !== $caller && method_exists($caller, $name)) {
147
            return $caller->{$name}(...$arguments);
148
        }
149
150
        return parent::__call($name, $arguments);
151
    }
152
153
    /**
154
     * Return instance of the current class.
155
     *
156
     * @param array $attributes
157
     *
158
     * @return static
159
     */
160
    public static function instance(array $attributes = [])
161
    {
162
        $model = new static($attributes);
163
        $model->exists = false;
164
165
        return $model;
166
    }
167
168
    /**
169
     * Returns the aggregate value of a field.
170
     *
171
     * @param string $field
172
     *
173
     * @return int
174
     */
175
    protected function getCountAttribute($field)
176
    {
177
        // if relation is not loaded already, let's do it first
178
        if (!array_key_exists($field, $this->relations)) {
179
            $this->load($field);
180
        }
181
182
        $related = $this->getRelation($field);
183
184
        // then return the count directly
185
        return ($related) ? (int)$related->aggregate : 0;
186
    }
187
}
188