collection.php 14.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
/**
 * Mahara: Electronic portfolio, weblog, resume builder and social networking
 * Copyright (C) 2006-2009 Catalyst IT Ltd and others; see:
 *                         http://wiki.mahara.org/Contributors
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @package    mahara
 * @subpackage core
 * @author     Catalyst IT Ltd
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
 * @copyright  (C) 2006-2009 Catalyst IT Ltd http://catalyst.net.nz
 *
 */

defined('INTERNAL') || die();

30
31
32
33
34
35
36
37
class Collection {

    private $id;
    private $name;
    private $description;
    private $owner;
    private $mtime;
    private $ctime;
38
    private $navigation;
39
    private $views;
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

    public function __construct($id=0, $data=null) {
        global $USER;
        $userid = $USER->get('id');

        if (!empty($id)) {
            $tempdata = get_record('collection','id',$id);
            if (empty($tempdata)) {
                throw new CollectionNotFoundException("Collection with id $id not found");
            }
            if (!empty($data)) {
                $data = array_merge((array)$tempdata, $data);
            }
            else {
                $data = $tempdata; // use what the database has
            }
            $this->id = $id;
        }
        else {
            $this->ctime = time();
            $this->mtime = time();
            $this->owner = $userid;
        }
63

64
65
66
67
68
69
70
        if (empty($data)) {
            $data = array();
        }
        foreach ((array)$data as $field => $value) {
            if (property_exists($this, $field)) {
                $this->{$field} = $value;
            }
71
72
73
        }
    }

74
75
76
77
    public function get($field) {
        if (!property_exists($this, $field)) {
            throw new InvalidArgumentException("Field $field wasn't found in class " . get_class($this));
        }
78
79
80
        if ($field == 'views') {
            return $this->views();
        }
81
82
        return $this->{$field};
    }
83

84
85
86
87
88
89
90
91
    public function set($field, $value) {
        if (property_exists($this, $field)) {
            $this->{$field} = $value;
            $this->mtime = time();
            return true;
        }
        throw new InvalidArgumentException("Field $field wasn't found in class " . get_class($this));
    }
92

93
94
95
96
97
98
99
100
101
102
    /**
     * Creates a new Collection for the given user.
     *
     * @param array $data
     * @return collection           The newly created Collection
     */
    public static function save($data) {
        $collection = new Collection(0, $data);
        $collection->commit();

103
        return $collection; // return newly created Collections id
104
    }
105

106
107
108
109
110
    /**
     * Deletes a Collection
     *
     */
    public function delete() {
111
        $viewids = get_column('collection_view', 'view', 'collection', $this->id);
112
        db_begin();
Stacey Walker's avatar
Stacey Walker committed
113
        delete_records('collection_view','collection',$this->id);
114
        delete_records('collection','id',$this->id);
115
116
117
118
119
120
121

        // Secret url records belong to the collection, so remove them from the view.
        // @todo: add user message to whatever calls this.
        if ($viewids) {
            delete_records_select('view_access', 'view IN (' . join(',', $viewids) . ') AND token IS NOT NULL');
        }

122
123
124
        db_commit();
    }

125
126
127
128
129
130
131
132
    /**
     * This method updates the contents of the collection table only.
     */
    public function commit() {

        $fordb = new StdClass;
        foreach (get_object_vars($this) as $k => $v) {
            $fordb->{$k} = $v;
Richard Mansfield's avatar
Richard Mansfield committed
133
            if (in_array($k, array('mtime', 'ctime')) && !empty($v)) {
134
135
136
                $fordb->{$k} = db_format_timestamp($v);
            }
        }
137

138
        db_begin();
139

140
141
142
143
144
        // if id is not empty we are editing an existing collection
        if (!empty($this->id)) {
            update_record('collection', $fordb, 'id');
        }
        else {
145
146
            $id = insert_record('collection', $fordb, 'id', true);
            if ($id) {
147
                $this->set('id', $id);
148
            }
149
        }
150

151
152
        db_commit();
    }
153

154
155
156
157
158
159
160
161
162
163
164
    /**
     * Returns a list of the current users collections
     *
     * @param offset current page to display
     * @param limit how many collections to display per page
     * @return array (count: integer, data: array, offset: integer, limit: integer)
     */
    public static function get_mycollections_data($offset=0, $limit=10) {
        global $USER;

        ($data = get_records_sql_array("
165
            SELECT c.id, c.description, c.name
166
                FROM {collection} c
167
                WHERE c.owner = ?
168
169
170
171
172
173
174
175
176
177
            ORDER BY c.name, c.ctime ASC
            LIMIT ? OFFSET ?", array($USER->get('id'), $limit, $offset)))
            || ($data = array());

        $result = (object) array(
            'count'  => count_records('collection', 'owner', $USER->get('id')),
            'data'   => $data,
            'offset' => $offset,
            'limit'  => $limit,
        );
178

179
180
        return $result;
    }
181

182
183
184
185
186
187
188
    /**
    * Gets the fields for the new/edit collection form
    * - populates the fields with collection data if it is an edit
    *
    * @param array collection
    * @return array $elements
    */
189
    public static function get_collectionform_elements($data=null) {
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
        $elements = array(
            'name' => array(
                'type' => 'text',
                'defaultvalue' => null,
                'title' => get_string('name', 'collection'),
                'size' => 30,
                'rules' => array(
                    'required' => true,
                ),
            ),
            'description' => array(
                'type'  => 'textarea',
                'rows' => 10,
                'cols' => 50,
                'resizable' => false,
                'defaultvalue' => null,
                'title' => get_string('description', 'collection'),
            ),
        );
209

210
        // populate the fields with the existing values if any
211
        if (!empty($data)) {
212
            foreach ($elements as $k => $element) {
213
                $elements[$k]['defaultvalue'] = $data->$k;
214
215
216
            }
            $elements['id'] = array(
                'type' => 'hidden',
217
                'value' => $data->id,
218
219
220
            );
            $elements['owner'] = array(
                'type' => 'hidden',
221
                'value' => $data->owner,
222
            );
223
224
225
226
            $elements['navigation'] = array(
                'type' => 'hidden',
                'value' => $data->navigation,
            );
227
228
        }

229
230
        return $elements;
    }
231

232
    /**
233
     * Returns array of views in the current collection
234
235
236
     *
     * @return array views 
     */
237
238
239
    public function views() {

        if (!isset($this->views)) {
240

241
242
243
            $sql = "SELECT cv.*, v.title
                FROM {collection_view} cv JOIN {view} v ON cv.view = v.id
                WHERE cv.collection = ?
244
                ORDER BY cv.displayorder, v.title, v.ctime ASC";
245

246
            $result = get_records_sql_array($sql, array($this->get('id')));
247

248
249
250
251
252
253
254
255
256
257
258
            if (!empty($result)) {
                $this->views = array(
                    'views'     => $result,
                    'count'     => count($result),
                    'max'       => get_field('collection_view', 'MAX(displayorder)', 'collection', $this->get('id')),
                    'min'       => get_field('collection_view', 'MIN(displayorder)', 'collection', $this->get('id')),
                );
            }
            else {
                $this->views = array();
            }
259

260
261
        }

262
        return $this->views;
263
    }
264

265
266
267
    /**
     * Get the available views the current user can choose from
     * - currently dashboard, group and profile views are ignored to solve access issues
268
     * - each view can only belong to one collection
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
     *
     * @return array $views
     */
    public static function available_views() {
        global $USER;

        $userid = $USER->get('id');
        ($views = get_records_sql_array("SELECT v.id, v.title
                  FROM {view} v
                WHERE v.owner = ? AND v.type NOT IN ('dashboard','grouphomepage','profile')
                AND v.id NOT IN (
                    SELECT cv.view
                      FROM {collection_view} cv
                )
                GROUP BY v.id, v.title", array($userid)))
                || ($views = array());

        return $views;
287
288
    }

289
    /**
290
     * Submits the selected views to the collection
291
292
293
294
295
     *
     * @param array values selected views
     * @return integer count so we know what SESSION message to display
     */
    public function add_views($values) {
296

297
        $count = 0; // how many views we are adding
298
299
        db_begin();

300
        // each view was marked with a key of view_<id> in order to identify the correct items
301
        // from the form values
302
303
304
305
306
        foreach ($values as $key => $value) {
            if (substr($key,0,5) === 'view_' AND $value == true) {
                $cv = array();
                $cv['view'] = substr($key,5);
                $cv['collection'] = $this->get('id');
307
308
309
310
311

                // set displayorder value
                $max = get_field('collection_view', 'MAX(displayorder)', 'collection', $this->get('id'));
                $cv['displayorder'] = is_numeric($max) ? $max + 1 : 0;

312
313
314
315
                insert_record('collection_view', (object)$cv);
                $count++;
            }
        }
316

317
318
        $this->combine_access();

319
320
        db_commit();

321
322
        return $count;
    }
323

324
    /**
325
     * Removes the selected views from the collection
326
327
328
329
330
331
     *
     * @param integer $view the view to remove
     */
    public function remove_view($view) {
        db_begin();
        delete_records('collection_view','view',$view,'collection',$this->get('id'));
332
333
334
335
336

        // Secret url records belong to the collection, so remove them from the view.
        // @todo: add user message to whatever calls this.
        delete_records_select('view_access', 'view = ? AND token IS NOT NULL', array($view));

337
338
339
        db_commit();
    }

340
341
342
    /**
     * Update access in collection
     *
343
     * Copy access records from one view to all other views
344
     */
345
346
347
348
349
350
351
352
353
354
355
356
357
    public function set_access($viewid) {
        if (!$views = $this->views()) {
            return;
        }

        if ($views['count'] < 2) {
            return;
        }

        $toupdate = array();
        foreach ($views['views'] as &$v) {
            if ($v->view != $viewid) {
                $toupdate[] = $v->view;
358
            }
359
        }
360
361
362
363
364
365
366
367

        if (count($toupdate) != $views['count'] - 1) {
            throw new SystemException('error setting collection access');
        }

        db_begin();
        delete_records_select('view_access', 'view IN (' . join(',', $toupdate) . ') AND visible = 1');
        $this->combine_access();
368
        db_commit();
369
370
    }

371
372
373
374
375
376
377
378

    /**
     * Synchronise access records across all views in the collection by
     * copying all access records to all views
     *
     * @todo: allow access records to apply to things other than views,
     * (e.g. collections), so we don't have to do this.
     */
379
    public function combine_access() {
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
        if (!$viewids = get_column('collection_view', 'view', 'collection', $this->id)) {
            return;
        }

        $select = 'view IN (' . join(',', $viewids) . ')';

        if (!$access = get_records_select_array('view_access', $select)) {
            return;
        }

        $unique = array();
        foreach ($access as &$a) {
            unset($a->view);
            $k = serialize($a);
            if (!isset($unique[$k])) {
                $unique[$k] = $a;
            }
        }

        db_begin();

        delete_records_select('view_access', $select);

        foreach ($unique as &$a) {
            foreach ($viewids as $id) {
                $a->view = $id;
                insert_record('view_access', $a);
            }
        }

        db_commit();
    }

413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
    /**
     * Sets the displayorder for a view
     *
     * @param integer view
     * @param string direction
     *
     */
    public function set_viewdisplayorder($id, $direction) {

        $ids = get_column_sql('
            SELECT view FROM {collection_view}
            WHERE collection = ?
            ORDER BY displayorder', array($this->get('id')));

        foreach ($ids as $k => $v) {
            if ($v == $id) {
                $oldorder = $k;
                break;
            }
        }

        if ($direction == 'up' && $oldorder > 0) {
            $neworder = array_merge(array_slice($ids, 0, $oldorder - 1),
                                    array($id, $ids[$oldorder-1]),
                                    array_slice($ids, $oldorder+1));
        }
        else if ($direction == 'down' && ($oldorder + 1 < count($ids))) {
            $neworder = array_merge(array_slice($ids, 0, $oldorder),
                                    array($ids[$oldorder+1], $id),
                                    array_slice($ids, $oldorder+2));
        }

        if (isset($neworder)) {
            foreach ($neworder as $k => $v) {
                set_field('collection_view', 'displayorder', $k, 'view', $v, 'collection',$this->get('id'));
            }
            $this->set('mtime', time());
            $this->commit();
        }
    }

454
455
456
457
458
459
460
461
    /**
     * after editing the collection, redirect back to the appropriate place
     */
    public function post_edit_redirect($new=false) {
        if ($new) {
            $redirecturl = '/collection/views.php?id=' . $this->get('id') . '&new=1';
        }
        else {
462
            $redirecturl = '/collection/index.php';
463
464
465
466
        }
        redirect($redirecturl);
    }

467
    public static function search_by_view_id($viewid) {
468
469
470
471
472
473
474
475
476
477
478
479
        $record = get_record_sql('
            SELECT c.*
            FROM {collection} c JOIN {collection_view} cv ON c.id = cv.collection
            WHERE cv.view = ?',
            array($viewid)
        );
        if ($record) {
            return new Collection(0, $record);
        }
        return false;
    }

480
}