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
/**
18
 * Date condition.
19
 *
20
 * @package availability_date
21
 * @copyright 2014 The Open University
22
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
namespace availability_date;
26
 
27
defined('MOODLE_INTERNAL') || die();
28
 
29
/**
30
 * Date condition.
31
 *
32
 * @package availability_date
33
 * @copyright 2014 The Open University
34
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35
 */
36
class condition extends \core_availability\condition {
37
    /** @var string Availabile only from specified date. */
38
    const DIRECTION_FROM = '>=';
39
 
40
    /** @var string Availabile only until specified date. */
41
    const DIRECTION_UNTIL = '<';
42
 
43
    /** @var string One of the DIRECTION_xx constants. */
44
    private $direction;
45
 
46
    /** @var int Time (Unix epoch seconds) for condition. */
47
    private $time;
48
 
49
    /** @var int Forced current time (for unit tests) or 0 for normal. */
50
    private static $forcecurrenttime = 0;
51
 
52
    /**
53
     * Constructor.
54
     *
55
     * @param \stdClass $structure Data structure from JSON decode
56
     * @throws \coding_exception If invalid data structure.
57
     */
58
    public function __construct($structure) {
59
        // Get direction.
60
        if (isset($structure->d) && in_array($structure->d,
61
                array(self::DIRECTION_FROM, self::DIRECTION_UNTIL))) {
62
            $this->direction = $structure->d;
63
        } else {
64
            throw new \coding_exception('Missing or invalid ->d for date condition');
65
        }
66
 
67
        // Get time.
68
        if (isset($structure->t) && is_int($structure->t)) {
69
            $this->time = $structure->t;
70
        } else {
71
            throw new \coding_exception('Missing or invalid ->t for date condition');
72
        }
73
    }
74
 
75
    public function save() {
76
        return (object)array('type' => 'date',
77
                'd' => $this->direction, 't' => $this->time);
78
    }
79
 
80
    /**
81
     * Returns a JSON object which corresponds to a condition of this type.
82
     *
83
     * Intended for unit testing, as normally the JSON values are constructed
84
     * by JavaScript code.
85
     *
86
     * @param string $direction DIRECTION_xx constant
87
     * @param int $time Time in epoch seconds
88
     * @return stdClass Object representing condition
89
     */
90
    public static function get_json($direction, $time) {
91
        return (object)array('type' => 'date', 'd' => $direction, 't' => (int)$time);
92
    }
93
 
94
    public function is_available($not, \core_availability\info $info, $grabthelot, $userid) {
95
        return $this->is_available_for_all($not);
96
    }
97
 
98
    public function is_available_for_all($not = false) {
99
        // Check condition.
100
        $now = self::get_time();
101
        switch ($this->direction) {
102
            case self::DIRECTION_FROM:
103
                $allow = $now >= $this->time;
104
                break;
105
            case self::DIRECTION_UNTIL:
106
                $allow = $now < $this->time;
107
                break;
108
            default:
109
                throw new \coding_exception('Unexpected direction');
110
        }
111
        if ($not) {
112
            $allow = !$allow;
113
        }
114
 
115
        return $allow;
116
    }
117
 
118
    /**
119
     * Obtains the actual direction of checking based on the $not value.
120
     *
121
     * @param bool $not True if condition is negated
122
     * @return string Direction constant
123
     * @throws \coding_exception
124
     */
125
    protected function get_logical_direction($not) {
126
        switch ($this->direction) {
127
            case self::DIRECTION_FROM:
128
                return $not ? self::DIRECTION_UNTIL : self::DIRECTION_FROM;
129
            case self::DIRECTION_UNTIL:
130
                return $not ? self::DIRECTION_FROM : self::DIRECTION_UNTIL;
131
            default:
132
                throw new \coding_exception('Unexpected direction');
133
        }
134
    }
135
 
136
    public function get_description($full, $not, \core_availability\info $info) {
137
        return $this->get_either_description($not, false);
138
    }
139
 
140
    public function get_standalone_description(
141
            $full, $not, \core_availability\info $info) {
142
        return $this->get_either_description($not, true);
143
    }
144
 
145
    /**
146
     * Shows the description using the different lang strings for the standalone
147
     * version or the full one.
148
     *
149
     * @param bool $not True if NOT is in force
150
     * @param bool $standalone True to use standalone lang strings
151
     */
152
    protected function get_either_description($not, $standalone) {
153
        $direction = $this->get_logical_direction($not);
154
        $midnight = self::is_midnight($this->time);
155
        $midnighttag = $midnight ? '_date' : '';
156
        $satag = $standalone ? 'short_' : 'full_';
157
        switch ($direction) {
158
            case self::DIRECTION_FROM:
159
                return get_string($satag . 'from' . $midnighttag, 'availability_date',
160
                        self::show_time($this->time, $midnight, false));
161
            case self::DIRECTION_UNTIL:
162
                return get_string($satag . 'until' . $midnighttag, 'availability_date',
163
                        self::show_time($this->time, $midnight, true));
164
        }
165
    }
166
 
167
    protected function get_debug_string() {
168
        return $this->direction . ' ' . gmdate('Y-m-d H:i:s', $this->time);
169
    }
170
 
171
    /**
172
     * Gets time. This function is implemented here rather than calling time()
173
     * so that it can be overridden in unit tests. (Would really be nice if
174
     * Moodle had a generic way of doing that, but it doesn't.)
175
     *
176
     * @return int Current time (seconds since epoch)
177
     */
178
    protected static function get_time() {
179
        if (self::$forcecurrenttime) {
180
            return self::$forcecurrenttime;
181
        } else {
182
            return time();
183
        }
184
    }
185
 
186
    /**
187
     * Forces the current time for unit tests.
188
     *
189
     * @param int $forcetime Time to return from the get_time function
190
     */
191
    public static function set_current_time_for_test($forcetime = 0) {
192
        self::$forcecurrenttime = $forcetime;
193
    }
194
 
195
    /**
196
     * Shows a time either as a date or a full date and time, according to
197
     * user's timezone.
198
     *
199
     * @param int $time Time
200
     * @param bool $dateonly If true, uses date only
201
     * @param bool $until If true, and if using date only, shows previous date
202
     * @return string Date
203
     */
204
    protected function show_time($time, $dateonly, $until = false) {
205
        // For 'until' dates that are at midnight, e.g. midnight 5 March, it
206
        // is better to word the text as 'until end 4 March'.
207
        $daybefore = false;
208
        if ($until && $dateonly) {
209
            $daybefore = true;
210
            $time = strtotime('-1 day', $time);
211
        }
212
        return userdate($time,
213
                get_string($dateonly ? 'strftimedate' : 'strftimedatetime', 'langconfig'));
214
    }
215
 
216
    /**
217
     * Checks whether a given time refers exactly to midnight (in current user
218
     * timezone).
219
     *
220
     * @param int $time Time
221
     * @return bool True if time refers to midnight, false otherwise
222
     */
223
    protected static function is_midnight($time) {
224
        return usergetmidnight($time) == $time;
225
    }
226
 
227
    public function update_after_restore(
228
            $restoreid, $courseid, \base_logger $logger, $name) {
229
        // Update the date, if restoring with changed date.
230
        $dateoffset = \core_availability\info::get_restore_date_offset($restoreid);
231
        if ($dateoffset) {
232
            $this->time += $dateoffset;
233
            return true;
234
        }
235
        return false;
236
    }
237
 
238
    /**
239
     * Changes all date restrictions on a course by the specified shift amount.
240
     * Used by the course reset feature.
241
     *
242
     * @param int $courseid Course id
243
     * @param int $timeshift Offset in seconds
244
     */
245
    public static function update_all_dates($courseid, $timeshift) {
246
        global $DB;
247
 
248
        $modinfo = get_fast_modinfo($courseid);
249
        $anychanged = false;
250
 
251
        // Adjust dates from all course modules.
252
        foreach ($modinfo->cms as $cm) {
253
            if (!$cm->availability) {
254
                continue;
255
            }
256
            $info = new \core_availability\info_module($cm);
257
            $tree = $info->get_availability_tree();
258
            $dates = $tree->get_all_children('availability_date\condition');
259
            $changed = false;
260
            foreach ($dates as $date) {
261
                $date->time += $timeshift;
262
                $changed = true;
263
            }
264
 
265
            // Save the updated course module.
266
            if ($changed) {
267
                $DB->set_field('course_modules', 'availability', json_encode($tree->save()),
268
                        array('id' => $cm->id));
269
                $anychanged = true;
270
            }
271
        }
272
 
273
        // Adjust dates from all course sections.
274
        foreach ($modinfo->get_section_info_all() as $section) {
275
            if (!$section->availability) {
276
                continue;
277
            }
278
 
279
            $info = new \core_availability\info_section($section);
280
            $tree = $info->get_availability_tree();
281
            $dates = $tree->get_all_children('availability_date\condition');
282
            $changed = false;
283
            foreach ($dates as $date) {
284
                $date->time += $timeshift;
285
                $changed = true;
286
            }
287
 
288
            // Save the updated course module.
289
            if ($changed) {
290
                $updatesection = new \stdClass();
291
                $updatesection->id = $section->id;
292
                $updatesection->availability = json_encode($tree->save());
293
                $updatesection->timemodified = time();
294
                $DB->update_record('course_sections', $updatesection);
295
                // Invalidate the section cache by given section id.
296
                \course_modinfo::purge_course_section_cache_by_id($courseid, $section->id);
297
 
298
                $anychanged = true;
299
            }
300
        }
301
 
302
        if ($anychanged) {
303
            // Partial rebuild the sections which have been invalidated.
304
            rebuild_course_cache($courseid, true, true);
305
        }
306
    }
307
}