3
* Mahara: Electronic portfolio, weblog, resume builder and social networking
4
* Copyright (C) 2006-2008 Catalyst IT Ltd (http://www.catalyst.net.nz)
6
* This program is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21
* @author Catalyst IT Ltd
22
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
23
* @copyright (C) 2006-2008 Catalyst IT Ltd http://catalyst.net.nz
27
defined('INTERNAL') || die();
28
require_once('view.php');
29
safe_require('blocktype', 'textbox'); // need this for labels, always
30
safe_require('artefact', 'internal'); // needed for blocktype creation
31
safe_require('artefact', 'resume'); // ditto
35
* Performs the template migration, from the old view template style of 0.8 to
36
* the new views format for 0.9
38
function upgrade_template_migration() {
39
log_debug('upgrade_template_migration()');
41
if (!$views = get_records_array('view', '', '', 'id')) {
42
log_debug('no views to migrate');
45
log_debug('we have ' . count($views) . ' views to migrate...');
49
// Static data needed by various templates when they are migrated
53
$blogreflection_numbers = array(1 => 'One', 2 => 'One', 3 => 'Two', 4 => 'Two', 5 => 'Three', 6 => 'Three');
57
'<h4>Group Name</h4>',
58
'<h4>Student Names</h4>',
59
'<h4>Mission and Vision Statement (Concept and Concept Outline)</h4>',
60
'<h4>Physical Design of the space</h4><p>Explain, using theorists, how you created ambeince and support of holistic learning for each child</p>',
61
'<h4>Schedule or timetable of tasks and events prior to opening</h4>',
62
'<h4>Curriculum Matrix for first six weeks, specific activities for beginners, intermediates, end-game</h4><p>provide NZCF AO/level cross-reference</p>',
63
'<h4>Yearlong Teaching and Learning Topics plan for beginners, intermediates and end-game.</h4><p>Justify your choices by citing educationalists, psychologists and other theorists</p>',
64
'<h4>Priorised table of equipment, materials and supplies</h4>'
68
// The main view migration loop
70
foreach ($views as $view) {
72
log_debug("Migrating view $view->id ($count)");
73
if ($view->template == 'test') {
74
// We are NOT migrating test templates. There's not much point. The
75
// only real data loss from this is the labels, which are only one
76
// line text inputs. If this annoys someone they could always have
77
// a go at writing a migration. There's no technical reason why one
79
log_debug("View $view->id is a test view. Deleting instead");
80
$view = new View($view->id);
81
delete_records('view_content', 'view', $view->get('id'));
87
// $viewcolumns is a datastructure representing the new structure of a
88
// view. It's an array of columns, which are arrays of label titles etc.
89
// All the values are null.
91
// We are trying to turn the nulls into blockinstances
93
if (!$viewcolumns = upgrade_template_get_structure($view->template)) {
94
log_warn("Unsupported custom template $view->template! Deleting!");
95
$view = new View($view->id);
96
delete_records('view_content', 'view', $view->get('id'));
100
$numcolumns = count($viewcolumns);
102
// Handle all label blocks, by converting them to WYSIWYG blocks
103
if ($lblocks = get_records_array('view_content', 'view', $view->id)) {
104
foreach ($lblocks as $block) {
105
upgrade_template_insert_block($viewcolumns, $block->block, upgrade_template_create_wysiwyg($block->content, $view->id));
109
// Get all artefact blocks in the view
110
if ($ablocks = get_records_sql_array('
111
SELECT va.*, a.artefacttype, a.title
112
FROM {view_artefact} va
113
INNER JOIN {artefact} a ON (va.artefact = a.id)
114
WHERE "view" = ?', array($view->id))) {
115
foreach ($ablocks as $block) {
116
if (!upgrade_template_block_exists($viewcolumns, $block->oldblock)) {
117
// There's no block here. We can make one and insert it
118
$bi = upgrade_template_convert_block_to_blockinstance($block, $view);
119
// note: the location to insert the block is known as
120
// 'oldblock', as the column as been renamed in the database
121
// in preparation for its removal
122
upgrade_template_insert_block($viewcolumns, $block->oldblock, $bi);
125
// We're dealing with multiple artefacts in the same block... just need to append
126
upgrade_template_update_block($viewcolumns, $block, $view);
132
// Special case code for each template, to make sure the labels and
133
// hard coded text are migrated nicely
135
if ($view->template == 'blogreflection') {
136
// There are six labels in this view - the three reflection titles
137
// and three 'last date available' fields
138
for ($i = 1; $i <= 6; $i++) {
139
// The labels were badly numbered, 2, 4 and 5 are the right
140
// hand side (and thus the 'last date available' ones)
141
if (in_array($i, array(2, 4, 5))) {
143
$text = '<h4>Reflection ' . $blogreflection_numbers[$i] . ': Last Date Available</h4>';
147
$text = '<h3>Reflection ' . $blogreflection_numbers[$i] . ' Title</h3>';
150
// The label migration would have put WYSIWYG blocks in where
151
// there was content. If there is none, let's ignore this block
152
if (empty($viewcolumns[$column]['tpl_label' . $i])) {
156
$labelkey = 'tpl_label' . $i;
157
$replace = $text . '<p>' . upgrade_template_get_wysiwyg_content($viewcolumns, $column, 'tpl_label' . $i) . '</p>';
159
// Update the WYSIWYG blocks to have the titles they need
160
if (in_array($i, array(2, 4, 5))) {
161
upgrade_template_update_wysiwyg($viewcolumns, $column, $labelkey, null, $replace);
164
upgrade_template_update_wysiwyg($viewcolumns, $column, 'tpl_label' . $i, null, $replace);
168
else if ($view->template == 'PPAE') {
169
if (!empty($viewcolumns[0]['tpl_label1'])) {
170
upgrade_template_update_wysiwyg($viewcolumns, 0, 'tpl_label1', null, '<h4>' . $ppae_text[0] . '</h4>' . upgrade_template_get_wysiwyg_content($viewcolumns, 0, 'tpl_label1'));
172
if (!empty($viewcolumns[0]['tpl_label2']) || !empty($viewcolumns[0]['tpl_label3']) || !empty($viewcolumns[0]['tpl_label4']) || !empty($viewcolumns[0]['tpl_label5'])) {
173
// mash it all into the first one and unset the rest
174
$label2_text = '<h4>' . $ppae_text[1] . '</h4>'
175
. upgrade_template_get_wysiwyg_content($viewcolumns, 0, 'tpl_label2') . '<br>'
176
. upgrade_template_get_wysiwyg_content($viewcolumns, 0, 'tpl_label3') . '<br>'
177
. upgrade_template_get_wysiwyg_content($viewcolumns, 0, 'tpl_label4') . '<br>'
178
. upgrade_template_get_wysiwyg_content($viewcolumns, 0, 'tpl_label5');
180
$label2_text = preg_replace('#(<br>)+$#', '', $label2_text);
182
if (upgrade_template_block_exists($viewcolumns, 'tpl_label2')) {
183
upgrade_template_update_wysiwyg($viewcolumns, 0, 'tpl_label2', null, $label2_text);
186
upgrate_template_insert_block($viewcolumns, 'tpl_label2', upgrade_template_create_wysiwyg($label2_text, $view->id));
188
unset($viewcolumns[0]['tpl_label3']);
189
unset($viewcolumns[0]['tpl_label4']);
190
unset($viewcolumns[0]['tpl_label5']);
192
if (!empty($viewcolumns[0]['tpl_blog1'])) {
193
$viewcolumns[0]['tpl_converted1'] = upgrade_template_create_wysiwyg($ppae_text[2], $view->id);
195
if (!empty($viewcolumns[0]['tpl_files1']) || !empty($viewcolumns[0]['tpl_blog2'])) {
196
$viewcolumns[0]['tpl_converted2'] = upgrade_template_create_wysiwyg($ppae_text[3], $view->id);
198
if (!empty($viewcolumns[0]['tpl_files2']) || !empty($viewcolumns[0]['tpl_blog3'])) {
199
$viewcolumns[0]['tpl_converted3'] = upgrade_template_create_wysiwyg($ppae_text[4], $view->id);
201
if (!empty($viewcolumns[0]['tpl_files3']) || !empty($viewcolumns[0]['tpl_blog4'])) {
202
$viewcolumns[0]['tpl_converted4'] = upgrade_template_create_wysiwyg($ppae_text[5], $view->id);
204
if (!empty($viewcolumns[0]['tpl_files4']) || !empty($viewcolumns[0]['tpl_blog5'])) {
205
$viewcolumns[0]['tpl_converted5'] = upgrade_template_create_wysiwyg($ppae_text[6], $view->id);
207
if (!empty($viewcolumns[0]['tpl_files5']) || !empty($viewcolumns[0]['tpl_blog6'])) {
208
$viewcolumns[0]['tpl_converted6'] = upgrade_template_create_wysiwyg($ppae_text[7], $view->id);
212
// Clean up empty columns, although the gallery should always have its
214
if ($view->template != 'gallery') {
215
foreach ($viewcolumns as $c => $col) {
217
foreach ($col as $key => $guff) {
224
unset($viewcolumns[$c]);
229
// Make all the block instances have the correct column and order
230
foreach ($viewcolumns as $c => $col) {
232
foreach ($col as $key => $block) {
233
if (is_array($block)) {
234
foreach ($block as $bi) {
235
$bi->set('column', ($c + 1));
236
$bi->set('order', $order);
242
if ($block instanceof BlockInstance) {
243
$block->set('column', ($c + 1));
244
$block->set('order', $order);
252
// Work out what layout to set the view to
253
$layout = upgrade_template_get_view_layout($view->template);
256
$view = new View($view->id);
257
$view->set('numcolumns', $numcolumns);
259
$view->set('layout', $layout);
262
} // End of the view loop
266
* Puts blockinstances into the appropriate place in the deeply nested array
268
* @param array (reference) $columns column structure
269
* @param string $key key to insert blockinstance at
270
* @param BlockInstance $bi blockinstance to insert
272
function upgrade_template_insert_block(&$columns, $key, BlockInstance $bi) {
273
foreach ($columns as &$c) {
274
if (array_key_exists($key, $c)) {
275
if (!empty($c[$key])) {
276
$e = new TemplateBlockExistsAlreadyException();
277
$e->set_block_data($c[$key]);
287
* Takes a block that, according to its oldblock setting, wants to be inserted
288
* somewhere where there is an existing blockinstance. With this information,
289
* establishes how to change the existing blockinstance, or what to replace it
290
* with, so that both artefacts are in the same blockinstance.
292
* @param array (reference) $columns column structure
293
* @param stdClass $block the new block data
295
function upgrade_template_update_block(&$columns, $block, $view) {
296
// $block->oldblock is where the existing blockinstance is
297
// Then we need to establish what to put in $columns, or in the blockinstance
300
foreach ($columns as &$c) {
301
if (array_key_exists($block->oldblock, $c)) {
303
if (!empty($c[$block->oldblock])) {
304
$bi = $c[$block->oldblock];
305
// Will be an array if there's more than one blockinstance here.
306
// See the 'else' clause below
316
log_debug("WTF: tried to update a block when there was nothing there to update");
320
// If the blockinstance is a filedownload block and we have a file or image
321
// to add, add it directly to the blockinstance
322
if ($bi->get('blocktype') == 'filedownload') {
323
if ($block->artefacttype == 'file' || $block->artefacttype == 'image') {
324
upgrade_template_add_artefact_to_blockinstance($bi, $block->artefact);
326
// More than one artefact in this filedownload block, so remove the title
327
$bi->set('title', '');
329
// If the blockinstance is profileinfo, we can keep adding profile fields to it
330
else if ($bi->get('blocktype') == 'profileinfo') {
331
if (in_array($block->artefacttype, PluginArtefactInternal::get_artefact_types())) {
332
if ($block->artefacttype != 'profileicon') {
333
upgrade_template_add_artefact_to_blockinstance($bi, $block->artefact);
336
// The profileicon is stored in a dedicated field, not 'artefactids'
337
$configdata = $bi->get('configdata');
338
$configdata['profileicon'] = $block->artefact;
339
$bi->set('configdata', $configdata);
343
else if ($bi->get('blocktype') == 'recentposts') {
344
if ($block->artefacttype == 'blog') {
345
upgrade_template_add_artefact_to_blockinstance($bi, $block->artefact);
349
// Make a new blockinstance and insert it below
350
$bi = upgrade_template_convert_block_to_blockinstance($block, $view);
351
if (!is_array($column[$block->oldblock])) {
352
$column[$block->oldblock] = array($column[$block->oldblock]);
354
$column[$block->oldblock] = array_merge(array($bi), $column[$block->oldblock]);
359
* Given a blockinstance that is assumed to have an 'artefactids' config field
360
* and an artefact, ensures that the blockinstance config includes the given
363
function upgrade_template_add_artefact_to_blockinstance(BlockInstance $bi, $artefact) {
364
$configdata = $bi->get('configdata');
365
$configdata['artefactids'][] = $artefact;
366
$bi->set('configdata', $configdata);
370
* Determines whether a block already exists at the given location
372
* @param array (reference) $columns column structure
373
* @param string $key key to check for existance
375
function upgrade_template_block_exists(&$columns, $key) {
376
foreach ($columns as &$c) {
377
if (array_key_exists($key, $c)) {
378
if (!empty($c[$key])) {
387
* Creates a WYSIWYG blockinstance
389
* @param string $content The content for the wysiwyg block
390
* @param int $view The view the new block will be in
392
function upgrade_template_create_wysiwyg($content, $view) {
393
$b = new BlockInstance(0, array(
395
'blocktype' => 'textbox',
396
'configdata' => serialize(array('text' => $content)),
404
* Given a location with a WYSIWYG blockinstance, either appends or replaces its content
406
function upgrade_template_update_wysiwyg(&$columns, $column, $key, $appendcontent=null, $replacecontent=null) {
407
$block = $columns[$column][$key];
408
$data = $block->get('configdata');
409
if (!empty($appendcontent)) {
410
$data['text'] .= $appendcontent;
413
$data['text'] = $replacecontent;
415
$block->set('configdata', $data);
419
* Gets content of an existing WYSIWYG blockinstance, or an empty string if the
422
function upgrade_template_get_wysiwyg_content($columns, $column, $key) {
423
$block = $columns[$column][$key];
427
$data = $block->get('configdata');
428
return $data['text'];
432
* Get the new view structure for the given template.
434
* @param string $template The template to get the structure for
437
function upgrade_template_get_structure($template) {
439
static $columnstructure;
440
if (empty($columnstructure)) {
442
$columnstructure = array(
443
'blogandprofile' => array(
446
// Each thing in the column, from top to bottom
447
'tpl_blogslabel' => null,
452
'tpl_profilelabel' => null,
453
'tpl_profile' => null,
456
'blogreflection' => array(
458
'tpl_label1' => null,
460
'tpl_label3' => null,
462
'tpl_label6' => null,
466
'tpl_label2' => null,
467
'tpl_label4' => null,
468
'tpl_label5' => null,
469
), // I know it looks like 5 and 6 are backwards, it's in the template html
473
'tpl_fileslabel1' => null,
474
'tpl_files1' => null,
475
'tpl_fileslabel2' => null,
476
'tpl_files2' => null,
477
'tpl_fileslabel3' => null,
478
'tpl_files3' => null,
481
'tpl_freelabel' => null
486
'tpl_image1' => null,
487
'tpl_label1' => null,
488
'tpl_image6' => null,
489
'tpl_label6' => null,
492
'tpl_image2' => null,
493
'tpl_label2' => null,
494
'tpl_image7' => null,
495
'tpl_label7' => null,
498
'tpl_image3' => null,
499
'tpl_label3' => null,
500
'tpl_image8' => null,
501
'tpl_label8' => null,
504
'tpl_image4' => null,
505
'tpl_label4' => null,
506
'tpl_image9' => null,
507
'tpl_label9' => null,
510
'tpl_image5' => null,
511
'tpl_label5' => null,
512
'tpl_image10' => null,
513
'tpl_label10' => null,
516
'generaltemplate' => array(
519
'tpl_generic1' => null,
520
'tpl_generic2' => null,
521
'tpl_generic3' => null,
522
'tpl_generic4' => null,
525
'professionalprofile' => array(
527
'tpl_firstname' => null,
528
'tpl_generic4' => null,
529
'tpl_generic1' => null,
530
'tpl_label1' => null,
531
'tpl_generic2' => null,
534
'tpl_lastname' => null,
536
'tpl_label2' => null,
537
'tpl_generic3' => null,
542
// Free text here (Group Name)
543
'tpl_label1' => null,
544
// Free text here (Student Names)
545
'tpl_label2' => null,
546
'tpl_label3' => null,
547
'tpl_label4' => null,
548
'tpl_label5' => null,
549
// Free text here (Mission.. )
550
'tpl_converted1' => null,
552
// Free text here (Physical Design.. )
553
'tpl_converted2' => null,
554
'tpl_files1' => null,
556
// Free text here (Schedule or timetable.. )
557
'tpl_converted3' => null,
558
'tpl_files2' => null,
560
// Free text here (Curriculum Matrix.. )
561
'tpl_converted4' => null,
562
'tpl_files3' => null,
564
// Free text here (Yearlong teaching.. )
565
'tpl_converted5' => null,
566
'tpl_files4' => null,
568
// Free text here (Prioritised table)
569
'tpl_converted6' => null,
570
'tpl_files5' => null,
577
if (!array_key_exists($template, $columnstructure)) {
580
return $columnstructure[$template];
584
* Select what view layout the template should be migrated to
586
function upgrade_template_get_view_layout($template) {
587
if ($template == 'blogreflection') {
594
* Given a record from the view_artefact table (otherwise known as a "block"),
595
* try and establish a blockinstance that it could be under the new system and
598
function upgrade_template_convert_block_to_blockinstance($block, $view) {
599
if ($block->artefacttype == 'blogpost') {
600
$bi = new BlockInstance(0, array(
601
'title' => $block->title,
602
'blocktype' => 'blogpost',
603
'configdata' => serialize(array('artefactid' => $block->artefact)),
608
else if ($block->artefacttype == 'blog') {
609
if ($block->format == 'listself') {
610
$blocktype = 'recentposts';
611
$configdata = array('artefactids' => array($block->artefact));
615
$configdata = array('artefactid' => $block->artefact);
618
$bi = new BlockInstance(0, array(
620
'blocktype' => $blocktype,
621
'configdata' => serialize($configdata),
626
else if ($block->artefacttype == 'image') {
627
if ($block->format == 'listself') {
628
$blocktype = 'filedownload';
629
$configdata = array('artefactids' => array($block->artefact));
632
$blocktype = 'image';
633
$configdata = array('artefactid' => $block->artefact, 'width' => ($view->template == 'gallery' ? 175 : 350));
635
$bi = new BlockInstance(0, array(
637
'blocktype' => $blocktype,
638
'configdata' => serialize($configdata),
643
else if ($block->artefacttype == 'file') {
644
$bi = new BlockInstance(0, array(
645
'title' => $block->title,
646
'blocktype' => 'filedownload',
647
'configdata' => serialize(array('artefactids' => array($block->artefact))),
652
else if (in_array($block->artefacttype, PluginArtefactResume::get_artefact_types())) {
653
$bi = new BlockInstance(0, array(
654
'title' => $block->title,
655
'blocktype' => 'resumefield',
656
'configdata' => serialize(array('artefactid' => $block->artefact)),
661
else if (in_array($block->artefacttype, PluginArtefactInternal::get_artefact_types())) {
662
// This happens in the blogandprofile template, there's a 'listself' internal artefact thing
663
$bi = new BlockInstance(0, array(
665
'blocktype' => 'profileinfo',
666
'configdata' => serialize(array('artefactids' => array($block->artefact))),
671
else if ($block->artefacttype == 'folder') {
672
$bi = new BlockInstance(0, array(
673
'title' => $block->title,
674
'blocktype' => 'folder',
675
'configdata' => serialize(array('artefactid' => $block->artefact)),
681
log_info("Created a placeholder blockinstance for:");
683
$bi = new BlockInstance(0, array(
684
'title' => 'TODO - correct blocktype',
685
'blocktype' => 'textbox',
686
'configdata' => serialize(array('text' => 'TODO - correct blocktype')),
692
class TemplateBlockExistsAlreadyException extends MaharaException {
696
public function set_block_data($data) {
697
$this->blockdata = $data;
700
public function get_block_data() {
701
return $this->blockdata;