18 require_once SQ_INCLUDE_PATH.
'/asset_management.inc';
19 require_once SQ_INCLUDE_PATH.
'/asset_edit_interface.inc';
54 var $description =
'';
61 var $assets = Array();
86 if (!isset($this->_full_path) || !is_dir($this->_full_path)) {
87 trigger_localised_error(
'SYS0238', E_USER_ERROR, get_class($this));
91 if (substr($this->_full_path, 0, strlen(SQ_SYSTEM_ROOT)) != SQ_SYSTEM_ROOT) {
92 trigger_localised_error(
'SYS0239', E_USER_ERROR, get_class($this));
96 $this->_base_path = substr($this->_full_path, strlen(SQ_SYSTEM_ROOT) + 1);
97 $package_path = $this->_full_path.
'/package.xml';
99 if (file_exists($package_path)) {
101 $info =
new SimpleXMLElement($package_path, NULL, TRUE);
102 }
catch (Exception $e) {
103 throw new Exception(
'Unable to parse package definition file "'.$package_path.
'": '.$e->getMessage());
107 throw new Exception(
'Unable to parse package definition file "'.$package_path.
'": package manager name "'.$this->getPackageName().
'" does not match package name in definition file "'.$info->{
'code_name'}.
'"');
109 $this->name = (string)$info->name;
110 $this->version = (
string)$info->version;
111 $this->description = (string)$info->description;
113 $GLOBALS[
'SQ_SYSTEM']->lm->includePackageStrings($this->name);
117 trigger_localised_error(
'SYS0199', E_USER_ERROR, $this->getPackageName());
128 function getPackageName()
130 return strtolower(substr(get_class($this), 16));
147 function checkPackageDetails($update_assets=Array(), $deferred_assets=Array())
149 $am = $GLOBALS[
'SQ_SYSTEM']->am;
151 for (reset($this->assets); null !== ($type_code = key($this->assets)); next($this->assets)) {
153 if (!empty($update_assets) && !in_array($type_code, $update_assets)) {
156 if (!isset($install_reqs[$type_code])) {
157 $install_reqs[$type_code] = Array();
161 $file = SQ_SYSTEM_ROOT.
'/'.$this->assets[$type_code][
'dir'].
'/asset.xml';
162 list($result, $req) = $this->checkRequirementsFromFile($file, $deferred_assets,
true);
167 if (!in_array($type_code, $deferred_assets)) {
168 pre_echo(
'Asset "'.$type_code.
'" fails the "'.$req[
'type'].
'" requirement for "'.$req[
'code'].
' v'.$req[
'version'].
'"'.
"\n".
'As specified by '.$file.
' and will be deferred');
169 $deferred_assets[] = $type_code;
176 $parent_type = $this->assets[$type_code][
'parent_type'];
177 if ($parent_type !=
'asset' && !$am->installed($parent_type) && !isset($this->assets[$parent_type])) {
180 if (!in_array($type_code, $deferred_assets)) {
181 pre_echo(
'Asset "'.$type_code.
'" attempts to inherit from the unknown type "'.$parent_type.
'"'.
"\n".
'As specified by '.$file);
182 $deferred_assets[] = $type_code;
188 return count($deferred_assets) ? $deferred_assets :
true;
203 function updatePackageDetails($update_assets=Array())
205 $em = $GLOBALS[
'SQ_SYSTEM']->getEventManager();
210 $last_deferred =
false;
216 while ($last_deferred !== $deferred) {
217 $last_deferred = $deferred;
218 $deferred = $this->checkPackageDetails($update_assets, is_array($deferred) ? $deferred : Array());
219 if (is_bool($deferred) && !$deferred) {
224 $GLOBALS[
'SQ_SYSTEM']->changeDatabaseConnection(
'db2');
225 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'BEGIN');
228 $deferred = is_array($deferred) ? $deferred : Array();
230 $install_order = $this->_getInstallOrder($update_assets, $deferred);
231 if (!empty($install_order)) {
233 pre_echo(
'Installing '.get_class($this).
':');
235 $package_name = $this->getPackageName();
239 $sql =
'SELECT code_name FROM sq_pkg WHERE code_name = :code_name';
244 }
catch (Exception $e) {
245 throw new Exception(
'Failed to get package information for package "'.$package_name.
'" due to database error: '.$e->getMessage());
251 'version' => $this->version,
252 'name' => $this->name,
253 'description' => $this->description,
254 'package_name' => $package_name,
258 $query_name =
'installPackage';
260 $query_name =
'updatePackage';
263 }
catch (Exception $e) {
267 throw new Exception(
'Failed to update package information for package "'.$package_name.
'" due to database error: '.$e->getMessage());
269 throw new Exception(
'Failed to add package information for new package "'.$package_name.
'" due to database error: '.$e->getMessage());
273 for (reset($install_order); null !== ($k = key($install_order)); next($install_order)) {
274 $type_code = $install_order[$k];
277 if (!empty($update_assets) && !in_array($type_code, $update_assets)) {
285 if (in_array($type_code, $deferred))
continue;
287 echo
"$k => $type_code \n";
290 $class = $type_code.
'_management';
291 $file = SQ_SYSTEM_ROOT.
'/'.$this->assets[$type_code][
'dir'].
'/'.$class.
'.inc';
295 if (!class_exists($class)) {
296 trigger_localised_error(
'SYS0083', E_USER_WARNING, $type_code, $file);
297 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'ROLLBACK');
298 $GLOBALS[
'SQ_SYSTEM']->restoreDatabaseConnection();
303 $management =
new $class($this);
304 if (!$management->update()) {
305 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'ROLLBACK');
306 $GLOBALS[
'SQ_SYSTEM']->restoreDatabaseConnection();
311 $events = $management->getEventList();
312 if (!is_array($events)) {
313 trigger_localised_error(
'SYS0142', E_USER_WARNING, $type_code, gettype($events));
314 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'ROLLBACK');
315 $GLOBALS[
'SQ_SYSTEM']->restoreDatabaseConnection();
319 if (!empty($events)) {
321 $em->installStaticEvents($events, $type_code);
327 $em->broadcastEvent($this,
'assetInstall', Array(
'type_code' => $type_code));
333 $em->broadcastEvent($this,
'packageInstall', $install_order);
338 if (!$this->_createAssetMapScreensXML($deferred)) {
339 trigger_localised_error(
'SYS0242', E_USER_WARNING);
340 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'ROLLBACK');
341 $GLOBALS[
'SQ_SYSTEM']->restoreDatabaseConnection();
345 $this->_postInstall();
347 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'COMMIT');
348 $GLOBALS[
'SQ_SYSTEM']->restoreDatabaseConnection();
350 return count($deferred) ? $deferred :
true;
361 function _loadPackageAssets()
363 $this->assets = Array();
364 $this->_recurseLoadPackageAssets($this->assets, $this->_full_path, $this->_base_path);
368 $GLOBALS[
'SQ_SYSTEM']->am->_loadAssetTypes();
383 function _recurseLoadPackageAssets(Array &$assets, $full_path, $base_path)
385 $package = $this->getPackageName();
386 $d =
new DirectoryIterator($full_path);
387 foreach ($d as $entry) {
388 $entry = (string)$entry;
389 if ($entry ===
'.' || $entry ===
'..') {
393 if ($entry ===
'asset.xml') {
396 $info = $mgt->getAssetInfo($full_path.
'/asset.xml');
397 if (empty($info))
continue;
399 if ($package != $info[
'package']) {
400 trigger_localised_error(
'SYS0210', E_USER_ERROR, $full_path, $package, $info[
'package']);
403 $info[
'dir'] = $base_path;
406 $GLOBALS[
'SQ_SYSTEM']->changeDatabaseConnection(
'db2');
408 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'BEGIN');
410 $sql =
'SELECT dir FROM sq_ast_typ WHERE type_code = :type_code';
417 throw new Exception (
'Unable to get directory of type code '.$info[
'type_code'].
' due to database error: '.$e->getMessage());
420 if (!empty($result) && ($result != $info[
'dir'])) {
427 type_code = :type_code';
435 throw new Exception (
'Unable to update directory of type code '.$info[
'type_code'].
' due to database error: '.$e->getMessage());
439 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'COMMIT');
440 $GLOBALS[
'SQ_SYSTEM']->restoreDatabaseConnection();
442 $assets[$info[
'type_code']] = $info;
444 }
else if (is_dir($full_path.
'/'.$entry)) {
446 $this->_recurseLoadPackageAssets($assets, $full_path.
'/'.$entry, $base_path.
'/'.$entry);
463 function _getInstallOrder($update_assets=Array(), $deferred=Array())
465 $asset_types = array_keys($this->assets);
466 $install_order = Array();
468 while ($last_count = count($asset_types)) {
470 for ($i = 0; $i < count($asset_types); $i++) {
472 $type_code = $asset_types[$i];
474 if (!empty($update_assets) && !in_array($type_code, $update_assets)) {
475 unset($asset_types[$i]);
476 $asset_types = array_values($asset_types);
481 if (in_array($type_code, $deferred)) {
482 unset($asset_types[$i]);
483 $asset_types = array_values($asset_types);
488 $parent = $this->assets[$type_code][
'parent_type'];
494 if (($parent ==
'asset' || $GLOBALS[
'SQ_SYSTEM']->am->installed($parent)) && !in_array($parent, $asset_types)) {
495 $install_order[] = $type_code;
499 }
else if (in_array($parent, $install_order)) {
500 $install_order[] = $type_code;
506 }
else if (!in_array($parent, $asset_types) && !in_array($parent, $deferred)) {
507 trigger_localised_error(
'SYS0080', E_USER_WARNING, $type_code, $parent);
513 unset($asset_types[$i]);
514 $asset_types = array_values($asset_types);
520 if ($last_count == count($asset_types)) {
521 trigger_localised_error(
'SYS0216', E_USER_WARNING, $this->getPackageName(), implode(
', ', $asset_types));
528 return $install_order;
541 function _createAssetMapScreensXML($deferred=Array())
543 $root =
new SimpleXMLElement(
'<tmp />');
546 for (reset($this->assets); null !== ($type_code = key($this->assets)); next($this->assets)) {
547 if (in_array($type_code, $deferred))
continue;
550 'type_code' => $type_code,
551 'name' => $this->assets[$type_code][
'name'],
552 'version' => $this->assets[$type_code][
'version'],
553 'instantiable' => $this->assets[$type_code][
'instantiable'],
554 'allowed_access' => $this->assets[$type_code][
'allowed_access'],
555 'parent_type' => $this->assets[$type_code][
'parent_type'],
556 'flash_menu_path' => $this->assets[$type_code][
'flash_menu_path'],
559 $type_node = $root->addChild(
'type');
560 foreach ($attrs as $attr_name => $attr_value) {
561 if ($attr_value !==
'') {
562 $type_node->addAttribute($attr_name, $attr_value);
566 $GLOBALS[
'SQ_SYSTEM']->am->includeAsset($type_code);
567 $as =
new $type_code();
568 $ef = $as->getEditFns();
571 if (!empty($ef->static_screens[
'details'])) {
572 $screen_node = $type_node->addChild(
'screen', $ef->static_screens[
'details'][
'name']);
573 $screen_node->addAttribute(
'code_name',
'details');
578 $screens = $ei->getScreens();
579 for (reset($screens); null !== ($code_name = key($screens)); next($screens)) {
580 if ($screens[$code_name][
'invisible'])
continue;
581 $screen_node = $type_node->addChild(
'screen', $screens[$code_name][
'name']);
582 $screen_node->addAttribute(
'code_name', $code_name);
586 $GLOBALS[
'SQ_SYSTEM']->am->includeAsset($type_code);
587 $as =
new $type_code();
588 $ef = $as->getEditFns();
589 for (reset($ef->static_screens); null !== ($code_name = key($ef->static_screens)); next($ef->static_screens)) {
590 if ($code_name ==
'details')
continue;
591 $screen_node = $type_node->addChild(
'screen', $ef->static_screens[$code_name][
'name']);
592 $screen_node->addAttribute(
'code_name', $code_name);
595 $str .= $type_node->asXml();
599 require_once SQ_FUDGE_PATH.
'/general/file_system.inc';
600 return string_to_file($str, SQ_DATA_PATH.
'/private/asset_map/'.$this->getPackageName().
'.xml');
624 function checkRequirementsFromFile($file, $deferred_assets=Array(), $need_feedback=
false)
629 $info =
new SimpleXMLElement($file, NULL, TRUE);
630 }
catch (Exception $e) {
631 throw new Exception(
'Could not parse asset definition file "'.$file.
'": '.$e->getMessage());
635 if (!isset($info->requirements->requirement)) {
636 return ($need_feedback) ? Array(
true, null) :
true;
639 foreach ($info->requirements->requirement as $req) {
640 $required_type = (string)$req->attributes()->type;
641 $required_code = (string)$req->code;
642 $required_version = (
string)$req->version;
645 switch ($required_type) {
647 $sql =
'SELECT version FROM sq_pkg WHERE code_name = :code_name';
654 throw new Exception(
'Unable to get version of package "'.$required_code.
'" due to database error: '.$e->getMessage());
657 if ($installed_version) {
658 $ok = version_compare($installed_version, $required_version,
'>=');
664 if (in_array($required_code, $deferred_assets)) {
668 if ($GLOBALS[
'SQ_SYSTEM']->am->installed($required_code)) {
669 $ok = version_compare($GLOBALS[
'SQ_SYSTEM']->am->getTypeInfo($required_code,
'version'), $required_version,
'>=');
672 if (!$ok && isset($this->assets[$required_code])) {
673 $ok = version_compare($this->assets[$required_code][
'version'], $required_version,
'>=');
677 if ($required_type ===
'system_asset' && $ok) {
678 $ok = $GLOBALS[
'SQ_SYSTEM']->am->isSystemAssetType($required_code);
684 switch ($required_code) {
686 $ok = version_compare(SQ_SYSTEM_VERSION, $required_version,
'>=');
689 $ok = version_compare(PHP_VERSION, $required_version,
'>=');
699 if ($need_feedback) {
701 'type' => $required_type,
702 'code' => $required_code,
703 'version' => $required_version,
705 return Array(
false, $ret_arr);
717 return ($need_feedback) ? Array(
true, null) :
true;
731 function getTypeAncestors($type_code)
733 if (!isset($this->assets[$type_code])) {
734 throw new Exception(
'Asset type "'.$type_code.
'" does not exist in the "'.$this->getPackageName().
'" package.');
735 trigger_localised_error(
'SYS0082', E_USER_ERROR, $type_code, $this->getPackageName());
741 while (isset($this->assets[$type_code]) && $this->assets[$type_code][
'parent_type'] !=
'asset') {
742 $type_code = $this->assets[$type_code][
'parent_type'];
747 if (!isset($this->assets[$type_code])) {
748 $new_arr = $GLOBALS[
'SQ_SYSTEM']->am->getTypeAncestors($type_code, TRUE, TRUE);
749 foreach ($new_arr as $type_code) {
772 function getTypeInfo($type_code, $field=
'')
774 if (!isset($this->assets[$type_code])) {
775 throw new Exception(
'Asset type "'.$type_code.
'" does not exist in the "'.$this->getPackageName().
'" package.');
776 trigger_localised_error(
'SYS0082', E_USER_ERROR, $type_code, $this->getPackageName());
777 return ($field) ? null : Array();
780 return ($field) ? $this->assets[$type_code][$field] : $this->assets[$type_code];
791 function installUserPreferences(&$preferences)
793 foreach (array_keys($this->assets) as $type_code) {
794 $file = SQ_SYSTEM_ROOT.
'/'.$this->assets[$type_code][
'dir'].
'/'.$type_code.
'_prefs.inc';
795 if (!is_file($file))
continue;
797 $class = $type_code.
'_prefs';
800 if (class_exists($class)) {
801 $prefs =
new $class();
802 if (!isset($preferences[$type_code])) {
803 $preferences[$type_code] = $prefs->pref_vars;
805 foreach ($preferences[$type_code] as $var => $data) {
806 if (!isset($prefs->pref_vars[$var])) {
807 unset($preferences[$type_code][$var]);
809 if ($preferences[$type_code][$var][
'name'] != $prefs->pref_vars[$var][
'name']) {
810 ($preferences[$type_code][$var][
'name'] = $prefs->pref_vars[$var][
'name']);
814 foreach ($prefs->pref_vars as $var => $data) {
815 if (!isset($preferences[$type_code][$var])) {
816 $preferences[$type_code][$var] = $data;
834 function getSystemAssetTypes()
847 function installSystemAssets()
853 foreach ($this->getSystemAssetTypes() as $type) {
854 if (!$GLOBALS[
'SQ_SYSTEM']->am->isSystemAssetType($type)) {
855 $function =
'create'.str_replace(
'_',
'',$type);
856 $new_system_asset = $this->$function();
857 if (!is_null($new_system_asset)) {
858 if ($new_system_asset->id) $updated =
true;
869 require_once SQ_INCLUDE_PATH.
'/system_asset_config.inc';
871 $sys_asset_cfg->save(Array(),
false);
874 return $assets_created;
885 function _postInstall()
897 function _installDALQueries()
899 $name = $this->getPackageName();
900 if ($name ==
'__core__') $name =
'core';
901 $old_path = ini_get(
'include_path');
902 ini_set(
'include_path', SQ_LIB_PATH);
903 require_once SQ_LIB_PATH.
'/MatrixDAL/MatrixDALBaker.inc';
905 if ($queries_found) {
908 ini_set(
'include_path', $old_path);