Completed
Push — master ( 254a9f...816248 )
by Romans
03:49 queued 03:44
created

Field_Reference::calculateSubQuery()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 22
rs 8.9197
cc 4
eloc 13
nc 6
nop 0
1
<?php
2
/**
3
 * Undocumented.
4
 */
5
class Field_Reference extends Field
6
{
7
    /** @var string */
8
    public $model_name = null;
9
10
    /** @var string */
11
    public $display_field = null;
12
13
    /** @var string */
14
    public $dereferenced_field = null;
15
16
    /** @var string */
17
    public $table_alias = null;
18
19
    /** @var Model */
20
    public $model;
21
22
23
24
    /**
25
     * Set model
26
     *
27
     * @param Model|string $model
28
     * @param string|bool $display_field
29
     *
30
     * @return Model|$this
31
     */
32
    public function setModel($model, $display_field = null)
33
    {
34
        if ($model instanceof Model) {
35
            return AbstractObject::setModel($model);
36
        }
37
38
        $this->model_name = is_string($model) ? $model : get_class($model);
39
        $this->model_name = (string) $this->app->normalizeClassName($this->model_name, 'Model');
40
41
        if ($display_field) {
42
            $this->display_field = (string) $display_field;
43
        }
44
45
        if ($display_field !== false) {
46
            $this->owner->addExpression($this->getDereferenced())
47
                ->set(array($this, 'calculateSubQuery'))->caption($this->caption());
48
        }
49
50
        $this->system(true);
51
        $this->editable(true);
52
        $this->visible(false);
53
54
        return $this;
55
    }
56
57
    /**
58
     * Return model of field
59
     *
60
     * @return Model
61
     */
62
    public function getModel()
63
    {
64
        if (!$this->model) {
65
            $this->model = $this->add($this->model_name);
66
        }
67
        if ($this->display_field) {
68
            $this->model->title_field = $this->display_field;
0 ignored issues
show
Bug introduced by
The property title_field does not seem to exist in AbstractObject.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
69
        }
70
        if ($this->table_alias) {
71
            $this->model->table_alias = $this->table_alias;
0 ignored issues
show
Bug introduced by
The property table_alias does not seem to exist in AbstractObject.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
72
        }
73
74
        return $this->model;
75
    }
76
77 View Code Duplication
    public function sortable($x = undefined)
78
    {
79
        /** @var Field|bool */
80
        $f = $this->owner->hasElement($this->getDereferenced());
81
        if ($f) {
82
            $f->sortable($x);
0 ignored issues
show
Documentation Bug introduced by
The method sortable does not exist on object<AbstractObject>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
83
        }
84
85
        return parent::sortable($x);
86
    }
87
88 View Code Duplication
    public function caption($x = undefined)
89
    {
90
        /** @var Field|bool */
91
        $f = $this->owner->hasElement($this->getDereferenced());
92
        if ($f) {
93
            $f->caption($x);
0 ignored issues
show
Documentation Bug introduced by
The method caption does not exist on object<AbstractObject>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
94
        }
95
96
        return parent::caption($x);
97
    }
98
99
    /**
100
     * ref() will traverse reference and will attempt to load related model's entry. If the entry will fail to load
101
     * it will return model which would not be loaded. This can be changed by specifying an argument:.
102
     *
103
     * 'model' - simply create new model and return it without loading anything
104
     * false or 'ignore' - will not even try to load anything
105
     * null (default) - will tryLoad()
106
     * 'load' - will always load the model and if record is not present, will fail
107
     * 'create' - if record fails to load, will create new record, save, get ID and insert into $this
108
     * 'link' - if record fails to load, will return new record, with appropriate afterSave hander, which will
109
     *          update current model also and save it too.
110
     *
111
     * @param string|bool|null $mode
112
     *
113
     * @return Model
114
     */
115
    public function ref($mode = null)
116
    {
117
        if ($mode == 'model') {
118
            return $this->add($this->model_name);
119
        }
120
121
        $this->getModel()->unload();
122
123
        if ($mode === false || $mode == 'ignore') {
124
            return $this->model;
125
        }
126
        if ($mode == 'load') {
127
            return $this->model->load($this->get());
128
        }
129
        if ($mode === null) {
130
            if ($this->get()) {
131
                $this->model->tryLoad($this->get());
132
            }
133
134
            return $this->model;
135
        }
136
        if ($mode == 'create') {
137
            if ($this->get()) {
138
                $this->model->tryLoad($this->get());
139
            }
140
            if (!$this->model->loaded()) {
141
                $this->model->save();
142
                $this->set($this->model->id);
143
                $this->owner->save();
144
145
                return $this->model;
146
            }
147
        }
148
        if ($mode == 'link') {
149
            /** @var Model */
150
            $m = $this->add($this->model_name);
151
            if ($this->get()) {
152
                $m->tryLoad($this->get());
0 ignored issues
show
Documentation Bug introduced by
The method tryLoad does not exist on object<AbstractObject>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
153
            }
154
            $t = $this;
155
            if (!$m->loaded()) {
0 ignored issues
show
Documentation Bug introduced by
The method loaded does not exist on object<AbstractObject>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
156
                $m->addHook('afterSave', function ($m) use ($t) {
157
                    $t->set($m->id);
158
                    $t->owner->saveLater();
159
                });
160
            }
161
162
            return $m;
163
        }
164
    }
165
166
    /**
167
     * Return DSQL for field
168
     *
169
     * @return SQL_Model
170
     */
171
    public function refSQL()
172
    {
173
        /** @var SQL_Model $q */
174
        $q = $this->ref('model');
175
        $q->addCondition($q->id_field, $this);
176
177
        return $q;
178
    }
179
180
    /**
181
     * Return name of dereferenced field
182
     *
183
     * @return string
184
     */
185
    public function getDereferenced()
186
    {
187
        if ($this->dereferenced_field) {
188
            return $this->dereferenced_field;
189
        }
190
        $f = preg_replace('/_id$/', '', $this->short_name);
191
        if ($f != $this->short_name) {
192
            return $f;
193
        }
194
195
        $f = $this->short_name.'_text';
196
        if ($this->owner->hasElement($f)) {
197
            return $f;
198
        }
199
200
        $f = $this->_unique($this->owner->elements, $f);
201
        $this->dereferenced_field = $f;
202
203
        return $f;
204
    }
205
206
    /**
207
     * Destroy this field and dereferenced field.
208
     *
209
     * @return $this
210
     */
211
    public function destroy()
212
    {
213
        if ($e = $this->owner->hasElement($this->getDereferenced())) {
214
            $e->destroy();
215
        }
216
217
        return parent::destroy();
218
    }
219
220
    /**
221
     * @return string
222
     */
223
    public function calculateSubQuery()
224
    {
225
        if (!$this->model) {
226
            $this->getModel(); //$this->model=$this->add($this->model_name);
227
        }
228
229
        if ($this->display_field) {
230
            /** @var SQL_Model $this->model */
231
            $title = $this->model->dsql()->del('fields');
232
            $this->model->getElement($this->display_field)->updateSelectQuery($title);
0 ignored issues
show
Documentation Bug introduced by
The method updateSelectQuery does not exist on object<AbstractObject>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
233
        } elseif ($this->model->hasMethod('titleQuery')) {
234
            /** @var SQL_Model $this->model */
235
            $title = $this->model->titleQuery();
236
        } else {
237
            // possibly references non-sql model, so just display field value
238
            return $this->owner->dsql()->bt($this->short_name);
239
        }
240
        $title->del('order')
241
            ->where($this, $title->getField($this->model->id_field));
242
243
        return $title;
244
    }
245
}
246