Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
76 / 76
100.00% covered (success)
100.00%
14 / 14
CRAP
100.00% covered (success)
100.00%
1 / 1
manager
100.00% covered (success)
100.00%
76 / 76
100.00% covered (success)
100.00%
14 / 14
37
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 register_avatar_drivers
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 get_driver
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
6
 load_enabled_drivers
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
 get_all_drivers
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 get_enabled_drivers
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 clean_row
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
5
 clean_driver_name
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 prepare_driver_name
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 is_enabled
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 get_avatar_settings
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 localize_errors
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 handle_avatar_delete
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
3
 prefix_avatar_columns
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2/**
3*
4* This file is part of the phpBB Forum Software package.
5*
6* @copyright (c) phpBB Limited <https://www.phpbb.com>
7* @license GNU General Public License, version 2 (GPL-2.0)
8*
9* For full copyright and license information, please see
10* the docs/CREDITS.txt file.
11*
12*/
13
14namespace phpbb\avatar;
15
16class manager
17{
18    /**
19    * phpBB configuration
20    * @var \phpbb\config\config
21    */
22    protected $config;
23
24    /**
25    * phpBB event dispatcher
26    * @var \phpbb\event\dispatcher_interface
27    */
28    protected $phpbb_dispatcher;
29
30    /**
31    * Array that contains a list of enabled drivers
32    * @var array|false
33    */
34    protected static $enabled_drivers = false;
35
36    /**
37    * Array that contains all available avatar drivers which are passed via the
38    * service container
39    * @var array
40    */
41    protected $avatar_drivers;
42
43    /**
44    * Default avatar data row
45    * @var array
46    */
47    protected static $default_row = array(
48        'avatar'        => '',
49        'avatar_type'    => '',
50        'avatar_width'    => 0,
51        'avatar_height'    => 0,
52    );
53
54    /**
55    * Construct an avatar manager object
56    *
57    * @param \phpbb\config\config $config phpBB configuration
58    * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher phpBB event dispatcher
59    * @param array $avatar_drivers Avatar drivers passed via the service container
60    */
61    public function __construct(\phpbb\config\config $config, \phpbb\event\dispatcher_interface $phpbb_dispatcher, $avatar_drivers)
62    {
63        $this->config = $config;
64        $this->phpbb_dispatcher = $phpbb_dispatcher;
65        $this->register_avatar_drivers($avatar_drivers);
66    }
67
68    /**
69    * Register avatar drivers
70    *
71    * @param array $avatar_drivers Service collection of avatar drivers
72    */
73    protected function register_avatar_drivers($avatar_drivers)
74    {
75        if (!empty($avatar_drivers))
76        {
77            foreach ($avatar_drivers as $driver)
78            {
79                $this->avatar_drivers[$driver->get_name()] = $driver;
80            }
81        }
82    }
83
84    /**
85    * Get the driver object specified by the avatar type
86    *
87    * @param string $avatar_type Avatar type; by default an avatar's service container name
88    * @param bool $load_enabled Load only enabled avatars
89    *
90    * @return object|null Avatar driver object
91    */
92    public function get_driver($avatar_type, $load_enabled = true)
93    {
94        if (self::$enabled_drivers === false)
95        {
96            $this->load_enabled_drivers();
97        }
98
99        $avatar_drivers = ($load_enabled) ? self::$enabled_drivers : $this->get_all_drivers();
100
101        // Legacy stuff...
102        switch ($avatar_type)
103        {
104            case AVATAR_GALLERY:
105                $avatar_type = 'avatar.driver.local';
106            break;
107
108            case AVATAR_UPLOAD:
109                $avatar_type = 'avatar.driver.upload';
110            break;
111        }
112
113        if (!isset($avatar_drivers[$avatar_type]))
114        {
115            return null;
116        }
117
118        /*
119        * There is no need to handle invalid avatar types as the following code
120        * will cause a ServiceNotFoundException if the type does not exist
121        */
122        $driver = $this->avatar_drivers[$avatar_type];
123
124        return $driver;
125    }
126
127    /**
128    * Load the list of enabled drivers
129    * This is executed once and fills self::$enabled_drivers
130    */
131    protected function load_enabled_drivers()
132    {
133        if (!empty($this->avatar_drivers))
134        {
135            self::$enabled_drivers = array();
136            foreach ($this->avatar_drivers as $driver)
137            {
138                if ($this->is_enabled($driver))
139                {
140                    self::$enabled_drivers[$driver->get_name()] = $driver->get_name();
141                }
142            }
143            asort(self::$enabled_drivers);
144        }
145    }
146
147    /**
148    * Get a list of all avatar drivers
149    *
150    * As this function will only be called in the ACP avatar settings page, it
151    * doesn't make much sense to cache the list of all avatar drivers like the
152    * list of the enabled drivers.
153    *
154    * @return array Array containing a list of all avatar drivers
155    */
156    public function get_all_drivers()
157    {
158        $drivers = array();
159
160        if (!empty($this->avatar_drivers))
161        {
162            foreach ($this->avatar_drivers as $driver)
163            {
164                $drivers[$driver->get_name()] = $driver->get_name();
165            }
166            asort($drivers);
167        }
168
169        return $drivers;
170    }
171
172    /**
173    * Get a list of enabled avatar drivers
174    *
175    * @return array Array containing a list of the enabled avatar drivers
176    */
177    public function get_enabled_drivers()
178    {
179        if (self::$enabled_drivers === false)
180        {
181            $this->load_enabled_drivers();
182        }
183
184        return self::$enabled_drivers ?: [];
185    }
186
187    /**
188    * Strip out user_, group_, or other prefixes from array keys
189    *
190    * @param array    $row            User data or group data
191    * @param string $prefix            Prefix of data keys (e.g. user), should not include the trailing underscore
192    *
193    * @return array    User or group data with keys that have been
194    *            stripped from the preceding "user_" or "group_"
195    *            Also the group id is prefixed with g, when the prefix group is removed.
196    */
197    public static function clean_row($row, $prefix = '')
198    {
199        // Upon creation of a user/group $row might be empty
200        if (empty($row))
201        {
202            return self::$default_row;
203        }
204
205        $output = [];
206        foreach ($row as $key => $value)
207        {
208            $key = preg_replace("#^(?:{$prefix}_)#", '', (string) $key);
209            $output[$key] = $value;
210        }
211
212        if ($prefix === 'group' && isset($output['id']))
213        {
214            $output['id'] = 'g' . $output['id'];
215        }
216
217        return $output;
218    }
219
220    /**
221    * Clean driver names that are returned from template files
222    * Underscores are replaced with dots
223    *
224    * @param string $name Driver name
225    *
226    * @return string Cleaned driver name
227    */
228    public static function clean_driver_name($name)
229    {
230        return str_replace(array('\\', '_'), '.', $name);
231    }
232
233    /**
234    * Prepare driver names for use in template files
235    * Dots are replaced with underscores
236    *
237    * @param string $name Clean driver name
238    *
239    * @return string Prepared driver name
240    */
241    public static function prepare_driver_name($name)
242    {
243        return str_replace('.', '_', $name);
244    }
245
246    /**
247    * Check if avatar is enabled
248    *
249    * @param object $driver Avatar driver object
250    *
251    * @return bool True if avatar is enabled, false if it's disabled
252    */
253    public function is_enabled($driver)
254    {
255        $config_name = $driver->get_config_name();
256
257        return (bool) $this->config["allow_avatar_{$config_name}"];
258    }
259
260    /**
261    * Get the settings array for enabling/disabling an avatar driver
262    *
263    * @param object $driver Avatar driver object
264    *
265    * @return array Array of configuration options as consumed by acp_board
266    */
267    public function get_avatar_settings($driver)
268    {
269        $config_name = $driver->get_config_name();
270
271        return array(
272            'allow_avatar_' . $config_name    => array('lang' => 'ALLOW_' . strtoupper(str_replace('\\', '_', $config_name)),        'validate' => 'bool',    'type' => 'radio:yes_no', 'explain' => true),
273        );
274    }
275
276    /**
277    * Replace "error" strings with their real, localized form
278    *
279    * @param \phpbb\user phpBB User object
280    * @param array    $error Array containing error strings
281    *        Key values can either be a string with a language key or an array
282    *        that will be passed to vsprintf() with the language key in the
283    *        first array key.
284    *
285    * @return array Array containing the localized error strings
286    */
287    public function localize_errors(\phpbb\user $user, $error)
288    {
289        foreach ($error as $key => $lang)
290        {
291            if (is_array($lang))
292            {
293                $lang_key = array_shift($lang);
294                $error[$key] = vsprintf($user->lang($lang_key), $lang);
295            }
296            else
297            {
298                $error[$key] = $user->lang("$lang");
299            }
300        }
301
302        return $error;
303    }
304
305    /**
306    * Handle deleting avatars
307    *
308    * @param \phpbb\db\driver\driver_interface $db phpBB dbal
309    * @param \phpbb\user    $user phpBB user object
310    * @param array          $avatar_data Cleaned user data containing the user's
311    *                               avatar data
312    * @param string         $table Database table from which the avatar should be deleted
313    * @param string         $prefix Prefix of user data columns in database
314    * @return void
315    */
316    public function handle_avatar_delete(\phpbb\db\driver\driver_interface $db, \phpbb\user $user, $avatar_data, $table, $prefix)
317    {
318        if ($driver = $this->get_driver($avatar_data['avatar_type']))
319        {
320            $driver->delete($avatar_data);
321        }
322
323        $result = $this->prefix_avatar_columns($prefix, self::$default_row);
324
325        $sql = 'UPDATE ' . $table . '
326            SET ' . $db->sql_build_array('UPDATE', $result) . '
327            WHERE ' . $prefix . 'id = ' . (int) $avatar_data['id'];
328        $db->sql_query($sql);
329
330        // Make sure we also delete this avatar from the users
331        if ($prefix === 'group_')
332        {
333            $result = $this->prefix_avatar_columns('user_', self::$default_row);
334
335            $sql = 'UPDATE ' . USERS_TABLE . '
336                SET ' . $db->sql_build_array('UPDATE', $result) . "
337                WHERE user_avatar = '" . $db->sql_escape($avatar_data['avatar']) . "'";
338            $db->sql_query($sql);
339        }
340
341        /**
342        * Event is triggered after user avatar has been deleted
343        *
344        * @event core.avatar_manager_avatar_delete_after
345        * @var    \phpbb\user    user        phpBB user object
346        * @var    array        avatar_data    Normalised avatar-related user data
347        * @var    string        table        Table to delete avatar from
348        * @var    string        prefix        Column prefix to delete avatar from
349        * @since 3.2.4-RC1
350        */
351        $vars = array('user', 'avatar_data', 'table', 'prefix');
352        extract($this->phpbb_dispatcher->trigger_event('core.avatar_manager_avatar_delete_after', compact($vars)));
353    }
354
355    /**
356     * Prefix avatar columns
357     *
358     * @param string $prefix Column prefix
359     * @param array $data Column data
360     *
361     * @return array Column data with prefixed column names
362     */
363    public function prefix_avatar_columns($prefix, $data)
364    {
365        foreach ($data as $key => $value)
366        {
367            $data[$prefix . $key] = $value;
368            unset($data[$key]);
369        }
370
371        return $data;
372    }
373}