Completed
Push — develop ( 7d6742...1c56f4 )
by John
02:09
created

RelationLookup::loadAllByAttributes()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 28
rs 9.1608
cc 5
nc 6
nop 7

2 Methods

Rating   Name   Duplication   Size   Complexity  
A RelationLookup::setHelper() 0 4 1
A RelationLookup::getValue() 0 4 1
1
<?php
2
3
namespace Alpha\Model\Type;
4
5
use Alpha\Model\ActiveRecord;
6
use Alpha\Util\Service\ServiceFactory;
7
use Alpha\Exception\FailedLookupCreateException;
8
use Alpha\Exception\IllegalArguementException;
9
use Alpha\Exception\AlphaException;
10
use Alpha\Util\Config\ConfigProvider;
11
use Alpha\Util\Logging\Logger;
12
use ReflectionClass;
13
14
/**
15
 * The RelationLookup complex data type.  Used to store object2object lookup tables for
16
 * MANY-TO-MANY relationships between record objects.
17
 *
18
 * @since 1.0
19
 *
20
 * @author John Collins <[email protected]>
21
 * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
22
 * @copyright Copyright (c) 2019, John Collins (founder of Alpha Framework).
23
 * All rights reserved.
24
 *
25
 * <pre>
26
 * Redistribution and use in source and binary forms, with or
27
 * without modification, are permitted provided that the
28
 * following conditions are met:
29
 *
30
 * * Redistributions of source code must retain the above
31
 *   copyright notice, this list of conditions and the
32
 *   following disclaimer.
33
 * * Redistributions in binary form must reproduce the above
34
 *   copyright notice, this list of conditions and the
35
 *   following disclaimer in the documentation and/or other
36
 *   materials provided with the distribution.
37
 * * Neither the name of the Alpha Framework nor the names
38
 *   of its contributors may be used to endorse or promote
39
 *   products derived from this software without specific
40
 *   prior written permission.
41
 *
42
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
43
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
44
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
45
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
46
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
47
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
49
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
50
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
53
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
54
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55
 * </pre>
56
 */
57
class RelationLookup extends ActiveRecord implements TypeInterface
58
{
59
    /**
60
     * The ID of the left business object in the relation.
61
     *
62
     * @var \Alpha\Model\Type\Integer
63
     *
64
     * @since 1.0
65
     */
66
    protected $leftID;
67
68
    /**
69
     * The ID of the right business object in the relation.
70
     *
71
     * @var \Alpha\Model\Type\Integer
72
     *
73
     * @since 1.0
74
     */
75
    protected $rightID;
76
77
    /**
78
     * The name of the left business object class in the relation.
79
     *
80
     * @var string
81
     *
82
     * @since 1.0
83
     */
84
    private $leftClassName;
85
86
    /**
87
     * The name of the right business object class in the relation.
88
     *
89
     * @var string
90
     *
91
     * @since 1.0
92
     */
93
    private $rightClassName;
94
95
    /**
96
     * Trace logger.
97
     *
98
     * @var \Alpha\Util\Logging\Logger
99
     *
100
     * @since 1.0
101
     */
102
    private static $logger = null;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
103
104
    /**
105
     * an array of data display labels for the class properties.
106
     *
107
     * @var array
108
     *
109
     * @since 1.0
110
     */
111
    protected $dataLabels = array('ID' => 'RelationLookup ID#', 'leftID' => 'Left Record ID#', 'rightID' => 'Right Record ID#');
112
113
    /**
114
     * The message to display to the user when validation fails.
115
     *
116
     * @var string
117
     *
118
     * @since 1.0
119
     */
120
    protected $helper = 'Not a valid RelationLookup value!';
121
122
    /**
123
     * The constructor.
124
     *
125
     * @throws \Alpha\Exception\FailedLookupCreateException
126
     * @throws \Alpha\Exception\IllegalArguementException
127
     *
128
     * @since 1.0
129
     */
130
    public function __construct($leftClassName, $rightClassName)
131
    {
132
        self::$logger = new Logger('RelationLookup');
133
        self::$logger->debug('>>__construct(leftClassName=['.$leftClassName.'], rightClassName=['.$rightClassName.'])');
134
135
        // ensure to call the parent constructor
136
        parent::__construct();
137
138
        if (empty($leftClassName) || empty($rightClassName)) {
139
            throw new IllegalArguementException('Cannot create RelationLookup object without providing the left and right class names!');
140
        }
141
142
        $this->leftClassName = $leftClassName;
143
        $this->rightClassName = $rightClassName;
144
145
        $this->leftID = new Integer();
146
        $this->rightID = new Integer();
147
148
        $this->markTransient('leftClassName');
149
        $this->markTransient('rightClassName');
150
        $this->markTransient('helper');
151
        $this->markTransient('TABLE_NAME');
152
153
        // add a unique composite key to these fields
154
        $this->markUnique('leftID', 'rightID');
155
156
        // make sure the lookup table exists
157
        if (!$this->checkTableExists() && ActiveRecord::isInstalled()) {
158
            // first make sure that the two Record tables exist before relating them with a lookup table
159
            if (ActiveRecord::checkRecordTableExists($leftClassName) && ActiveRecord::checkRecordTableExists($rightClassName)) {
160
                $this->makeTable();
161
            } else {
162
                throw new FailedLookupCreateException('Error trying to create a lookup table ['.$this->getTableName().'], as tables for records ['.$leftClassName.'] or ['.$rightClassName.'] don\'t exist!');
163
            }
164
        }
165
166
        self::$logger->debug('<<__construct');
167
    }
168
169
    /**
170
     * Get the leftClassName value.
171
     *
172
     * @return string
173
     *
174
     * @since 1.0
175
     */
176
    public function getLeftClassName()
177
    {
178
        return $this->leftClassName;
179
    }
180
181
    /**
182
     * Get the rightClassName value.
183
     *
184
     * @return string
185
     *
186
     * @since 1.0
187
     */
188
    public function getRightClassName()
189
    {
190
        return $this->rightClassName;
191
    }
192
193
    /**
194
     * Custom getter for the TABLE_NAME, which can't be static in this class due to
195
     * the lookup tablenames being different each time.
196
     *
197
     * @return string
198
     *
199
     * @since 1.0
200
     *
201
     * @throws \Alpha\Exception\AlphaException
202
     */
203
    public function getTableName()
204
    {
205
        if (isset($this->leftClassName) && isset($this->rightClassName)) {
206
            $leftClass = new ReflectionClass($this->leftClassName);
207
            $left = $leftClass->getShortname();
208
            $rightClass = new ReflectionClass($this->rightClassName);
209
            $right = $rightClass->getShortname();
210
            self::$logger->debug('Setting table name to ['.$left.'2'.$right.']');
211
212
            return $left.'2'.$right;
213
        } else {
214
            throw new AlphaException('No table name set for the class ['.get_class($this).'], left or right class name(s) missing');
215
        }
216
    }
217
218
    /**
219
     * This custom version provides the left/right class names to the business object constructor, required
220
     * for RelationLookup objects.
221
     *
222
     * (non-PHPdoc)
223
     *
224
     * @see Alpha\Model\ActiveRecord::loadAllByAttribute()
225
     */
226
    public function loadAllByAttribute($attribute, $value, $start = 0, $limit = 0, $orderBy = 'ID', $order = 'ASC', $ignoreClassType = false, $constructorArgs = array())
227
    {
228
        if (!isset(self::$logger)) {
229
            self::$logger = new Logger('RelationLookup');
230
        }
231
232
        self::$logger->debug('>>loadAllByAttribute(attribute=['.$attribute.'], value=['.$value.'], start=['.$start.'], limit=['.$limit.'], orderBy=['.$orderBy.'], order=['.$order.'], ignoreClassType=['.$ignoreClassType.'], constructorArgs=['.print_r($constructorArgs, true).']');
233
234
        if (method_exists($this, 'before_loadAllByAttribute_callback')) {
235
            $this->{'before_loadAllByAttribute_callback'}();
236
        }
237
238
        $config = ConfigProvider::getInstance();
239
240
        $provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface');
241
        $provider->setRecord($this);
242
        $objects = $provider->loadAllByAttribute($attribute, $value, $start, $limit, $orderBy, $order, $ignoreClassType, array($this->leftClassName, $this->rightClassName));
243
244
        if (method_exists($this, 'after_loadAllByAttribute_callback')) {
245
            $this->{'after_loadAllByAttribute_callback'}();
246
        }
247
248
        self::$logger->debug('<<loadAllByAttribute ['.count($objects).']');
249
250
        return $objects;
251
    }
252
253
    /**
254
     * Getter for the validation helper string.
255
     *
256
     * @return string
257
     *
258
     * @since 1.0
259
     */
260
    public function getHelper()
261
    {
262
        return $this->helper;
263
    }
264
265
    /**
266
     * Set the validation helper text.
267
     *
268
     * @param string $helper
269
     *
270
     * @since 1.0
271
     */
272
    public function setHelper($helper)
273
    {
274
        $this->helper = $helper;
275
    }
276
277
    /**
278
     * Returns an array of the IDs of the related objects.
279
     *
280
     * @return integer[]
281
     *
282
     * @since 1.0
283
     */
284
    public function getValue()
285
    {
286
        return array($this->leftID->getValue(), $this->rightID->getValue());
287
    }
288
289
    /**
290
     * Used to set the IDs of the related objects.  Pass a two-item array of IDs, the first
291
     * one being the left object ID, the second being the right.
292
     *
293
     * @param string[] $IDs
294
     *
295
     * @since 1.0
296
     *
297
     * @throws \Alpha\Exception\IllegalArguementException
298
     */
299
    public function setValue($IDs)
300
    {
301
        try {
302
            $this->leftID->setValue($IDs[0]);
303
            $this->rightID->setValue($IDs[1]);
304
        } catch (\Exception $e) {
305
            throw new IllegalArguementException('Array value passed to setValue is not valid ['.var_export($IDs, true).'], array should contain two IDs');
306
        }
307
    }
308
309
    /**
310
     * Used to convert the object to a printable string.
311
     *
312
     * @return string
313
     *
314
     * @since 1.0
315
     */
316
    public function __toString()
317
    {
318
        return strval($this->getTableName());
319
    }
320
}
321