├── 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 = ''; 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 .= ''; 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 | --------------------------------------------------------------------------------