Completed
Push — master ( eef885...465d0c )
by
unknown
30:08 queued 12:49
created

User_Class::get()   C

Complexity

Conditions 11
Paths 12

Size

Total Lines 49
Code Lines 30

Duplication

Lines 28
Ratio 57.14 %

Importance

Changes 0
Metric Value
cc 11
eloc 30
nc 12
nop 2
dl 28
loc 49
rs 5.2653
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Gestion des utilisateurs (POST, PUT, GET, DELETE)
4
 *
5
 * @author Jimmy Latour <[email protected]>
6
 * @since 1.0.0.0
7
 * @version 1.3.0.0
8
 * @copyright 2015-2017
9
 * @package wpeo_model
10
 * @subpackage class
11
 */
12
13
namespace eoxia;
14
15
if ( ! defined( 'ABSPATH' ) ) { exit; }
16
17
if ( ! class_exists( '\eoxia\User_Class' ) ) {
18
	/**
19
	 * Gestion des utilisateurs (POST, PUT, GET, DELETE)
20
	 */
21
	class User_Class extends Singleton_Util {
22
		/**
23
		 * Le nom du modèle
24
		 *
25
		 * @var string
26
		 */
27
		protected $model_name = 'user_model';
28
29
		/**
30
		 * La clé principale pour post_meta
31
		 *
32
		 * @var string
33
		 */
34
		protected $meta_key = '_wpeo_user';
35
36
		/**
37
		 * Utiles pour récupérer la clé unique
38
		 *
39
		 * @todo Rien à faire ici
40
		 * @var string
41
		 */
42
		protected $identifier_helper = 'user';
43
44
		/**
45
		 * Utiles pour DigiRisk
46
		 *
47
		 * @todo Rien à faire ici
48
		 * @var string
49
		 */
50
		public $element_prefix = 'U';
51
52
		/**
53
		 * Fonction de callback après avoir récupérer les données dans la base de donnée en mode GET.
54
		 *
55
		 * @var array
56
		 */
57
		protected $after_get_function = array( 'build_user_initial' );
58
59
		/**
60
		 * Fonction de callback avant d'insérer les données en mode POST.
61
		 *
62
		 * @var array
63
		 */
64
		protected $before_post_function = array();
65
66
		/**
67
		 * Fonction de callback avant de dispatcher les données en mode POST.
68
		 *
69
		 * @var array
70
		 */
71
		protected $before_model_post_function = array();
72
73
		/**
74
		 * Fonction de callback après avoir inséré les données en mode POST.
75
		 *
76
		 * @var array
77
		 */
78
		protected $after_post_function = array();
79
80
		/**
81
		 * Fonction de callback avant de mêttre à jour les données en mode PUT.
82
		 *
83
		 * @var array
84
		 */
85
		protected $before_put_function = array();
86
87
		/**
88
		 * Fonction de callback avant de dispatcher les données en mode PUT.
89
		 *
90
		 * @var array
91
		 */
92
		protected $before_model_put_function = array();
93
94
		/**
95
		 * Fonction de callback après avoir mis à jour les données en mode PUT.
96
		 *
97
		 * @var array
98
		 */
99
		protected $after_put_function = array();
100
101
		/**
102
		 * Le constructeur pour Singleton_Util
103
		 *
104
		 * @since 1.0.0.0
105
		 * @version 1.3.0.0
106
		 *
107
		 * @return void
108
		 */
109
		protected function construct() {}
110
111
		/**
112
		 * Permet de récupérer le schéma avec les données du modèle par défault.
113
		 *
114
		 * @since 1.0.0.0
115
		 * @version 1.3.0.0
116
		 *
117
		 * @return Object
118
		 */
119
		public function get_schema() {
120
			$model_name = $this->model_name;
121
			$model = new $model_name( array(), array() );
122
			return $model->get_model();
123
		}
124
125
		/**
126
		 * Récupères les données selon le modèle définis.
127
		 *
128
		 * @since 1.0.0.0
129
		 * @version 1.3.0.0
130
		 *
131
		 * @param array   $args Les paramètres de get_users @https://codex.wordpress.org/Function_Reference/get_users.
132
		 * @param boolean $single Si on veut récupérer un tableau, ou qu'une seule entrée.
133
		 *
134
		 * @return Comment_Model
135
		 */
136
		public function get( $args = array(), $single = false ) {
137
			$list_user = array();
138
			$list_model_user = array();
139
140
			$model_name = $this->model_name;
141
142
			if ( ! empty( $args['id'] ) ) {
143
				$list_user[] = get_user_by( 'id', $args['id'] );
144
			} elseif ( isset( $args['schema'] ) ) {
145
				$list_user[] = array();
146
			} else {
147
				$list_user = get_users( $args );
148
			}
149
150 View Code Duplication
			if ( ! empty( $list_user ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
151
				foreach ( $list_user as $element ) {
152
					$element = (array) $element;
153
154
					if ( ! empty( $element['ID'] ) ) {
155
						$list_meta = get_user_meta( $element['ID'] );
156
						foreach ( $list_meta as &$meta ) {
157
							$meta = array_shift( $meta );
158
						}
159
160
						$element = array_merge( $element, $list_meta );
161
162
						if ( ! empty( $element['data'] ) ) {
163
							$element = array_merge( $element, (array) $element['data'] );
164
							unset( $element['data'] );
165
						}
166
167
						if ( ! empty( $element[ $this->meta_key ] ) ) {
168
							$element = array_merge( $element, json_decode( $element[ $this->meta_key ], true ) );
169
							unset( $element[ $this->meta_key ] );
170
						}
171
					}
172
173
					$data = new $model_name( $element );
174
					$data = Model_Util::exec_callback( $data, $this->after_get_function );
175
					$list_model_user[] = $data;
176
				}
177
			}
178
179
			if ( true === $single && 1 === count( $list_model_user ) ) {
180
				$list_model_user = $list_model_user[0];
181
			}
182
183
			return $list_model_user;
184
		}
185
186
		/**
187
		 * Appelle la méthode update.
188
		 *
189
		 * @since 1.0.0.0
190
		 * @version 1.3.0.0
191
		 *
192
		 * @param  Array $data Les données.
193
		 * @return Array $data Les données
194
		 */
195
		public function create( $data ) {
196
			return $this->update( $data );
197
		}
198
199
		/**
200
		 * Insère ou met à jour les données dans la base de donnée.
201
		 *
202
		 * @since 1.0.0.0
203
		 * @version 1.3.0.0
204
		 *
205
		 * @param  Array $data Les données a insérer ou à mêttre à jour.
206
		 * @return Object      L'objet construit grâce au modèle.
207
		 */
208
		public function update( $data ) {
209
			$data = (array) $data;
210
			$model_name = $this->model_name;
211
212
			if ( empty( $data['id'] ) ) {
213
				$data = Model_Util::exec_callback( $data, $this->before_model_post_function );
214
				$data = new $model_name( (array) $data );
215
				$data = Model_Util::exec_callback( $data, $this->before_post_function );
216
217
				if ( ! empty( $data->error ) && $data->error ) {
218
					return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by eoxia\User_Class::update of type object.

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...
219
				}
220
221
				$data->id = wp_insert_user( $data->do_wp_object() );
222
223
				$data = Model_Util::exec_callback( $data, $this->after_post_function );
224 View Code Duplication
			} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
225
				$data = Model_Util::exec_callback( $data, $this->before_model_put_function );
226
				$current_data = $this->get( array(
227
					'id' => $data['id'],
228
				), true );
229
230
				$obj_merged = (object) array_merge( (array) $current_data, (array) $data );
231
				$data = new $model_name( (array) $obj_merged );
232
				$data = Model_Util::exec_callback( $data, $this->before_put_function );
233
234
				if ( ! empty( $data->error ) && $data->error ) {
235
					return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by eoxia\User_Class::update of type object.

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...
236
				}
237
238
				wp_update_user( $data->do_wp_object() );
239
240
				$data = Model_Util::exec_callback( $data, $this->after_put_function );
241
			}
242
243
			Save_Meta_Class::g()->save_meta_data( $data, 'update_user_meta', $this->meta_key );
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class eoxia\Singleton_Util as the method save_meta_data() does only exist in the following sub-classes of eoxia\Singleton_Util: eoxia\Save_Meta_Class. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

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

class MyUser extends 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 sub-classes 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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
244
245
			return $data;
246
		}
247
248
		/**
249
		 * Supprimes un utilisateur
250
		 *
251
		 * @todo: Utile ?
252
		 *
253
		 * @since 1.0.0.0
254
		 * @version 1.3.0.0
255
		 *
256
		 * @param  integer $id L'ID de l'utilisateur.
257
		 */
258
		public function delete( $id ) {
259
			wp_delete_user( $id );
260
		}
261
262
		/**
263
		 * Utile uniquement pour DigiRisk.
264
		 *
265
		 * @since 1.0.0.0
266
		 * @version 1.3.0.0
267
		 *
268
		 * @return string L'identifiant des commentaires pour DigiRisk.
269
		 */
270
		public function get_identifier_helper() {
271
			return $this->identifier_helper;
272
		}
273
	}
274
}
275