ElggRelationship::get()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 3
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Relationship class.
4
 *
5
 * @package    Elgg.Core
6
 * @subpackage Core
7
 * 
8
 * @property int    $id           The unique identifier (read-only)
9
 * @property int    $guid_one     The GUID of the subject of the relationship
10
 * @property string $relationship The type of the relationship (limit of 50 characters long)
11
 * @property int    $guid_two     The GUID of the target of the relationship
12
 * @property int    $time_created A UNIX timestamp of when the relationship was created (read-only, set on first save)
13
 */
14
class ElggRelationship extends \ElggData implements
15
	Importable // deprecated
0 ignored issues
show
Deprecated Code introduced by
The interface Importable has been deprecated with message: 1.9

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
16
{
17
	// database column limit
18
	const RELATIONSHIP_LIMIT = 50;
19
20
	/**
21
	 * Create a relationship object
22
	 *
23
	 * @param \stdClass $row Database row or null for new relationship
24
	 * @throws InvalidArgumentException
25
	 */
26
	public function __construct($row = null) {
27
		$this->initializeAttributes();
28
29
		if ($row === null) {
30
			elgg_deprecated_notice('Passing null to constructor is deprecated. Use add_entity_relationship()', 1.9);
31
			return;
32
		}
33
34
		if (!($row instanceof \stdClass)) {
35
			if (!is_numeric($row)) {
36
				throw new \InvalidArgumentException("Constructor accepts only a \stdClass or null.");
37
			}
38
39
			$id = (int)$row;
40
			elgg_deprecated_notice('Passing an ID to constructor is deprecated. Use get_relationship()', 1.9);
41
			$row = _elgg_get_relationship_row($id);
42
			if (!$row) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $row of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
43
				throw new \InvalidArgumentException("Relationship not found with ID $id");
44
			}
45
		}
46
47
		foreach ((array)$row as $key => $value) {
48
			$this->attributes[$key] = $value;
49
		}
50
51
		$this->attributes['id'] = (int)$this->attributes['id'];
52
	}
53
54
	/**
55
	 * (non-PHPdoc)
56
	 *
57
	 * @see \ElggData::initializeAttributes()
58
	 *
59
	 * @return void
60
	 */
61
	protected function initializeAttributes() {
62
		parent::initializeAttributes();
63
64
		$this->attributes['id'] = null;
65
		$this->attributes['guid_one'] = null;
66
		$this->attributes['relationship'] = null;
67
		$this->attributes['guid_two'] = null;
68
	}
69
70
	/**
71
	 * Set an attribute of the relationship
72
	 *
73
	 * @param string $name  Name
74
	 * @param mixed  $value Value
75
	 * @return void
76
	 */
77 1
	public function __set($name, $value) {
78 1
		$this->attributes[$name] = $value;
79 1
	}
80
81
	/**
82
	 * Class member set overloading
83
	 *
84
	 * @param string $name  Name
85
	 * @param mixed  $value Value
86
	 * @return mixed
87
	 * @deprecated 1.9
88
	 */
89
	public function set($name, $value) {
90
		elgg_deprecated_notice("Use -> instead of set()", 1.9);
91
		$this->__set($name, $value);
92
		return true;
93
	}
94
95
	/**
96
	 * Get an attribute of the relationship
97
	 *
98
	 * @param string $name Name
99
	 * @return mixed
100
	 */
101 2
	public function __get($name) {
102 2
		if (array_key_exists($name, $this->attributes)) {
103 1
			return $this->attributes[$name];
104
		}
105
106 1
		return null;
107
	}
108
	
109
	/**
110
	 * Class member get overloading
111
	 *
112
	 * @param string $name Name
113
	 * @return mixed
114
	 * @deprecated 1.9
115
	 */
116
	public function get($name) {
117
		elgg_deprecated_notice("Use -> instead of get()", 1.9);
118
		return $this->__get($name);
119
	}
120
121
	/**
122
	 * Save the relationship
123
	 *
124
	 * @return int the relationship ID
125
	 * @throws IOException
126
	 */
127
	public function save() {
128
		if ($this->id > 0) {
129
			delete_relationship($this->id);
130
		}
131
132
		$this->id = _elgg_services()->relationshipsTable->add(
133
			$this->guid_one,
134
			$this->relationship,
135
			$this->guid_two,
136
			true
137
		);
138
		if (!$this->id) {
139
			throw new \IOException("Unable to save new " . get_class());
140
		}
141
142
		return $this->id;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->id; of type integer|boolean adds the type integer to the return on line 142 which is incompatible with the return type declared by the abstract method ElggData::save of type boolean.
Loading history...
143
	}
144
145
	/**
146
	 * Delete this relationship from the database.
147
	 *
148
	 * @return bool
149
	 */
150
	public function delete() {
151
		return delete_relationship($this->id);
0 ignored issues
show
Bug introduced by
It seems like $this->id can also be of type boolean; however, delete_relationship() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug Compatibility introduced by
The expression delete_relationship($this->id); of type integer|false adds the type integer to the return on line 151 which is incompatible with the return type declared by the abstract method ElggData::delete of type boolean.
Loading history...
152
	}
153
154
	/**
155
	 * Get a URL for this relationship.
156
	 *
157
	 * Plugins can register for the 'relationship:url', 'relationship' plugin hook to
158
	 * customize the url for a relationship.
159
	 *
160
	 * @return string
161
	 */
162
	public function getURL() {
163
		$url = '';
164
		// @todo remove when elgg_register_relationship_url_handler() has been removed
165
		if ($this->id) {
166
			global $CONFIG;
167
168
			$subtype = $this->getSubtype();
169
170
			$function = "";
171
			if (isset($CONFIG->relationship_url_handler[$subtype])) {
172
				$function = $CONFIG->relationship_url_handler[$subtype];
173
			}
174
			if (isset($CONFIG->relationship_url_handler['all'])) {
175
				$function = $CONFIG->relationship_url_handler['all'];
176
			}
177
178
			if (is_callable($function)) {
179
				$url = call_user_func($function, $this);
180
			}
181
182
			if ($url) {
183
				$url = elgg_normalize_url($url);
184
			}
185
		}
186
187
		$type = $this->getType();
188
		$params = array('relationship' => $this);
189
		$url = _elgg_services()->hooks->trigger('relationship:url', $type, $params, $url);
190
191
		return elgg_normalize_url($url);
192
	}
193
194
	/**
195
	 * {@inheritdoc}
196
	 */
197
	public function toObject() {
198
		$object = new \stdClass();
199
		$object->id = $this->id;
200
		$object->subject_guid = $this->guid_one;
201
		$object->relationship = $this->relationship;
202
		$object->object_guid = $this->guid_two;
203
		$object->time_created = date('c', $this->getTimeCreated());
204
		$params = array('relationship' => $this);
205
		return _elgg_services()->hooks->trigger('to:object', 'relationship', $params, $object);
206
	}
207
208
	// EXPORTABLE INTERFACE ////////////////////////////////////////////////////////////
209
210
	/**
211
	 * Return an array of fields which can be exported.
212
	 *
213
	 * @return array
214
	 * @deprecated 1.9 Use toObject()
215
	 */
216
	public function getExportableValues() {
217
		elgg_deprecated_notice(__METHOD__ . ' has been deprecated by toObject()', 1.9);
218
		return array(
219
			'id',
220
			'guid_one',
221
			'relationship',
222
			'guid_two'
223
		);
224
	}
225
226
	/**
227
	 * Export this relationship
228
	 *
229
	 * @return array
230
	 * @deprecated 1.9 Use toObject()
231
	 */
232
	public function export() {
233
		elgg_deprecated_notice(__METHOD__ . ' has been deprecated', 1.9);
234
		$uuid = get_uuid_from_object($this);
235
		$relationship = new ODDRelationship(
0 ignored issues
show
Deprecated Code introduced by
The class ODDRelationship has been deprecated with message: 1.9

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
236
			guid_to_uuid($this->guid_one),
237
			$this->relationship,
238
			guid_to_uuid($this->guid_two)
239
		);
240
241
		$relationship->setAttribute('uuid', $uuid);
242
243
		return $relationship;
244
	}
245
246
	// IMPORTABLE INTERFACE ////////////////////////////////////////////////////////////
247
248
	/**
249
	 * Import a relationship
250
	 *
251
	 * @param ODD $data ODD data
252
253
	 * @return bool
254
	 * @throws ImportException|InvalidParameterException
255
	 * @deprecated 1.9
256
	 */
257
	public function import(ODD $data) {
258
		elgg_deprecated_notice(__METHOD__ . ' has been deprecated', 1.9);
259
		if (!($data instanceof ODDRelationship)) {
260
			throw new \InvalidParameterException("import() passed an unexpected ODD class");
261
		}
262
263
		$uuid_one = $data->getAttribute('uuid1');
264
		$uuid_two = $data->getAttribute('uuid2');
265
266
		// See if this entity has already been imported, if so then we need to link to it
267
		$entity1 = get_entity_from_uuid($uuid_one);
268
		$entity2 = get_entity_from_uuid($uuid_two);
269
		if (($entity1) && ($entity2)) {
270
			// Set the item ID
271
			$this->attributes['guid_one'] = $entity1->getGUID();
272
			$this->attributes['guid_two'] = $entity2->getGUID();
273
274
			// Map verb to relationship
275
			//$verb = $data->getAttribute('verb');
276
			//$relationship = get_relationship_from_verb($verb);
277
			$relationship = $data->getAttribute('type');
278
279
			if ($relationship) {
280
				$this->attributes['relationship'] = $relationship;
281
				// save
282
				$result = $this->save();
283
				if (!$result) {
284
					throw new \ImportException("There was a problem saving " . get_class());
0 ignored issues
show
Deprecated Code introduced by
The class ImportException has been deprecated with message: 1.9

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
285
				}
286
287
				return true;
288
			}
289
		}
290
291
		return false;
292
	}
293
294
	// SYSTEM LOG INTERFACE ////////////////////////////////////////////////////////////
295
296
	/**
297
	 * Return an identification for the object for storage in the system log.
298
	 * This id must be an integer.
299
	 *
300
	 * @return int
301
	 */
302
	public function getSystemLogID() {
303
		return $this->id;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->id; of type integer|boolean adds the type boolean to the return on line 303 which is incompatible with the return type declared by the interface Loggable::getSystemLogID of type integer.
Loading history...
304
	}
305
306
	/**
307
	 * For a given ID, return the object associated with it.
308
	 * This is used by the river functionality primarily.
309
	 * This is useful for checking access permissions etc on objects.
310
	 *
311
	 * @param int $id ID
312
	 *
313
	 * @return \ElggRelationship
314
	 */
315
	public function getObjectFromID($id) {
316
		return get_relationship($id);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return get_relationship($id); (false|ElggRelationship) is incompatible with the return type declared by the interface Loggable::getObjectFromID of type ElggEntity.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
317
	}
318
319
	/**
320
	 * Return a type of the object - eg. object, group, user, relationship, metadata, annotation etc
321
	 *
322
	 * @return string 'relationship'
323
	 */
324
	public function getType() {
325
		return 'relationship';
326
	}
327
328
	/**
329
	 * Return a subtype. For metadata & annotations this is the 'name' and for relationship this
330
	 * is the relationship type.
331
	 *
332
	 * @return string
333
	 */
334
	public function getSubtype() {
335
		return $this->relationship;
336
	}
337
}
338