├── pix
├── check0.gif
├── check1.gif
└── check2.gif
├── styles.css
├── version.php
├── settings.php
├── flavours_xml_transformer.class.php
├── flavours_xml_writer.class.php
├── README.md
├── forms
├── flavours_generatedefaults_form.php
├── flavours_deployment_upload_form.php
├── flavours_deployment_form.php
└── flavours_packaging_form.php
├── index.php
├── lib.php
├── module.js
├── cligeneratedefaults.php
├── flavours_generatedefaults.class.php
├── ingredient
├── flavours_ingredient.class.php
├── flavours_ingredient_customlang.class.php
├── flavours_ingredient_lang.class.php
├── flavours_ingredient_plugin.class.php
└── flavours_ingredient_setting.class.php
├── renderer.php
├── lang
├── ca
│ └── local_flavours.php
├── en
│ └── local_flavours.php
└── es
│ └── local_flavours.php
├── flavours_packaging.class.php
├── flavours_deployment.class.php
└── flavours.class.php
/pix/check0.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmonllao/moodle-local_flavours/HEAD/pix/check0.gif
--------------------------------------------------------------------------------
/pix/check1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmonllao/moodle-local_flavours/HEAD/pix/check1.gif
--------------------------------------------------------------------------------
/pix/check2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmonllao/moodle-local_flavours/HEAD/pix/check2.gif
--------------------------------------------------------------------------------
/styles.css:
--------------------------------------------------------------------------------
1 | .ygtv-checkbox .ygtv-highlight0 .ygtvcontent{padding-left:1em;background:url([[pix:local_flavours|check0]]) no-repeat;}
2 | .ygtv-checkbox .ygtv-highlight0 .ygtvfocus.ygtvcontent,.ygtv-checkbox .ygtv-highlight1 .ygtvfocus.ygtvcontent,.ygtv-checkbox .ygtv-highlight2 .ygtvfocus.ygtvcontent{background-color:#c0e0e0;}
3 | .ygtv-checkbox .ygtv-highlight1 .ygtvcontent{padding-left:1em;background:url([[pix:local_flavours|check1]]) no-repeat;}
4 | .ygtv-checkbox .ygtv-highlight2 .ygtvcontent{padding-left:1em;background:url([[pix:local_flavours|check2]]) no-repeat;}
5 | #id_ingredients_tree .treenode{margin-left:2px;}
--------------------------------------------------------------------------------
/version.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * version.php
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die;
27 |
28 | $plugin->component = 'local_flavours';
29 |
30 | $plugin->version = 2015113000;
31 | $plugin->requires = 2015102300;
32 |
33 | $plugin->maturity = MATURITY_RC;
34 | $plugin->release = '30.0 (Build: 2015113000)';
35 |
--------------------------------------------------------------------------------
/settings.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * To add the flavours links to the administration block
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die;
27 |
28 | $flavoursplugin = 'local_flavours';
29 | $flavoursurl = '/local/flavours/index.php?sesskey=' . sesskey();
30 |
31 | $ADMIN->add('server', new admin_externalpage($flavoursplugin.'_packaging',
32 | get_string('package', $flavoursplugin),
33 | new moodle_url($flavoursurl)));
34 |
35 | $ADMIN->add('server', new admin_externalpage($flavoursplugin.'_deployment',
36 | get_string('deploy', $flavoursplugin),
37 | new moodle_url($flavoursurl . '&action=deployment_upload')));
38 |
39 | $ADMIN->add('server', new admin_externalpage($flavoursplugin.'_generatedefaults',
40 | get_string('generatedefaults', $flavoursplugin),
41 | new moodle_url($flavoursurl . '&action=generatedefaults_form')));
42 |
43 |
--------------------------------------------------------------------------------
/flavours_xml_transformer.class.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * The flavours XML transformer
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require_once($CFG->dirroot. '/backup/util/xml/contenttransformer/xml_contenttransformer.class.php');
27 |
28 | /**
29 | * Implementation of xml_contenttransformer to add CDATA tags
30 | *
31 | * @package local
32 | * @subpackage flavours
33 | * @copyright 2011 David Monllaó
34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 | */
36 | class flavours_xml_transformer extends xml_contenttransformer {
37 |
38 | /**
39 | * Modify the content before it is writter to a file
40 | *
41 | * @param string|mixed $content
42 | */
43 | public function process($content) {
44 |
45 | if (is_numeric($content) ||
46 | is_null($content) ||
47 | is_bool($content) ||
48 | $content == '') {
49 | return $content;
50 | }
51 |
52 | return '';
53 | }
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/flavours_xml_writer.class.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * A simple extension of the moodle xml_writer
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require_once($CFG->dirroot . '/backup/util/xml/xml_writer.class.php');
27 |
28 | /**
29 | * Extending the xml_writer base to avoid CDATA tags reformat
30 | *
31 | * @package local
32 | * @subpackage flavours
33 | * @copyright 2011 David Monllaó
34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 | */
36 | class flavours_xml_writer extends xml_writer {
37 |
38 |
39 | /**
40 | * Just to avoid the parent method execution
41 | *
42 | * The parent method cleans < and > to avoid XML parsing problems
43 | * but flavours implements an xml_transformer to wrap all the non-numeric
44 | * & non-null values in a CDATA tag, so the < and > cleaning is not necessary
45 | * @param string $content
46 | * @return string
47 | */
48 | protected function xml_safe_text_content($content) {
49 | return $content;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Allows Moodle administrators to package and deploy sets of Moodle plugins, site settings, language packs... (see http://docs.moodle.org/en/Development:Moodle_flavours for more info)
2 |
3 | # Description
4 | A flavour is a packaged set of Moodle site settings, plugins and language packs. Moodle Administrators will be able to create a flavour from their installation, selecting which settings, plugins and language packs will be packaged into a compressed file. They can then, share the package with the Moodle community, store it as a backup or use it to replicate the flavour to other installations they manages. It could also be useful for administrators with little Moodle experienced, allowing them to explore the Moodle settings and setup recommended by others.
5 |
6 | **Warning!** To export and import settings it is better to use [Admin presets block](https://moodle.org/plugins/block_admin_presets) as the process used here is not reliable. The longer explanation is that this is only using get\_config/set\_config functions, block\_admin\_presets is using Moodle's admin settings API.
7 |
8 | ## Install from a compressed .zip
9 | * Extract the compressed file data
10 | * Rename the main folder to flavours
11 | * Copy it to local/ folder
12 | * Click 'Notifications' link on the frontpage administration block
13 |
14 | ## Install using git
15 | * Navigate to Moodle root folder
16 | * **git clone git://github.com/dmonllao/moodle-local_flavours local/flavours**
17 | * **cd local/flavours**
18 | * **git checkout MOODLE_XY_STABLE**
19 | * **php admin/cli/upgrade.php**
20 |
21 | # Usage
22 |
23 | Available under Administration block -> Site settings -> Server -> Package a flavour & Deploy a flavour
24 |
25 | # License
26 |
27 | [GPL-2.0](http://www.gnu.org/licenses/gpl-2.0.txt)
28 |
29 | # More info
30 | * [Source code repository](https://github.com/dmonllao/moodle-local_flavours)
31 | * [moodle.org plugins page](https://moodle.org/plugins/local_flavours)
32 | * [Documentation](http://docs.moodle.org/en/Development:Moodle_flavours)
33 | * [Original Moodle tracker entry](http://tracker.moodle.org/browse/CONTRIB-2948)
34 |
--------------------------------------------------------------------------------
/forms/flavours_generatedefaults_form.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Form definition to settings to add to local/defaults.php
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2012 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require_once($CFG->libdir . '/formslib.php');
27 |
28 | /**
29 | * Form to select the settings
30 | *
31 | * @package local
32 | * @subpackage flavours
33 | * @copyright 2011 David Monllaó
34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 | */
36 | class flavours_generatedefaults_form extends moodleform implements renderable {
37 |
38 | public function definition() {
39 |
40 | global $USER, $CFG;
41 |
42 | $mform = & $this->_form;
43 |
44 |
45 | // Warning overwrite
46 | $mform->addElement('header', 'settings', get_string('defaultoverwritesoptions', 'local_flavours'));
47 | $mform->addElement('checkbox', 'overwrite', get_string('defaultsoverwrite', 'local_flavours'));
48 |
49 | // Settings
50 | $mform->addElement('header', 'ingredients',
51 | get_string('selectsettings', 'local_flavours'));
52 | $mform->addElement('html', '
'.
53 | $this->_customdata["treedata"].'
');
54 |
55 | $mform->addElement('hidden', 'action', 'generatedefaults_execute');
56 | $mform->setType('action', PARAM_ALPHAEXT);
57 | $mform->addElement('submit', 'ingredients_submit',
58 | get_string('generatedefaults', 'local_flavours'));
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Flavours front controller
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require_once(dirname(__FILE__) . '/../../config.php');
27 | require_once($CFG->libdir . '/adminlib.php');
28 | require_once($CFG->dirroot . '/local/flavours/flavours_packaging.class.php');
29 | require_once($CFG->dirroot . '/local/flavours/flavours_deployment.class.php');
30 | require_once($CFG->dirroot . '/local/flavours/flavours_generatedefaults.class.php');
31 | require_once($CFG->dirroot . '/local/flavours/lib.php');
32 |
33 | $action = optional_param('action', 'packaging_form', PARAM_ALPHAEXT);
34 |
35 | $context = context_system::instance();
36 |
37 | // Access control
38 | require_capability('moodle/site:config', $context);
39 | if (!confirm_sesskey()) {
40 | print_error('confirmsesskeybad', 'error');
41 | }
42 |
43 | $url = new moodle_url('/local/flavours/index.php');
44 | $url->param('action', $action);
45 | $PAGE->set_url($url);
46 | $PAGE->set_context($context);
47 |
48 | // Calling the appropiate class
49 | $manager = substr($action, 0, strpos($action, '_'));
50 | $classname = 'flavours_' . $manager;
51 | $instance = new $classname($action);
52 |
53 | $name = explode('_', $action);
54 | $actualsettingspage = array_shift($name);
55 | admin_externalpage_setup('local_flavours_'.$actualsettingspage);
56 |
57 | // Process the action
58 | if (!method_exists($instance, $action)) {
59 | print_error('actionnotsupported', 'local_flavours');
60 | }
61 | $instance->$action();
62 |
63 | echo $instance->render();
64 |
--------------------------------------------------------------------------------
/forms/flavours_deployment_upload_form.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * To upload a flavour
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require_once($CFG->dirroot.'/lib/formslib.php');
27 |
28 | /**
29 | * Form to upload a flavour
30 | *
31 | * @package local
32 | * @subpackage flavours
33 | * @copyright 2011 David Monllaó
34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 | */
36 | class flavours_deployment_upload_form extends moodleform implements renderable {
37 |
38 | public function definition () {
39 |
40 | global $CFG;
41 |
42 | $mform = & $this->_form;
43 |
44 | $steplabel = get_string('deploymentuploadheader', 'local_flavours');
45 | $mform->addElement('header', 'general', $steplabel);
46 |
47 | // File picker
48 | $mform->addElement('filepicker', 'flavourfile', get_string('selectfile', 'local_flavours'));
49 | $mform->addRule('flavourfile', null, 'required');
50 |
51 | // Overwrite
52 | $overwritelabel = get_string('overwrite', 'local_flavours');
53 | $overwriteoptions = array(0 => get_string('overwriteno', 'local_flavours'),
54 | 1 => get_string('overwriteyes', 'local_flavours'));
55 | $mform->addElement('select', 'overwrite', $overwritelabel, $overwriteoptions);
56 | $mform->setType('overwrite', PARAM_INT);
57 |
58 | $mform->addElement('hidden', 'action', 'deployment_preview');
59 | $mform->setType('action', PARAM_ALPHAEXT);
60 | $mform->addElement('submit', 'deployment_upload_submit', get_string('next'));
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/lib.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Moodle flavours renderable classes
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 |
27 | /**
28 | * Renderable class to display the deployment results
29 | *
30 | * @package local
31 | * @subpackage flavours
32 | * @copyright 2011 David Monllaó
33 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34 | */
35 | class flavours_renderable_deployment_execute implements renderable {
36 |
37 | protected $table;
38 |
39 |
40 | /**
41 | * Just a setter
42 | * @param html_table $table
43 | */
44 | public function __construct(html_table $table) {
45 | $this->table = $table;
46 | }
47 |
48 | /**
49 | * $table getter
50 | * @return html_table
51 | */
52 | public function get_table() {
53 | return $this->table;
54 | }
55 |
56 | }
57 |
58 |
59 | /**
60 | * Simple class to pass info to the generatedefaults_execute renderer
61 | */
62 | class flavours_renderable_generatedefaults_execute implements renderable {
63 |
64 | protected $info;
65 | protected $phparray;
66 |
67 | /**
68 | * Sets the instance attributes
69 | * @param array $phparray
70 | * @param object $info
71 | */
72 | public function __construct($phparray, $info = false) {
73 | $this->phparray = $phparray;
74 | $this->info = $info;
75 | }
76 |
77 | /**
78 | * phparray getter
79 | */
80 | public function get_phparray() {
81 | return $this->phparray;
82 | }
83 |
84 | /**
85 | * info getter
86 | */
87 | public function get_info() {
88 | return $this->info;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/forms/flavours_deployment_form.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * To select which ingredients will be deployed
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require_once($CFG->libdir . '/formslib.php');
27 |
28 | /**
29 | * Form to select the ingredients to deploy
30 | *
31 | * @package local
32 | * @subpackage flavours
33 | * @copyright 2011 David Monllaó
34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 | */
36 | class flavours_deployment_form extends moodleform implements renderable {
37 |
38 | public function definition() {
39 |
40 | $mform = & $this->_form;
41 |
42 | // Step header
43 | $steplabel = get_string('deploymentpreviewheader', 'local_flavours');
44 | $mform->addElement('header', 'flavourdata', $steplabel);
45 |
46 | // Flavour info
47 | $fields = array('name', 'description', 'author', 'timecreated', 'sourceurl',
48 | 'sourcemoodlerelease', 'sourcemoodleversion');
49 | foreach ($fields as $field) {
50 | $label = ''.get_string('flavour' . $field, 'local_flavours').'';
51 | $mform->addElement('static', $field, $label);
52 | }
53 |
54 | // Ingredients
55 | $mform->addElement('header', 'ingredients',
56 | get_string('selectingredients', 'local_flavours'));
57 | $mform->addElement('html', ''.
58 | $this->_customdata["treedata"].'
');
59 |
60 | $mform->addElement('hidden', 'overwrite');
61 | $mform->setType('overwrite', PARAM_INT);
62 | $mform->addElement('hidden', 'flavourhash', $this->_customdata['flavourhash']);
63 | $mform->setType('flavourhash', PARAM_ALPHANUMEXT);
64 | $mform->addElement('hidden', 'action', 'deployment_execute');
65 | $mform->setType('action', PARAM_ALPHAEXT);
66 | $mform->addElement('submit', 'ingredients_submit',
67 | get_string('deployflavour', 'local_flavours'));
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/forms/flavours_packaging_form.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Form definition to selec system ingredients to package
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require_once($CFG->libdir . '/formslib.php');
27 |
28 | /**
29 | * Form to select the flavour ingredients
30 | *
31 | * @package local
32 | * @subpackage flavours
33 | * @copyright 2011 David Monllaó
34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 | */
36 | class flavours_packaging_form extends moodleform implements renderable {
37 |
38 | public function definition() {
39 |
40 | global $USER, $OUTPUT;
41 |
42 | $mform = & $this->_form;
43 |
44 | // General data
45 | $mform->addElement('header', 'flavourdata', get_string('flavourdata', 'local_flavours'));
46 |
47 | $mform->addElement('text', 'name', get_string('flavourname', 'local_flavours'));
48 | $mform->addRule('name', null, 'required', null, 'client');
49 | $mform->setType('name', PARAM_TEXT);
50 |
51 | $mform->addElement('editor', 'description',
52 | get_string('flavourdescription', 'local_flavours'));
53 | $mform->setType('description', PARAM_RAW);
54 |
55 | $mform->addElement('text', 'author', get_string('flavourauthor', 'local_flavours'),
56 | 'maxlength="154" size="40"');
57 | $mform->setType('author', PARAM_TEXT);
58 | $mform->setDefault('author', $USER->firstname.' '.$USER->lastname);
59 |
60 | // Ingredients
61 | $mform->addElement('header', 'ingredients',
62 | get_string('selectingredients', 'local_flavours'));
63 |
64 | // Warning about settings.
65 | $mform->addElement('html', $OUTPUT->notification(get_string('settingswarning', 'local_flavours')));
66 |
67 | $mform->addElement('html', ''.
68 | $this->_customdata["treedata"].'
');
69 |
70 | $mform->addElement('hidden', 'action', 'packaging_execute');
71 | $mform->setType('action', PARAM_ALPHAEXT);
72 |
73 | $mform->addElement('submit', 'ingredients_submit',
74 | get_string('packageflavour', 'local_flavours'));
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/module.js:
--------------------------------------------------------------------------------
1 | M.local_flavours = {
2 |
3 | tree: null,
4 | nodes: null,
5 |
6 |
7 | /**
8 | * Initializes the TreeView object
9 | */
10 | init: function(Y) {
11 |
12 | Y.use('yui2-treeview', function(Y) {
13 |
14 | var context = M.local_flavours;
15 |
16 | context.tree = new Y.YUI2.widget.TreeView("id_ingredients_tree");
17 |
18 | context.nodes = new Array();
19 | context.nodes['root'] = context.tree.getRoot();
20 | });
21 | },
22 |
23 |
24 | /**
25 | * Outputs the tree
26 | */
27 | render: function(Y, expandall) {
28 |
29 | var context = M.local_flavours;
30 |
31 | context.tree.setNodesProperty('propagateHighlightUp', true);
32 | context.tree.setNodesProperty('propagateHighlightDown', true);
33 | context.tree.subscribe('clickEvent', context.tree.onEventToggleHighlight);
34 | context.tree.render();
35 |
36 | if (expandall) {
37 | context.tree.expandAll();
38 | context.tree.getRoot().highlight();
39 |
40 | // And uncheck the ones with restrictions (the user will be able to check again)
41 | // In a happy world I would set an attribute, something like 'checked'
42 | var nodes = context.tree.getNodesByProperty('highlightState', '1'); // All
43 | if (!Y.YUI2.lang.isNull(nodes)) {
44 | for (var i = 0; i < nodes.length; i++) {
45 | if (nodes[i].target != '_self' && nodes[i].title == undefined) {
46 | nodes[i].toggleHighlight();
47 | }
48 | }
49 | } else {
50 | alert('null');
51 | }
52 | }
53 |
54 | // Listener to create one node for each selected setting
55 | Y.YUI2.util.Event.on('id_ingredients_submit', 'click', function() {
56 |
57 | // We need the moodle form to add the checked settings
58 | var FlavoursForm = document.getElementById('mform1');
59 |
60 | // TODO: Arghhhh! Look for other solutions! moodleform id can't be forced
61 | if (!FlavoursForm) {
62 | FlavoursForm = document.getElementById('mform2');
63 | }
64 |
65 | // Only the highlighted nodes
66 | var hiLit = context.tree.getNodesByProperty('highlightState', 1);
67 | if (Y.YUI2.lang.isNull(hiLit)) {
68 | Y.YUI2.log("Nothing selected");
69 |
70 | } else {
71 |
72 | for (var i = 0; i < hiLit.length; i++) {
73 |
74 | var treeNode = Y.Node.create(hiLit[i].getContentHtml());
75 | var nodeId = treeNode.getAttribute('alt').substr(5);
76 |
77 | // The way to identify a ingredient (ingredients branches not allowed)
78 | if (nodeId != 'undefined' && nodeId != '') {
79 |
80 | // If the node does not exists we add it
81 | if (!document.getElementById(nodeId)) {
82 |
83 | var ingredientelement = document.createElement('input');
84 | ingredientelement.setAttribute('type', 'hidden');
85 | ingredientelement.setAttribute('name', nodeId);
86 | ingredientelement.setAttribute('value', '1');
87 | FlavoursForm.appendChild(ingredientelement);
88 | }
89 | }
90 | }
91 | }
92 | });
93 |
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/cligeneratedefaults.php:
--------------------------------------------------------------------------------
1 | .
17 |
18 | /**
19 | * This script creates config.php file and prepares database.
20 | *
21 | * This script is not intended for beginners!
22 | * Potential problems:
23 | * - environment check is not present yet
24 | * - su to apache account or sudo before execution
25 | * - not compatible with Windows platform
26 | *
27 | * @package local
28 | * @subpackage flavours
29 | * @copyright 2012 David Monllaó
30 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
31 | */
32 |
33 | define('CLI_SCRIPT', true);
34 |
35 | require(dirname(dirname(dirname(__FILE__))).'/config.php');
36 | require_once($CFG->libdir.'/adminlib.php'); // various admin-only functions
37 | require_once($CFG->libdir.'/clilib.php'); // cli only functions
38 | require_once($CFG->libdir.'/environmentlib.php');
39 |
40 | require_once($CFG->dirroot . '/local/flavours/lib.php');
41 | require_once($CFG->dirroot . '/local/flavours/flavours_generatedefaults.class.php');
42 | require_once($CFG->dirroot . '/local/flavours/ingredient/flavours_ingredient_setting.class.php');
43 |
44 |
45 | // now get cli options
46 | list($options, $unrecognized) = cli_get_params(
47 | array(
48 | 'help' => false,
49 | 'overwrite-defaults' => false
50 | ),
51 | array(
52 | 'h' => 'help'
53 | )
54 | );
55 |
56 | if ($unrecognized) {
57 | $unrecognized = implode("\n ", $unrecognized);
58 | cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
59 | }
60 |
61 | if ($options['help']) {
62 | $help =
63 | "Command line Moodle default system settings updater.
64 | Please note you must execute this script with the same uid as apache!
65 |
66 | Options:
67 | --overwrite-defaults Overwrite local/defaults.php
68 | -h, --help Print out this help
69 |
70 | Example:
71 | \$sudo -u www-data /usr/bin/php local/flavours/cligeneratedefaults.php
72 | "; //TODO: localize - to be translated later when everything is finished
73 |
74 | echo $help;
75 | die;
76 | }
77 |
78 | $overwrite = false;
79 | if (!empty($options['overwrite-defaults'])) {
80 | $overwrite = true;
81 | }
82 |
83 | // Logged as admin to get the full admin tree
84 | $admins = get_admins();
85 | $admin = reset($admins);
86 | session_set_user($admin);
87 |
88 | // Get all system settings (like selecting from flavours packaging form)
89 | $settingsingredient = new flavours_ingredient_setting();
90 | $settingsingredient->get_system_info();
91 |
92 | // Formatting the branches as selected nodes
93 | $returnarray = array();
94 | $selectedsettings = $settingsingredient->get_all_nodes(false, '', $returnarray);
95 |
96 |
97 | // Execute
98 | $generator = new flavours_generatedefaults('generatedefaults_execute');
99 | $generator->generatedefaults_execute($overwrite, $selectedsettings);
100 |
101 |
102 | if (!$overwrite) {
103 | echo get_string('clinooverwrite', 'local_flavours') . "\n";
104 | } else {
105 | echo get_string('clifinished', 'local_flavours')."\n";
106 | }
107 |
108 | exit(0); // 0 means success
109 |
--------------------------------------------------------------------------------
/flavours_generatedefaults.class.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Flavours local/defaults generator
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2012 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require_once($CFG->dirroot . '/local/flavours/flavours.class.php');
27 | require_once($CFG->dirroot . '/local/flavours/forms/flavours_generatedefaults_form.php');
28 |
29 | class flavours_generatedefaults extends flavours {
30 |
31 |
32 | /**
33 | * Allows users to select which settings will be saved
34 | */
35 | public function generatedefaults_form() {
36 |
37 | global $CFG, $PAGE;
38 |
39 | $this->ingredients['setting'] = $this->instance_ingredient_type('setting');
40 | $this->ingredients['setting']->get_system_info();
41 |
42 | // Initializing the tree
43 | $PAGE->requires->js_init_call('M.local_flavours.init', null, true);
44 |
45 | // And rendering on dom ready
46 | $PAGE->requires->js_init_call('M.local_flavours.render', array(true), true);
47 |
48 | // Fill the ingredients tree with this->ingredients (ondomready)
49 | $customdata['treedata'] = $this->get_tree_ingredients();
50 |
51 | $this->renderable = new flavours_generatedefaults_form($this->url, $customdata);
52 | }
53 |
54 |
55 | /**
56 | * Displays / writes the PHP code
57 | * @param boolean $overwrite Forces local/defaults.php to be overwritten
58 | * @param array $selectedingredients Forces the selected ingredients
59 | */
60 | public function generatedefaults_execute($overwrite = false, $selectedingredients = false) {
61 |
62 | global $USER, $CFG;
63 |
64 | // For cli execution
65 | if (!$overwrite) {
66 | $overwrite = optional_param('overwrite', false, PARAM_INT);
67 | }
68 |
69 | // Getting selected data
70 | // Second argument true when generating the settings from cli
71 | if (!$selectedingredients) {
72 | $selectedingredients = $this->get_ingredients_from_form();
73 | }
74 | if (!$selectedingredients) {
75 | $url = $CFG->wwwroot . '/local/flavours/index.php?action=generatedefaults_form' .
76 | '&sesskey=' . sesskey();
77 | redirect($url, get_string('nothingselected', 'local_flavours'), 2);
78 | }
79 |
80 | // Delegating to flavours_ingredient_setting
81 | $settingingredient = $this->instance_ingredient_type('setting');
82 | $phparray = $settingingredient->settings_to_php($selectedingredients['setting']);
83 |
84 | // Depending on the form checkbox
85 | if ($overwrite) {
86 |
87 | // Try to write file
88 | $path = $CFG->dirroot . '/local';
89 | $file = $path .'/defaults.php';
90 |
91 | if (is_writable($path) && !file_exists($file) ||
92 | is_writable($file)) {
93 |
94 | $fh = fopen($file, 'w');
95 | fwrite($fh, 'text = get_string('defaultsfileoverwritten', 'local_flavours');
101 | $info->class = 'notifysuccess';
102 | } else {
103 | $info = new stdClass();
104 | $info->class = 'notifyproblem';
105 | $info->text = get_string('errordefaultfilenotwritable', 'local_flavours');
106 | }
107 |
108 | // Add an info text to copy & paste
109 | } else {
110 | $info->text = get_string('copyandpastedefaults', 'local_flavours');
111 | $info->class = '';
112 | }
113 |
114 | // Sends the PHP code and the info about local/defaults.php to the rendere
115 | $renderer = new flavours_renderable_generatedefaults_execute($phparray, $info);
116 | $this->renderable = $renderer;
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/ingredient/flavours_ingredient.class.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Class to specify the public interface of the ingredient classes
19 | *
20 | * It also contains common methods
21 | *
22 | * @package local
23 | * @subpackage flavours
24 | * @copyright 2011 David Monllaó
25 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 | */
27 |
28 | /**
29 | * Abstract class to define the ingredients interface
30 | *
31 | * @abstract
32 | * @package local
33 | * @subpackage flavours
34 | * @copyright 2011 David Monllaó
35 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36 | */
37 | abstract class flavours_ingredient {
38 |
39 |
40 | /**
41 | * Ingredient type id
42 | * @var string
43 | */
44 | public $id;
45 |
46 |
47 | /**
48 | * Name given to the ingredient type, to identify it on the ingredients tree
49 | * @var string
50 | */
51 | public $name;
52 |
53 |
54 | /**
55 | * The ingredient type ingredients
56 | * @var array
57 | */
58 | public $branches;
59 |
60 |
61 | /**
62 | * Gets an ingredients list with the ingredients availables on the system
63 | * @abstract
64 | */
65 | abstract public function get_system_info();
66 |
67 |
68 | /**
69 | * Stores the selected ingredients into the flavour folder
70 | *
71 | * @abstract
72 | * @param xml_writer $xmlwriter The XML writer, by reference
73 | * @param array $ingredients The ingredients to store
74 | * @param string $path Where to store the flavour tmp files
75 | * @return boolean Not treated but true if it adds something
76 | */
77 | abstract public function package_ingredients(&$xmlwriter, $ingredients, $path);
78 |
79 |
80 | /**
81 | * Gets an ingredients list with the ingredients availables on a flavour
82 | * @abstract
83 | * @param SimpleXMLElement $xml
84 | */
85 | abstract public function get_flavour_info($xml);
86 |
87 |
88 | /**
89 | * From the flavour to the system
90 | *
91 | * @abstract
92 | * @param array $ingredients What to deploy
93 | * @param string $path Path to the ingredient type file system
94 | * @param SimpleXMLElement $xml The XML of the ingredient type with the zip description
95 | * @return array Problems encountered during the ingredients deployment
96 | */
97 | abstract public function deploy_ingredients($ingredients, $path, SimpleXMLElement $xml);
98 |
99 |
100 | /**
101 | * Support function - copied from backup/lib.php and adapted to avoid SCV files
102 | *
103 | * @param string $from
104 | * @param string $to
105 | * @return boolean Feedback
106 | */
107 | protected function copy($from, $to) {
108 |
109 | global $CFG;
110 |
111 | if (!file_exists($from)) {
112 | return false;
113 | }
114 |
115 | // SCV systems to avoid
116 | $scvs = array('.git', 'CVS', '.svn');
117 | $scvsdirs = array_combine($scvs, $scvs);
118 |
119 | $status = true; // Initialize this, next code will change its value if needed
120 |
121 | if (is_file($from)) {
122 | umask(0000);
123 | if (!copy($from, $to)) {
124 | $status = false;
125 | } else {
126 | chmod($to, $CFG->directorypermissions);
127 | $status = true;
128 | }
129 |
130 | } else {
131 |
132 | if (!is_dir($to)) {
133 | umask(0000);
134 | if (!is_dir($to)) {
135 | $status = mkdir($to, $CFG->directorypermissions);
136 | }
137 | }
138 |
139 | $dir = opendir($from);
140 | while (false !== ($file = readdir($dir))) {
141 |
142 | // We don't want SCVS files
143 | if ($file == "." || $file == ".." || !empty($scvsdirs[$file])) {
144 | continue;
145 | }
146 | $status = $this->copy("$from/$file", "$to/$file");
147 | }
148 | closedir($dir);
149 | }
150 |
151 | return $status;
152 | }
153 |
154 |
155 | /**
156 | * Support function - Adapter to flavours->unlink
157 | *
158 | * @param string $path The path to delete
159 | * @return boolean
160 | */
161 | protected function unlink($path) {
162 |
163 | // All that dirty code to maintain 'flavours' as an abstract class
164 | // As a reminder, PHP > 5.2.? does not allow static methods of abstract classes
165 | $action = optional_param('action', 'packaging_form', PARAM_ALPHAEXT);
166 | $tmparray = explode('_', $action);
167 | $classname = 'flavours_' . $tmparray[0];
168 | $instance = new $classname($action);
169 |
170 | return $instance->unlink($path);
171 | }
172 |
173 | }
174 |
--------------------------------------------------------------------------------
/renderer.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Moodle flavours renderers
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 |
27 | /**
28 | * Moodle flavours renderer class
29 | *
30 | * @package local
31 | * @subpackage flavours
32 | * @copyright 2011 David Monllaó
33 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34 | */
35 | class local_flavours_renderer extends plugin_renderer_base {
36 |
37 | /**
38 | * Wraps all the actions
39 | *
40 | * @param renderable $renderable
41 | * @param string $action
42 | * @return string
43 | */
44 | public function render_flavours_wrapper(renderable $renderable, $action) {
45 | global $PAGE, $SITE;
46 |
47 | $PAGE->set_heading($SITE->fullname);
48 | $PAGE->set_title(get_string('action' . $action, 'local_flavours'));
49 |
50 | $output = $this->output->header();
51 | $output .= $this->output->heading(get_string('action' . $action, 'local_flavours'));
52 |
53 | // Redirects the flow to the specific method
54 | $actiontorender = 'render_flavours_' . $action;
55 | $output .= $this->$actiontorender($renderable);
56 |
57 | $output .= $this->output->footer();
58 |
59 | return $output;
60 |
61 | }
62 |
63 | /**
64 | * Packaging form renderer
65 | * @param renderable $renderable
66 | */
67 | protected function render_flavours_packaging_form(renderable $renderable) {
68 | return $this->render_form($renderable);
69 | }
70 |
71 |
72 | /**
73 | * Not necessary, just to maintain coherence action -> render
74 | * @param renderable $renderable
75 | */
76 | protected function render_flavours_packaging_execute(renderable $renderable) {
77 | //
78 | }
79 |
80 | /**
81 | * Deployment upload form renderer
82 | * @param renderable $renderable
83 | */
84 | protected function render_flavours_deployment_upload(renderable $renderable) {
85 | return $this->render_form($renderable);
86 | }
87 |
88 | /**
89 | * Deployment preview form renderer
90 | * @param renderable $renderable
91 | */
92 | protected function render_flavours_deployment_preview(renderable $renderable) {
93 | return $this->render_form($renderable);
94 | }
95 |
96 |
97 | /**
98 | * Deployment results renderer
99 | * @param renderable $renderable
100 | */
101 | protected function render_flavours_deployment_execute(renderable $renderable) {
102 | global $CFG;
103 |
104 | // The table with the results
105 | $output = html_writer::table($renderable->get_table());
106 |
107 | // The button to go to notifications
108 | $notificationsurl = new moodle_url($CFG->wwwroot . '/admin/index.php');
109 | $output .= $this->output->single_button($notificationsurl,
110 | get_string('deploymentcontinue', 'local_flavours'), 'get');
111 |
112 | return $output;
113 | }
114 |
115 |
116 | /**
117 | * Generate defaults.php file form renderer
118 | * @param renderable $renderable
119 | */
120 | protected function render_flavours_generatedefaults_form(renderable $renderable) {
121 |
122 | // Info box + form
123 | $output = $this->output->box(get_string('generatedefaultsinfo', 'local_flavours'));
124 | $output .= $this->render_form($renderable);
125 | return $output;
126 | }
127 |
128 |
129 | /**
130 | * To display the generated HTML
131 | * @param renderable $renderable
132 | */
133 | protected function render_flavours_generatedefaults_execute(renderable $renderable) {
134 |
135 | // Display info about the execution (was local/defaults.php overwritten?)
136 | $class = 'generalbox ' . $renderable->get_info()->class;
137 | $output = $this->output->box($renderable->get_info()->text, $class);
138 |
139 | // The php code to copy & paste
140 | $userfriendlycode = '<?php
';
141 | $userfriendlycode .= implode('
', $renderable->get_phparray());
142 | $userfriendlycode .= '
';
143 | $userfriendlycode .= '// It ends after this two comment lines, there is no php closing tag in this file,
';
144 | $userfriendlycode .= '// it is intentional because it prevents trailing whitespace problems!
';
145 |
146 |
147 | $output .= $this->output->box($userfriendlycode, 'configphp');
148 |
149 | return $output;
150 | }
151 |
152 |
153 | /**
154 | * Gets the HTML of a moodle form
155 | *
156 | * @param moodleform $form
157 | * @return string The HTML of the form
158 | */
159 | protected function render_form(moodleform $form) {
160 |
161 | ob_start();
162 |
163 | $form->display();
164 | $output = ob_get_contents();
165 |
166 | ob_end_clean();
167 |
168 | return $output;
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/lang/ca/local_flavours.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Catalan language strings
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | $string['actionnotsupported'] = 'Acció no suportada en aquesta versió';
27 | $string['actiondeployment_execute'] = 'Desplegament de sabors';
28 | $string['actiondeployment_preview'] = 'Desplegament de sabors - Previsualizació dels ingredients';
29 | $string['actiondeployment_upload'] = 'Desplegament de sabors - Pujar un sabor';
30 | $string['actiongeneratedefaults_form'] = 'Generació de paràmetres per defecte - Selecciona paràmetres';
31 | $string['actiongeneratedefaults_execute'] = 'Generació de paràmetres per defecte';
32 | $string['actionpackaging_form'] = 'Empaquetament de sabors';
33 | $string['actionpackaging_execute'] = 'Empaquetament de sabors';
34 | $string['clifinished'] = 'Execució completada amb èxit, canvis actualitzats a local/defaults.php';
35 | $string['clinooverwrite'] = 'Execució completada sense errors, executar amb --overwrite-defaults per desar els canvis a local/defaults.php';
36 | $string['copyandpastedefaults'] = 'Copia i pega el codi inferior a l\'arxiu local/defaults.php';
37 | $string['defaultsfileoverwritten'] = 'local/defaults.php s\'ha creat/modificat correctament';
38 | $string['defaultsoverwrite'] = 'Sobreescriure local/defaults.php';
39 | $string['defaultoverwritesoptions'] = 'Opcions';
40 | $string['deploy'] = 'Desplega un sabor';
41 | $string['deploymentcontinue'] = 'Continua cap a la pàgina de notificacions';
42 | $string['deploymentpreviewheader'] = 'Pas 2 - Previsualizació d\'ingredients';
43 | $string['deploymentresult'] = 'Resultats del desplegament';
44 | $string['deploymentuploadheader'] = 'Pas 1 - Pujar un sabor';
45 | $string['errorcantunzip'] = 'El sabor no es pot descomprimir';
46 | $string['errorcopying'] = 'Error copiant ingredients';
47 | $string['errordefaultfilenotwritable'] = 'No es pot escriure a local/defaults.php copia i pega el codi inferior';
48 | $string['errordeployflavour'] = 'Problema obtenint l\'arxiu del sabor';
49 | $string['errordeployingpermissions'] = 'Comprova els permissos de la carpeta temporal';
50 | $string['errordeploying'] = 'Error desplegant el sabor';
51 | $string['errorpackaging'] = 'Error empaquetant el sabor';
52 | $string['errorunknownsettingspage'] = 'Pàgina de paràmetres de configuració desconeguda';
53 | $string['deployflavour'] = 'Deplega';
54 | $string['flavourauthor'] = 'Autor';
55 | $string['flavourdata'] = 'Informació del sabor';
56 | $string['flavourdescription'] = 'Descripció';
57 | $string['flavoursourceurl'] = 'Lloc d\'origen';
58 | $string['flavoursourcemoodleversion'] = 'Versió de Moodle d\'origen';
59 | $string['flavoursourcemoodlerelease'] = 'Moodle d\'origen';
60 | $string['flavourname'] = 'Nom';
61 | $string['flavourtimecreated'] = 'Creat el';
62 | $string['generatedefaults'] = 'Actualitza paràmetres per defecte del sistema';
63 | $string['generatedefaultsinfo'] = 'Selecciona quins paràmetres de configuració en ús sobreescriuran els paràmetres per defecte del sistema';
64 | $string['ingredient'] = 'Ingredient';
65 | $string['ingredienttype'] = 'Tipus d\'ingredient';
66 | $string['ingredienttypenotavailable'] = 'Tipus d\'ingredient no disponible';
67 | $string['nothingselected'] = 'Has de seleccionar alguna cosa';
68 | $string['overwrite'] = 'Sobreescriure';
69 | $string['overwriteno'] = 'No sobreescriure plugins ja instal·lats';
70 | $string['overwriteyes'] = 'Només sobreescriure plugins amb versions superiors al sabor';
71 | $string['package'] = 'Empaqueta un sabor';
72 | $string['packageflavour'] = 'Empaqueta';
73 | $string['pluginname'] = 'Sabors';
74 | $string['problem'] = 'Problema!';
75 | $string['reselect'] = 'No hi ha res seleccionat!';
76 | $string['restrictioncustomlangnotinstalled'] = 'El paquet d\'idioma "{$a}" no està instal·lat al sistema';
77 | $string['restrictioncustomlangalreadycreated'] = 'Ja disposes d\'una modificació del paquet d\'idioma';
78 | $string['restrictionlangalreadyinstalled'] = 'Paquete d\'idioma "{$a}" ja disponible';
79 | $string['restrictionlangfilepermissions'] = 'Permissos incorrectes';
80 | $string['restrictionlangnotvalid'] = 'Paquet d\'idioma "{$a}" no vàlid';
81 | $string['restrictionpluginalreadyinstalled'] = 'Plugin "{$a}" ja instal·lat';
82 | $string['restrictionplugincantremove'] = 'La versió actual de "{$a}" no es pot actualizar, revisa els permissos';
83 | $string['restrictionplugincopyerror'] = 'Error copiant';
84 | $string['restrictionpluginflavournotnewer'] = 'La versió del sabor no és més nova que la instal·lada actualment';
85 | $string['restrictionpluginnowritable'] = 'Permissos incorrectes per a instal·lar o actualitzar a "{$a}"';
86 | $string['restrictionpluginnotfound'] = 'Plugin "{$a}" no trobat';
87 | $string['restrictionpluginnoversiondiskupgrade'] = 'El plugin "{$a}" j existeix i no es pot actualitzar, el plugin del sabor no indica la seva versió';
88 | $string['restrictionpluginsystemold'] = 'El plugin requereix una versió superior de Moodle';
89 | $string['restrictionsettingnosettingpage'] = 'La pàgina de paràmetres de configuració no existeix. La funcionalitat deu estar deshabilitada o ja no existeix.';
90 | $string['restrictionsettingsproblemsarray'] = 'Problemas desplegant aquests paràmetres: "{$a}"';
91 | $string['restrictionsettingwarningoverwrite'] = 'Els paràmetres actuals seran sobreescrits';
92 | $string['selectfile'] = 'Selecciona arxiu';
93 | $string['selectingredients'] = 'Selecciona ingredients';
94 | $string['selectingredientstodeploy'] = 'Selecciona els ingredients a desplegar';
95 | $string['selectsettings'] = 'Selecciona els paràmetres de configuració';
96 | $string['warning'] = 'Atenció!';
97 |
--------------------------------------------------------------------------------
/lang/en/local_flavours.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * English language strings
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | $string['actionnotsupported'] = 'Action not supported';
27 | $string['actiondeployment_execute'] = 'Flavours Deployment';
28 | $string['actiondeployment_preview'] = 'Flavours Deployment - Ingredients previsualization';
29 | $string['actiondeployment_upload'] = 'Flavours Deployment - Upload a flavour';
30 | $string['actiongeneratedefaults_form'] = 'Default system settings generator - Select settings';
31 | $string['actiongeneratedefaults_execute'] = 'Default system settings generator';
32 | $string['actionpackaging_form'] = 'Flavours Packaging';
33 | $string['actionpackaging_execute'] = 'Flavours Packaging';
34 | $string['clifinished'] = 'Execution completed successfully, changes updated in local/defaults.php';
35 | $string['clinooverwrite'] = 'Execution finished without problems, execute with --overwrite-defaults to save the settings in local/defaults.php';
36 | $string['copyandpastedefaults'] = 'Copy and paste the below PHP code in local/defaults.php file';
37 | $string['defaultsfileoverwritten'] = 'local/defaults.php has been succesfully created/modified';
38 | $string['defaultsoverwrite'] = 'Overwrite local/defaults.php';
39 | $string['defaultoverwritesoptions'] = 'Options';
40 | $string['deploy'] = 'Deploy a flavour';
41 | $string['deploymentcontinue'] = 'Continue to notifications page';
42 | $string['deploymentpreviewheader'] = 'Step 2 - Ingredients previsualization';
43 | $string['deploymentresult'] = 'Deployment result';
44 | $string['deploymentuploadheader'] = 'Step 1 - Upload a flavour';
45 | $string['errorcantunzip'] = 'The flavour can\'t be upzipped';
46 | $string['errorcopying'] = 'Error copying ingredients';
47 | $string['errordefaultfilenotwritable'] = 'local/defaults.php not writable, copy and paste the below PHP code';
48 | $string['errordeployflavour'] = 'Problem getting the flavour file';
49 | $string['errordeployingpermissions'] = 'Check the temporal folder permissions';
50 | $string['errordeploying'] = 'Error deploying the flavour';
51 | $string['errorpackaging'] = 'Error packaging the flavour';
52 | $string['errorunknownsettingspage'] = 'Unknown settings page';
53 | $string['deployflavour'] = 'Deploy';
54 | $string['flavourauthor'] = 'Author';
55 | $string['flavourdata'] = 'Flavour data';
56 | $string['flavourdescription'] = 'Description';
57 | $string['flavoursourceurl'] = 'Source Site';
58 | $string['flavoursourcemoodleversion'] = 'Source Moodle Version';
59 | $string['flavoursourcemoodlerelease'] = 'Source Moodle Release';
60 | $string['flavourname'] = 'Name';
61 | $string['flavourtimecreated'] = 'Time created';
62 | $string['generatedefaults'] = 'Update default system settings';
63 | $string['generatedefaultsinfo'] = 'Select which of the current settings will overwrite the system default values';
64 | $string['ingredient'] = 'Ingredient';
65 | $string['ingredienttype'] = 'Ingredient type';
66 | $string['ingredienttypenotavailable'] = 'Ingredient type not available';
67 | $string['nothingselected'] = 'You must select something';
68 | $string['overwrite'] = 'Over-write';
69 | $string['overwriteno'] = 'Don\'t over-write plugins already on my system';
70 | $string['overwriteyes'] = 'Only over-write plugins with a newer version on the flavour';
71 | $string['package'] = 'Package a flavour';
72 | $string['packageflavour'] = 'Package';
73 | $string['pluginname'] = 'Flavours';
74 | $string['problem'] = 'Problem!';
75 | $string['reselect'] = 'Nothing selected!';
76 | $string['restrictioncustomlangnotinstalled'] = 'The "{$a}" language pack is not installed on the system';
77 | $string['restrictioncustomlangalreadycreated'] = 'Custom strings already created';
78 | $string['restrictionlangalreadyinstalled'] = 'Language "{$a}" already installed';
79 | $string['restrictionlangfilepermissions'] = 'Wrong permissions to install new language packs';
80 | $string['restrictionlangnotvalid'] = 'Language pack "{$a}" not valid';
81 | $string['restrictionpluginalreadyinstalled'] = 'Plugin "{$a}" already installed';
82 | $string['restrictionplugincantremove'] = 'The "{$a}" plugin current version can\'t be upgraded, check the folder permissions';
83 | $string['restrictionplugincopyerror'] = 'Error copying';
84 | $string['restrictionpluginflavournotnewer'] = 'The flavour version not newer than the installed version';
85 | $string['restrictionpluginnowritable'] = 'Wrong permissions to install or upgrade on "{$a}"';
86 | $string['restrictionpluginnotfound'] = 'Plugin "{$a}" not found';
87 | $string['restrictionpluginnoversiondiskupgrade'] = 'The plugin "{$a}" already exists and can\'t be upgraded, the flavour one does not contains the version';
88 | $string['restrictionpluginsystemold'] = 'The plugin requires an higher Moodle version';
89 | $string['restrictionsettingnosettingpage'] = 'The settings page does not exists in this site. The feature may be disabled or is not available any more.';
90 | $string['restrictionsettingsproblemsarray'] = 'Problems deploying this settings: "{$a}"';
91 | $string['restrictionsettingwarningoverwrite'] = 'The system settings will be overwritten';
92 | $string['selectfile'] = 'Select file';
93 | $string['selectingredients'] = 'Select ingredients';
94 | $string['selectingredientstodeploy'] = 'Select ingredients to deploy';
95 | $string['selectsettings'] = 'Select settings';
96 | $string['settingswarning'] = 'Please, note that \'Settings\' ingredient is not reliable and may lead to unexpected results. Consider using https://moodle.org/plugins/block_admin_presets to import/export site settings.';
97 | $string['warning'] = 'Warning!';
98 |
--------------------------------------------------------------------------------
/lang/es/local_flavours.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Español language strings
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | $string['actionnotsupported'] = 'Acción no soportada en esta versión';
27 | $string['actiondeployment_execute'] = 'Despliegue de sabores';
28 | $string['actiondeployment_preview'] = 'Despliegue de sabores - Previsualización de los ingredientes';
29 | $string['actiondeployment_upload'] = 'Despliegue de sabores - Subir un sabor';
30 | $string['actiongeneratedefaults_form'] = 'Generador de parámetros por defecto - Selecciona parámetros';
31 | $string['actiongeneratedefaults_execute'] = 'Generador de parámetros por defecto';
32 | $string['actionpackaging_form'] = 'Empaquetado de sabores';
33 | $string['actionpackaging_execute'] = 'Empaquetado de sabores';
34 | $string['clifinished'] = 'Ejecucución completada con éxito, parámetros de configuración actualizados en local/defaults.php';
35 | $string['clinooverwrite'] = 'Ejecución completada sin errores, ejecutar con --overwrite-defaults para guardar los cambios en local/defaults.php';
36 | $string['copyandpastedefaults'] = 'Copia y pega el código inferior en el archivo local/defaults.php';
37 | $string['defaultsfileoverwritten'] = 'local/defaults.php se ha creado/modificado correctamente';
38 | $string['defaultsoverwrite'] = 'Sobreescribir local/defaults.php';
39 | $string['defaultoverwritesoptions'] = 'Opciones';
40 | $string['deploy'] = 'Despliega un sabor';
41 | $string['deploymentcontinue'] = 'Continua hacia la página de notificaciones';
42 | $string['deploymentpreviewheader'] = 'Paso 2 - Previsualización de ingredientes';
43 | $string['deploymentresult'] = 'Resultados del despliegue';
44 | $string['deploymentuploadheader'] = 'Paso 1 - Subir un sabor';
45 | $string['errorcantunzip'] = 'El sabor no se puede descomprimir';
46 | $string['errorcopying'] = 'Error copiando ingredientes';
47 | $string['errordefaultfilenotwritable'] = 'No se puede escribir en local/defaults.php, copia y pega el código inferior';
48 | $string['errordeployflavour'] = 'Problema obteniendo el archivo del sabor';
49 | $string['errordeployingpermissions'] = 'Comprueba los permisos de la carpeta temporal';
50 | $string['errordeploying'] = 'Error desplegando el sabor';
51 | $string['errorpackaging'] = 'Error empaquetando el sabor';
52 | $string['errorunknownsettingspage'] = 'Página de parámetros de configuración desconocida';
53 | $string['deployflavour'] = 'Despliega';
54 | $string['flavourauthor'] = 'Autor';
55 | $string['flavourdata'] = 'Información del sabor';
56 | $string['flavourdescription'] = 'Descripción';
57 | $string['flavoursourceurl'] = 'Sitio de origen';
58 | $string['flavoursourcemoodleversion'] = 'Versión de Moodle de origen';
59 | $string['flavoursourcemoodlerelease'] = 'Moodle de origen';
60 | $string['flavourname'] = 'Nombre';
61 | $string['flavourtimecreated'] = 'Creado el';
62 | $string['generatedefaults'] = 'Actualiza parámetros por defecto del sistema';
63 | $string['generatedefaultsinfo'] = 'Selecciona qué parámetros de configuración en uso sobreescribirán los parámetros por defecto del sistema';
64 | $string['ingredient'] = 'Ingrediente';
65 | $string['ingredienttype'] = 'Tipo de ingrediente';
66 | $string['ingredienttypenotavailable'] = 'Tipo de ingrediente no disponible';
67 | $string['nothingselected'] = 'Debes seleccionar algo';
68 | $string['overwrite'] = 'Sobreescribir';
69 | $string['overwriteno'] = 'No sobreescribir plugins ya instalados';
70 | $string['overwriteyes'] = 'Solo sobreescribir plugins con versiones superiores en el sabor';
71 | $string['package'] = 'Empaqueta un sabor';
72 | $string['packageflavour'] = 'Empaqueta';
73 | $string['pluginname'] = 'Sabores';
74 | $string['problem'] = 'Problema!';
75 | $string['reselect'] = 'No hay nada seleccionado!';
76 | $string['restrictioncustomlangnotinstalled'] = 'El paquete de idioma "{$a}" no está instalado en el sistema';
77 | $string['restrictioncustomlangalreadycreated'] = 'Ya dispones de una modificación del paquete de idioma';
78 | $string['restrictionlangalreadyinstalled'] = 'Paquete de idioma "{$a}" ya disponible';
79 | $string['restrictionlangfilepermissions'] = 'Permisos incorrectos';
80 | $string['restrictionlangnotvalid'] = 'Paquete de idioma "{$a}" no válido';
81 | $string['restrictionpluginalreadyinstalled'] = 'Plugin "{$a}" ya instalado';
82 | $string['restrictionplugincantremove'] = 'La versión actual de "{$a}" no se puede actualizar, revisa los permisos';
83 | $string['restrictionplugincopyerror'] = 'Error copiando';
84 | $string['restrictionpluginflavournotnewer'] = 'La versión del sabor no és más nueva que la instalada actualmente';
85 | $string['restrictionpluginnowritable'] = 'Permisos incorrectos para instalar o actualizar en "{$a}"';
86 | $string['restrictionpluginnotfound'] = 'Plugin "{$a}" no encontrado';
87 | $string['restrictionpluginnoversiondiskupgrade'] = 'El plugin "{$a}" ya existe y no se puede actualizar, el plugin del sabor no indica su versión';
88 | $string['restrictionpluginsystemold'] = 'El plugin requiere una versión superior de Moodle';
89 | $string['restrictionsettingnosettingpage'] = 'La página de parámetros de configuración no existe. La funcionalidad está deshabilitada o ya no existe.';
90 | $string['restrictionsettingsproblemsarray'] = 'Problemas desplegando estos parámetros: "{$a}"';
91 | $string['restrictionsettingwarningoverwrite'] = 'Los parámetros actuales serán sobreescritos';
92 | $string['selectfile'] = 'Selecciona archivo';
93 | $string['selectingredients'] = 'Selecciona ingredientes';
94 | $string['selectingredientstodeploy'] = 'Selecciona los ingredientes a desplegar';
95 | $string['selectsettings'] = 'Selecciona los parámetros de configuración';
96 | $string['warning'] = 'Atención!';
97 |
--------------------------------------------------------------------------------
/ingredient/flavours_ingredient_customlang.class.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Customized languages ingredient type
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require_once($CFG->dirroot . '/local/flavours/ingredient/flavours_ingredient_lang.class.php');
27 |
28 |
29 | /**
30 | * Manages the packaging and deployment of customized languages
31 | *
32 | * @package local
33 | * @subpackage flavours
34 | * @copyright 2011 David Monllaó
35 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36 | */
37 | class flavours_ingredient_customlang extends flavours_ingredient_lang {
38 |
39 |
40 | /**
41 | * Sets the ingredient name and identifier
42 | */
43 | public function __construct() {
44 | global $CFG;
45 |
46 | $this->id = 'customlang';
47 | $this->name = get_string('localstringcustomization', 'admin');
48 |
49 | $this->langpath = rtrim($CFG->langlocalroot, '/') . '/';
50 |
51 | $this->check_lang_dir();
52 | }
53 |
54 |
55 | /**
56 | * Gets the language packs with modified strings
57 | */
58 | public function get_system_info() {
59 |
60 | // System language customizations
61 | $customs = $this->get_system_customlangs();
62 |
63 | // Get all the system languages
64 | parent::get_system_info();
65 |
66 | // Remove the ones without local modifications
67 | if (!empty($this->branches)) {
68 | foreach ($this->branches as $langid => $data) {
69 |
70 | $customlangdir = $langid . '_local';
71 | if (empty($customs[$customlangdir])) {
72 | unset($this->branches[$langid]);
73 | }
74 | }
75 | }
76 |
77 | // Adding 'en' if necessary, which is avoided when getting the system info
78 | $id = 'en';
79 | if (!empty($customs[$id . '_local'])) {
80 |
81 | // To obtain the name
82 | $string = get_string_manager()->load_component_strings('langconfig', $id);
83 |
84 | $this->branches[$id] = new stdClass();
85 | $this->branches[$id]->id = $id;
86 | $this->branches[$id]->name = $string['thislanguage'] . ' ('. $id .')';
87 | }
88 | }
89 |
90 |
91 | /**
92 | * Gets the custom languages availables on the flavour
93 | *
94 | * It also loads $this->restrictions with ->general and ->specific attributes (array type both).
95 | * The array key will be used to get the language string
96 | *
97 | * @param SimpleXMLElement $xml
98 | */
99 | public function get_flavour_info($xml) {
100 | global $CFG;
101 |
102 | $systemlangs = get_string_manager()->get_list_of_translations();
103 | $alllangs = get_string_manager()->get_list_of_languages();
104 |
105 | // System language customizations
106 | $customs = $this->get_system_customlangs();
107 |
108 | // File permissions
109 | $langsfolder = $CFG->dataroot.'/lang/';
110 | if (!is_writable($langsfolder)) {
111 | $nowritable = true;
112 | }
113 |
114 | $ingredients = $xml->children();
115 | if (!$ingredients) {
116 | return false;
117 | }
118 |
119 | foreach ($ingredients as $lang => $langdata) {
120 |
121 | $this->branches[$lang] = new stdClass();
122 |
123 | // Writable directory?
124 | if (!empty($nowritable)) {
125 | $this->branches[$lang]->restrictions['langfilepermissions'] = $langsfolder;
126 | }
127 |
128 | // Installed language?
129 | // Commented to avoid problem when deploying customlangs before langs
130 | //if (empty($systemlangs[$lang])) {
131 | // $this->branches[$lang]->restrictions['customlangnotinstalled'] = $lang;
132 | //}
133 |
134 | // Custom strings already created?
135 | if (!empty($customs[$lang . '_local'])) {
136 | $this->branches[$lang]->restrictions['customlangalreadycreated'] = $lang;
137 | }
138 |
139 | // Valid language?
140 | if (empty($alllangs[$lang])) {
141 | $this->branches[$lang]->restrictions['langnotvalid'] = $lang;
142 |
143 | }
144 |
145 | $this->branches[$lang]->id = $lang;
146 | $this->branches[$lang]->name = (String) $langdata->name;
147 | }
148 | }
149 |
150 |
151 | /**
152 | * Returns the name of the dir containing the modified strings
153 | *
154 | * @param string $langid
155 | * @return string
156 | */
157 | protected function get_lang_dir($langid) {
158 | return $langid . '_local';
159 | }
160 |
161 |
162 | /**
163 | * Returns the list of languages with customizations
164 | *
165 | * @return array An associative array with the filename as key
166 | */
167 | protected function get_system_customlangs() {
168 |
169 | $customs = array();
170 |
171 | if (!$dir = @opendir($this->langpath)) {
172 | return false;
173 | }
174 |
175 | // Iterate through the langs folder to get language customizations
176 | while (false !== ($file = readdir($dir))) {
177 | if ($file == "." || $file == ".." || strstr($file, '_local') === false) {
178 | continue;
179 | }
180 |
181 | $customs[$file] = $file;
182 | }
183 | closedir($dir);
184 |
185 | return $customs;
186 | }
187 |
188 | }
189 |
--------------------------------------------------------------------------------
/flavours_packaging.class.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Flavours packaging system
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require_once($CFG->libdir . '/filestorage/zip_packer.php');
27 | require_once($CFG->dirroot . '/local/flavours/flavours_xml_writer.class.php');
28 | require_once($CFG->dirroot . '/local/flavours/flavours_xml_transformer.class.php');
29 | require_once($CFG->dirroot . '/backup/util/xml/output/xml_output.class.php');
30 | require_once($CFG->dirroot . '/backup/util/xml/output/memory_xml_output.class.php');
31 |
32 | require_once($CFG->dirroot . '/local/flavours/flavours.class.php');
33 | require_once($CFG->dirroot . '/local/flavours/forms/flavours_packaging_form.php');
34 |
35 | /**
36 | * Packaging system manager
37 | *
38 | * @package local
39 | * @subpackage flavours
40 | * @copyright 2011 David Monllaó
41 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
42 | */
43 | class flavours_packaging extends flavours {
44 |
45 | /**
46 | * Outputs the packaging form
47 | */
48 | public function packaging_form() {
49 |
50 | global $CFG, $PAGE;
51 |
52 | // Getting the ingredient types data
53 | foreach ($this->ingredienttypes as $type) {
54 |
55 | // instnace_ingredient_type get a new flavours_ingredient_* object
56 | $this->ingredients[$type] = $this->instance_ingredient_type($type);
57 | $this->ingredients[$type]->get_system_info();
58 | }
59 |
60 | // Initializing the tree
61 | $PAGE->requires->js_init_call('M.local_flavours.init', null, true);
62 |
63 | // And rendering on dom ready
64 | $PAGE->requires->js_init_call('M.local_flavours.render', null, true);
65 |
66 | // Fill the ingredients tree with this->ingredients (ondomready)
67 | $customdata['treedata'] = $this->get_tree_ingredients();
68 |
69 | $this->renderable = new flavours_packaging_form($this->url, $customdata);
70 | }
71 |
72 |
73 | /**
74 | * Packages the entire flavour and returns it
75 | * @todo Add a checksum
76 | */
77 | public function packaging_execute() {
78 |
79 | global $USER, $CFG;
80 |
81 | $errorredirect = $this->url . '?sesskey=' . sesskey();
82 |
83 | // Getting selected data
84 | $selectedingredients = $this->get_ingredients_from_form();
85 | if (!$selectedingredients) {
86 | redirect($errorredirect, get_string('nothingselected', 'local_flavours'), 2);
87 | }
88 |
89 | // Flavour data
90 | $form = new flavours_packaging_form($this->url);
91 | if (!$data = $form->get_data()) {
92 | print_error('errorpackaging', 'local_flavours');
93 | }
94 |
95 | // Starting
96 | $xmloutput = new memory_xml_output();
97 | $xmltransformer = new flavours_xml_transformer();
98 | $xmlwriter = new flavours_xml_writer($xmloutput, $xmltransformer);
99 | $xmlwriter->start();
100 | $xmlwriter->begin_tag('flavour');
101 | $xmlwriter->full_tag('name', $data->name);
102 | // Ignoring the format, the received description format should be included
103 | // in the package to display it properly.
104 | $xmlwriter->full_tag('description', $data->description['text']);
105 | $xmlwriter->full_tag('author', $data->author);
106 | $xmlwriter->full_tag('timecreated', time());
107 | $xmlwriter->full_tag('sourceurl', $CFG->wwwroot);
108 | $xmlwriter->full_tag('sourcemoodlerelease', $CFG->release);
109 | $xmlwriter->full_tag('sourcemoodleversion', $CFG->version);
110 |
111 | // Random code to store the flavour data
112 | $hash = sha1('flavour_'.$USER->id.'_'.time());
113 | $flavourpath = $this->flavourstmpfolder.'/'.$hash;
114 |
115 | if (file_exists($flavourpath) || !mkdir($flavourpath, $CFG->directorypermissions)) {
116 | print_error('errorpackaging', 'local_flavours');
117 | }
118 |
119 | // Adding the selected ingredients data
120 | $xmlwriter->begin_tag('ingredient');
121 | foreach ($selectedingredients as $ingredienttype => $ingredientsdata) {
122 |
123 | // instance_ingredient_type gets a new flavours_ingredient_* object
124 | $type = $this->instance_ingredient_type($ingredienttype);
125 |
126 | $xmlwriter->begin_tag($type->id);
127 |
128 | // It executes the ingredient type specific actions to package
129 | $type->package_ingredients($xmlwriter, $flavourpath, $ingredientsdata);
130 |
131 | $xmlwriter->end_tag($type->id);
132 | }
133 | $xmlwriter->end_tag('ingredient');
134 |
135 | // Finishing flavour index
136 | $xmlwriter->end_tag('flavour');
137 | $xmlwriter->stop();
138 | $flavourxml = $xmloutput->get_allcontents();
139 |
140 | // Creating the .xml with the flavour info
141 | $xmlfilepath = $flavourpath . '/flavour.xml';
142 | if (!$xmlfh = fopen($xmlfilepath, 'w')) {
143 | print_error('errorpackaging', 'local_flavours');
144 | }
145 | fwrite($xmlfh, $flavourxml);
146 | fclose($xmlfh);
147 |
148 | // Flavour contents compression
149 | $packer = new zip_packer();
150 | $zipfilename = clean_param('flavour_' . userdate(time(), get_string('backupnameformat', 'langconfig')) . '.zip', PARAM_FILE);
151 | $zipfilepath = $this->flavourstmpfolder . DIRECTORY_SEPARATOR . $zipfilename;
152 |
153 | if (!$packer->archive_to_pathname(array('flavour' => $flavourpath), $zipfilepath)) {
154 | print_error('errorpackaging', 'local_flavours');
155 | }
156 | send_file($zipfilepath, $zipfilename);
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/ingredient/flavours_ingredient_lang.class.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Lang ingredient type
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require_once($CFG->dirroot . '/local/flavours/ingredient/flavours_ingredient.class.php');
27 |
28 |
29 | /**
30 | * Manages the packaging and deployment of language packs
31 | *
32 | * @package local
33 | * @subpackage flavours
34 | * @copyright 2011 David Monllaó
35 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36 | */
37 | class flavours_ingredient_lang extends flavours_ingredient {
38 |
39 |
40 | /**
41 | * The path where the language packs are stored
42 | * @var string
43 | */
44 | protected $langpath;
45 |
46 | /**
47 | * Sets the ingredient name and identifier
48 | */
49 | public function __construct() {
50 | global $CFG;
51 |
52 | $this->id = 'lang';
53 | $this->name = get_string('language');
54 |
55 | $this->langpath = rtrim($CFG->langotherroot, '/') . '/';
56 |
57 | $this->check_lang_dir();
58 | }
59 |
60 |
61 | /**
62 | * Gets the installed languages
63 | */
64 | public function get_system_info() {
65 |
66 | $langs = get_string_manager()->get_list_of_translations();
67 | if ($langs) {
68 | foreach ($langs as $lang => $langname) {
69 | if ($lang != 'en') {
70 | $this->branches[$lang] = new StdClass();
71 | $this->branches[$lang]->id = $lang;
72 | $this->branches[$lang]->name = $langname;
73 | }
74 | }
75 | }
76 | }
77 |
78 |
79 | /**
80 | * Copies the selected languages to the temp path
81 | *
82 | * @param xml_writer $xmlwriter The XML writer, by reference
83 | * @param string $path Where to store the data
84 | * @param array $ingredientsdata Ingredients to store
85 | */
86 | public function package_ingredients(&$xmlwriter, $path, $ingredientsdata) {
87 |
88 | global $CFG;
89 |
90 | if (!$ingredientsdata) {
91 | return false;
92 | }
93 |
94 | mkdir($path . '/' . $this->id, $CFG->directorypermissions);
95 |
96 | foreach ($ingredientsdata as $langid) {
97 |
98 | // External method to allow methods overwrite
99 | $langdirname = $this->get_lang_dir($langid);
100 |
101 | // All the languages are stored in dataroot, english is the only exception AFAIK
102 | $frompath = $this->langpath . '/' . $langdirname;
103 |
104 | // Recursive copy
105 | $topath = $path . '/' . $this->id . '/' . $langdirname;
106 | if (!$this->copy($frompath, $topath)) {
107 | debugging($frompath);
108 | debugging($topath);
109 | print_error('errorcopying', 'local_flavours');
110 | }
111 | $language = get_string_manager()->load_component_strings('langconfig', $langid);
112 | $xmlwriter->begin_tag($langid);
113 | $xmlwriter->full_tag('name', $language['thislanguage']);
114 | $xmlwriter->full_tag('path', $langid);
115 | $xmlwriter->end_tag($langid);
116 | }
117 |
118 | return true;
119 | }
120 |
121 |
122 | /**
123 | * Gets the languages availables on the flavour
124 | *
125 | * It also loads $this->restrictions with ->general and ->specific attributes (array type both).
126 | * The array key will be used to get the language string
127 | *
128 | * @param SimpleXMLElement $xml
129 | */
130 | public function get_flavour_info($xml) {
131 | global $CFG;
132 |
133 | $systemlangs = get_string_manager()->get_list_of_translations();
134 | $alllangs = get_string_manager()->get_list_of_languages();
135 |
136 | // File permissions
137 | if (!file_exists($this->langpath) || !is_writable($this->langpath)) {
138 | $nowritable = true;
139 | }
140 |
141 | $ingredients = $xml->children();
142 | if (!$ingredients) {
143 | return false;
144 | }
145 |
146 | foreach ($ingredients as $lang => $langdata) {
147 |
148 | $this->branches[$lang] = new stdClass();
149 |
150 | // Writable directory?
151 | if (!empty($nowritable)) {
152 | $this->branches[$lang]->restrictions['langfilepermissions'] = $this->langpath;
153 | }
154 |
155 | // Installed language?
156 | if (!empty($systemlangs[$lang])) {
157 | $this->branches[$lang]->restrictions['langalreadyinstalled'] = $lang;
158 | }
159 |
160 | // Valid language?
161 | if (empty($alllangs[$lang])) {
162 | $this->branches[$lang]->restrictions['langnotvalid'] = $lang;
163 |
164 | }
165 |
166 | $this->branches[$lang]->id = $lang;
167 | $this->branches[$lang]->name = (String) $langdata->name;
168 | }
169 |
170 | }
171 |
172 |
173 | /**
174 | * Installs the selected languages
175 | *
176 | * @todo Language md5 verification?
177 | * @param array $ingredients
178 | * @param string $path Path to the ingredient type file system
179 | * @param SimpleXMLElement $xml
180 | * @return array Problems during the ingredients deployment
181 | */
182 | public function deploy_ingredients($ingredients, $path, SimpleXMLElement $xml) {
183 | global $CFG;
184 |
185 | // Checking again and storing data in $this->branches
186 | $this->get_flavour_info($xml);
187 |
188 | $problems = array();
189 | foreach ($ingredients as $ingredient) {
190 |
191 | // Only if there are no problems with the ingredient
192 | if (!empty($this->branches[$ingredient]->restrictions)) {
193 | $problems[$ingredient] = $this->branches[$ingredient]->restrictions;
194 | continue;
195 | }
196 |
197 | $langpath = $this->langpath . '/' . $this->get_lang_dir($ingredient);
198 | mkdir($langpath, $CFG->directorypermissions);
199 |
200 | $tmplangpath = $path . '/' . $this->get_lang_dir($ingredient);
201 | if (!$this->copy($tmplangpath, $langpath)) {
202 | debugging('From: ' . $tmplangpath . ' To: '.$langpath);
203 | $problems[$ingredient]['langfilepermissions'] = true;
204 | }
205 | }
206 |
207 | return $problems;
208 | }
209 |
210 |
211 | /**
212 | * Returns the dir name of the language
213 | *
214 | * Useful to allow overwrite of methods
215 | *
216 | * @param string $langid
217 | * @return string
218 | */
219 | protected function get_lang_dir($langid) {
220 | return $langid;
221 | }
222 |
223 | /**
224 | * Checks if the lang dir in moodledata exists and tries to create it if it does not.
225 | *
226 | * @return void
227 | */
228 | protected function check_lang_dir() {
229 | global $CFG;
230 |
231 | // Try to create it if it does not exist, should be created during install though.
232 | // If we can't we will later show a nice problem to the user, no need for an exception.
233 | if (!file_exists($this->langpath)) {
234 | @mkdir($this->langpath, $CFG->directorypermissions, true);
235 | }
236 | }
237 | }
238 |
--------------------------------------------------------------------------------
/flavours_deployment.class.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Deployment system
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require_once($CFG->libdir . '/filestorage/zip_packer.php');
27 |
28 | require_once($CFG->dirroot . '/local/flavours/flavours.class.php');
29 | require_once($CFG->dirroot . '/local/flavours/forms/flavours_deployment_upload_form.php');
30 | require_once($CFG->dirroot . '/local/flavours/forms/flavours_deployment_form.php');
31 |
32 | /**
33 | * Manages the deployment steps
34 | *
35 | * @package local
36 | * @subpackage flavours
37 | * @copyright 2011 David Monllaó
38 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39 | */
40 | class flavours_deployment extends flavours {
41 |
42 |
43 | /**
44 | * Initialization of the upload form
45 | */
46 | public function deployment_upload() {
47 | $this->renderable = new flavours_deployment_upload_form($this->url);
48 | }
49 |
50 |
51 | /**
52 | * Flavour contents preview
53 | *
54 | * Based on the flavour.xml data, if there are flavour file structure problems like
55 | * missing files/directories it will be checked on the deployment execution
56 | */
57 | public function deployment_preview() {
58 | global $USER, $CFG, $PAGE;
59 |
60 | $errorredirect = $this->url . '?action=deployment_upload&sesskey=' . sesskey();
61 | $previousform = new flavours_deployment_upload_form($this->url);
62 |
63 | // Redirect in no data was submitted
64 | if (!$formdata = $previousform->get_data()) {
65 | redirect($errorredirect, get_string('reselect', 'local_flavours'), 2);
66 | }
67 |
68 | // Creating the temp/ path
69 | $uniquename = md5($USER->id . '_' . time() . '_' . random_string(10));
70 | $flavourpath = $CFG->dataroot . '/temp/' . $uniquename;
71 | if (!mkdir($flavourpath, $CFG->directorypermissions)) {
72 | redirect($errorredirect, get_string('errordeployingpermissions', 'local_flavours'), 2);
73 | }
74 |
75 | // Saving the flavour file
76 | $flavourfilename = $flavourpath . '/flavour.zip';
77 | if (!$previousform->save_file('flavourfile', $flavourfilename, true)) {
78 | $this->unlink($flavourpath);
79 | redirect($errorredirect, get_string('errordeployflavour', 'local_flavours'), 4);
80 | }
81 |
82 | // Opening zip
83 | $flavourzip = new ZipArchive();
84 | if (!$flavourzip->open($flavourfilename, 0)) {
85 | $this->unlink($flavourpath);
86 | redirect($errorredirect, get_string('errordeployflavour', 'local_flavours'), 4);
87 | }
88 |
89 | // Getting the flavour xml which describes the flavour contents
90 | $xml = $this->get_flavour_xml($flavourzip);
91 |
92 | $flavourzip->close();
93 |
94 | // Some clean up.
95 | $toform = new stdClass();
96 | $toform->name = format_string($xml->name[0]);
97 | // TODO We should have the description format in the package.
98 | $toform->description = format_text($xml->description, FORMAT_HTML);
99 | $toform->author = format_string($xml->author);
100 | $toform->timecreated = userdate($xml->timecreated);
101 | $toform->sourceurl = clean_param($xml->sourceurl, PARAM_URL);
102 | $toform->sourcemoodlerelease = format_string($xml->sourcemoodlerelease, PARAM_TEXT);
103 | $toform->sourcemoodleversion = clean_param($xml->sourcemoodleversion, PARAM_INT);
104 |
105 | // Adding the over-write value from the upload flavour form and adding it as hidden
106 | $toform->overwrite = $formdata->overwrite;
107 |
108 | // Fill $this->ingredients with the xml ingredients
109 | foreach ($xml->ingredient[0] as $type => $ingredientsxml) {
110 |
111 | $this->ingredients[$type] = $this->instance_ingredient_type($type);
112 |
113 | // It also looks for restrictions like file permissions, plugins already added
114 | $this->ingredients[$type]->get_flavour_info($ingredientsxml);
115 | }
116 |
117 | // Initializing the tree
118 | $PAGE->requires->js_init_call('M.local_flavours.init', null, true);
119 |
120 | // And rendering on dom ready
121 | $PAGE->requires->js_init_call('M.local_flavours.render', array('true'), true);
122 |
123 | // Fill the ingredients tree with this->ingredients (ondomready)
124 | $customdata['treedata'] = $this->get_tree_ingredients();
125 | $customdata['flavourhash'] = $uniquename;
126 |
127 | $this->renderable = new flavours_deployment_form($this->url, $customdata);
128 | $this->renderable->set_data($toform);
129 |
130 | }
131 |
132 |
133 | /**
134 | * Flavours deployment
135 | *
136 | * Executes the deployment delegating to the specific ingredient types managers, it
137 | * opens the flavour compressed file to extract the data and cleans the flavour temp
138 | * directory when finishes
139 | */
140 | public function deployment_execute() {
141 | global $CFG;
142 |
143 | $outputs = array(); // Deployment results
144 |
145 | $errorredirect = $this->url . '?action=deployment_upload&sesskey=' . sesskey();
146 |
147 | $form = new flavours_deployment_form($this->url);
148 | if (!$formdata = $form->get_data()) {
149 | $this->unlink($flavourpath);
150 | redirect($errorredirect, get_string('reselect', 'local_flavours'), 2);
151 | }
152 |
153 | // Flavour contents
154 | $flavourpath = $CFG->dataroot . '/temp/' . $formdata->flavourhash;
155 | $flavourfilename = $flavourpath . '/flavour.zip';
156 |
157 | // Getting the ingredients to deploy
158 | if (!$flavouringredients = $this->get_ingredients_from_form()) {
159 | $this->unlink($flavourpath);
160 | redirect($errorredirect, get_string('reselect', 'local_flavours'), 2);
161 | }
162 |
163 | // Getting zip contents
164 | if (!unzip_file($flavourfilename, $flavourpath, false)) {
165 | print_error('errorcantunzip', 'local_flavours');
166 | }
167 |
168 | $flavourzip = new ZipArchive();
169 | if (!$flavourzip->open($flavourfilename, 0)) {
170 | $this->unlink($flavourpath);
171 | redirect($errorredirect, get_string('errordeployflavour', 'local_flavours'), 4);
172 | }
173 |
174 | // Getting the flavour xml which describes the flavour contents
175 | $xml = $this->get_flavour_xml($flavourzip);
176 |
177 | // Deploying ingredients when possible
178 | foreach ($flavouringredients as $type => $ingredientstodeploy) {
179 |
180 | $this->ingredients[$type] = $this->instance_ingredient_type($type);
181 |
182 | // Ingredient type filesystem
183 | $ingredienttypepath = $flavourpath . '/flavour/' . $type;
184 | if (!file_exists($ingredienttypepath)) {
185 | $ingredienttypepath = false;
186 | }
187 |
188 | // Deploying ingredients and storing the problems encountered to give feedback
189 | $xmldata = $xml->ingredient[0]->$type;
190 | $outputs[$type] = $this->ingredients[$type]->deploy_ingredients($ingredientstodeploy,
191 | $ingredienttypepath, $xmldata);
192 |
193 | // Prepare to display deployment results
194 | foreach ($ingredientstodeploy as $ingredientname => $ingredientdata) {
195 |
196 | // Then success
197 | if (empty($outputs[$type][$ingredientname])) {
198 | $outputs[$type][$ingredientname] = true;
199 | }
200 | }
201 | }
202 |
203 | // Output results
204 | $table = new html_table();
205 | $table->attributes['class'] = 'generaltable boxaligncenter';
206 | $table->align = array('left', 'left', 'center');
207 | $table->head = array(get_string('ingredienttype', 'local_flavours'),
208 | get_string('ingredient', 'local_flavours'),
209 | get_string('deploymentresult', 'local_flavours'));
210 |
211 | // Fill the table
212 | foreach ($outputs as $type => $ingredients) {
213 | foreach ($ingredients as $ingredientname => $outputs) {
214 |
215 | // Success
216 | if (is_bool($outputs)) {
217 | $feedback = get_string('success');
218 | $classname = 'notifysuccess';
219 | } else {
220 | $feedback = $this->get_restrictions_string($outputs);
221 | $classname = 'notifyproblem';
222 | }
223 |
224 | $feedback = '' . $feedback . '';
225 | $table->data[] = array($this->ingredients[$type]->name, $ingredientname, $feedback);
226 | }
227 | }
228 |
229 | // Will be printed on the renderer
230 | $this->renderable = new flavours_renderable_deployment_execute($table);
231 |
232 | // Finishing
233 | $this->unlink($flavourpath);
234 |
235 | purge_all_caches();
236 | }
237 |
238 |
239 | /**
240 | * Returns the flavour XML which describes the flavour contents
241 | * @param ZipArchive $flavourzip
242 | * @return SimpleXMLElement
243 | */
244 | protected function get_flavour_xml(ZipArchive $flavourzip) {
245 |
246 | $flavourxml = $flavourzip->getFromName('flavour/flavour.xml');
247 |
248 | // Parsing the .xml content to extract flavour info
249 | return simplexml_load_string($flavourxml, null, LIBXML_NOCDATA);
250 | }
251 |
252 | }
253 |
--------------------------------------------------------------------------------
/flavours.class.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Parent main manager class implementation
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | /**
27 | * Common methods to manage the packaging and deployment of Moodle flavours
28 | *
29 | * @package local
30 | * @subpackage flavours
31 | * @copyright 2011 David Monllaó
32 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33 | */
34 | abstract class flavours {
35 |
36 | protected $action;
37 | protected $url;
38 | protected $flavourstmpfolder;
39 | protected $ingredienttypes;
40 |
41 | // Output
42 | protected $renderer;
43 | protected $renderable;
44 |
45 | public function __construct($action) {
46 |
47 | global $CFG;
48 |
49 | $this->action = $action;
50 | $this->url = $CFG->wwwroot.'/local/flavours/index.php';
51 | $this->flavourstmpfolder = $CFG->tempdir.'/flavours';
52 |
53 | // Temp directory may be absent on fresh installs
54 | if (!file_exists($CFG->tempdir)) {
55 | @mkdir ($CFG->tempdir . '/', $CFG->directorypermissions);
56 | }
57 |
58 | // Ensure that the flavours temp folder exists
59 | if (!file_exists($this->flavourstmpfolder)) {
60 | @mkdir ($this->flavourstmpfolder, $CFG->directorypermissions);
61 | }
62 |
63 | // Clean garbage caused by the packaging system or workflow exceptions
64 | $this->clean_garbage();
65 |
66 | // Getting the system ingredient types
67 | $this->set_ingredient_types();
68 | }
69 |
70 |
71 | /**
72 | * Creates the tree structure based on $this->ingredients
73 | *
74 | * @return array The tree html following the TreeView structure
75 | */
76 | protected function get_tree_ingredients() {
77 |
78 | global $PAGE;
79 |
80 | if (empty($this->ingredients)) {
81 | return false;
82 | }
83 |
84 | $treedata = '';
85 | foreach ($this->ingredients as $ingredienttype => $branch) {
86 |
87 | // A main ingredient/ namespace to ease the ingredients detection
88 | $prefix = 'ingredient/'.$ingredienttype;
89 | $this->get_tree_data($treedata, $branch, $prefix);
90 | }
91 | $treedata .= '
';
92 |
93 | return $treedata;
94 | }
95 |
96 |
97 | /**
98 | * Gets the html to display the tree
99 | *
100 | * @param string $output
101 | * @param object $branch
102 | * @param string $prefix
103 | */
104 | protected function get_tree_data(&$output, $branch, $prefix) {
105 |
106 | $output .= '';
107 | $output .= $branch->name;
108 |
109 | $output .= '';
110 | if (!empty($branch->branches)) {
111 |
112 | foreach ($branch->branches as $name => $data) {
113 |
114 | // To identify that branch/leaf and pass it through his branches
115 | $branchprefix = $prefix.'/'.$data->id;
116 | $branchnodeprefix = 'node_' . $branchprefix;
117 |
118 | // If it does not have children it's a leaf
119 | if (empty($data->branches)) {
120 |
121 | $string = $data->name;
122 | $title = $string; // We set the title attribute
123 |
124 | // Should we add restrictions info?
125 | if (!empty($data->restrictions)) {
126 |
127 | // A way to mark which ones have restrictions to work with TreeView
128 | $title = '';
129 |
130 | $string = '' . $string . ' - ';
131 | $string .= $this->get_restrictions_string($data->restrictions);
132 | $string .= '';
133 | } else {
134 | $string = '' . $string . '';
135 | }
136 |
137 | $output .= '- ' . $string . '
';
138 |
139 | } else {
140 | // Let's get the branch children
141 | $this->get_tree_data($output, $data, $branchprefix);
142 | }
143 | }
144 | }
145 |
146 | $output .= '
';
147 | $output .= '';
148 | }
149 |
150 |
151 | /**
152 | * Returns a new instance of a ingredient_type
153 | *
154 | * @param string $type The ingredient type
155 | * @param flavours_ingredient $type
156 | */
157 | protected function instance_ingredient_type($type) {
158 |
159 | global $CFG;
160 |
161 | $classname = 'flavours_ingredient_'.$type;
162 | $filepath = $CFG->dirroot . '/local/flavours/ingredient/'.$classname.'.class.php';
163 | if (!file_exists($filepath)) {
164 | print_error('ingredienttypenotavailable', 'local_flavours');
165 | }
166 |
167 | // Getting the system ingredients of that type
168 | require_once($filepath);
169 |
170 | return new $classname();
171 | }
172 |
173 |
174 | /**
175 | * Centralized output
176 | * @return string The HTML to display
177 | */
178 | public function render() {
179 |
180 | global $PAGE;
181 |
182 | $renderer = $PAGE->get_renderer('local_flavours');
183 |
184 | return $renderer->render_flavours_wrapper($this->renderable, $this->action);
185 | }
186 |
187 |
188 | /**
189 | * Extracts the selected ingredients from $_POST
190 | * @return array The selected ingredients organized by ingredient type
191 | */
192 | public function get_ingredients_from_form() {
193 |
194 | if (empty($_POST)) {
195 | return false;
196 | }
197 |
198 | // Looking for selected ingredients and the ingredient type
199 | foreach ($_POST as $varname => $enabled) {
200 |
201 | if (strstr($varname, '/') == false) {
202 | continue;
203 | }
204 |
205 | $namespace = explode('/', $varname);
206 | if (array_shift($namespace) == 'ingredient') {
207 |
208 | $ingredienttype = array_shift($namespace);
209 |
210 | foreach ($namespace as $key => $value) {
211 | $namespace[$key] = preg_replace('/[^0-9a-zA-Z_]/i', '', $value);
212 | }
213 | $ingredientpath = implode('/', $namespace);
214 |
215 | // Only organized by ingredient type, each type will
216 | // treat his ingredients on a different way
217 | $ingredients[$ingredienttype][$ingredientpath] = $ingredientpath;
218 | }
219 | }
220 |
221 | if (empty($ingredients)) {
222 | return false;
223 | }
224 |
225 | ksort($ingredients);
226 |
227 | return $ingredients;
228 | }
229 |
230 |
231 | /**
232 | * Sets the available ingredient types of the system
233 | *
234 | * Reads the flavours/ingredient/ folder to extract the ingredient names
235 | * from the available classes, excluding the parent class
236 | */
237 | protected function set_ingredient_types() {
238 | global $CFG;
239 |
240 | $this->ingredienttypes = array();
241 |
242 | $ingredientsdir = $CFG->dirroot . '/local/flavours/ingredient/';
243 | if ($dirhandler = opendir($ingredientsdir)) {
244 | while (($file = readdir($dirhandler)) !== false) {
245 |
246 | // Excluding the parent class (and maybe SCV hidden files or something like that)
247 | preg_match('/flavours_ingredient_(.*?).class.php/', $file, $ingredienttype);
248 | if ($ingredienttype) {
249 | $this->ingredienttypes[] = $ingredienttype[1];
250 | }
251 | }
252 | closedir($dirhandler);
253 | }
254 | }
255 |
256 |
257 | /**
258 | * Recursive implementation of unlink() to remove directories
259 | *
260 | * @param string $path The path to remove
261 | * @return boolean
262 | */
263 | public function unlink($path) {
264 |
265 | if ($path == false || $path == '') {
266 | return false;
267 | }
268 |
269 | $status = true;
270 |
271 | if (!is_dir($path)) {
272 | $status = @unlink($path);
273 |
274 | } else {
275 | if (!$dir = opendir($path)) {
276 | return false;
277 | }
278 | while (false !== ($file = readdir($dir))) {
279 | if ($file == "." || $file == "..") {
280 | continue;
281 | }
282 |
283 | $status = $status && $this->unlink($path . '/' . $file);
284 | }
285 | closedir($dir);
286 |
287 | $status = $status && @rmdir($path);
288 | }
289 |
290 | return $status;
291 | }
292 |
293 |
294 | /**
295 | * The restrictions in a string
296 | *
297 | * @param array $restrictions
298 | * @return string
299 | */
300 | protected function get_restrictions_string($restrictions) {
301 |
302 | $strs = array();
303 | if ($restrictions) {
304 | foreach ($restrictions as $restriction => $a) {
305 |
306 | if (strstr($restriction, 'warning') != false) {
307 | $prefixstr = 'warning';
308 | } else {
309 | $prefixstr = 'problem';
310 | }
311 | $strs[] = get_string($prefixstr, 'local_flavours') . ' ' .
312 | get_string('restriction'.$restriction, 'local_flavours', $a);
313 | }
314 | }
315 |
316 | return implode(' / ', $strs);
317 | }
318 |
319 |
320 | /**
321 | * Deletes all the old moodledata/temp/flavours folders
322 | */
323 | protected function clean_garbage() {
324 | global $CFG;
325 |
326 | $olderthan = 3600; // One hour
327 | $now = time();
328 |
329 | if (!$dir = opendir($this->flavourstmpfolder)) {
330 | return;
331 | }
332 | while (false !== ($file = readdir($dir))) {
333 | if ($file == "." || $file == "..") {
334 | continue;
335 | }
336 |
337 | $filepath = $this->flavourstmpfolder . '/' . $file;
338 |
339 | // If it's older than $olderthan remove it
340 | if ($now > (filemtime($filepath) + $olderthan)) {
341 | $this->unlink($filepath);
342 | }
343 | }
344 | closedir($dir);
345 | }
346 | }
347 |
348 |
349 | /**
350 | * Void function to pass to upgrade_plugins()
351 | */
352 | function flavours_print_upgrade_void() {
353 | return;
354 | }
355 |
--------------------------------------------------------------------------------
/ingredient/flavours_ingredient_plugin.class.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Plugin ingredient type
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require_once($CFG->dirroot . '/local/flavours/ingredient/flavours_ingredient.class.php');
27 | require_once($CFG->dirroot . '/lib/upgradelib.php');
28 |
29 | /**
30 | * Manages the packaging and deployment of all the moodle plugins
31 | *
32 | * @package local
33 | * @subpackage flavours
34 | * @copyright 2011 David Monllaó
35 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36 | */
37 | class flavours_ingredient_plugin extends flavours_ingredient {
38 |
39 |
40 | /**
41 | * Sets the ingredient name and identifier
42 | */
43 | public function __construct() {
44 | $this->id = 'plugin';
45 | $this->name = get_string('plugin');
46 | }
47 |
48 |
49 | /**
50 | * Gets the list of plugin types and the system available ingredients
51 | */
52 | public function get_system_info() {
53 |
54 | // Load moodle plugins manager and get the plugins
55 | $pluginman = core_plugin_manager::instance();
56 | $pluginman->get_plugins();
57 | $pluginman->get_subplugins();
58 |
59 | // Getting the plugin types
60 | $plugintypes = get_plugin_types();
61 |
62 | foreach ($plugintypes as $type => $path) {
63 |
64 | $plugins = get_plugin_list($type);
65 |
66 | // We only add the plugin type if it has plugins
67 | if ($plugins) {
68 |
69 | // Core plugins
70 | if ($coreplugins = $pluginman->standard_plugins_list($type)) {
71 | $coreplugins = array_combine($coreplugins, $coreplugins);
72 | }
73 |
74 | // The plugin type data
75 | $branchid = $type;
76 | $branchname = $pluginman->plugintype_name_plural($type);
77 |
78 | foreach ($plugins as $pluginname => $pluginpath) {
79 |
80 | // We will only list the non standard plugins
81 | if (!empty($coreplugins) && !empty($coreplugins[$pluginname])) {
82 | continue;
83 | }
84 |
85 | $this->branches[$type]->branches[$pluginname] = new StdClass();
86 | $this->branches[$type]->branches[$pluginname]->id = $pluginname;
87 |
88 | // The plugin user friendly name
89 | $pluginvisiblename = $this->get_system_plugin_visiblename($type, $pluginname);
90 | $this->branches[$type]->branches[$pluginname]->name = $pluginvisiblename;
91 | }
92 |
93 | // Only if there is non core plugins
94 | if (empty($this->branches[$type]->branches)) {
95 | continue;
96 | }
97 |
98 | $this->branches[$type]->id = $branchid;
99 | $this->branches[$type]->name = $branchname;
100 | }
101 | }
102 | }
103 |
104 |
105 | /**
106 | * Copies the selected plugins to the flavour file structure
107 | *
108 | * @param xml_writer $xmlwriter The XML writer, by reference
109 | * @param string $path Where to store the data
110 | * @param array $ingredientsdata Ingredients to store
111 | */
112 | public function package_ingredients(&$xmlwriter, $path, $ingredientsdata) {
113 |
114 | global $CFG;
115 |
116 | if (!$ingredientsdata) {
117 | return false;
118 | }
119 |
120 | // Required to find plugin types paths
121 | $plugintypesdata = get_plugin_types();
122 |
123 | // To find the plugins versions
124 | $pluginman = core_plugin_manager::instance();
125 | $systemplugins = $pluginman->get_plugins(true);
126 |
127 | mkdir($path . '/' . $this->id, $CFG->directorypermissions);
128 |
129 | // A first iteration to group ingredients by plugin type
130 | foreach ($ingredientsdata as $plugintype) {
131 | $tmparray = explode('/', $plugintype);
132 | $plugins[$tmparray[0]][$tmparray[1]] = $tmparray[1];
133 | }
134 |
135 | foreach ($plugins as $plugintype => $ingredients) {
136 |
137 | $xmlwriter->begin_tag($plugintype);
138 |
139 | // The plugin type folder
140 | $plugintypepath = $plugintypesdata[$plugintype];
141 | $plugintypebasepath = str_replace($CFG->dirroot, '', $plugintypepath);
142 | $plugintypeflavourpath = str_replace(
143 | rtrim($CFG->dirroot, '/'),
144 | $path . '/' . $this->id,
145 | $plugintypepath);
146 |
147 | // First condition to avoid subplugins conflicts
148 | if (!is_dir($plugintypeflavourpath)) {
149 | if (!mkdir($plugintypeflavourpath, $CFG->directorypermissions, true)) {
150 | debugging($plugintypeflavourpath);
151 | continue;
152 | }
153 | }
154 |
155 | foreach ($ingredients as $ingredient) {
156 |
157 | // Copying to the flavour filesystem
158 | $frompath = $plugintypepath . '/' . $ingredient;
159 |
160 | // Recursive copy
161 | $topath = $plugintypeflavourpath . '/' . $ingredient;
162 | if (!$this->copy($frompath, $topath)) {
163 | debugging($frompath . '---' . $topath);
164 | print_error('errorcopying', 'local_flavours');
165 | }
166 |
167 | // Adding the ingredient to the flavour data
168 | $xmlwriter->begin_tag($ingredient);
169 | $xmlwriter->full_tag('name',
170 | $this->get_system_plugin_visiblename($plugintype, $ingredient));
171 | $xmlwriter->full_tag('path',
172 | ltrim($plugintypebasepath, '/') . '/' . $ingredient);
173 |
174 | // The plugin version and required moodle version
175 | if (!empty($systemplugins[$plugintype][$ingredient]->versionrequires)) {
176 | $requires = $systemplugins[$plugintype][$ingredient]->versionrequires;
177 | } else {
178 | $requires = '';
179 | }
180 | if (!empty($systemplugins[$plugintype][$ingredient]->versiondisk)) {
181 | $version = $systemplugins[$plugintype][$ingredient]->versiondisk;
182 | } else {
183 | $version = '';
184 | }
185 |
186 | $xmlwriter->full_tag('versiondisk', $version);
187 | $xmlwriter->full_tag('requires', $requires);
188 | $xmlwriter->end_tag($ingredient);
189 | }
190 |
191 | $xmlwriter->end_tag($plugintype);
192 | }
193 |
194 | return true;
195 | }
196 |
197 |
198 | /**
199 | * Lists the flavour plugins
200 | * @param SimpleXMLElement $xml
201 | */
202 | public function get_flavour_info($xml) {
203 | global $CFG;
204 |
205 | $overwrite = required_param('overwrite', PARAM_INT);
206 |
207 | $pluginman = core_plugin_manager::instance();
208 | $systemplugins = $pluginman->get_plugins();
209 | $plugintypespaths = get_plugin_types();
210 |
211 | $ingredients = $xml->children();
212 | foreach ($ingredients as $plugintype => $plugins) {
213 |
214 | unset($nowritable);
215 |
216 | // Writable directory?
217 | $dir = $plugintypespaths[$plugintype];
218 | if (!is_writable($dir)) {
219 | $nowritable = true;
220 | }
221 |
222 | $this->branches[$plugintype] = new stdClass();
223 |
224 | foreach ($plugins as $pluginname => $plugindata) {
225 |
226 |
227 | $this->branches[$plugintype]->branches[$pluginname] = new stdClass();
228 |
229 | // Only to display on notifications
230 | $pluginfull = $plugintype . '/' . $pluginname;
231 |
232 | // Versioning checkings
233 | if (!empty($systemplugins[$plugintype][$pluginname])) {
234 |
235 | $systemplugin = $systemplugins[$plugintype][$pluginname];
236 |
237 | $pluginversiondisk = (String) $plugindata->versiondisk;
238 | $pluginrequires = (String) $plugindata->requires;
239 |
240 | // Overwrite disabled
241 | if (!empty($systemplugin) && !$overwrite) {
242 | $this->branches[$plugintype]->branches[$pluginname]->restrictions['pluginalreadyinstalled'] = $pluginfull;
243 | }
244 |
245 | // If the flavour plugin doesn't have a versiondisk (filters for example)
246 | // don't overwrite (and skip notification if the upper one has been displayed
247 | if (empty($pluginversiondisk) &&
248 | empty($this->branches[$plugintype]->branches[$pluginname]->restrictions)) {
249 | $this->branches[$plugintype]->branches[$pluginname]->restrictions['pluginnoversiondiskupgrade'] = $pluginfull;
250 | }
251 |
252 | // Overwrite if newer release on flavour
253 | if (!empty($systemplugin) && $overwrite && !empty($pluginversiondisk) &&
254 | $pluginversiondisk <= $systemplugin->versiondisk) {
255 |
256 | $this->branches[$plugintype]->branches[$pluginname]->restrictions['pluginflavournotnewer'] = $pluginfull;
257 | }
258 |
259 | }
260 |
261 | // Required Moodle version to use the plugin
262 | if (!empty($pluginrequires) && $CFG->version < $pluginrequires) {
263 | $this->branches[$plugintype]->branches[$pluginname]->restrictions['pluginsystemold'] = $pluginfull;
264 | }
265 |
266 | $this->branches[$plugintype]->id = $plugintype;
267 | $this->branches[$plugintype]->name = $pluginman->plugintype_name_plural($plugintype);
268 | $this->branches[$plugintype]->branches[$pluginname]->id = $pluginname;
269 | $this->branches[$plugintype]->branches[$pluginname]->name = (String)$plugindata->name;
270 |
271 | if (!empty($nowritable)) {
272 | $this->branches[$plugintype]->branches[$pluginname]->restrictions['pluginnowritable'] = $dir;
273 | }
274 | }
275 |
276 | }
277 | }
278 |
279 |
280 | /**
281 | * Adds and upgrades the selected plugins
282 | *
283 | * @param array $ingredients
284 | * @param string $path Path to the ingredient type file system
285 | * @param SimpleXMLElement $xml
286 | * @return array Problems during the ingredients deployment
287 | */
288 | public function deploy_ingredients($ingredients, $path, SimpleXMLElement $xml) {
289 |
290 | // Using the $ingredients array keys to maintain coherence with the main deployment method
291 | $problems = array();
292 |
293 | $pluginman = core_plugin_manager::instance();
294 | $plugintypespaths = get_plugin_types();
295 |
296 | $this->get_flavour_info($xml);
297 |
298 | foreach ($ingredients as $selection) {
299 |
300 | // [0] => ingredienttype, [1] => ingredientname
301 | $ingredientdata = explode('/', $selection);
302 | $type = $ingredientdata[0];
303 | $ingredient = $ingredientdata[1];
304 |
305 | if (empty($this->branches[$type]->branches[$ingredient])) {
306 | $problems[$selection]['pluginnotfound'] = $selection;
307 | continue;
308 | }
309 | $ingredientdata = $this->branches[$type]->branches[$ingredient];
310 |
311 | // Adapter to the restrictions array
312 | if (!empty($ingredientdata->restrictions)) {
313 | $problems[$selection] = $ingredientdata->restrictions;
314 | continue;
315 | }
316 |
317 | if (empty($xml->{$type}) || empty($xml->{$type}->{$ingredient})) {
318 | $problems[$selection]['pluginnotfound'] = $selection;
319 | continue;
320 | }
321 |
322 | // Deploy then
323 | $ingredientpath = $plugintypespaths[$type] . '/' . $ingredient;
324 |
325 | // Remove old dir if present
326 | if (file_exists($ingredientpath)) {
327 |
328 | // Report if the old plugin directory can't be removed
329 | if (!$this->unlink($ingredientpath)) {
330 | $problems[$selection]['plugincantremove'] = $selection;
331 | continue;
332 | }
333 | }
334 |
335 | // Copy the new contents where the flavour says
336 | $tmppath = $path . '/' . $xml->{$type}->{$ingredient}->path;
337 | if (!$this->copy($tmppath, $ingredientpath)) {
338 | debugging('From : ' . $tmppath . ' To: ' . $ingredientpath);
339 | $problems[$selection]['plugincopyerror'] = $selection;
340 | }
341 | }
342 |
343 | // Execute the moodle upgrade process
344 | try {
345 | foreach ($plugintypespaths as $type => $location) {
346 | upgrade_plugins($type, 'flavours_print_upgrade_void', 'flavours_print_upgrade_void', false);
347 | }
348 | } catch (Exception $ex) {
349 | abort_all_db_transactions();
350 | $info = get_exception_info($ex);
351 | upgrade_log(UPGRADE_LOG_ERROR, $ex->module, 'Exception: ' . get_class($ex), $info->message, $info->backtrace);
352 | }
353 |
354 | return $problems;
355 | }
356 |
357 |
358 | /**
359 | * Returns (if possible) the visible name of the plugin
360 | *
361 | * Not all the Moodle plugins follows the "pluginname" convention so let's
362 | * display the plugin string identifier instead of the human readable pluginname
363 | *
364 | * @param string $plugintype
365 | * @param string $pluginname
366 | * @return string The name to show
367 | */
368 | private function get_system_plugin_visiblename($plugintype, $pluginname) {
369 |
370 | $component = $plugintype.'_'.$pluginname;
371 | if (!get_string_manager()->string_exists('pluginname', $component)) {
372 | $pluginvisiblename = $pluginname;
373 | } else {
374 | $pluginvisiblename = get_string('pluginname', $component);
375 | }
376 |
377 | return $pluginvisiblename;
378 | }
379 |
380 | }
381 |
--------------------------------------------------------------------------------
/ingredient/flavours_ingredient_setting.class.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Settings ingredient type
19 | *
20 | * @package local
21 | * @subpackage flavours
22 | * @copyright 2011 David Monllaó
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require_once($CFG->dirroot . '/local/flavours/ingredient/flavours_ingredient.class.php');
27 |
28 |
29 | /**
30 | * Manages the packaging and deployment of administration settings
31 | *
32 | * @package local
33 | * @subpackage flavours
34 | * @copyright 2011 David Monllaó
35 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36 | */
37 | class flavours_ingredient_setting extends flavours_ingredient {
38 |
39 | /**
40 | * For the settings with more than one value
41 | *
42 | * The extra values will be attributes of the "main" setting, using the CFG setting name
43 | * to ease the deployment.
44 | * @var array
45 | */
46 | private $multiplevaluemapping = array('fix' => '_adv', 'adv' => '_adv', 'locked' => '_locked');
47 |
48 | /**
49 | * Manages the warnings output
50 | *
51 | * There should be a warning on the preview screen but the execution results
52 | * should display feedback. deploy_ingredients() sets it and get_flavour_branches()
53 | * treats it
54 | *
55 | * @var bool
56 | */
57 | private $displaywarnings = true;
58 |
59 | /**
60 | * Sets the ingredient name and identifier
61 | */
62 | public function __construct() {
63 | $this->id = 'setting';
64 | $this->name = get_string('settings');
65 | }
66 |
67 |
68 | /**
69 | * Gets the admin tree instance and populates $this->branch
70 | * with the admin tree categories and pages
71 | */
72 | public function get_system_info() {
73 | $adminroot = admin_get_root();
74 | $this->get_branch_settings($adminroot->children, $this);
75 | }
76 |
77 |
78 | /**
79 | * Writes the xml with the selected admin settings
80 | *
81 | * @param xml_writer $xmlwriter The XML writer, by reference
82 | * @param string $path Where to store the data
83 | * @param array $ingredientsdata Settings to store
84 | */
85 | public function package_ingredients(&$xmlwriter, $path, $ingredientsdata) {
86 |
87 | if (!$ingredientsdata) {
88 | return false;
89 | }
90 |
91 | $adminroot = admin_get_root();
92 | $this->get_branch_settings($adminroot->children, $this, true);
93 |
94 | foreach ($ingredientsdata as $settingspage) {
95 |
96 | // Settings page path
97 | $namespace = explode('/', $settingspage);
98 |
99 | // The admin settingspage is the last one
100 | $page = array_pop($namespace);
101 |
102 | if (!$settings = $this->get_settingspage_settings($namespace, $page, $this)) {
103 | continue;
104 | }
105 |
106 | $settingspagetagname = str_replace('/', '.', $settingspage);
107 | $xmlwriter->begin_tag($settingspagetagname);
108 |
109 | // Adding settings
110 | foreach ($settings as $setting) {
111 |
112 | // Getting the attributes of the tag
113 | // Some plugins has slashes, not availables as part of the tag name
114 | $attrs = array('plugin' => str_replace('/', '.', $setting->plugin));
115 |
116 | // Adding the extra values of the setting (if present) to the attributes array
117 | if (!empty($setting->attrs)) {
118 | $attrs = array_merge($attrs, $setting->attrs);
119 | $attrs['hasextra'] = '1';
120 | }
121 |
122 | $xmlwriter->full_tag($setting->name,
123 | $this->get_setting_value($setting->name, $setting->plugin),
124 | $attrs);
125 | }
126 |
127 | $xmlwriter->end_tag($settingspagetagname);
128 | }
129 |
130 | return true;
131 | }
132 |
133 |
134 | /**
135 | * Obtains the settings pages availables on the flavour
136 | *
137 | * @todo Think of other ways to get the visiblename without so much trouble!
138 | * @param SimpleXMLElement $xml
139 | */
140 | public function get_flavour_info($xml) {
141 |
142 | // Getting all the system settings to verify the available settings pages and to
143 | // get the real visiblename of the flavour settings pages and settings categories
144 | $adminroot = admin_get_root();
145 | $this->get_branch_settings($adminroot->children, $systemsettings);
146 |
147 | foreach ($xml as $namespace => $settings) {
148 |
149 | // Converting from the xml settingspage namespace to the tree branches format
150 | $treepath = explode('.', $namespace);
151 |
152 | // Recursive call to get all the settings pages
153 | $this->get_flavour_branches($treepath, $this->branches, $systemsettings->branches);
154 | }
155 |
156 | }
157 |
158 |
159 | /**
160 | * Sets the settings values
161 | *
162 | * @param array $ingredients
163 | * @param string $path Path to the ingredient type file system
164 | * @param SimpleXMLElement $xml
165 | * @return array Problems during the ingredients deployment
166 | */
167 | public function deploy_ingredients($ingredients, $path, SimpleXMLElement $xml) {
168 |
169 | $problems = array();
170 |
171 | // We don't want warnings, we want real feeback
172 | $this->displaywarnings = false;
173 |
174 | $xmlingredients = $xml->children();
175 |
176 | foreach ($ingredients as $ingredient) {
177 |
178 | $xmlingredient = str_replace('/', '.', $ingredient);
179 |
180 | if (empty($xmlingredients->$xmlingredient)) {
181 | $problems[$ingredient]['settingnosettingpage'] = $xmlingredient;
182 | continue;
183 | }
184 |
185 | // Getting settings and overwritting
186 | $pagesettings = $xmlingredients->$xmlingredient->children();
187 |
188 | $settingsproblemsarray = array();
189 | foreach ($pagesettings as $settingname => $settingdata) {
190 |
191 | $plugin = (String) $settingdata->attributes()->plugin;
192 | if (!$plugin) {
193 | $settingsproblemsarray[$ingredient][] = $settingname;
194 | continue;
195 | }
196 |
197 | if ($plugin == 'core') {
198 | $plugin = null;
199 | }
200 |
201 | // Restoring the slashes removed on packaging
202 | $plugin = str_replace('.', '/', $plugin);
203 |
204 | set_config($settingname, (String) $settingdata[0], $plugin);
205 |
206 | // If it's a setting with multiple values set them
207 | if (!empty($settingdata->attributes()->hasextra)) {
208 | $attrs = $settingdata->attributes()->hasextra;
209 | foreach ($attrs as $key => $value) {
210 |
211 | $value = (String) $value;
212 | if ($key != 'hasextra' && $key != 'plugin') {
213 | set_config($key, $value, $plugin);
214 | }
215 | }
216 | }
217 | }
218 | }
219 |
220 | // Imploding settings of the same settings page with problems
221 | foreach ($settingsproblemsarray as $ingredient => $settingsarray) {
222 | $problems[$ingredient]['settingsettingproblems'] = implode(', ', $settingsarray);
223 | }
224 |
225 | return $problems;
226 | }
227 |
228 |
229 | /**
230 | * Gets a string with PHP code to inject default values to the upgrade processes
231 | *
232 | * @todo Try to respect DRY and unify part of package_ingredients with settings_to_php
233 | * @uses flavours_php_writer
234 | * @param array $selectedsettings
235 | * @returns array PHP code, one line per array element, the caller will make a string or a file
236 | */
237 | public function settings_to_php($selectedsettings) {
238 |
239 | $phparray = array();
240 |
241 | $adminroot = admin_get_root();
242 | $this->get_branch_settings($adminroot->children, $this, true);
243 |
244 | foreach ($selectedsettings as $settingspage) {
245 |
246 | // Settings page path
247 | $namespace = explode('/', $settingspage);
248 |
249 | // The admin settingspage is the last one
250 | $page = array_pop($namespace);
251 |
252 | if (!$settings = $this->get_settingspage_settings($namespace, $page, $this)) {
253 | continue;
254 | }
255 |
256 | $settingspagetagname = str_replace('/', '.', $settingspage);
257 |
258 | // Adding settings
259 | foreach ($settings as $setting) {
260 |
261 | // Can\'t refactor the whole 'core' code to 'moodle' to maintain
262 | // backward compatibility with flavours packages
263 | if ($setting->plugin == 'core') {
264 | $setting->plugin = 'moodle';
265 | }
266 |
267 | // Restore slashes
268 | $setting->plugin = str_replace('.', '/', $setting->plugin);
269 |
270 | // Valu with addslashes only in the single qoute
271 | $value = $this->get_setting_value($setting->name, $setting->plugin);
272 | $value = str_replace("'", "\'", $value);
273 |
274 | $phparray[] = $this->add_setting_php($setting->plugin, $setting->name, $value);
275 |
276 | // Adding the extra values of the setting (if present) to the attributes array
277 | if (!empty($setting->attrs)) {
278 | foreach ($setting->attrs as $attrname => $value) {
279 | $phparray[] = $this->add_setting_php($setting->plugin, $attrname, $value);
280 | }
281 | }
282 | }
283 |
284 | }
285 |
286 | return $phparray;
287 | }
288 |
289 |
290 | /**
291 | * Iterates through the moodle admin tree to extract the settings categories & pages hierarchy
292 | *
293 | * @param object $admintreebranch
294 | * @param object $branch
295 | * @param boolean $addsettings Should settings be included?
296 | */
297 | protected function get_branch_settings($admintreebranch, &$branch, $addsettings = false) {
298 |
299 | foreach ($admintreebranch as $key => $child) {
300 |
301 | // Adding settings category and it's children
302 | if (is_a($child, 'admin_category')) {
303 |
304 | if ($child->children) {
305 | $branch->branches[$child->name] = new StdClass();
306 | $branch->branches[$child->name]->id = $child->name;
307 | $branch->branches[$child->name]->name = $child->visiblename;
308 |
309 | // Adding branch branches
310 | $this->get_branch_settings($child->children, $branch->branches[$child->name],
311 | $addsettings);
312 | }
313 |
314 | } else if (is_a($child, 'admin_settingpage') && $child->settings) {
315 | // Adding the settings pages if we find settings
316 | $branch->branches[$child->name] = new StdClass();
317 | $branch->branches[$child->name]->id = $child->name;
318 | $branch->branches[$child->name]->name = $child->visiblename;
319 |
320 | // Adding the settings if required
321 | if ($addsettings && !empty($child->settings)) {
322 | foreach ($child->settings as $settingname => $setting) {
323 |
324 | $branch->branches[$child->name]->settings[$settingname] = new stdClass();
325 |
326 | if ($setting->plugin == '') {
327 | $branch->branches[$child->name]->settings[$settingname]->plugin = 'core';
328 | } else {
329 |
330 | // Some plugins has slashes, not availables as part of the tag name
331 | $setting->plugin = str_replace('/', '.', $setting->plugin);
332 | $branch->branches[$child->name]->settings[$settingname]->plugin = $setting->plugin;
333 | }
334 |
335 | // Setting value
336 | $branch->branches[$child->name]->settings[$settingname]->name = $settingname;
337 |
338 | // Look for (.*?)_adv settings and add them as attributes
339 | if (is_array($setting->defaultsetting)) {
340 | foreach ($setting->defaultsetting as $key => $value) {
341 |
342 | // Value is the name of the "main" value
343 | if ($key != 'value' && isset($this->multiplevaluemapping[$key])) {
344 | $cfgkey = $settingname . $this->multiplevaluemapping[$key];
345 | $branch->branches[$child->name]->settings[$settingname]->attrs[$cfgkey] = $value;
346 | }
347 | }
348 | }
349 | }
350 | }
351 | }
352 | }
353 | }
354 |
355 |
356 | /**
357 | * Returns all the settings of a settingspage
358 | *
359 | * @param array $settingspagenamespace The path of the settingspage inside the admin tree
360 | * @param string $settingspage The name of the settings page
361 | * @param admin_tree $settingpagebranch Where to search
362 | * @return array An array of admin_settings
363 | */
364 | protected function get_settingspage_settings($settingspagenamespace, $settingspage, $settingpagebranch) {
365 |
366 | // Iteration through the namespace to locate the settingspage and get it's settings
367 | foreach ($settingspagenamespace as $settingscategory) {
368 | if (empty($settingpagebranch->branches[$settingscategory])) {
369 | print_error('errorunknownsettingspage', 'local_flavours', $settingspage);
370 | }
371 | $settingpagebranch = $settingpagebranch->branches[$settingscategory];
372 | }
373 |
374 | // It there aren't available settings skip it
375 | if (empty($settingpagebranch->branches[$settingspage]->settings)) {
376 | return false;
377 | }
378 |
379 | return $settingpagebranch->branches[$settingspage]->settings;
380 | }
381 |
382 |
383 | /**
384 | * Gets the setting value
385 | *
386 | * @todo Take into account site name and things like that which are not stored on config* tables
387 | * @param string $name
388 | * @param string $plugin
389 | * @return mixed
390 | */
391 | protected function get_setting_value($name, $plugin) {
392 | return get_config($plugin, $name);
393 | }
394 |
395 |
396 | /**
397 | * Recursive method to fill the array with all the settings pages and with the common format
398 | *
399 | * It checks if there is an available settingpage on the system for each flavour settingpage
400 | * @param array $treepath An array containing the path to the settingpage
401 | * @param array $branch Where to put the resulting data
402 | * @param array $systemsettings To check the settingpage existence and to get the visiblename
403 | */
404 | protected function get_flavour_branches($treepath, &$branch, $systemsettings) {
405 |
406 | $node = array_shift($treepath);
407 |
408 | if (empty($branch[$node])) {
409 | $branch[$node] = new stdClass();
410 | }
411 | $branch[$node]->id = $node;
412 |
413 | // Checking the existence of the settingpage on this moodle release
414 | if (empty($systemsettings[$node])) {
415 |
416 | $branch[$node]->restrictions['settingnosettingpage'] = true;
417 |
418 | // Can't be shown if we leave the name empty
419 | $branch[$node]->name = $node;
420 | return false;
421 | }
422 |
423 | // Display warnings, basically on preview
424 | if ($this->displaywarnings) {
425 | $branch[$node]->restrictions['settingwarningoverwrite'] = true;
426 | }
427 |
428 | $branch[$node]->name = $systemsettings[$node]->name;
429 |
430 | // Continue reaching the settings page
431 | if (!empty($treepath)) {
432 |
433 | // If the branch does not exist (disabled features/plugins for example) we pass an empty
434 | // array as we will notify the settingnosettingpage restriction to the user.
435 | if (empty($systemsettings[$node]->branches)) {
436 | $systemsettings[$node]->branches = array();
437 | }
438 | $this->get_flavour_branches($treepath, $branch[$node]->branches, $systemsettings[$node]->branches);
439 | }
440 |
441 | }
442 |
443 |
444 | /**
445 | * Prepares a string in PHP representing a array[][]
446 | * @param string $plugin
447 | * @param string $name
448 | * @param mixed $value
449 | * @return string The PHP to add to the list
450 | */
451 | protected function add_setting_php($plugin, $name, $value) {
452 | return '$defaults[\'' . $plugin . '\'][\'' . $name . '\'] = \'' . $value . '\';';
453 | }
454 |
455 |
456 | /**
457 | * Get all the branches nodes as form elements names
458 | *
459 | * Used to force the selection of all the elements without a prev form selection
460 | * Uses the same format get by flavours->get_ingredients_from_form()
461 | *
462 | * @return array Array with all the settings
463 | */
464 | public function get_all_nodes($branches = false, $prefix = '', & $returnarray) {
465 |
466 | // Initialize the search
467 | if (!$branches) {
468 | $branches = $this->branches;
469 | }
470 |
471 | foreach ($branches as $name => $branchdata) {
472 |
473 | // Iterate recursively
474 | if (!empty($branchdata->branches)) {
475 | $this->get_all_nodes($branchdata->branches, $prefix . $branchdata->id . '/', $returnarray);
476 |
477 | // Then let's add it's children
478 | } else {
479 | $settingkey = $prefix . $branchdata->id;
480 | $returnarray['setting'][$settingkey] = $settingkey;
481 | }
482 | }
483 |
484 | return $returnarray;
485 | }
486 |
487 | }
488 |
--------------------------------------------------------------------------------