Completed
Push — dna-import-module ( 10739b )
by
unknown
264:33 queued 255:46
created

Import::get_importer_name()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Automattic\Jetpack\Sync\Modules;
4
5
class Import extends \Jetpack_Sync_Module {
6
7
	/**
8
	 * Tracks which actions have already been synced for the import
9
	 * to prevent the same event from being triggered a second time
10
	 *
11
	 * @var array
12
	 */
13
	private $synced_actions = array();
14
15
	/**
16
	 * A mapping of action types to sync action name.
17
	 * Keys are the name of the import action.
18
	 * Values are the resulting sync action.
19
	 *
20
	 * Note: import_done and import_end both intentionally map to
21
	 * jetpack_sync_import_end, as they both track the same type of action,
22
	 * the successful completion of an import. Different import plugins use
23
	 * differently named actions, and this is an attempt to consolidate.
24
	 *
25
	 * @var array
26
	 */
27
	private static $import_sync_action_map = array(
28
		'import_start' => 'jetpack_sync_import_start',
29
		'import_done'  => 'jetpack_sync_import_end',
30
		'import_end'   => 'jetpack_sync_import_end',
31
	);
32
33
	public function name() {
34
		return 'import';
35
	}
36
37
	public function init_listeners( $callable ) {
38
		add_action( 'export_wp', $callable );
39
		add_action( 'jetpack_sync_import_start', $callable, 10, 2 );
40
		add_action( 'jetpack_sync_import_end', $callable, 10, 2 );
41
42
		// WordPress.
43
		add_action( 'import_start', array( $this, 'sync_import_action' ) );
44
45
		// Movable type, RSS, Livejournal.
46
		add_action( 'import_done', array( $this, 'sync_import_action' ) );
47
48
		// WordPress, Blogger, Livejournal, woo tax rate.
49
		add_action( 'import_end', array( $this, 'sync_import_action' ) );
50
	}
51
52
	public function set_defaults() {
53
		$this->synced_actions = array();
54
	}
55
56
	public function sync_import_action( $importer ) {
57
		$import_action = current_filter();
58
		// Map action to event name.
59
		$sync_action = self::$import_sync_action_map[ $import_action ];
60
61
		// Only sync each action once per import.
62
		if ( array_key_exists( $sync_action, $this->synced_actions ) && $this->synced_actions[ $sync_action ] ) {
63
			return;
64
		}
65
66
		// Mark this action as synced.
67
		$this->synced_actions[ $sync_action ] = true;
68
69
		// Prefer self-reported $importer value.
70
		if ( ! $importer ) {
71
			// Fall back to inferring by calling class name.
72
			$importer = self::get_calling_importer_class();
73
		}
74
75
		// Get $importer from known_importers.
76
		$known_importers = \Jetpack_Sync_Settings::get_setting( 'known_importers' );
77
		if ( isset( $known_importers[ $importer ] ) ) {
78
			$importer = $known_importers[ $importer ];
79
		}
80
81
		$importer_name = $this->get_importer_name( $importer );
82
83
		switch ( $sync_action ) {
84
			case 'jetpack_sync_import_start':
85
				/**
86
				 * Used for syncing the start of an import
87
				 *
88
				 * @since 7.3.0
89
				 *
90
				 * @module sync
91
				 *
92
				 * @param string $importer      Either a string reported by the importer, the class name of the importer, or 'unknown'.
93
				 * @param string $importer_name The name reported by the importer, or 'Unknown Importer'.
94
				 */
95
				do_action( 'jetpack_sync_import_start', $importer, $importer_name );
96
				break;
97
98
			case 'jetpack_sync_import_end':
99
				/**
100
				 * Used for syncing the end of an import
101
				 *
102
				 * @since 7.3.0
103
				 *
104
				 * @module sync
105
				 *
106
				 * @param string $importer      Either a string reported by the importer, the class name of the importer, or 'unknown'.
107
				 * @param string $importer_name The name reported by the importer, or 'Unknown Importer'.
108
				 */
109
				do_action( 'jetpack_sync_import_end', $importer, $importer_name );
110
				break;
111
		}
112
	}
113
114
	private function get_importer_name( $importer ) {
115
		$importers = get_importers();
116
		return isset( $importers[ $importer ] ) ? $importers[ $importer ][0] : 'Unknown Importer';
117
	}
118
119
	/**
120
	 * Determine the class that extends `WP_Importer` which is responsible for
121
	 * the current action. Designed to be used within an action handler.
122
	 *
123
	 * @return string  The name of the calling class, or 'unknown'.
124
	 */
125
	private static function get_calling_importer_class() {
126
		// If WP_Importer doesn't exist, neither will any importer that extends it.
127
		if ( ! class_exists( '\WP_Importer', false ) ) {
128
			return 'unknown';
129
		}
130
131
		$action    = current_filter();
132
		$backtrace = debug_backtrace( false ); //phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.debug_backtrace_optionsFound,WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace
133
134
		$do_action_pos = -1;
135
		$backtrace_len = count( $backtrace );
136
		for ( $i = 0; $i < $backtrace_len; $i++ ) {
137
			// Find the location in the stack of the calling action.
138
			if ( 'do_action' === $backtrace[ $i ]['function'] && $action === $backtrace[ $i ]['args'][0] ) {
139
				$do_action_pos = $i;
140
				break;
141
			}
142
		}
143
144
		// If the action wasn't called, the calling class is unknown.
145
		if ( -1 === $do_action_pos ) {
146
			return 'unknown';
147
		}
148
149
		// Continue iterating the stack looking for a caller that extends WP_Importer.
150
		for ( $i = $do_action_pos + 1; $i < $backtrace_len; $i++ ) {
151
			// If there is no class on the trace, continue.
152
			if ( ! isset( $backtrace[ $i ]['class'] ) ) {
153
				continue;
154
			}
155
156
			$class_name = $backtrace[ $i ]['class'];
157
158
			// Check if the class extends WP_Importer.
159
			if ( class_exists( $class_name, false ) ) {
160
				$parents = class_parents( $class_name, false );
161
				if ( $parents && in_array( '\WP_Importer', $parents, true ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $parents 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...
162
					return $class_name;
163
				}
164
			}
165
		}
166
167
		// If we've exhausted the stack without a match, the calling class is unknown.
168
		return 'unknown';
169
	}
170
}
171