Passed
Push — master ( ca958d...132f84 )
by Blizzz
41:56 queued 29:27
created
apps/dav/lib/CardDAV/AddressBookImpl.php 2 patches
Indentation   +306 added lines, -306 removed lines patch added patch discarded remove patch
@@ -42,310 +42,310 @@
 block discarded – undo
42 42
 
43 43
 class AddressBookImpl implements IAddressBook {
44 44
 
45
-	/** @var CardDavBackend */
46
-	private $backend;
47
-
48
-	/** @var array */
49
-	private $addressBookInfo;
50
-
51
-	/** @var AddressBook */
52
-	private $addressBook;
53
-
54
-	/** @var IURLGenerator */
55
-	private $urlGenerator;
56
-
57
-	/**
58
-	 * AddressBookImpl constructor.
59
-	 *
60
-	 * @param AddressBook $addressBook
61
-	 * @param array $addressBookInfo
62
-	 * @param CardDavBackend $backend
63
-	 * @param IUrlGenerator $urlGenerator
64
-	 */
65
-	public function __construct(
66
-			AddressBook $addressBook,
67
-			array $addressBookInfo,
68
-			CardDavBackend $backend,
69
-			IURLGenerator $urlGenerator) {
70
-		$this->addressBook = $addressBook;
71
-		$this->addressBookInfo = $addressBookInfo;
72
-		$this->backend = $backend;
73
-		$this->urlGenerator = $urlGenerator;
74
-	}
75
-
76
-	/**
77
-	 * @return string defining the technical unique key
78
-	 * @since 5.0.0
79
-	 */
80
-	public function getKey() {
81
-		return $this->addressBookInfo['id'];
82
-	}
83
-
84
-	/**
85
-	 * @return string defining the unique uri
86
-	 * @since 16.0.0
87
-	 */
88
-	public function getUri(): string {
89
-		return $this->addressBookInfo['uri'];
90
-	}
91
-
92
-	/**
93
-	 * In comparison to getKey() this function returns a human readable (maybe translated) name
94
-	 *
95
-	 * @return mixed
96
-	 * @since 5.0.0
97
-	 */
98
-	public function getDisplayName() {
99
-		return $this->addressBookInfo['{DAV:}displayname'];
100
-	}
101
-
102
-	/**
103
-	 * @param string $pattern which should match within the $searchProperties
104
-	 * @param array $searchProperties defines the properties within the query pattern should match
105
-	 * @param array $options Options to define the output format and search behavior
106
-	 * 	- 'types' boolean (since 15.0.0) If set to true, fields that come with a TYPE property will be an array
107
-	 *    example: ['id' => 5, 'FN' => 'Thomas Tanghus', 'EMAIL' => ['type => 'HOME', 'value' => '[email protected]']]
108
-	 * 	- 'escape_like_param' - If set to false wildcards _ and % are not escaped
109
-	 * 	- 'limit' - Set a numeric limit for the search results
110
-	 * 	- 'offset' - Set the offset for the limited search results
111
-	 * 	- 'wildcard' - Whether the search should use wildcards
112
-	 * @psalm-param array{types?: bool, escape_like_param?: bool, limit?: int, offset?: int, wildcard?: bool} $options
113
-	 * @return array an array of contacts which are arrays of key-value-pairs
114
-	 *  example result:
115
-	 *  [
116
-	 *		['id' => 0, 'FN' => 'Thomas Müller', 'EMAIL' => '[email protected]', 'GEO' => '37.386013;-122.082932'],
117
-	 *		['id' => 5, 'FN' => 'Thomas Tanghus', 'EMAIL' => ['[email protected]', '[email protected]']]
118
-	 *	]
119
-	 * @since 5.0.0
120
-	 */
121
-	public function search($pattern, $searchProperties, $options) {
122
-		$results = $this->backend->search($this->getKey(), $pattern, $searchProperties, $options);
123
-
124
-		$withTypes = \array_key_exists('types', $options) && $options['types'] === true;
125
-
126
-		$vCards = [];
127
-		foreach ($results as $result) {
128
-			$vCards[] = $this->vCard2Array($result['uri'], $this->readCard($result['carddata']), $withTypes);
129
-		}
130
-
131
-		return $vCards;
132
-	}
133
-
134
-	/**
135
-	 * @param array $properties this array if key-value-pairs defines a contact
136
-	 * @return array an array representing the contact just created or updated
137
-	 * @since 5.0.0
138
-	 */
139
-	public function createOrUpdate($properties) {
140
-		$update = false;
141
-		if (!isset($properties['URI'])) { // create a new contact
142
-			$uid = $this->createUid();
143
-			$uri = $uid . '.vcf';
144
-			$vCard = $this->createEmptyVCard($uid);
145
-		} else { // update existing contact
146
-			$uri = $properties['URI'];
147
-			$vCardData = $this->backend->getCard($this->getKey(), $uri);
148
-			$vCard = $this->readCard($vCardData['carddata']);
149
-			$update = true;
150
-		}
151
-
152
-		foreach ($properties as $key => $value) {
153
-			if (is_array($value)) {
154
-				$vCard->remove($key);
155
-				foreach ($value as $entry) {
156
-					if (is_string($entry)) {
157
-						$property = $vCard->createProperty($key, $entry);
158
-					} else {
159
-						if (($key === "ADR" || $key === "PHOTO") && is_string($entry["value"])) {
160
-							$entry["value"] = stripslashes($entry["value"]);
161
-							$entry["value"] = explode(';', $entry["value"]);
162
-						}
163
-						$property = $vCard->createProperty($key, $entry["value"]);
164
-						if (isset($entry["type"])) {
165
-							$property->add('TYPE', $entry["type"]);
166
-						}
167
-					}
168
-					$vCard->add($property);
169
-				}
170
-			} elseif ($key !== 'URI') {
171
-				$vCard->$key = $vCard->createProperty($key, $value);
172
-			}
173
-		}
174
-
175
-		if ($update) {
176
-			$this->backend->updateCard($this->getKey(), $uri, $vCard->serialize());
177
-		} else {
178
-			$this->backend->createCard($this->getKey(), $uri, $vCard->serialize());
179
-		}
180
-
181
-		return $this->vCard2Array($uri, $vCard);
182
-	}
183
-
184
-	/**
185
-	 * @return mixed
186
-	 * @since 5.0.0
187
-	 */
188
-	public function getPermissions() {
189
-		$permissions = $this->addressBook->getACL();
190
-		$result = 0;
191
-		foreach ($permissions as $permission) {
192
-			switch ($permission['privilege']) {
193
-				case '{DAV:}read':
194
-					$result |= Constants::PERMISSION_READ;
195
-					break;
196
-				case '{DAV:}write':
197
-					$result |= Constants::PERMISSION_CREATE;
198
-					$result |= Constants::PERMISSION_UPDATE;
199
-					break;
200
-				case '{DAV:}all':
201
-					$result |= Constants::PERMISSION_ALL;
202
-					break;
203
-			}
204
-		}
205
-
206
-		return $result;
207
-	}
208
-
209
-	/**
210
-	 * @param int $id the unique identifier to a contact
211
-	 * @return bool successful or not
212
-	 * @since 5.0.0
213
-	 */
214
-	public function delete($id) {
215
-		$uri = $this->backend->getCardUri($id);
216
-		return $this->backend->deleteCard($this->addressBookInfo['id'], $uri);
217
-	}
218
-
219
-	/**
220
-	 * read vCard data into a vCard object
221
-	 *
222
-	 * @param string $cardData
223
-	 * @return VCard
224
-	 */
225
-	protected function readCard($cardData) {
226
-		return  Reader::read($cardData);
227
-	}
228
-
229
-	/**
230
-	 * create UID for contact
231
-	 *
232
-	 * @return string
233
-	 */
234
-	protected function createUid() {
235
-		do {
236
-			$uid = $this->getUid();
237
-			$contact = $this->backend->getContact($this->getKey(), $uid . '.vcf');
238
-		} while (!empty($contact));
239
-
240
-		return $uid;
241
-	}
242
-
243
-	/**
244
-	 * getUid is only there for testing, use createUid instead
245
-	 */
246
-	protected function getUid() {
247
-		return UUIDUtil::getUUID();
248
-	}
249
-
250
-	/**
251
-	 * create empty vcard
252
-	 *
253
-	 * @param string $uid
254
-	 * @return VCard
255
-	 */
256
-	protected function createEmptyVCard($uid) {
257
-		$vCard = new VCard();
258
-		$vCard->UID = $uid;
259
-		return $vCard;
260
-	}
261
-
262
-	/**
263
-	 * create array with all vCard properties
264
-	 *
265
-	 * @param string $uri
266
-	 * @param VCard $vCard
267
-	 * @param boolean $withTypes (optional) return the values as arrays of value/type pairs
268
-	 * @return array
269
-	 */
270
-	protected function vCard2Array($uri, VCard $vCard, $withTypes = false) {
271
-		$result = [
272
-			'URI' => $uri,
273
-		];
274
-
275
-		foreach ($vCard->children() as $property) {
276
-			if ($property->name === 'PHOTO' && in_array($property->getValueType(), ['BINARY', 'URI'])) {
277
-				$url = $this->urlGenerator->getAbsoluteURL(
278
-					$this->urlGenerator->linkTo('', 'remote.php') . '/dav/');
279
-				$url .= implode('/', [
280
-					'addressbooks',
281
-					substr($this->addressBookInfo['principaluri'], 11), //cut off 'principals/'
282
-					$this->addressBookInfo['uri'],
283
-					$uri
284
-				]) . '?photo';
285
-
286
-				$result['PHOTO'] = 'VALUE=uri:' . $url;
287
-			} elseif (in_array($property->name, ['URL', 'GEO', 'CLOUD', 'ADR', 'EMAIL', 'IMPP', 'TEL', 'X-SOCIALPROFILE', 'RELATED', 'LANG', 'X-ADDRESSBOOKSERVER-MEMBER'])) {
288
-				if (!isset($result[$property->name])) {
289
-					$result[$property->name] = [];
290
-				}
291
-
292
-				$type = $this->getTypeFromProperty($property);
293
-				if ($withTypes) {
294
-					$result[$property->name][] = [
295
-						'type' => $type,
296
-						'value' => $property->getValue()
297
-					];
298
-				} else {
299
-					$result[$property->name][] = $property->getValue();
300
-				}
301
-			} else {
302
-				$result[$property->name] = $property->getValue();
303
-			}
304
-		}
305
-
306
-		if ($this->isSystemAddressBook()) {
307
-			$result['isLocalSystemBook'] = true;
308
-		}
309
-		return $result;
310
-	}
311
-
312
-	/**
313
-	 * Get the type of the current property
314
-	 *
315
-	 * @param Property $property
316
-	 * @return null|string
317
-	 */
318
-	protected function getTypeFromProperty(Property $property) {
319
-		$parameters = $property->parameters();
320
-		// Type is the social network, when it's empty we don't need this.
321
-		if (isset($parameters['TYPE'])) {
322
-			/** @var \Sabre\VObject\Parameter $type */
323
-			$type = $parameters['TYPE'];
324
-			return $type->getValue();
325
-		}
326
-
327
-		return null;
328
-	}
329
-
330
-	/**
331
-	 * @inheritDoc
332
-	 */
333
-	public function isShared(): bool {
334
-		if (!isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) {
335
-			return false;
336
-		}
337
-
338
-		return $this->addressBookInfo['principaluri']
339
-			!== $this->addressBookInfo['{http://owncloud.org/ns}owner-principal'];
340
-	}
341
-
342
-	/**
343
-	 * @inheritDoc
344
-	 */
345
-	public function isSystemAddressBook(): bool {
346
-		return $this->addressBookInfo['principaluri'] === 'principals/system/system' && (
347
-			$this->addressBookInfo['uri'] === 'system' ||
348
-			$this->addressBookInfo['{DAV:}displayname'] === $this->urlGenerator->getBaseUrl()
349
-		);
350
-	}
45
+    /** @var CardDavBackend */
46
+    private $backend;
47
+
48
+    /** @var array */
49
+    private $addressBookInfo;
50
+
51
+    /** @var AddressBook */
52
+    private $addressBook;
53
+
54
+    /** @var IURLGenerator */
55
+    private $urlGenerator;
56
+
57
+    /**
58
+     * AddressBookImpl constructor.
59
+     *
60
+     * @param AddressBook $addressBook
61
+     * @param array $addressBookInfo
62
+     * @param CardDavBackend $backend
63
+     * @param IUrlGenerator $urlGenerator
64
+     */
65
+    public function __construct(
66
+            AddressBook $addressBook,
67
+            array $addressBookInfo,
68
+            CardDavBackend $backend,
69
+            IURLGenerator $urlGenerator) {
70
+        $this->addressBook = $addressBook;
71
+        $this->addressBookInfo = $addressBookInfo;
72
+        $this->backend = $backend;
73
+        $this->urlGenerator = $urlGenerator;
74
+    }
75
+
76
+    /**
77
+     * @return string defining the technical unique key
78
+     * @since 5.0.0
79
+     */
80
+    public function getKey() {
81
+        return $this->addressBookInfo['id'];
82
+    }
83
+
84
+    /**
85
+     * @return string defining the unique uri
86
+     * @since 16.0.0
87
+     */
88
+    public function getUri(): string {
89
+        return $this->addressBookInfo['uri'];
90
+    }
91
+
92
+    /**
93
+     * In comparison to getKey() this function returns a human readable (maybe translated) name
94
+     *
95
+     * @return mixed
96
+     * @since 5.0.0
97
+     */
98
+    public function getDisplayName() {
99
+        return $this->addressBookInfo['{DAV:}displayname'];
100
+    }
101
+
102
+    /**
103
+     * @param string $pattern which should match within the $searchProperties
104
+     * @param array $searchProperties defines the properties within the query pattern should match
105
+     * @param array $options Options to define the output format and search behavior
106
+     * 	- 'types' boolean (since 15.0.0) If set to true, fields that come with a TYPE property will be an array
107
+     *    example: ['id' => 5, 'FN' => 'Thomas Tanghus', 'EMAIL' => ['type => 'HOME', 'value' => '[email protected]']]
108
+     * 	- 'escape_like_param' - If set to false wildcards _ and % are not escaped
109
+     * 	- 'limit' - Set a numeric limit for the search results
110
+     * 	- 'offset' - Set the offset for the limited search results
111
+     * 	- 'wildcard' - Whether the search should use wildcards
112
+     * @psalm-param array{types?: bool, escape_like_param?: bool, limit?: int, offset?: int, wildcard?: bool} $options
113
+     * @return array an array of contacts which are arrays of key-value-pairs
114
+     *  example result:
115
+     *  [
116
+     *		['id' => 0, 'FN' => 'Thomas Müller', 'EMAIL' => '[email protected]', 'GEO' => '37.386013;-122.082932'],
117
+     *		['id' => 5, 'FN' => 'Thomas Tanghus', 'EMAIL' => ['[email protected]', '[email protected]']]
118
+     *	]
119
+     * @since 5.0.0
120
+     */
121
+    public function search($pattern, $searchProperties, $options) {
122
+        $results = $this->backend->search($this->getKey(), $pattern, $searchProperties, $options);
123
+
124
+        $withTypes = \array_key_exists('types', $options) && $options['types'] === true;
125
+
126
+        $vCards = [];
127
+        foreach ($results as $result) {
128
+            $vCards[] = $this->vCard2Array($result['uri'], $this->readCard($result['carddata']), $withTypes);
129
+        }
130
+
131
+        return $vCards;
132
+    }
133
+
134
+    /**
135
+     * @param array $properties this array if key-value-pairs defines a contact
136
+     * @return array an array representing the contact just created or updated
137
+     * @since 5.0.0
138
+     */
139
+    public function createOrUpdate($properties) {
140
+        $update = false;
141
+        if (!isset($properties['URI'])) { // create a new contact
142
+            $uid = $this->createUid();
143
+            $uri = $uid . '.vcf';
144
+            $vCard = $this->createEmptyVCard($uid);
145
+        } else { // update existing contact
146
+            $uri = $properties['URI'];
147
+            $vCardData = $this->backend->getCard($this->getKey(), $uri);
148
+            $vCard = $this->readCard($vCardData['carddata']);
149
+            $update = true;
150
+        }
151
+
152
+        foreach ($properties as $key => $value) {
153
+            if (is_array($value)) {
154
+                $vCard->remove($key);
155
+                foreach ($value as $entry) {
156
+                    if (is_string($entry)) {
157
+                        $property = $vCard->createProperty($key, $entry);
158
+                    } else {
159
+                        if (($key === "ADR" || $key === "PHOTO") && is_string($entry["value"])) {
160
+                            $entry["value"] = stripslashes($entry["value"]);
161
+                            $entry["value"] = explode(';', $entry["value"]);
162
+                        }
163
+                        $property = $vCard->createProperty($key, $entry["value"]);
164
+                        if (isset($entry["type"])) {
165
+                            $property->add('TYPE', $entry["type"]);
166
+                        }
167
+                    }
168
+                    $vCard->add($property);
169
+                }
170
+            } elseif ($key !== 'URI') {
171
+                $vCard->$key = $vCard->createProperty($key, $value);
172
+            }
173
+        }
174
+
175
+        if ($update) {
176
+            $this->backend->updateCard($this->getKey(), $uri, $vCard->serialize());
177
+        } else {
178
+            $this->backend->createCard($this->getKey(), $uri, $vCard->serialize());
179
+        }
180
+
181
+        return $this->vCard2Array($uri, $vCard);
182
+    }
183
+
184
+    /**
185
+     * @return mixed
186
+     * @since 5.0.0
187
+     */
188
+    public function getPermissions() {
189
+        $permissions = $this->addressBook->getACL();
190
+        $result = 0;
191
+        foreach ($permissions as $permission) {
192
+            switch ($permission['privilege']) {
193
+                case '{DAV:}read':
194
+                    $result |= Constants::PERMISSION_READ;
195
+                    break;
196
+                case '{DAV:}write':
197
+                    $result |= Constants::PERMISSION_CREATE;
198
+                    $result |= Constants::PERMISSION_UPDATE;
199
+                    break;
200
+                case '{DAV:}all':
201
+                    $result |= Constants::PERMISSION_ALL;
202
+                    break;
203
+            }
204
+        }
205
+
206
+        return $result;
207
+    }
208
+
209
+    /**
210
+     * @param int $id the unique identifier to a contact
211
+     * @return bool successful or not
212
+     * @since 5.0.0
213
+     */
214
+    public function delete($id) {
215
+        $uri = $this->backend->getCardUri($id);
216
+        return $this->backend->deleteCard($this->addressBookInfo['id'], $uri);
217
+    }
218
+
219
+    /**
220
+     * read vCard data into a vCard object
221
+     *
222
+     * @param string $cardData
223
+     * @return VCard
224
+     */
225
+    protected function readCard($cardData) {
226
+        return  Reader::read($cardData);
227
+    }
228
+
229
+    /**
230
+     * create UID for contact
231
+     *
232
+     * @return string
233
+     */
234
+    protected function createUid() {
235
+        do {
236
+            $uid = $this->getUid();
237
+            $contact = $this->backend->getContact($this->getKey(), $uid . '.vcf');
238
+        } while (!empty($contact));
239
+
240
+        return $uid;
241
+    }
242
+
243
+    /**
244
+     * getUid is only there for testing, use createUid instead
245
+     */
246
+    protected function getUid() {
247
+        return UUIDUtil::getUUID();
248
+    }
249
+
250
+    /**
251
+     * create empty vcard
252
+     *
253
+     * @param string $uid
254
+     * @return VCard
255
+     */
256
+    protected function createEmptyVCard($uid) {
257
+        $vCard = new VCard();
258
+        $vCard->UID = $uid;
259
+        return $vCard;
260
+    }
261
+
262
+    /**
263
+     * create array with all vCard properties
264
+     *
265
+     * @param string $uri
266
+     * @param VCard $vCard
267
+     * @param boolean $withTypes (optional) return the values as arrays of value/type pairs
268
+     * @return array
269
+     */
270
+    protected function vCard2Array($uri, VCard $vCard, $withTypes = false) {
271
+        $result = [
272
+            'URI' => $uri,
273
+        ];
274
+
275
+        foreach ($vCard->children() as $property) {
276
+            if ($property->name === 'PHOTO' && in_array($property->getValueType(), ['BINARY', 'URI'])) {
277
+                $url = $this->urlGenerator->getAbsoluteURL(
278
+                    $this->urlGenerator->linkTo('', 'remote.php') . '/dav/');
279
+                $url .= implode('/', [
280
+                    'addressbooks',
281
+                    substr($this->addressBookInfo['principaluri'], 11), //cut off 'principals/'
282
+                    $this->addressBookInfo['uri'],
283
+                    $uri
284
+                ]) . '?photo';
285
+
286
+                $result['PHOTO'] = 'VALUE=uri:' . $url;
287
+            } elseif (in_array($property->name, ['URL', 'GEO', 'CLOUD', 'ADR', 'EMAIL', 'IMPP', 'TEL', 'X-SOCIALPROFILE', 'RELATED', 'LANG', 'X-ADDRESSBOOKSERVER-MEMBER'])) {
288
+                if (!isset($result[$property->name])) {
289
+                    $result[$property->name] = [];
290
+                }
291
+
292
+                $type = $this->getTypeFromProperty($property);
293
+                if ($withTypes) {
294
+                    $result[$property->name][] = [
295
+                        'type' => $type,
296
+                        'value' => $property->getValue()
297
+                    ];
298
+                } else {
299
+                    $result[$property->name][] = $property->getValue();
300
+                }
301
+            } else {
302
+                $result[$property->name] = $property->getValue();
303
+            }
304
+        }
305
+
306
+        if ($this->isSystemAddressBook()) {
307
+            $result['isLocalSystemBook'] = true;
308
+        }
309
+        return $result;
310
+    }
311
+
312
+    /**
313
+     * Get the type of the current property
314
+     *
315
+     * @param Property $property
316
+     * @return null|string
317
+     */
318
+    protected function getTypeFromProperty(Property $property) {
319
+        $parameters = $property->parameters();
320
+        // Type is the social network, when it's empty we don't need this.
321
+        if (isset($parameters['TYPE'])) {
322
+            /** @var \Sabre\VObject\Parameter $type */
323
+            $type = $parameters['TYPE'];
324
+            return $type->getValue();
325
+        }
326
+
327
+        return null;
328
+    }
329
+
330
+    /**
331
+     * @inheritDoc
332
+     */
333
+    public function isShared(): bool {
334
+        if (!isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) {
335
+            return false;
336
+        }
337
+
338
+        return $this->addressBookInfo['principaluri']
339
+            !== $this->addressBookInfo['{http://owncloud.org/ns}owner-principal'];
340
+    }
341
+
342
+    /**
343
+     * @inheritDoc
344
+     */
345
+    public function isSystemAddressBook(): bool {
346
+        return $this->addressBookInfo['principaluri'] === 'principals/system/system' && (
347
+            $this->addressBookInfo['uri'] === 'system' ||
348
+            $this->addressBookInfo['{DAV:}displayname'] === $this->urlGenerator->getBaseUrl()
349
+        );
350
+    }
351 351
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -140,7 +140,7 @@  discard block
 block discarded – undo
140 140
 		$update = false;
141 141
 		if (!isset($properties['URI'])) { // create a new contact
142 142
 			$uid = $this->createUid();
143
-			$uri = $uid . '.vcf';
143
+			$uri = $uid.'.vcf';
144 144
 			$vCard = $this->createEmptyVCard($uid);
145 145
 		} else { // update existing contact
146 146
 			$uri = $properties['URI'];
@@ -234,7 +234,7 @@  discard block
 block discarded – undo
234 234
 	protected function createUid() {
235 235
 		do {
236 236
 			$uid = $this->getUid();
237
-			$contact = $this->backend->getContact($this->getKey(), $uid . '.vcf');
237
+			$contact = $this->backend->getContact($this->getKey(), $uid.'.vcf');
238 238
 		} while (!empty($contact));
239 239
 
240 240
 		return $uid;
@@ -275,15 +275,15 @@  discard block
 block discarded – undo
275 275
 		foreach ($vCard->children() as $property) {
276 276
 			if ($property->name === 'PHOTO' && in_array($property->getValueType(), ['BINARY', 'URI'])) {
277 277
 				$url = $this->urlGenerator->getAbsoluteURL(
278
-					$this->urlGenerator->linkTo('', 'remote.php') . '/dav/');
278
+					$this->urlGenerator->linkTo('', 'remote.php').'/dav/');
279 279
 				$url .= implode('/', [
280 280
 					'addressbooks',
281 281
 					substr($this->addressBookInfo['principaluri'], 11), //cut off 'principals/'
282 282
 					$this->addressBookInfo['uri'],
283 283
 					$uri
284
-				]) . '?photo';
284
+				]).'?photo';
285 285
 
286
-				$result['PHOTO'] = 'VALUE=uri:' . $url;
286
+				$result['PHOTO'] = 'VALUE=uri:'.$url;
287 287
 			} elseif (in_array($property->name, ['URL', 'GEO', 'CLOUD', 'ADR', 'EMAIL', 'IMPP', 'TEL', 'X-SOCIALPROFILE', 'RELATED', 'LANG', 'X-ADDRESSBOOKSERVER-MEMBER'])) {
288 288
 				if (!isset($result[$property->name])) {
289 289
 					$result[$property->name] = [];
Please login to merge, or discard this patch.