Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 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\output;
18
 
19
use stdClass;
20
 
21
/**
22
 * This class keeps track of which HTML tags are currently open.
23
 *
24
 * This makes it much easier to always generate well formed XHTML output, even
25
 * if execution terminates abruptly. Any time you output some opening HTML
26
 * without the matching closing HTML, you should push the necessary close tags
27
 * onto the stack.
28
 *
29
 * @copyright 2009 Tim Hunt
30
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
31
 * @since Moodle 2.0
32
 * @package core
33
 * @category output
34
 */
35
class xhtml_container_stack {
36
    /**
37
     * @var array Stores the list of open containers.
38
     */
39
    protected $opencontainers = [];
40
 
41
    /**
42
     * @var array In developer debug mode, stores a stack trace of all opens and
43
     * closes, so we can output helpful error messages when there is a mismatch.
44
     */
45
    protected $log = [];
46
 
47
    /**
48
     * @var bool Store whether we are developer debug mode. We need this in
49
     * several places including in the destructor where we may not have access to $CFG.
50
     */
51
    protected $isdebugging;
52
 
53
    /**
54
     * Constructor
55
     */
56
    public function __construct() {
57
        global $CFG;
58
        $this->isdebugging = $CFG->debugdeveloper;
59
    }
60
 
61
    /**
62
     * Push the close HTML for a recently opened container onto the stack.
63
     *
64
     * @param string $type The type of container. This is checked when {@see pop()}
65
     *      is called and must match, otherwise a developer debug warning is output.
66
     * @param string $closehtml The HTML required to close the container.
67
     */
68
    public function push($type, $closehtml) {
69
        $container = new stdClass();
70
        $container->type = $type;
71
        $container->closehtml = $closehtml;
72
        if ($this->isdebugging) {
73
            $this->log('Open', $type);
74
        }
75
        array_push($this->opencontainers, $container);
76
    }
77
 
78
    /**
79
     * Pop the HTML for the next closing container from the stack. The $type
80
     * must match the type passed when the container was opened, otherwise a
81
     * warning will be output.
82
     *
83
     * @param string $type The type of container.
84
     * @return ?string the HTML required to close the container.
85
     */
86
    public function pop($type) {
87
        if (empty($this->opencontainers)) {
88
            debugging('<p>There are no more open containers. This suggests there is a nesting problem.</p>' .
89
                    $this->output_log(), DEBUG_DEVELOPER);
90
            return;
91
        }
92
 
93
        $container = array_pop($this->opencontainers);
94
        if ($container->type != $type) {
95
            debugging('<p>The type of container to be closed (' . $container->type .
96
                    ') does not match the type of the next open container (' . $type .
97
                    '). This suggests there is a nesting problem.</p>' .
98
                    $this->output_log(), DEBUG_DEVELOPER);
99
        }
100
        if ($this->isdebugging) {
101
            $this->log('Close', $type);
102
        }
103
        return $container->closehtml;
104
    }
105
 
106
    /**
107
     * Close all but the last open container. This is useful in places like error
108
     * handling, where you want to close all the open containers (apart from <body>)
109
     * before outputting the error message.
110
     *
111
     * @param bool $shouldbenone assert that the stack should be empty now - causes a
112
     *      developer debug warning if it isn't.
113
     * @return string the HTML required to close any open containers inside <body>.
114
     */
115
    public function pop_all_but_last($shouldbenone = false) {
116
        if ($shouldbenone && count($this->opencontainers) != 1) {
117
            debugging('<p>Some HTML tags were opened in the body of the page but not closed.</p>' .
118
                    $this->output_log(), DEBUG_DEVELOPER);
119
        }
120
        $output = '';
121
        while (count($this->opencontainers) > 1) {
122
            $container = array_pop($this->opencontainers);
123
            $output .= $container->closehtml;
124
        }
125
        return $output;
126
    }
127
 
128
    /**
129
     * You can call this function if you want to throw away an instance of this
130
     * class without properly emptying the stack (for example, in a unit test).
131
     * Calling this method stops the destruct method from outputting a developer
132
     * debug warning. After calling this method, the instance can no longer be used.
133
     */
134
    public function discard() {
135
        $this->opencontainers = null;
136
    }
137
 
138
    /**
139
     * Adds an entry to the log.
140
     *
141
     * @param string $action The name of the action
142
     * @param string $type The type of action
143
     */
144
    protected function log($action, $type) {
145
        $this->log[] = '<li>' . $action . ' ' . $type . ' at:' .
146
                format_backtrace(debug_backtrace()) . '</li>';
147
    }
148
 
149
    /**
150
     * Outputs the log's contents as a HTML list.
151
     *
152
     * @return string HTML list of the log
153
     */
154
    protected function output_log() {
155
        return '<ul>' . implode("\n", $this->log) . '</ul>';
156
    }
157
}
158
 
159
// Alias this class to the old name.
160
// This file will be autoloaded by the legacyclasses autoload system.
161
// In future all uses of this class will be corrected and the legacy references will be removed.
162
class_alias(xhtml_container_stack::class, \xhtml_container_stack::class);