Proyectos de Subversion Moodle

Rev

Rev 1 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 1 Rev 1441
Línea 16... Línea 16...
16
 
16
 
Línea 17... Línea 17...
17
declare(strict_types=1);
17
declare(strict_types=1);
Línea 18... Línea 18...
18
 
18
 
19
namespace core_reportbuilder\local\helpers;
19
namespace core_reportbuilder\local\helpers;
20
 
20
 
21
use context_system;
-
 
22
use core_text;
-
 
23
use core_reportbuilder\local\filters\boolean_select;
-
 
24
use core_reportbuilder\local\filters\date;
-
 
25
use core_reportbuilder\local\filters\select;
21
use core\lang_string;
26
use core_reportbuilder\local\filters\text;
-
 
27
use core_reportbuilder\local\report\column;
22
use core_text;
28
use core_reportbuilder\local\report\filter;
23
use core_reportbuilder\local\filters\{boolean_select, date, select, text};
Línea 29... Línea 24...
29
use lang_string;
24
use core_reportbuilder\local\report\{column, filter};
Línea 42... Línea 37...
42
 * @copyright 2021 David Matamoros <davidmc@moodle.com>
37
 * @copyright 2021 David Matamoros <davidmc@moodle.com>
43
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44
 */
39
 */
45
class user_profile_fields {
40
class user_profile_fields {
Línea 46... Línea -...
46
 
-
 
47
    /** @var array user profile fields */
41
 
Línea 48... Línea -...
48
    private $userprofilefields;
-
 
49
 
-
 
50
    /** @var string $entityname Name of the entity */
-
 
51
    private $entityname;
42
    use join_trait;
52
 
43
 
53
    /** @var int $usertablefieldalias The user table/field alias */
-
 
54
    private $usertablefieldalias;
-
 
55
 
-
 
Línea 56... Línea 44...
56
    /** @var array additional joins */
44
    /** @var profile_field_base[] User profile fields */
57
    private $joins = [];
45
    private array $userprofilefields;
58
 
46
 
59
    /**
47
    /**
60
     * Class userprofilefields constructor.
48
     * Constructor
61
     *
49
     *
62
     * @param string $usertablefieldalias The user table/field alias used when adding columns and filters.
50
     * @param string $usertablefieldalias The table/field alias to match the user ID when adding columns and filters.
63
     * @param string $entityname The entity name used when adding columns and filters.
51
     * @param string $entityname The entity name used when adding columns and filters.
64
     */
-
 
65
    public function __construct(string $usertablefieldalias, string $entityname) {
52
     */
66
        $this->usertablefieldalias = $usertablefieldalias;
-
 
67
        $this->entityname = $entityname;
-
 
68
        $this->userprofilefields = $this->get_user_profile_fields();
-
 
69
    }
53
    public function __construct(
70
 
-
 
71
    /**
-
 
72
     * Retrieves the list of available/visible user profile fields
-
 
73
     *
-
 
74
     * @return profile_field_base[]
-
 
75
     */
-
 
76
    private function get_user_profile_fields(): array {
-
 
77
        return array_filter(profile_get_user_fields_with_data(0), static function(profile_field_base $profilefield): bool {
-
 
78
            return $profilefield->is_visible();
-
 
79
        });
-
 
80
    }
54
        /** @var string The table/field alias to match the user ID when adding columns and filters */
81
 
55
        private readonly string $usertablefieldalias,
82
    /**
-
 
83
     * Additional join that is needed.
-
 
84
     *
-
 
85
     * @param string $join
-
 
86
     * @return self
56
        /** @var string The entity name used when adding columns and filters */
87
     */
-
 
88
    public function add_join(string $join): self {
-
 
89
        $this->joins[trim($join)] = trim($join);
-
 
90
        return $this;
-
 
91
    }
-
 
92
 
-
 
93
    /**
-
 
94
     * Additional joins that are needed.
-
 
95
     *
-
 
96
     * @param array $joins
-
 
97
     * @return self
-
 
98
     */
-
 
99
    public function add_joins(array $joins): self {
-
 
100
        foreach ($joins as $join) {
-
 
101
            $this->add_join($join);
-
 
102
        }
-
 
103
        return $this;
-
 
104
    }
-
 
105
 
-
 
106
    /**
-
 
107
     * Return joins
-
 
108
     *
-
 
109
     * @return string[]
-
 
110
     */
57
        private readonly string $entityname,
Línea 111... Línea 58...
111
    private function get_joins(): array {
58
    ) {
112
        return array_values($this->joins);
59
        $this->userprofilefields = profile_get_user_fields_with_data(0);
113
    }
60
    }
Línea 153... Línea 100...
153
     */
100
     */
154
    public function get_columns(): array {
101
    public function get_columns(): array {
155
        global $DB;
102
        global $DB;
Línea 156... Línea 103...
156
 
103
 
-
 
104
        $columns = [];
157
        $columns = [];
105
 
-
 
106
        foreach ($this->userprofilefields as $profilefield) {
-
 
107
            $userinfotablealias = $this->get_table_alias($profilefield);
-
 
108
            $userinfosql = "{$userinfotablealias}.data";
-
 
109
 
158
        foreach ($this->userprofilefields as $profilefield) {
110
            // Numeric column (non-text) should coalesce with default, for aggregation.
159
            $columntype = $this->get_user_field_type($profilefield->field->datatype);
111
            $columntype = $this->get_user_field_type($profilefield->field->datatype);
Línea 160... Línea 112...
160
            $columnfieldsql = $this->get_table_alias($profilefield) . '.data';
112
            if (!in_array($columntype, [column::TYPE_TEXT, column::TYPE_LONGTEXT])) {
161
 
113
 
162
            // Numeric (checkbox/time) fields should be cast, as should all fields for Oracle, for aggregation support.
114
                // See MDL-78783 regarding no bound parameters, and SQL Server limitations of GROUP BY.
-
 
115
                $userinfosql = "
163
            if ($columntype === column::TYPE_BOOLEAN || $columntype === column::TYPE_TIMESTAMP) {
116
                    CASE WHEN {$this->usertablefieldalias} IS NOT NULL
164
                $columnfieldsql = "CASE WHEN {$columnfieldsql} IS NULL THEN NULL ELSE " .
117
                         THEN " .
165
                    $DB->sql_cast_char2int($columnfieldsql, true) . " END";
118
                            $DB->sql_cast_char2int("COALESCE({$userinfosql}, '" . (float) $profilefield->field->defaultdata . "')")
-
 
119
                            . "
166
            } else if ($DB->get_dbfamily() === 'oracle') {
120
                         ELSE NULL
Línea 167... Línea -...
167
                $columnfieldsql = $DB->sql_order_by_text($columnfieldsql, 1024);
-
 
168
            }
121
                    END";
169
 
122
            }
170
            $columns[] = (new column(
123
 
171
                'profilefield_' . core_text::strtolower($profilefield->field->shortname),
124
            $columnname = 'profilefield_' . core_text::strtolower($profilefield->field->shortname);
172
                new lang_string('customfieldcolumn', 'core_reportbuilder',
125
            $columns[$columnname] = (new column(
173
                    format_string($profilefield->field->name, true,
126
                $columnname,
174
                        ['escape' => false, 'context' => context_system::instance()])),
127
                new lang_string('customfieldcolumn', 'core_reportbuilder', $profilefield->display_name(false)),
175
                $this->entityname
128
                $this->entityname
176
            ))
-
 
177
                ->add_joins($this->get_joins())
129
            ))
-
 
130
                ->add_joins($this->get_joins())
-
 
131
                ->add_join($this->get_table_join($profilefield))
-
 
132
                ->set_type($columntype)
178
                ->add_join($this->get_table_join($profilefield))
133
                ->add_field($userinfosql, 'data')
179
                ->add_field($columnfieldsql, 'data')
134
                ->add_field("{$userinfotablealias}.dataformat")
180
                ->set_type($columntype)
135
                ->add_field($this->usertablefieldalias, 'userid')
181
                ->set_is_sortable($columntype !== column::TYPE_LONGTEXT)
136
                ->set_is_sortable(true)
182
                ->add_callback(static function($value, stdClass $row, profile_field_base $field): string {
137
                ->add_callback(static function($value, stdClass $row, profile_field_base $field): string {
Línea 183... Línea 138...
183
                    if ($value === null) {
138
                    if ($row->userid === null && $value === null) {
-
 
139
                        return '';
-
 
140
                    }
-
 
141
 
-
 
142
                    $field->set_user_data(
184
                        return '';
143
                        $row->data ?? $field->field->defaultdata,
185
                    }
144
                        $row->dataformat ?? $field->field->defaultdataformat,
-
 
145
                    );
186
 
146
 
Línea 187... Línea 147...
187
                    $field->data = $value;
147
                    return $field->display_data();
188
                    return (string) $field->display_data();
148
                }, $profilefield)
Línea 189... Línea 149...
189
                }, $profilefield);
149
                ->set_is_available($profilefield->is_visible());
190
        }
150
        }
191
 
151
 
Línea 199... Línea 159...
199
     */
159
     */
200
    public function get_filters(): array {
160
    public function get_filters(): array {
201
        global $DB;
161
        global $DB;
Línea 202... Línea 162...
202
 
162
 
-
 
163
        $filters = [];
203
        $filters = [];
164
 
204
        foreach ($this->userprofilefields as $profilefield) {
165
        foreach ($this->userprofilefields as $profilefield) {
-
 
166
            $userinfotablealias = $this->get_table_alias($profilefield);
205
            $field = $this->get_table_alias($profilefield) . '.data';
167
            $userinfosql = "{$userinfotablealias}.data";
Línea -... Línea 168...
-
 
168
            $userinfoparams = [];
206
            $params = [];
169
 
207
 
170
            // Perform casts where necessary, as this is a text DB field.
208
            switch ($profilefield->field->datatype) {
171
            switch ($profilefield->field->datatype) {
209
                case 'checkbox':
172
                case 'checkbox':
210
                    $classname = boolean_select::class;
173
                    $classname = boolean_select::class;
211
                    $fieldsql = "COALESCE(" . $DB->sql_cast_char2int($field, true) . ", 0)";
174
                    $userinfosql = $DB->sql_cast_char2int($userinfosql, true);
212
                    break;
175
                    break;
213
                case 'datetime':
176
                case 'datetime':
214
                    $classname = date::class;
177
                    $classname = date::class;
215
                    $fieldsql = $DB->sql_cast_char2int($field, true);
178
                    $userinfosql = $DB->sql_cast_char2int($userinfosql, true);
216
                    break;
179
                    break;
217
                case 'menu':
-
 
218
                    $classname = select::class;
-
 
219
 
-
 
220
                    $emptyparam = database::generate_param_name();
-
 
221
                    $fieldsql = "COALESCE(" . $DB->sql_compare_text($field, 255) . ", :{$emptyparam})";
-
 
222
                    $params[$emptyparam] = '';
180
                case 'menu':
223
 
181
                    $classname = select::class;
224
                    break;
182
                    break;
225
                case 'text':
183
                case 'text':
226
                case 'textarea':
184
                case 'textarea':
227
                default:
-
 
228
                    $classname = text::class;
-
 
229
 
-
 
230
                    $emptyparam = database::generate_param_name();
-
 
231
                    $fieldsql = "COALESCE(" . $DB->sql_compare_text($field, 255) . ", :{$emptyparam})";
-
 
232
                    $params[$emptyparam] = '';
185
                default:
233
 
186
                    $classname = text::class;
Línea -... Línea 187...
-
 
187
                    break;
-
 
188
            }
-
 
189
 
-
 
190
            // Account for field default value, when joined to the user table.
-
 
191
            if (($fielddefault = $profilefield->field->defaultdata) !== null) {
-
 
192
                $paramdefault = database::generate_param_name();
-
 
193
                $userinfosql = "
-
 
194
                        CASE WHEN {$this->usertablefieldalias} IS NOT NULL
-
 
195
                             THEN COALESCE({$userinfosql}, :{$paramdefault})
-
 
196
                             ELSE NULL
-
 
197
                        END";
-
 
198
                $userinfoparams[$paramdefault] = $fielddefault;
234
                    break;
199
            }
235
            }
200
 
236
 
201
            $filtername = 'profilefield_' . core_text::strtolower($profilefield->field->shortname);
237
            $filter = (new filter(
202
            $filter = (new filter(
238
                $classname,
-
 
239
                'profilefield_' . core_text::strtolower($profilefield->field->shortname),
-
 
240
                new lang_string('customfieldcolumn', 'core_reportbuilder',
203
                $classname,
241
                    format_string($profilefield->field->name, true,
204
                $filtername,
242
                        ['escape' => false, 'context' => context_system::instance()])),
205
                new lang_string('customfieldcolumn', 'core_reportbuilder', $profilefield->display_name(false)),
243
                $this->entityname,
206
                $this->entityname,
244
                $fieldsql,
207
                $userinfosql,
245
                $params
208
                $userinfoparams,
-
 
209
            ))
Línea 246... Línea 210...
246
            ))
210
                ->add_joins($this->get_joins())
247
                ->add_joins($this->get_joins())
211
                ->add_join($this->get_table_join($profilefield))
248
                ->add_join($this->get_table_join($profilefield));
212
                ->set_is_available($profilefield->is_visible());
249
 
213
 
Línea 250... Línea 214...
250
            // If menu type then set filter options as appropriate.
214
            // If using a select filter, then populate the options.
251
            if ($profilefield->field->datatype === 'menu') {
215
            if ($filter->get_filter_class() === select::class) {
Línea 252... Línea 216...
252
                $filter->set_options($profilefield->options);
216
                $filter->set_options_callback(fn(): array => $profilefield->options);
253
            }
217
            }
Línea 254... Línea 218...
254
 
218
 
255
            $filters[] = $filter;
219
            $filters[$filtername] = $filter;
256
        }
220
        }