Passed
Push — development ( 2bb3b4...48f606 )
by Emanuele
53s
created

SmfCommonOriginStep2::getMsgMemberID()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 26
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 26
rs 8.8571
cc 2
eloc 12
nc 2
nop 1
1
<?php
2
/**
3
 * @name      OpenImporter
4
 * @copyright OpenImporter contributors
5
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
6
 *
7
 * @version 2.0 Alpha
8
 *
9
 * This file contains code based on:
10
 *
11
 * Simple Machines Forum (SMF)
12
 * copyright:    2011 Simple Machines (http://www.simplemachines.org)
13
 * license:    BSD, See included LICENSE.TXT for terms and conditions.
14
 */
15
16
namespace OpenImporter\Importers\destinations;
17
18
/**
19
 * Class SmfCommonOriginStep2
20
 *
21
 * @package OpenImporter\Importers\destinations
22
 */
23
abstract class SmfCommonOriginStep2 extends Step2BaseImporter
24
{
25
	abstract public function substep0();
26
27
	public function substep10()
28
	{
29
		$to_prefix = $this->config->to_prefix;
30
31
		$request = $this->db->query("
32
			SELECT id_board, MAX(id_msg) AS id_last_msg, MAX(modified_time) AS last_edited
33
			FROM {$to_prefix}messages
34
			GROUP BY id_board");
35
36
		$modifyData = array();
37
		$modifyMsg = array();
38
		while ($row = $this->db->fetch_assoc($request))
39
		{
40
			$this->setBoardProperty($row['id_board'], array('id_last_msg' => $row['id_last_msg'], 'id_msg_updated' => $row['id_last_msg']));
41
42
			$modifyData[$row['id_board']] = array(
43
				'last_msg' => $row['id_last_msg'],
44
				'last_edited' => $row['last_edited'],
45
			);
46
			$modifyMsg[] = $row['id_last_msg'];
47
		}
48
		$this->db->free_result($request);
49
50
		// Are there any boards where the updated message is not the last?
51
		if (!empty($modifyMsg))
52
		{
53
			$request = $this->db->query("
54
				SELECT id_board, id_msg, modified_time, poster_time
55
				FROM {$to_prefix}messages
56
				WHERE id_msg IN (" . implode(',', $modifyMsg) . ")");
57
			while ($row = $this->db->fetch_assoc($request))
58
			{
59
				// Have we got a message modified before this was posted?
60
				if (max($row['modified_time'], $row['poster_time']) < $modifyData[$row['id_board']]['last_edited'])
61
				{
62
					// Work out the ID of the message (This seems long but it won't happen much.
63
					$request2 = $this->db->query("
64
						SELECT id_msg
65
						FROM {$to_prefix}messages
66
						WHERE modified_time = " . $modifyData[$row['id_board']]['last_edited'] . "
67
						LIMIT 1");
68
					if ($this->db->num_rows($request2) != 0)
69
					{
70
						list ($id_msg) = $this->db->fetch_row($request2);
71
72
						$this->setBoardProperty($row['id_board'], array('id_msg_updated' => $id_msg));
73
					}
74
					$this->db->free_result($request2);
75
				}
76
			}
77
			$this->db->free_result($request);
78
		}
79
	}
80
81
	protected function setBoardProperty($board, $property, $where = null)
82
	{
83
		$to_prefix = $this->config->to_prefix;
84
85
		$sets = array();
86
		foreach ($property as $k => $v)
87
		{
88
			$sets[] = $k . ' = ' . $v;
89
		}
90
		$set = implode(', ', $sets);
91
92
		if ($where === null)
93
		{
94
			if (empty($board))
95
			{
96
				return;
97
			}
98
99
			$where = "id_board = $board";
100
		}
101
102
		$this->db->query("
103
			UPDATE {$to_prefix}boards
104
			SET $set
105
			WHERE $where");
106
	}
107
108
	public function substep20()
109
	{
110
		$to_prefix = $this->config->to_prefix;
111
112
		$request = $this->db->query("
113
			SELECT id_group
114
			FROM {$to_prefix}membergroups
115
			WHERE min_posts = -1
116
				AND id_group != 2");
117
118
		$all_groups = array();
119
		while ($row = $this->db->fetch_assoc($request))
120
			$all_groups[] = $row['id_group'];
121
		$this->db->free_result($request);
122
123
		$request = $this->db->query("
124
			SELECT id_board, member_groups
125
			FROM {$to_prefix}boards
126
			WHERE FIND_IN_SET(0, member_groups)");
127
128
		while ($row = $this->db->fetch_assoc($request))
129
		{
130
			$member_groups = "'" . implode(',', array_unique(array_merge($all_groups, explode(',', $row['member_groups'])))) . "'";
131
			$this->setBoardProperty($row['id_board'], array('member_groups' => $member_groups));
132
		}
133
		$this->db->free_result($request);
134
	}
135
136
	public function substep30()
137
	{
138
		$to_prefix = $this->config->to_prefix;
139
140
		// Get the number of messages...
141
		$result = $this->db->query("
142
			SELECT COUNT(*) AS totalMessages, MAX(id_msg) AS maxMsgID
143
			FROM {$to_prefix}messages");
144
		$row = $this->db->fetch_assoc($result);
145
		$this->db->free_result($result);
146
147
		// Update the latest member. (Highest ID_MEMBER)
148
		$result = $this->db->query("
149
			SELECT id_member AS latestMember, real_name AS latestreal_name
150
			FROM {$to_prefix}members
151
			ORDER BY id_member DESC
152
			LIMIT 1");
153
154
		if ($this->db->num_rows($result))
155
		{
156
			$row += $this->db->fetch_assoc($result);
157
		}
158
		else
159
		{
160
			$row += array('latestMember' => '', 'latestreal_name' => '');
161
		}
162
163
		$this->db->free_result($result);
164
165
		// Update the member count.
166
		$result = $this->db->query("
167
			SELECT COUNT(*) AS totalMembers
168
			FROM {$to_prefix}members");
169
		$row += $this->db->fetch_assoc($result);
170
		$this->db->free_result($result);
171
172
		// Get the number of topics.
173
		$result = $this->db->query("
174
			SELECT COUNT(*) AS totalTopics
175
			FROM {$to_prefix}topics");
176
		$row += $this->db->fetch_assoc($result);
177
		$this->db->free_result($result);
178
179
		$this->db->query("
180
			REPLACE INTO {$to_prefix}settings
181
				(variable, value)
182
			VALUES ('latestMember', '$row[latestMember]'),
183
				('latestreal_name', '$row[latestreal_name]'),
184
				('totalMembers', '$row[totalMembers]'),
185
				('totalMessages', '$row[totalMessages]'),
186
				('maxMsgID', '$row[maxMsgID]'),
187
				('totalTopics', '$row[totalTopics]'),
188
				('disableHashTime', " . (time() + 7776000) . ")");
189
	}
190
191
	/**
192
	 * Fix the post-based membergroups
193
	 */
194
	public function substep40()
195
	{
196
		$to_prefix = $this->config->to_prefix;
197
198
		$request = $this->db->query("
199
			SELECT id_group, min_posts
200
			FROM {$to_prefix}membergroups
201
			WHERE min_posts != -1
202
			ORDER BY min_posts DESC");
203
204
		$post_groups = array();
205
		$max = $this->db->fetch_assoc($request);
206
		while ($row = $this->db->fetch_assoc($request))
207
			$post_groups[] = $row;
208
		$this->db->free_result($request);
209
210
		if (empty($max))
211
		{
212
			return;
213
		}
214
215
		$case = "CASE WHEN posts > " . $max['min_posts'] . " THEN " . $max['id_group'];
216
217
		$first = true;
218
		foreach ($post_groups as $id => $group)
219
		{
220
			if ($first)
221
			{
222
				$case .= " WHEN posts BETWEEN " . $group['min_posts'] . " AND " . $max['min_posts'] . " THEN " . $group['id_group'];
223
				$first = false;
224
			}
225
			else
226
			{
227
				$case .= " WHEN posts BETWEEN " . $group['min_posts'] . " AND " . $post_groups[$id - 1]['min_posts'] . " THEN " . $group['id_group'];
228
			}
229
		}
230
		$case .= " ELSE 4 END";
231
232
		$this->db->query("
233
			UPDATE {$to_prefix}members
234
			SET id_post_group = $case");
235
	}
236
237
	/**
238
	 * Fix the boards total posts and topics.
239
	 */
240
	public function substep50()
241
	{
242
		$to_prefix = $this->config->to_prefix;
243
244
		$result_topics = $this->db->query("
245
			SELECT id_board, COUNT(*) as num_topics
246
			FROM {$to_prefix}topics
247
			GROUP BY id_board");
248
249
		$updates = array();
250
		while ($row = $this->db->fetch_assoc($result_topics))
251
			$updates[$row['id_board']] = array(
252
				'num_topics' => $row['num_topics']
253
			);
254
		$this->db->free_result($result_topics);
255
256
		// Find how many messages are in the board.
257
		$result_posts = $this->db->query("
258
			SELECT id_board, COUNT(*) as num_posts
259
			FROM {$to_prefix}messages
260
			GROUP BY id_board");
261
262
		while ($row = $this->db->fetch_assoc($result_posts))
263
			$updates[$row['id_board']]['num_posts'] = $row['num_posts'];
264
		$this->db->free_result($result_posts);
265
266
		// Fix the board's totals.
267
		foreach ($updates as $id_board => $vals)
268
		{
269
			$this->setBoardProperty($id_board, $vals);
270
		}
271
	}
272
273
	public function substep60()
274
	{
275
		$to_prefix = $this->config->to_prefix;
276
277
		while (true)
278
		{
279
			$resultTopic = $this->db->query("
280
				SELECT t.id_topic, COUNT(m.id_msg) AS num_msg
281
				FROM {$to_prefix}topics AS t
282
					LEFT JOIN {$to_prefix}messages AS m ON (m.id_topic = t.id_topic)
283
				GROUP BY t.id_topic
284
				HAVING num_msg = 0
285
				LIMIT {$this->config->progress->start}, 200");
286
287
			$numRows = $this->db->num_rows($resultTopic);
288
289
			if ($numRows > 0)
290
			{
291
				$stupidTopics = array();
292
				while ($topicArray = $this->db->fetch_assoc($resultTopic))
293
					$stupidTopics[] = $topicArray['id_topic'];
294
				$this->db->query("
295
					DELETE FROM {$to_prefix}topics
296
					WHERE id_topic IN (" . implode(',', $stupidTopics) . ')
297
					LIMIT ' . count($stupidTopics));
298
				$this->db->query("
299
					DELETE FROM {$to_prefix}log_topics
300
					WHERE id_topic IN (" . implode(',', $stupidTopics) . ')');
301
			}
302
			$this->db->free_result($resultTopic);
303
304
			if ($numRows < 200)
305
			{
306
				$this->config->progress->stepCompleted();
307
				break;
308
			}
309
310
			$this->config->progress->start += 200;
311
			$this->config->progress->pastTime(6);
312
		}
313
	}
314
315
	public function substep70()
316
	{
317
		$to_prefix = $this->config->to_prefix;
318
319
		while (true)
320
		{
321
			$resultTopic = $this->db->query("
322
				SELECT
323
					t.id_topic, MIN(m.id_msg) AS myid_first_msg, t.id_first_msg,
324
					MAX(m.id_msg) AS myid_last_msg, t.id_last_msg, COUNT(m.id_msg) - 1 AS my_num_replies,
325
					t.num_replies
326
				FROM {$to_prefix}topics AS t
327
					LEFT JOIN {$to_prefix}messages AS m ON (m.id_topic = t.id_topic)
328
				GROUP BY t.id_topic
329
				HAVING id_first_msg != myid_first_msg OR id_last_msg != myid_last_msg OR num_replies != my_num_replies
330
				LIMIT {$this->config->progress->start}, 200");
331
332
			$numRows = $this->db->num_rows($resultTopic);
333
334
			while ($topicArray = $this->db->fetch_assoc($resultTopic))
335
			{
336
				$memberStartedID = $this->getMsgMemberID($topicArray['myid_first_msg']);
337
				$memberUpdatedID = $this->getMsgMemberID($topicArray['myid_last_msg']);
338
339
				$this->db->query("
340
					UPDATE {$to_prefix}topics
341
					SET id_first_msg = '$topicArray[myid_first_msg]',
342
						id_member_started = '$memberStartedID', id_last_msg = '$topicArray[myid_last_msg]',
343
						id_member_updated = '$memberUpdatedID', num_replies = '$topicArray[my_num_replies]'
344
					WHERE id_topic = $topicArray[id_topic]
345
					LIMIT 1");
346
			}
347
			$this->db->free_result($resultTopic);
348
349
			if ($numRows < 200)
350
			{
351
				$this->config->progress->stepCompleted();
352
				break;
353
			}
354
355
			$this->config->progress->start += 100;
356
			$this->config->progress->pastTime(7);
357
		}
358
	}
359
360
	/**
361
	 *
362
	 * Get the id_member associated with the specified message.
363
	 *
364
	 * @param type $messageID
365
	 *
366
	 * @return int
367
	 */
368
	protected function getMsgMemberID($messageID)
369
	{
370
		$to_prefix = $this->config->to_prefix;
371
372
		// Find the topic and make sure the member still exists.
373
		$result = $this->db->query("
374
			SELECT IFNULL(mem.id_member, 0)
375
			FROM {$to_prefix}messages AS m
376
			LEFT JOIN {$to_prefix}members AS mem ON (mem.id_member = m.id_member)
377
			WHERE m.id_msg = " . (int) $messageID . "
378
			LIMIT 1");
379
380
		if ($this->db->num_rows($result) > 0)
381
		{
382
			list ($memberID) = $this->db->fetch_row($result);
383
		}
384
		// The message doesn't even exist.
385
		else
386
		{
387
			$memberID = 0;
388
		}
389
390
		$this->db->free_result($result);
391
392
		return $memberID;
393
	}
394
395
	/**
396
	 * Fix the board parents.
397
	 */
398
	public function substep80()
399
	{
400
		$to_prefix = $this->config->to_prefix;
401
402
		// First, let's get an array of boards and parents.
403
		$request = $this->db->query("
404
			SELECT id_board, id_parent, id_cat
405
			FROM {$to_prefix}boards");
406
407
		$child_map = array();
408
		$cat_map = array();
409
		while ($row = $this->db->fetch_assoc($request))
410
		{
411
			$child_map[$row['id_parent']][] = $row['id_board'];
412
			$cat_map[$row['id_board']] = $row['id_cat'];
413
		}
414
		$this->db->free_result($request);
415
416
		// Let's look for any boards with obviously invalid parents...
417
		foreach ($child_map as $parent => $dummy)
418
		{
419
			if ($parent != 0 && !isset($cat_map[$parent]))
420
			{
421
				// Perhaps it was supposed to be their id_cat?
422
				foreach ($dummy as $board)
423
				{
424
					if (empty($cat_map[$board]))
425
					{
426
						$cat_map[$board] = $parent;
427
					}
428
				}
429
430
				$child_map[0] = array_merge(isset($child_map[0]) ? $child_map[0] : array(), $dummy);
431
				unset($child_map[$parent]);
432
			}
433
		}
434
435
		$cat_map = $this->fixBoards($cat_map, $child_map);
436
437
		$this->fixInexistentCategories($cat_map);
438
	}
439
440
	protected function fixBoards($cat_map, $child_map)
441
	{
442
		$fixed_boards = array();
443
		$level = 0;
444
445
		// The above id_parents and id_cats may all be wrong; we know id_parent = 0 is right.
446
		$solid_parents = array(array(0, 0));
447
		while (!empty($solid_parents))
448
		{
449
			list ($parent, $level) = array_pop($solid_parents);
450
			if (!isset($child_map[$parent]))
451
			{
452
				continue;
453
			}
454
455
			// Fix all of this board's children.
456
			foreach ($child_map[$parent] as $board)
457
			{
458
				if ($parent != 0)
459
				{
460
					$cat_map[$board] = $cat_map[$parent];
461
				}
462
463
				$this->setBoardProperty((int) $board, array('id_parent' => (int) $parent, 'id_cat' => (int) $cat_map[$board], 'child_level' => (int) $level));
464
465
				$fixed_boards[] = $board;
466
				$solid_parents[] = array($board, $level + 1);
467
			}
468
		}
469
470
		// Leftovers should be brought to the root. They had weird parents we couldn't find.
471
		if (count($fixed_boards) < count($cat_map))
472
		{
473
			$this->setBoardProperty(0, array('child_level' => 0, 'id_parent' => 0, 'child_level' => (int) $level), empty($fixed_boards) ? "1=1" : "id_board NOT IN (" . implode(', ', $fixed_boards) . ")");
474
		}
475
476
		return $cat_map;
477
	}
478
479
	/**
480
	 * Assigns any board belonging to a category that doesn't exist
481
	 * to a newly created category.
482
	 */
483
	protected function fixInexistentCategories($cat_map)
484
	{
485
		$to_prefix = $this->config->to_prefix;
486
487
		// Last check: any boards not in a good category?
488
		$request = $this->db->query("
489
			SELECT id_cat
490
			FROM {$to_prefix}categories");
491
		$real_cats = array();
492
		while ($row = $this->db->fetch_assoc($request))
493
			$real_cats[] = $row['id_cat'];
494
		$this->db->free_result($request);
495
496
		$fix_cats = array();
497
		foreach ($cat_map as $cat)
498
		{
499
			if (!in_array($cat, $real_cats))
500
			{
501
				$fix_cats[] = $cat;
502
			}
503
		}
504
505
		if (!empty($fix_cats))
506
		{
507
			$this->db->query("
508
				INSERT INTO {$to_prefix}categories
509
					(name)
510
				VALUES ('General Category')");
511
			$catch_cat = $this->db->insert_id();
512
513
			$this->setBoardProperty(0, array('id_cat' => (int) $catch_cat), "id_cat IN (" . implode(', ', array_unique($fix_cats)) . ")");
514
		}
515
	}
516
517
	/**
518
	 * Adjust boards and categories orders.
519
	 */
520
	public function substep90()
521
	{
522
		$to_prefix = $this->config->to_prefix;
523
524
		$request = $this->db->query("
525
			SELECT c.id_cat, c.cat_order, b.id_board, b.board_order
526
			FROM {$to_prefix}categories AS c
527
				LEFT JOIN {$to_prefix}boards AS b ON (b.id_cat = c.id_cat)
528
			ORDER BY c.cat_order, b.child_level, b.board_order, b.id_board");
529
		$cat_order = -1;
530
		$board_order = -1;
531
		$curCat = -1;
532
		while ($row = $this->db->fetch_assoc($request))
533
		{
534
			if ($curCat != $row['id_cat'])
535
			{
536
				$curCat = $row['id_cat'];
537
				if (++$cat_order != $row['cat_order'])
538
				{
539
					$this->db->query("
540
						UPDATE {$to_prefix}categories
541
						SET cat_order = $cat_order
542
						WHERE id_cat = $row[id_cat]
543
						LIMIT 1");
544
				}
545
			}
546
			if (!empty($row['id_board']) && ++$board_order != $row['board_order'])
547
			{
548
				$this->setBoardProperty($row['id_board'], array('board_order' => $board_order));
549
			}
550
		}
551
		$this->db->free_result($request);
552
	}
553
554
	public function substep100()
555
	{
556
		$to_prefix = $this->config->to_prefix;
557
558
		$request = $this->db->query("
559
			SELECT COUNT(*)
560
			FROM {$to_prefix}attachments");
561
		list ($attachments) = $this->db->fetch_row($request);
562
		$this->db->free_result($request);
563
564
		while ($this->config->progress->start < $attachments)
565
		{
566
			$request = $this->db->query("
567
				SELECT id_attach, filename, attachment_type, id_folder
568
				FROM {$to_prefix}attachments
569
				WHERE id_thumb = 0
570
					AND (RIGHT(filename, 4) IN ('.gif', '.jpg', '.png', '.bmp') OR RIGHT(filename, 5) = '.jpeg')
571
					AND width = 0
572
					AND height = 0
573
				LIMIT {$this->config->progress->start}, 500");
574
575
			if ($this->db->num_rows($request) == 0)
576
			{
577
				$this->config->progress->stepCompleted();
578
				break;
579
			}
580
581
			while ($row = $this->db->fetch_assoc($request))
582
			{
583
				$filename = $this->avatarFullPath($row);
584
585
				// Probably not one of the imported ones, then?
586
				if (!file_exists($filename))
587
				{
588
					continue;
589
				}
590
591
				$size = @getimagesize($filename);
592
				$filesize = @filesize($filename);
593
				if (!empty($size) && !empty($size[0]) && !empty($size[1]) && !empty($filesize))
594
				{
595
					$this->db->query("
596
						UPDATE {$to_prefix}attachments
597
						SET
598
							size = " . (int) $filesize . ",
599
							width = " . (int) $size[0] . ",
600
							height = " . (int) $size[1] . "
601
						WHERE id_attach = $row[id_attach]
602
						LIMIT 1");
603
				}
604
			}
605
			$this->db->free_result($request);
606
607
			// More?
608
			// We can't keep importing the same files over and over again!
609
			$this->config->progress->start += 500;
610
			$this->config->progress->pastTime(11);
611
		}
612
	}
613
614
	protected function avatarFullPath($row)
615
	{
616
		$dir = $this->config->destination->getAvatarDir($row);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OpenImporter\Importers\d...nationImporterInterface as the method getAvatarDir() does only exist in the following implementations of said interface: OpenImporter\Importers\d...ons\ElkArte1_0\Importer, OpenImporter\Importers\d...nations\SmfCommonOrigin, OpenImporter\Importers\d...tions\Wedge1_0\Importer.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
617
618
		if ($row['attachment_type'] == 1)
619
		{
620
			// @todo Honestly I'm not sure what the final name looks like
621
			// I'm pretty sure there could be at least three options:
622
			//   1) filename
623
			//   2) avatar_{id_member}_{time()}.{file_extension}
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
624
			//   3) {id_attach}_{file_hash}.{->attach_extension}
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
625
			$filename = $row['filename'];
626
		}
627
		else
628
		{
629
			$filename = $this->config->destination->getLegacyAttachmentFilename($row['filename'], $row['id_attach']);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OpenImporter\Importers\d...nationImporterInterface as the method getLegacyAttachmentFilename() does only exist in the following implementations of said interface: OpenImporter\Importers\d...ons\ElkArte1_0\Importer, OpenImporter\Importers\d...nations\SmfCommonOrigin, OpenImporter\Importers\d...tions\Wedge1_0\Importer.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
630
		}
631
632
		return $dir . '/' . $filename;
633
	}
634
}