Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
namespace core_user;
18
 
19
/**
20
 * Unit tests for \core_user\fields
21
 *
22
 * @package core
23
 * @copyright 2014 The Open University
24
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25
 * @covers \core_user\fields
26
 */
27
class fields_test extends \advanced_testcase {
28
 
29
    /**
30
     * Tests getting the user picture fields.
31
     */
11 efrain 32
    public function test_get_picture_fields(): void {
1 efrain 33
        $this->assertEquals(['id', 'picture', 'firstname', 'lastname', 'firstnamephonetic',
34
                'lastnamephonetic', 'middlename', 'alternatename', 'imagealt', 'email'],
35
                fields::get_picture_fields());
36
    }
37
 
38
    /**
39
     * Tests getting the user name fields.
40
     */
11 efrain 41
    public function test_get_name_fields(): void {
1 efrain 42
        $this->assertEquals(['firstnamephonetic', 'lastnamephonetic', 'middlename', 'alternatename',
43
                'firstname', 'lastname'],
44
                fields::get_name_fields());
45
 
46
        $this->assertEquals(['firstname', 'lastname',
47
                'firstnamephonetic', 'lastnamephonetic', 'middlename', 'alternatename'],
48
                fields::get_name_fields(true));
49
    }
50
 
51
    /**
52
     * Tests getting the identity fields.
53
     */
11 efrain 54
    public function test_get_identity_fields(): void {
1 efrain 55
        global $DB, $CFG, $COURSE;
56
 
57
        $this->resetAfterTest();
58
 
59
        require_once($CFG->dirroot . '/user/profile/lib.php');
60
 
61
        // Create custom profile fields, one with each visibility option.
62
        $generator = self::getDataGenerator();
63
        $generator->create_custom_profile_field(['datatype' => 'text', 'shortname' => 'a', 'name' => 'A',
64
                'visible' => PROFILE_VISIBLE_ALL]);
65
        $generator->create_custom_profile_field(['datatype' => 'text', 'shortname' => 'b', 'name' => 'B',
66
                'visible' => PROFILE_VISIBLE_PRIVATE]);
67
        $generator->create_custom_profile_field(['datatype' => 'text', 'shortname' => 'c', 'name' => 'C',
68
                'visible' => PROFILE_VISIBLE_NONE]);
69
        $generator->create_custom_profile_field(['datatype' => 'text', 'shortname' => 'd', 'name' => 'D',
70
                'visible' => PROFILE_VISIBLE_TEACHERS]);
71
 
72
        // Set the extra user fields to include email, department, and all custom profile fields.
73
        set_config('showuseridentity', 'email,department,profile_field_a,profile_field_b,' .
74
                'profile_field_c,profile_field_d');
75
        set_config('hiddenuserfields', 'email');
76
 
77
        // Create a test course and a student in the course.
78
        $course = $generator->create_course();
79
        $coursecontext = \context_course::instance($course->id);
80
        $user = $generator->create_user();
81
        $anotheruser = $generator->create_user();
82
        $usercontext = \context_user::instance($anotheruser->id);
83
        $generator->enrol_user($user->id, $course->id, 'student');
84
 
85
        // When no context is provided, it does no access checks and should return all specified (other than non-visible).
86
        $this->assertEquals(['email', 'department', 'profile_field_a', 'profile_field_b', 'profile_field_d'],
87
                fields::get_identity_fields(null));
88
 
89
        // If you turn off custom profile fields, you don't get those.
90
        $this->assertEquals(['email', 'department'], fields::get_identity_fields(null, false));
91
 
92
        // Request in context as an administator.
93
        $this->setAdminUser();
94
        $this->assertEquals(['email', 'department', 'profile_field_a', 'profile_field_b',
95
                'profile_field_c', 'profile_field_d'],
96
                fields::get_identity_fields($coursecontext));
97
        $this->assertEquals(['email', 'department'],
98
                fields::get_identity_fields($coursecontext, false));
99
 
100
        // Request in context as a student - they don't have any of the capabilities to see identity
101
        // fields or profile fields.
102
        $this->setUser($user);
103
        $this->assertEquals([], fields::get_identity_fields($coursecontext));
104
 
105
        // Give the student the basic identity fields permission (also makes them count as 'teacher'
106
        // for the teacher-restricted field).
107
        $COURSE = $course; // Horrible hack, because PROFILE_VISIBLE_TEACHERS relies on this global.
108
        $roleid = $DB->get_field('role', 'id', ['shortname' => 'student']);
109
        role_change_permission($roleid, $coursecontext, 'moodle/site:viewuseridentity', CAP_ALLOW);
110
        $this->assertEquals(['department', 'profile_field_a', 'profile_field_d'],
111
                fields::get_identity_fields($coursecontext));
112
        $this->assertEquals(['department'],
113
                fields::get_identity_fields($coursecontext, false));
114
 
115
        // Give them permission to view hidden user fields.
116
        role_change_permission($roleid, $coursecontext, 'moodle/course:viewhiddenuserfields', CAP_ALLOW);
117
        $this->assertEquals(['email', 'department', 'profile_field_a', 'profile_field_d'],
118
                fields::get_identity_fields($coursecontext));
119
        $this->assertEquals(['email', 'department'],
120
                fields::get_identity_fields($coursecontext, false));
121
 
122
        // Also give them permission to view all profile fields.
123
        role_change_permission($roleid, $coursecontext, 'moodle/user:viewalldetails', CAP_ALLOW);
124
        $this->assertEquals(['email', 'department', 'profile_field_a', 'profile_field_b',
125
                'profile_field_c', 'profile_field_d'],
126
                fields::get_identity_fields($coursecontext));
127
        $this->assertEquals(['email', 'department'],
128
                fields::get_identity_fields($coursecontext, false));
129
 
130
        // Even if we give them student role in the user context they can't view anything...
131
        $generator->role_assign($roleid, $user->id, $usercontext->id);
132
        $this->assertEquals([], fields::get_identity_fields($usercontext));
133
 
134
        // Give them basic permission.
135
        role_change_permission($roleid, $usercontext, 'moodle/site:viewuseridentity', CAP_ALLOW);
136
        $this->assertEquals(['department', 'profile_field_a', 'profile_field_d'],
137
                fields::get_identity_fields($usercontext));
138
        $this->assertEquals(['department'],
139
                fields::get_identity_fields($usercontext, false));
140
 
141
        // Give them the hidden user fields permission (it's a different one).
142
        role_change_permission($roleid, $usercontext, 'moodle/user:viewhiddendetails', CAP_ALLOW);
143
        $this->assertEquals(['email', 'department', 'profile_field_a', 'profile_field_d'],
144
                fields::get_identity_fields($usercontext));
145
        $this->assertEquals(['email', 'department'],
146
                fields::get_identity_fields($usercontext, false));
147
 
148
        // Also give them permission to view all profile fields.
149
        role_change_permission($roleid, $usercontext, 'moodle/user:viewalldetails', CAP_ALLOW);
150
        $this->assertEquals(['email', 'department', 'profile_field_a', 'profile_field_b',
151
                'profile_field_c', 'profile_field_d'],
152
                fields::get_identity_fields($usercontext));
153
        $this->assertEquals(['email', 'department'],
154
                fields::get_identity_fields($usercontext, false));
155
    }
156
 
157
    /**
158
     * Test getting identity fields, when one of them refers to a non-existing custom profile field
159
     */
160
    public function test_get_identity_fields_invalid(): void {
161
        $this->resetAfterTest();
162
 
163
        $this->getDataGenerator()->create_custom_profile_field([
164
            'datatype' => 'text',
165
            'shortname' => 'real',
166
            'name' => 'I\'m real',
167
        ]);
168
 
169
        // The "fake" profile field does not exist.
170
        set_config('showuseridentity', 'email,profile_field_real,profile_field_fake');
171
 
172
        $this->assertEquals([
173
            'email',
174
            'profile_field_real',
175
        ], fields::get_identity_fields(null));
176
    }
177
 
178
    /**
179
     * Tests the get_required_fields function.
180
     *
181
     * This function composes the results of get_identity/name/picture_fields, so we are not going
182
     * to test the details of the identity permissions as that was already covered. Just how they
183
     * are included/combined.
184
     */
11 efrain 185
    public function test_get_required_fields(): void {
1 efrain 186
        $this->resetAfterTest();
187
 
188
        // Set up some profile fields.
189
        $generator = self::getDataGenerator();
190
        $generator->create_custom_profile_field(['datatype' => 'text', 'shortname' => 'a', 'name' => 'A']);
191
        $generator->create_custom_profile_field(['datatype' => 'text', 'shortname' => 'b', 'name' => 'B']);
192
        set_config('showuseridentity', 'email,department,profile_field_a');
193
 
194
        // What happens if you don't ask for anything?
195
        $fields = fields::empty();
196
        $this->assertEquals([], $fields->get_required_fields());
197
 
198
        // Try each invidual purpose.
199
        $fields = fields::for_identity(null);
200
        $this->assertEquals(['email', 'department', 'profile_field_a'], $fields->get_required_fields());
201
        $fields = fields::for_userpic();
202
        $this->assertEquals(fields::get_picture_fields(), $fields->get_required_fields());
203
        $fields = fields::for_name();
204
        $this->assertEquals(fields::get_name_fields(), $fields->get_required_fields());
205
 
206
        // Try combining them all. There should be no duplicates (e.g. email), and the 'id' field
207
        // should be moved to the start.
208
        $fields = fields::for_identity(null)->with_name()->with_userpic();
209
        $this->assertEquals(['id', 'email', 'department', 'profile_field_a', 'picture',
210
                'firstname', 'lastname', 'firstnamephonetic', 'lastnamephonetic', 'middlename',
211
                'alternatename', 'imagealt'], $fields->get_required_fields());
212
 
213
        // Add some specified fields to a default result.
214
        $fields = fields::for_identity(null, true)->including('city', 'profile_field_b');
215
        $this->assertEquals(['email', 'department', 'profile_field_a', 'city', 'profile_field_b'],
216
                $fields->get_required_fields());
217
 
218
        // Remove some fields, one of which actually is in the list.
219
        $fields = fields::for_identity(null, true)->excluding('email', 'city');
220
        $this->assertEquals(['department', 'profile_field_a'], $fields->get_required_fields());
221
 
222
        // Add and remove fields.
223
        $fields = fields::for_identity(null, true)->including('city', 'profile_field_b')->excluding('city', 'department');
224
        $this->assertEquals(['email', 'profile_field_a', 'profile_field_b'],
225
                $fields->get_required_fields());
226
 
227
        // Request the list without profile fields, check that still works with both sources.
228
        $fields = fields::for_identity(null, false)->including('city', 'profile_field_b')->excluding('city', 'department');
229
        $this->assertEquals(['email'], $fields->get_required_fields());
230
    }
231
 
232
    /**
233
     * Tests the get_required_fields function when you use the $limitpurposes parameter.
234
     */
11 efrain 235
    public function test_get_required_fields_limitpurposes(): void {
1 efrain 236
        $this->resetAfterTest();
237
 
238
        // Set up some profile fields.
239
        $generator = self::getDataGenerator();
240
        $generator->create_custom_profile_field(['datatype' => 'text', 'shortname' => 'a', 'name' => 'A']);
241
        $generator->create_custom_profile_field(['datatype' => 'text', 'shortname' => 'b', 'name' => 'B']);
242
        set_config('showuseridentity', 'email,department,profile_field_a');
243
 
244
        // Create a fields object with all three purposes, plus included and excluded fields.
245
        $fields = fields::for_identity(null, true)->with_name()->with_userpic()
246
            ->including('city', 'profile_field_b')->excluding('firstnamephonetic', 'middlename', 'alternatename');
247
 
248
        // Check the result with all purposes.
249
        $this->assertEquals(['id', 'email', 'department', 'profile_field_a', 'picture',
250
                'firstname', 'lastname', 'lastnamephonetic', 'imagealt', 'city',
251
                'profile_field_b'],
252
                $fields->get_required_fields([fields::PURPOSE_IDENTITY, fields::PURPOSE_NAME,
253
                fields::PURPOSE_USERPIC, fields::CUSTOM_INCLUDE]));
254
 
255
        // Limit to identity and custom includes.
256
        $this->assertEquals(['email', 'department', 'profile_field_a', 'city', 'profile_field_b'],
257
                $fields->get_required_fields([fields::PURPOSE_IDENTITY, fields::CUSTOM_INCLUDE]));
258
 
259
        // Limit to name fields.
260
        $this->assertEquals(['firstname', 'lastname', 'lastnamephonetic'],
261
                $fields->get_required_fields([fields::PURPOSE_NAME]));
262
    }
263
 
264
    /**
265
     * There should be an exception if you try to 'limit' purposes to one that wasn't even included.
266
     */
11 efrain 267
    public function test_get_required_fields_limitpurposes_not_in_constructor(): void {
1 efrain 268
        $fields = fields::for_identity(null);
269
        $this->expectExceptionMessage('$limitpurposes can only include purposes defined in object');
270
        $fields->get_required_fields([fields::PURPOSE_USERPIC]);
271
    }
272
 
273
    /**
274
     * Sets up data and a fields object for all the get_sql tests.
275
     *
276
     * @return fields Constructed fields object for testing
277
     */
278
    protected function init_for_sql_tests(): fields {
279
        $generator = self::getDataGenerator();
280
        $generator->create_custom_profile_field(['datatype' => 'text', 'shortname' => 'a', 'name' => 'A']);
281
        $generator->create_custom_profile_field(['datatype' => 'text', 'shortname' => 'b', 'name' => 'B']);
282
 
283
        // Create a couple of users. One doesn't have a profile field set, so we can test that.
284
        $generator->create_user(['profile_field_a' => 'A1', 'profile_field_b' => 'B1',
285
                'city' => 'C1', 'department' => 'D1', 'email' => 'e1@example.org',
286
                'idnumber' => 'XXX1', 'username' => 'u1']);
287
        $generator->create_user(['profile_field_a' => 'A2',
288
                'city' => 'C2', 'department' => 'D2', 'email' => 'e2@example.org',
289
                'idnumber' => 'XXX2', 'username' => 'u2']);
290
 
291
        // It doesn't matter how we construct it (we already tested get_required_fields which is
292
        // where all those values are actually used) so let's just list the fields we want manually.
293
        return fields::empty()->including('department', 'city', 'profile_field_a', 'profile_field_b');
294
    }
295
 
296
    /**
297
     * Tests getting SQL (and actually using it).
298
     */
11 efrain 299
    public function test_get_sql_variations(): void {
1 efrain 300
        global $DB;
301
        $this->resetAfterTest();
302
 
303
        $fields = $this->init_for_sql_tests();
304
        fields::reset_unique_identifier();
305
 
306
        // Basic SQL.
307
        ['selects' => $selects, 'joins' => $joins, 'params' => $joinparams, 'mappings' => $mappings] =
308
                (array)$fields->get_sql();
309
        $sql = "SELECT idnumber
310
                       $selects
311
                  FROM {user}
312
                       $joins
313
                 WHERE idnumber LIKE ?
314
              ORDER BY idnumber";
315
        $records = $DB->get_records_sql($sql, array_merge($joinparams, ['X%']));
316
        $this->assertCount(2, $records);
317
        $expected1 = (object)['profile_field_a' => 'A1', 'profile_field_b' => 'B1',
318
                'city' => 'C1', 'department' => 'D1', 'idnumber' => 'XXX1'];
319
        $expected2 = (object)['profile_field_a' => 'A2', 'profile_field_b' => null,
320
                'city' => 'C2', 'department' => 'D2', 'idnumber' => 'XXX2'];
321
        $this->assertEquals($expected1, $records['XXX1']);
322
        $this->assertEquals($expected2, $records['XXX2']);
323
 
324
        $this->assertEquals([
325
                'department' => '{user}.department',
326
                'city' => '{user}.city',
327
                'profile_field_a' => $DB->sql_compare_text('uf1d_1.data', 255),
328
                'profile_field_b' => $DB->sql_compare_text('uf1d_2.data', 255)], $mappings);
329
 
330
        // SQL using named params.
331
        ['selects' => $selects, 'joins' => $joins, 'params' => $joinparams] =
332
                (array)$fields->get_sql('', true);
333
        $sql = "SELECT idnumber
334
                       $selects
335
                  FROM {user}
336
                       $joins
337
                 WHERE idnumber LIKE :idnum
338
              ORDER BY idnumber";
339
        $records = $DB->get_records_sql($sql, array_merge($joinparams, ['idnum' => 'X%']));
340
        $this->assertCount(2, $records);
341
        $this->assertEquals($expected1, $records['XXX1']);
342
        $this->assertEquals($expected2, $records['XXX2']);
343
 
344
        // SQL using alias for user table.
345
        ['selects' => $selects, 'joins' => $joins, 'params' => $joinparams, 'mappings' => $mappings] =
346
                (array)$fields->get_sql('u');
347
        $sql = "SELECT idnumber
348
                       $selects
349
                  FROM {user} u
350
                       $joins
351
                 WHERE idnumber LIKE ?
352
              ORDER BY idnumber";
353
        $records = $DB->get_records_sql($sql, array_merge($joinparams, ['X%']));
354
        $this->assertCount(2, $records);
355
        $this->assertEquals($expected1, $records['XXX1']);
356
        $this->assertEquals($expected2, $records['XXX2']);
357
 
358
        $this->assertEquals([
359
                'department' => 'u.department',
360
                'city' => 'u.city',
361
                'profile_field_a' => $DB->sql_compare_text('uf3d_1.data', 255),
362
                'profile_field_b' => $DB->sql_compare_text('uf3d_2.data', 255)], $mappings);
363
 
364
        // Returning prefixed fields.
365
        ['selects' => $selects, 'joins' => $joins, 'params' => $joinparams] =
366
                (array)$fields->get_sql('', false, 'u_');
367
        $sql = "SELECT idnumber
368
                       $selects
369
                  FROM {user}
370
                       $joins
371
                 WHERE idnumber LIKE ?
372
              ORDER BY idnumber";
373
        $records = $DB->get_records_sql($sql, array_merge($joinparams, ['X%']));
374
        $this->assertCount(2, $records);
375
        $expected1 = (object)['u_profile_field_a' => 'A1', 'u_profile_field_b' => 'B1',
376
                'u_city' => 'C1', 'u_department' => 'D1', 'idnumber' => 'XXX1'];
377
        $this->assertEquals($expected1, $records['XXX1']);
378
 
379
        // Renaming the id field. We need to use a different set of fields so it actually has the
380
        // id field.
381
        $fields = fields::for_userpic();
382
        ['selects' => $selects, 'joins' => $joins, 'params' => $joinparams] =
383
                (array)$fields->get_sql('', false, '', 'userid');
384
        $sql = "SELECT idnumber
385
                       $selects
386
                  FROM {user}
387
                       $joins
388
                 WHERE idnumber LIKE ?
389
              ORDER BY idnumber";
390
        $records = $DB->get_records_sql($sql, array_merge($joinparams, ['X%']));
391
        $this->assertCount(2, $records);
392
 
393
        // User id was renamed.
394
        $this->assertObjectNotHasProperty('id', $records['XXX1']);
395
        $this->assertObjectHasProperty('userid', $records['XXX1']);
396
 
397
        // Other fields are normal (just try a couple).
398
        $this->assertObjectHasProperty('firstname', $records['XXX1']);
399
        $this->assertObjectHasProperty('imagealt', $records['XXX1']);
400
 
401
        // Check the user id is actually right.
402
        $this->assertEquals('XXX1',
403
                $DB->get_field('user', 'idnumber', ['id' => $records['XXX1']->userid]));
404
 
405
        // Rename the id field and also use a prefix.
406
        ['selects' => $selects, 'joins' => $joins, 'params' => $joinparams] =
407
                (array)$fields->get_sql('', false, 'u_', 'userid');
408
        $sql = "SELECT idnumber
409
                       $selects
410
                  FROM {user}
411
                       $joins
412
                 WHERE idnumber LIKE ?
413
              ORDER BY idnumber";
414
        $records = $DB->get_records_sql($sql, array_merge($joinparams, ['X%']));
415
        $this->assertCount(2, $records);
416
 
417
        // User id was renamed.
418
        $this->assertObjectNotHasProperty('id', $records['XXX1']);
419
        $this->assertObjectNotHasProperty('u_id', $records['XXX1']);
420
        $this->assertObjectHasProperty('userid', $records['XXX1']);
421
 
422
        // Other fields are prefixed (just try a couple).
423
        $this->assertObjectHasProperty('u_firstname', $records['XXX1']);
424
        $this->assertObjectHasProperty('u_imagealt', $records['XXX1']);
425
 
426
        // Without a leading comma.
427
        ['selects' => $selects, 'joins' => $joins, 'params' => $joinparams] =
428
                (array)$fields->get_sql('', false, '', '', false);
429
        $sql = "SELECT $selects
430
                  FROM {user}
431
                       $joins
432
                 WHERE idnumber LIKE ?
433
              ORDER BY idnumber";
434
        $records = $DB->get_records_sql($sql, array_merge($joinparams, ['X%']));
435
        $this->assertCount(2, $records);
436
        foreach ($records as $key => $record) {
437
            // ID should be the first field used by get_records_sql.
438
            $this->assertEquals($key, $record->id);
439
            // Check 2 other sample properties.
440
            $this->assertObjectHasProperty('firstname', $record);
441
            $this->assertObjectHasProperty('imagealt', $record);
442
        }
443
    }
444
 
445
    /**
446
     * Tests what happens if you use the SQL multiple times in a query (i.e. that it correctly
447
     * creates the different identifiers).
448
     */
11 efrain 449
    public function test_get_sql_multiple(): void {
1 efrain 450
        global $DB;
451
        $this->resetAfterTest();
452
 
453
        $fields = $this->init_for_sql_tests();
454
 
455
        // Inner SQL.
456
        ['selects' => $selects1, 'joins' => $joins1, 'params' => $joinparams1] =
457
                (array)$fields->get_sql('u1', true);
458
        // Outer SQL.
459
        $fields2 = fields::empty()->including('profile_field_a', 'email');
460
        ['selects' => $selects2, 'joins' => $joins2, 'params' => $joinparams2] =
461
                (array)$fields2->get_sql('u2', true);
462
 
463
        // Crazy combined query.
464
        $sql = "SELECT username, details.profile_field_b AS innerb, details.city AS innerc
465
                       $selects2
466
                  FROM {user} u2
467
                       $joins2
468
             LEFT JOIN (
469
                          SELECT u1.id
470
                                 $selects1
471
                            FROM {user} u1
472
                                 $joins1
473
                           WHERE idnumber LIKE :idnum
474
                       ) details ON details.id = u2.id
475
              ORDER BY username";
476
        $records = $DB->get_records_sql($sql, array_merge($joinparams1, $joinparams2, ['idnum' => 'X%']));
477
        // The left join won't match for admin.
478
        $this->assertNull($records['admin']->innerb);
479
        $this->assertNull($records['admin']->innerc);
480
        // It should match for one of the test users though.
481
        $expected1 = (object)['username' => 'u1', 'innerb' => 'B1', 'innerc' => 'C1',
482
                'profile_field_a' => 'A1', 'email' => 'e1@example.org'];
483
        $this->assertEquals($expected1, $records['u1']);
484
    }
485
 
486
    /**
487
     * Tests the get_sql function when there are no fields to retrieve.
488
     */
11 efrain 489
    public function test_get_sql_nothing(): void {
1 efrain 490
        $fields = fields::empty();
491
        ['selects' => $selects, 'joins' => $joins, 'params' => $joinparams] = (array)$fields->get_sql();
492
        $this->assertEquals('', $selects);
493
        $this->assertEquals('', $joins);
494
        $this->assertEquals([], $joinparams);
495
    }
496
 
497
    /**
498
     * Tests get_sql when there are no custom fields; in this scenario, the joins and joinparams
499
     * are always blank.
500
     */
11 efrain 501
    public function test_get_sql_no_custom_fields(): void {
1 efrain 502
        $fields = fields::empty()->including('city', 'country');
503
        ['selects' => $selects, 'joins' => $joins, 'params' => $joinparams, 'mappings' => $mappings] =
504
                (array)$fields->get_sql('u');
505
        $this->assertEquals(', u.city, u.country', $selects);
506
        $this->assertEquals('', $joins);
507
        $this->assertEquals([], $joinparams);
508
        $this->assertEquals(['city' => 'u.city', 'country' => 'u.country'], $mappings);
509
    }
510
 
511
    /**
512
     * Tests the format of the $selects string, which is important particularly for backward
513
     * compatibility.
514
     */
11 efrain 515
    public function test_get_sql_selects_format(): void {
1 efrain 516
        global $DB;
517
 
518
        $this->resetAfterTest();
519
        fields::reset_unique_identifier();
520
 
521
        $generator = self::getDataGenerator();
522
        $generator->create_custom_profile_field(['datatype' => 'text', 'shortname' => 'a', 'name' => 'A']);
523
 
524
        // When we list fields that include custom profile fields...
525
        $fields = fields::empty()->including('id', 'profile_field_a');
526
 
527
        // Supplying an alias: all fields have alias.
528
        $selects = $fields->get_sql('u')->selects;
529
        $this->assertEquals(', u.id, ' . $DB->sql_compare_text('uf1d_1.data', 255) . ' AS profile_field_a', $selects);
530
 
531
        // No alias: all files have {user} because of the joins.
532
        $selects = $fields->get_sql()->selects;
533
        $this->assertEquals(', {user}.id, ' . $DB->sql_compare_text('uf2d_1.data', 255) . ' AS profile_field_a', $selects);
534
 
535
        // When the list doesn't include custom profile fields...
536
        $fields = fields::empty()->including('id', 'city');
537
 
538
        // Supplying an alias: all fields have alias.
539
        $selects = $fields->get_sql('u')->selects;
540
        $this->assertEquals(', u.id, u.city', $selects);
541
 
542
        // No alias: fields do not have alias at all.
543
        $selects = $fields->get_sql()->selects;
544
        $this->assertEquals(', id, city', $selects);
545
    }
546
 
547
    /**
548
     * Data provider for {@see test_get_sql_fullname}
549
     *
550
     * @return array
551
     */
552
    public function get_sql_fullname_provider(): array {
553
        return [
554
            ['firstname lastname', 'FN LN'],
555
            ['lastname, firstname', 'LN, FN'],
556
            ['alternatename \'middlename\' lastname!', 'AN \'MN\' LN!'],
557
            ['[firstname lastname alternatename]', '[FN LN AN]'],
558
            ['firstnamephonetic lastnamephonetic', 'FNP LNP'],
559
            ['firstname alternatename lastname', 'FN AN LN'],
560
        ];
561
    }
562
 
563
    /**
564
     * Test sql_fullname_display method with various fullname formats
565
     *
566
     * @param string $fullnamedisplay
567
     * @param string $expectedfullname
568
     *
569
     * @dataProvider get_sql_fullname_provider
570
     */
571
    public function test_get_sql_fullname(string $fullnamedisplay, string $expectedfullname): void {
572
        global $DB;
573
 
574
        $this->resetAfterTest();
575
 
576
        set_config('fullnamedisplay', $fullnamedisplay);
577
        $user = $this->getDataGenerator()->create_user([
578
            'firstname' => 'FN',
579
            'lastname' => 'LN',
580
            'firstnamephonetic' => 'FNP',
581
            'lastnamephonetic' => 'LNP',
582
            'middlename' => 'MN',
583
            'alternatename' => 'AN',
584
        ]);
585
 
586
        [$sqlfullname, $params] = fields::get_sql_fullname('u');
587
        $fullname = $DB->get_field_sql("SELECT {$sqlfullname} FROM {user} u WHERE u.id = :id", $params + [
588
            'id' => $user->id,
589
        ]);
590
 
591
        $this->assertEquals($expectedfullname, $fullname);
592
    }
593
 
594
    /**
595
     * Test sql_fullname_display when one of the configured name fields is null
596
     */
597
    public function test_get_sql_fullname_null_field(): void {
598
        global $DB;
599
 
600
        $this->resetAfterTest();
601
 
602
        set_config('fullnamedisplay', 'firstname lastname alternatename');
603
        $user = $this->getDataGenerator()->create_user([
604
            'firstname' => 'FN',
605
            'lastname' => 'LN',
606
        ]);
607
 
608
        // Set alternatename field to null, ensure we still get result in later assertion.
609
        $user->alternatename = null;
610
        user_update_user($user, false);
611
 
612
        [$sqlfullname, $params] = fields::get_sql_fullname('u');
613
        $fullname = $DB->get_field_sql("SELECT {$sqlfullname} FROM {user} u WHERE u.id = :id", $params + [
614
            'id' => $user->id,
615
        ]);
616
 
617
        $this->assertEquals('FN LN ', $fullname);
618
    }
619
}