2 namespace Civi\Setup\UI
;
4 use Civi\Setup\UI\Event\UIBootEvent
;
6 class SetupController
implements SetupControllerInterface
{
8 const PREFIX
= 'civisetup';
17 * Some mix of the following:
18 * - res: The base URL for loading resource files (images/javascripts) for this
19 * project. Includes trailing slash.
20 * - ctrl: The URL of this setup controller. May be used for POST-backs.
26 * A list of blocks to display on the setup page. Each item has:
27 * - file: string, relative path
28 * - class: string, a space-delimited list of CSS classes
31 * Note: When rendering a block, content of the block's definition
32 * will be available as `$_tpl_block`. For example, `$_tpl_block['is_active']`
33 * would be the same boolean.
38 * SetupController constructor.
39 * @param \Civi\Setup $setup
41 public function __construct(\Civi\Setup
$setup) {
42 $this->setup
= $setup;
43 $this->blocks
= array();
47 * @param string $method
48 * Ex: 'GET' or 'POST'.
49 * @param array $fields
50 * List of any HTTP GET/POST fields.
52 * The HTTP headers and response text.
53 * [0 => array $headers, 1 => string $body].
55 public function run($method, $fields = array()) {
56 $this->setup
->getDispatcher()->dispatch('civi.setupui.run', new UIBootEvent($this, $method, $fields));
57 if (!$this->setup
->checkAuthorized()->isAuthorized()) {
58 return $this->createError("Not authorized to perform installation");
61 $this->boot($method, $fields);
62 $action = $this->parseAction($fields, 'Start');
63 $func = 'run' . $action;
64 if (!preg_match('/^[a-zA-Z0-9_]+$/', $action) ||
!is_callable([$this, $func])) {
65 return $this->createError("Invalid action");
67 return call_user_func([$this, $func], $method, $fields);
71 * Run the main installer page.
73 * @param string $method
74 * Ex: 'GET' or 'POST'.
75 * @param array $fields
76 * List of any HTTP GET/POST fields.
78 * The HTTP headers and response text.
79 * [0 => array $headers, 1 => string $body].
81 public function runStart($method, $fields) {
82 $checkInstalled = $this->setup
->checkInstalled();
83 if ($checkInstalled->isDatabaseInstalled() ||
$checkInstalled->isSettingInstalled()) {
84 return $this->createError("CiviCRM is already installed");
88 * @var \Civi\Setup\Model $model
90 $model = $this->setup
->getModel();
92 $tplFile = $this->getResourcePath('template.php');
95 'civicrm_version' => \CRM_Utils_System
::version(),
96 'installURLPath' => $this->urls
['res'],
97 'short_lang_code' => \CRM_Core_I18n_PseudoConstant
::shortForLong($GLOBALS['tsLocale']),
98 'text_direction' => (\CRM_Core_I18n
::isLanguageRTL($GLOBALS['tsLocale']) ?
'rtl' : 'ltr'),
100 'reqs' => $this->setup
->checkRequirements(),
103 // $body = "<pre>" . htmlentities(print_r(['method' => $method, 'urls' => $this->urls, 'data' => $fields], 1)) . "</pre>";
104 $body = $this->render($tplFile, $tplVars);
106 return array(array(), $body);
110 * Perform the installation action.
112 * @param string $method
113 * Ex: 'GET' or 'POST'.
114 * @param array $fields
115 * List of any HTTP GET/POST fields.
117 * The HTTP headers and response text.
118 * [0 => array $headers, 1 => string $body].
120 public function runInstall($method, $fields) {
121 $checkInstalled = $this->setup
->checkInstalled();
122 if ($checkInstalled->isDatabaseInstalled() ||
$checkInstalled->isSettingInstalled()) {
123 return $this->createError("CiviCRM is already installed");
126 $reqs = $this->setup
->checkRequirements();
127 if (count($reqs->getErrors())) {
128 return $this->runStart($method, $fields);
131 $this->setup
->installFiles();
132 $this->setup
->installDatabase();
134 $m = $this->setup
->getModel();
135 $tplFile = $this->getResourcePath('finished.' . $m->cms
. '.php');
136 if (file_exists($tplFile)) {
138 return array(array(), $this->render($tplFile, $tplVars));
141 return $this->createError("Installation succeeded. However, the final page ($tplFile) was not available.");
146 * Partially bootstrap Civi services (such as localization).
148 protected function boot($method, $fields) {
149 $model = $this->setup
->getModel();
151 define('CIVICRM_UF', $model->cms
);
153 // Set the Locale (required by CRM_Core_Config)
157 // CRM-16801 This validates that lang is valid by looking in $langs.
158 // NB: the variable is initial a $_REQUEST for the initial page reload,
159 // then becomes a $_POST when the installation form is submitted.
160 $langs = $model->getField('lang', 'options');
161 if (array_key_exists('lang', $fields)) {
162 $model->lang
= $fields['lang'];
164 if ($model->lang
and isset($langs[$model->lang
])) {
165 $tsLocale = $model->lang
;
168 \CRM_Core_Config
::singleton(FALSE);
169 $GLOBALS['civicrm_default_error_scope'] = NULL;
171 // The translation files are in the parent directory (l10n)
172 \CRM_Core_I18n
::singleton();
174 $this->setup
->getDispatcher()->dispatch('civi.setupui.boot', new UIBootEvent($this, $method, $fields));
177 public function createError($message, $title = 'Error') {
180 $this->render($this->getResourcePath('error.html'), [
181 'errorTitle' => htmlentities($title),
182 'errorMsg' => htmlentities($message),
183 'installURLPath' => $this->urls
['res'],
189 * Render a *.php template file.
191 * @param string $_tpl_file
192 * The path to the file.
193 * @param array $_tpl_params
194 * Any variables that should be exported to the scope of the template.
197 public function render($_tpl_file, $_tpl_params = array()) {
198 extract($_tpl_params);
201 return ob_get_clean();
204 public function getResourcePath($parts) {
205 $parts = (array) $parts;
206 array_unshift($parts, 'res');
207 array_unshift($parts, $this->setup
->getModel()->setupPath
);
208 return implode(DIRECTORY_SEPARATOR
, $parts);
211 public function getUrl($name) {
212 return isset($this->urls
[$name]) ?
$this->urls
[$name] : NULL;
218 public function setUrls($urls) {
219 foreach ($urls as $k => $v) {
220 $this->urls
[$k] = $v;
226 * Given an HTML submission, determine the name.
228 * @param array $fields
229 * HTTP inputs -- e.g. with a form element like this:
230 * `<input type="submit" name="civisetup[action][Foo]" value="Do the foo">`
231 * @param string $default
232 * The action-name to return if no other action is identified.
234 * The name of the action.
237 protected function parseAction($fields, $default) {
238 if (empty($fields[self
::PREFIX
]['action'])) {
242 if (is_array($fields[self
::PREFIX
]['action'])) {
243 foreach ($fields[self
::PREFIX
]['action'] as $name => $label) {
247 elseif (is_string($fields[self
::PREFIX
]['action'])) {
248 return $fields[self
::PREFIX
]['action'];
254 public function renderBlocks($_tpl_params) {
257 // Cleanup - Ensure 'name' is present.
258 foreach (array_keys($this->blocks
) as $name) {
259 $this->blocks
[$name]['name'] = $name;
262 // Sort by weight+name.
263 uasort($this->blocks
, function($a, $b) {
264 if ($a['weight'] != $b['weight']) {
265 return $a['weight'] - $b['weight'];
267 return strcmp($a['name'], $b['name']);
270 foreach ($this->blocks
as $name => $block) {
271 if (!$block['is_active']) {
274 $buf .= sprintf("<div class=\"civicrm-setup-block-%s %s\">%s</div>",
279 $_tpl_params +
array('_tpl_block' => $block)
287 * @return \Civi\Setup
289 public function getSetup() {