Proyectos de Subversion Moodle

Rev

Rev 836 | | 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
/**
18
 * Class that does all the magic.
19
 *
20
 * @package   block_multiblock
21
 * @copyright 2019 Peter Spicer <peter.spicer@catalyst-eu.net> 2021 James Pearce <jmp201@bath.ac.uk>
22
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
use block_multiblock\helper;
26
use block_multiblock\icon_helper;
27
use block_multiblock\adddefaultblock;
28
 
29
/**
30
 * Block multiblock class definition.
31
 *
32
 * This block can be added to a variety of places to display multiple blocks in one space.
33
 *
34
 * @package   block_multiblock
35
 * @copyright 2019 Peter Spicer <peter.spicer@catalyst-eu.net>
36
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37
 */
836 ariadna 38
class block_multiblock extends block_base
39
{
1 efrain 40
    /** @var object $output Temporary storage of the injected page renderer so we can pass it to child blocks at render time. */
41
    private $output;
42
 
43
    /**
44
     * Core function used to initialize the block.
45
     */
836 ariadna 46
    public function init()
47
    {
1 efrain 48
        $this->title = get_string('pluginname', 'block_multiblock');
49
    }
50
 
51
    /**
52
     * has_config - denotes whether your block wants to present a configuration interface to site admins or not
53
     *
54
     * @return boolean
55
     */
836 ariadna 56
    public function has_config()
57
    {
1 efrain 58
        return true;
59
    }
60
 
61
    /**
62
     * Core function, specifies where the block can be used.
63
     *
64
     * @return array
65
     */
836 ariadna 66
    public function applicable_formats()
67
    {
1 efrain 68
        return [
69
            'all' => true,
70
        ];
71
    }
72
 
73
    /**
74
     * Sets the block's title for a specific instance based on its configuration.
75
     */
836 ariadna 76
    public function specialization()
77
    {
1 efrain 78
        $defaulttitle = get_config('block_multiblock', 'title');
79
        if (isset($this->config->title)) {
80
            $this->title = format_string($this->config->title, true, ['context' => $this->context]);
81
        } else if ($defaulttitle) {
82
            $this->title = format_string($defaulttitle, true, ['context' => $this->context]);
83
        } else {
84
            $this->title = get_string('pluginname', 'block_multiblock');
85
        }
86
    }
87
 
836 ariadna 88
    /* Set block attributes */
89
    function html_attributes()
90
    {
91
        $attributes = array(
92
            'id' => 'inst' . $this->instance->id,
837 ariadna 93
            'class' => 'block_' . $this->name() . ' block' . ' multiblock-columns-2-parent',
836 ariadna 94
            'role' => $this->get_aria_role()
95
        );
96
        if ($this->hide_header()) {
97
            $attributes['class'] .= ' no-header';
98
        }
99
        if ($this->instance_can_be_docked() && get_user_preferences('docked_block_instance_' . $this->instance->id, 0)) {
100
            $attributes['class'] .= ' dock_on_load';
101
        }
102
        return $attributes;
103
    }
104
 
1 efrain 105
    /**
106
     * Loads the child blocks of the current multiblock.
107
     *
108
     * @param int $contextid The multiblock's context instance id.
109
     * @return array An array of child blocks.
110
     */
836 ariadna 111
    public function load_multiblocks($contextid)
112
    {
1 efrain 113
        global $DB;
114
 
115
        // Find all the things that relate to this block.
116
        $this->blocks = $DB->get_records('block_instances', ['parentcontextid' => $contextid], 'defaultweight, id');
117
        foreach ($this->blocks as $id => $block) {
118
            if (block_load_class($block->blockname)) {
119
                // Make the proxy class we'll need.
120
                $this->blocks[$id]->blockinstance = block_instance($block->blockname, $block);
121
                $this->blocks[$id]->blockname = $block->blockname;
122
                $this->blocks[$id]->visible = true;
123
                $this->blocks[$id]->blockpositionid = 0;
124
            }
125
        }
126
 
127
        return $this->blocks;
128
    }
129
 
130
    /**
131
     *  Used to add the default blocks to the multiblock.
132
     */
836 ariadna 133
    public function add_default_blocks()
134
    {
1 efrain 135
        global $DB, $CFG;
136
 
137
        if (empty($this->instance)) {
138
            return $this->content;
139
        }
140
 
141
        $context = $DB->get_record('context', ['contextlevel' => CONTEXT_BLOCK, 'instanceid' => $this->instance->id]);
142
 
143
        $this->load_multiblocks($context->id);
144
 
145
        $multiblock = [];
146
        $isodd = true;
147
        $blockid = $this->instance->id;
148
        if (empty($this->blocks)) {
149
 
150
            $defaultblocksarray = explode(',', get_config('block_multiblock')->subblock);
151
 
152
            $addblock = new adddefaultblock();
153
            $addblock->init($blockid, $defaultblocksarray, $this->instance);
154
        }
155
    }
156
 
157
    /**
158
     * Used to generate the content for the block.
159
     *
160
     * @return string
161
     */
836 ariadna 162
    public function get_content()
163
    {
1 efrain 164
        global $DB, $CFG;
165
        if ($this->content !== null) {
166
            return $this->content;
167
        }
168
        $this->content = new stdClass;
169
        $this->content->text = '';
170
        $this->content->footer = '';
171
        if (empty($this->instance)) {
172
            return $this->content;
173
        }
174
        $context = $DB->get_record('context', ['contextlevel' => CONTEXT_BLOCK, 'instanceid' => $this->instance->id]);
175
 
176
        $this->load_multiblocks($context->id);
177
 
178
        $multiblock = [];
179
        $isodd = true;
180
        $blockid = $this->instance->id;
181
 
182
        if (empty($this->blocks)) {
183
            $this->add_default_blocks();
184
            $this->load_multiblocks($context->id);
185
        }
186
 
187
        foreach ($this->blocks as $id => $block) {
188
            if (empty($block->blockinstance)) {
189
                continue;
190
            }
191
            $content = $block->blockinstance->get_content_for_output($this->output);
192
            $multiblock[] = [
193
                'id' => $id,
194
                'class' => 'block_' . $block->blockinstance->name(),
195
                'type' => $block->blockinstance->name(),
196
                'is_odd' => $isodd,
197
                'title' => $block->blockinstance->get_title(),
198
                'content' => !empty($content->content) ? $content->content : '',
199
                'footer' => !empty($content->footer) ? $content->footer : '',
200
            ];
201
            $isodd = !$isodd;
202
        }
203
 
204
        $template = '';
205
        $presentations = static::get_valid_presentations();
206
        $multiblockpresentationoptions = [];
207
        foreach ($presentations as $presentationid => $presentation) {
208
            array_push($multiblockpresentationoptions, $presentationid);
209
        }
210
        $configuredpresentation = get_config('block_multiblock', 'presentation');
211
        if (!empty($this->config->presentation)) {
212
            $template = $this->config->presentation;
213
        } else if (isset($configuredpresentation)) {
214
            $template = $multiblockpresentationoptions[$configuredpresentation];
215
        } else if (isset($presentations['tabbed-list'])) {
216
            $template = 'tabbed-list';
217
        }
218
 
219
        $renderable = new \block_multiblock\output\main((int) $this->instance->id, $multiblock, $template);
220
        $renderer = $this->page->get_renderer('block_multiblock');
221
 
222
        $this->content = (object) [
223
            'text' => $renderer->render($renderable),
224
            'footer' => ''
225
        ];
226
        return $this->content;
227
    }
228
 
229
    /**
230
     * Return a block_contents object representing the full contents of this block.
231
     *
232
     * This internally calls ->get_content(), and then adds the editing controls etc.
233
     *
234
     * @param object $output The output renderer from the parent context (e.g. page renderer)
235
     * @return block_contents a representation of the block, for rendering.
236
     */
836 ariadna 237
    public function get_content_for_output($output)
238
    {
1 efrain 239
        $this->output = $output;
240
        $bc = parent::get_content_for_output($output);
241
 
242
        if (empty($bc->controls)) {
243
            return $bc;
244
        }
245
 
246
        $str = get_string('managemultiblock', 'block_multiblock', $this->title);
247
 
248
        $newcontrols = [];
249
        foreach ($bc->controls as $control) {
250
            $newcontrols[] = $control;
251
            // Append our new item onto the controls if we're on the correct item.
252
            if (strpos($control->attributes['class'], 'editing_edit') !== false) {
253
                $newcontrols[] = new action_menu_link_secondary(
254
                    new moodle_url('/blocks/multiblock/manage.php', ['id' => $this->instance->id, 'sesskey' => sesskey()]),
255
                    icon_helper::preferences($str),
256
                    $str,
257
                    ['class' => 'editing_manage']
258
                );
259
            }
260
        }
261
        // Append a delete+split item on the end.
262
        $newcontrols[] = new action_menu_link_secondary(
836 ariadna 263
            new moodle_url('/blocks/multiblock/manage.php', [
264
                'id' => $this->instance->id,
265
                'sesskey' => sesskey(),
266
                'action' => 'splitdelete'
267
            ]),
1 efrain 268
            icon_helper::delete($str),
269
            get_string('splitanddelete', 'block_multiblock', $this->title),
270
            ['class' => 'editing_manage']
271
        );
272
        $bc->controls = $newcontrols;
273
        return $bc;
274
    }
275
 
276
    /**
277
     * Allows the block to be added multiple times to a single page
278
     * @return boolean
279
     */
836 ariadna 280
    public function instance_allow_multiple()
281
    {
1 efrain 282
        return true;
283
    }
284
 
285
    /**
286
     * Copy all the children when copying to a new block instance.
287
     *
288
     * @param int $fromid The id number of the block instance to copy from
289
     * @return bool
290
     */
836 ariadna 291
    public function instance_copy($fromid)
292
    {
1 efrain 293
        global $DB;
294
 
295
        $fromcontext = context_block::instance($fromid);
296
 
297
        $blockinstances = $DB->get_records('block_instances', ['parentcontextid' => $fromcontext->id], 'defaultweight, id');
298
 
299
        // Create all the new block instances.
300
        $newblockinstanceids = [];
301
        foreach ($blockinstances as $instance) {
302
            $originalid = $instance->id;
303
            unset($instance->id);
304
            $instance->parentcontextid = $this->context->id;
305
            $instance->timecreated = time();
306
            $instance->timemodified = $instance->timecreated;
307
            $instance->id = $DB->insert_record('block_instances', $instance);
308
            $newblockinstanceids[$originalid] = $instance->id;
309
            $blockcontext = context_block::instance($instance->id);  // Just creates the context record.
310
            $block = block_instance($instance->blockname, $instance);
311
            if (!$block->instance_copy($originalid)) {
312
                debugging("Unable to copy block-specific data for original block instance: $originalid
313
                    to new block instance: $instance->id", DEBUG_DEVELOPER);
314
            }
315
        }
316
        return true;
317
    }
318
 
319
    /**
320
     * Callback for when this block instance is being deleted, to clean up child blocks.
321
     *
322
     * @return bool
323
     */
836 ariadna 324
    public function instance_delete()
325
    {
1 efrain 326
        global $DB;
327
 
328
        // Find all the things that relate to this block.
329
        foreach ($DB->get_records('block_instances', ['parentcontextid' => $this->context->id]) as $subblock) {
330
            blocks_delete_instance($subblock);
331
        }
332
        return true;
333
    }
334
 
335
    /**
336
     * Lists all the known presentation types that exist in the block.
337
     *
338
     * @return array An array of presentations for block rendering.
339
     */
836 ariadna 340
    public static function get_valid_presentations(): array
341
    {
1 efrain 342
        static $presentations = null;
343
 
344
        if ($presentations === null) {
345
 
346
            foreach (core_component::get_component_classes_in_namespace('block_multiblock', 'layout') as $class => $ns) {
347
                if (strpos($class, $ns[0]) === 0) {
348
                    // We only care about non-abstract classes here.
349
                    $reflection = new ReflectionClass($class);
350
                    if ($reflection->isAbstract()) {
351
                        continue;
352
                    }
353
                    $classname = substr($class, strlen($ns[0]));
354
 
355
                    $instance = new $class;
356
                    $presentations[$instance->get_layout_id()] = $instance;
357
                }
358
            }
359
        }
360
 
361
        return $presentations;
362
    }
363
 
364
    /**
365
     * Returns the default presentation for the multiblock.
366
     *
367
     * @return string The default presentation's identifier.
368
     */
836 ariadna 369
    public static function get_default_presentation(): string
370
    {
1 efrain 371
        $presentations = static::get_valid_presentations();
372
        $multiblockpresentationoptions = [];
373
        $configuredpresentation = get_config('block_multiblock', 'presentation');
374
        foreach ($presentations as $presentationid => $presentation) {
375
            array_push($multiblockpresentationoptions, $presentationid);
376
        }
377
        if ($configuredpresentation) {
378
            return $multiblockpresentationoptions[$configuredpresentation];
379
        }
380
        // Our expected default is not present, make sure we fall back to something.
381
        return array_keys($presentations)[0];
382
    }
383
}