Proyectos de Subversion Moodle

Rev

| 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
declare(strict_types=1);
18
 
19
namespace core_reportbuilder\local\report;
20
 
21
use action_menu_link;
22
use lang_string;
23
use moodle_url;
24
use pix_icon;
25
use popup_action;
26
use stdClass;
27
 
28
/**
29
 * Class to represent a report action
30
 *
31
 * @package     core_reportbuilder
32
 * @copyright   2021 Paul Holden <paulh@moodle.com>
33
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34
 */
35
final class action {
36
 
37
    /** @var moodle_url $url */
38
    protected $url;
39
 
40
    /** @var pix_icon $icon */
41
    protected $icon;
42
 
43
    /** @var array $attributes */
44
    protected $attributes;
45
 
46
    /** @var bool $popup */
47
    protected $popup;
48
 
49
    /** @var callable[] $callbacks */
50
    protected $callbacks = [];
51
 
52
    /** @var lang_string|string $title */
53
    protected $title;
54
 
55
    /**
56
     * Create an instance of an action to be added to a report. Both the parameters of the URL, and the attributes parameter
57
     * support placeholders which will be replaced with appropriate row values, e.g.:
58
     *
59
     * new action(new moodle_url('/', ['id' => ':id']), new pix_icon(...), ['data-id' => ':id'])
60
     *
61
     * Note that all expected placeholders should be added as base fields to the report
62
     *
63
     * @param moodle_url $url
64
     * @param pix_icon $icon
65
     * @param string[] $attributes Array of attributes to include in action, each will be cast to string prior to use
66
     * @param bool $popup
67
     * @param ?lang_string $title
68
     */
69
    public function __construct(
70
        moodle_url $url,
71
        pix_icon $icon,
72
        array $attributes = [],
73
        bool $popup = false,
74
        ?lang_string $title = null
75
    ) {
76
        $this->url = $url;
77
        $this->icon = $icon;
78
        $this->attributes = $attributes;
79
        $this->popup = $popup;
80
        // If title is not passed, check the title attribute from the icon.
81
        $this->title = $title ?? $icon->attributes['title'] ?? '';
82
    }
83
 
84
    /**
85
     * Adds callback to the action. Used to verify action is available to current user, or preprocess values used in placeholders
86
     *
87
     * Multiple callbacks can be added. If at least one returns false then the action will not be displayed
88
     *
89
     * @param callable $callback
90
     * @return self
91
     */
92
    public function add_callback(callable $callback): self {
93
        $this->callbacks[] = $callback;
94
        return $this;
95
    }
96
 
97
    /**
98
     * Return action menu link suitable for output, or null if the action cannot be displayed (because one of its callbacks
99
     * returned false, {@see add_callback})
100
     *
101
     * @param stdClass $row
102
     * @return action_menu_link|null
103
     */
104
    public function get_action_link(stdClass $row): ?action_menu_link {
105
 
106
        foreach ($this->callbacks as $callback) {
107
            $row = clone $row; // Clone so we don't modify the shared row inside a callback.
108
            if (!$callback($row)) {
109
                return null;
110
            }
111
        }
112
 
113
        // Create a new moodle_url instance with our filled in placeholders for this row.
114
        $url = new moodle_url(
115
            $this->url->out_omit_querystring(true),
116
            self::replace_placeholders($this->url->params(), $row)
117
        );
118
 
119
        // Ensure we have a title attribute set, if one wasn't already provided.
120
        if (!array_key_exists('title', $this->attributes)) {
121
            $this->attributes['title'] = (string) $this->title;
122
        }
123
        $this->attributes['aria-label'] = $this->attributes['title'];
124
 
125
        if ($this->popup) {
126
            $this->attributes['data-action'] = 'report-action-popup';
127
            $this->attributes['data-popup-action'] = json_encode(new popup_action('click', $url));
128
        }
129
 
130
        // Interpolate any placeholders with correct values.
131
        $attributes = self::replace_placeholders($this->attributes, $row);
132
 
133
        // Ensure title attribute isn't duplicated.
134
        $title = $attributes['title'];
135
        unset($attributes['title']);
136
 
137
        return new action_menu_link($url, $this->icon, $title, null, $attributes);
138
    }
139
 
140
    /**
141
     * Given an array of values, replace all placeholders with corresponding property of the given row
142
     *
143
     * @param string[] $values
144
     * @param stdClass $row
145
     * @return array
146
     */
147
    private static function replace_placeholders(array $values, stdClass $row): array {
148
        return array_map(static function($value) use ($row) {
149
            return preg_replace_callback('/^:(?<property>.*)$/', static function(array $matches) use ($row): string {
150
                return (string) ($row->{$matches['property']} ?? '');
151
            }, (string) $value);
152
        }, $values);
153
    }
154
}