ILIAS  release_7 Revision v7.30-3-g800a261c036
All Data Structures Namespaces Files Functions Variables Modules Pages
class.ilSystemStyleSkinContainer.php
Go to the documentation of this file.
1 <?php
2 include_once("Services/Style/System/classes/Utilities/class.ilSkinStyleXML.php");
3 include_once("Services/Style/System/classes/class.ilStyleDefinition.php");
4 include_once("Services/Style/System/classes/Exceptions/class.ilSystemStyleException.php");
5 include_once("Services/Style/System/classes/Utilities/class.ilSystemStyleMessageStack.php");
6 include_once("Services/Style/System/classes/Utilities/class.ilSystemStyleMessage.php");
7 include_once("Services/Style/System/classes/Less/class.ilSystemStyleLessFile.php");
8 include_once("Services/Style/System/classes/Utilities/class.ilSystemStyleConfig.php");
9 
20 {
21 
25  protected $lng;
26 
32  protected $skin;
33 
39  protected static $message_stack = null;
40 
47 
56  {
57  global $DIC;
58 
59  $this->lng = $DIC->language();
60 
61  $this->skin = $skin;
62 
63  if (!$message_stack) {
65  } else {
67  }
68 
69  if (!$system_styles_conf) {
71  } else {
73  }
74  }
75 
86  {
87  if (!$skin_id) {
89  }
90 
91  if (!$system_styles_conf) {
93  }
94 
95  if ($skin_id != "default") {
96  return new self(ilSkinXML::parseFromXML($system_styles_conf->getCustomizingSkinPath() . $skin_id . "/template.xml"), $message_stack, $system_styles_conf);
97  } else {
98  return new self(ilSkinXML::parseFromXML($system_styles_conf->getDefaultTemplatePath()), $message_stack, $system_styles_conf);
99  }
100  }
101 
109  {
110  if (file_exists($this->getSkinDirectory())) {
112  }
113 
114 
115  mkdir($this->getSkinDirectory(), 0777, true);
116 
117  foreach ($this->getSkin()->getStyles() as $style) {
118  $this->createResourceDirectory($this->getSystemStylesConf()->getDefaultImagesPath(), $style->getImageDirectory());
119  $this->createResourceDirectory($this->getSystemStylesConf()->getDefaultSoundsPath(), $style->getSoundDirectory());
120  $this->createResourceDirectory($this->getSystemStylesConf()->getDefaultFontsPath(), $style->getFontDirectory());
121  try {
122  $this->createLessStructure($style);
123  } catch (Exception $e) {
124  $message_stack->addMessage(new ilSystemStyleMessage($this->lng->txt("less_compile_failed") . " " . $e->getMessage(), ilSystemStyleMessage::TYPE_ERROR));
125  }
126  }
127  $this->writeSkinToXML();
128  }
129 
136  public function updateSkin(ilSkinXML $old_skin = null)
137  {
138  if (!$old_skin) {
139  $old_skin = $this->getSkin();
140  }
141  $old_customizing_skin_directory = $this->getSystemStylesConf()->getCustomizingSkinPath() . $old_skin->getId() . "/";
142 
143  //Move if skin id has been changed
144  if ($old_skin->getId() != $this->getSkin()->getId()) {
145  $this->move($old_customizing_skin_directory, $this->getSkinDirectory());
146  }
147 
148  //Delete old template.xml and write a new one
149  unlink($this->getSkinDirectory() . "template.xml");
150  $this->writeSkinToXML();
151  }
152 
159  public function updateStyle($style_id, ilSkinStyleXML $old_style)
160  {
161  $style = $this->getSkin()->getStyle($style_id);
162 
163  if ($style->getImageDirectory() != $old_style->getImageDirectory()) {
164  if (file_exists($this->getSkinDirectory() . $old_style->getImageDirectory())) {
165  $this->changeResourceDirectory($style->getImageDirectory(), $old_style->getImageDirectory());
166  } else {
167  $this->createResourceDirectory($this->getSystemStylesConf()->getDefaultImagesPath(), $style->getImageDirectory());
168  }
169  }
170 
171  if ($style->getFontDirectory() != $old_style->getFontDirectory()) {
172  if (file_exists($this->getSkinDirectory() . $old_style->getFontDirectory())) {
173  $this->changeResourceDirectory($style->getFontDirectory(), $old_style->getFontDirectory());
174  } else {
175  $this->createResourceDirectory($this->getSystemStylesConf()->getDefaultFontsPath(), $style->getFontDirectory());
176  }
177  }
178 
179  if ($style->getSoundDirectory() != $old_style->getSoundDirectory()) {
180  if (file_exists($this->getSkinDirectory() . $old_style->getSoundDirectory())) {
181  $this->changeResourceDirectory($style->getSoundDirectory(), $old_style->getSoundDirectory());
182  } else {
183  $this->createResourceDirectory($this->getSystemStylesConf()->getDefaultSoundsPath(), $style->getSoundDirectory());
184  }
185  }
186 
187 
188 
189  if (file_exists($this->getSkinDirectory() . $old_style->getCssFile() . ".less")) {
190  rename($this->getSkinDirectory() . $old_style->getCssFile() . ".less", $this->getLessFilePath($style->getId()));
191  } else {
192  $this->createMainLessFile($style);
193  }
194 
195  if (file_exists($this->getSkinDirectory() . $old_style->getCssFile() . "-variables.less")) {
196  rename($this->getSkinDirectory() . $old_style->getCssFile() . "-variables.less", $this->getLessVariablesFilePath($style->getId()));
197  } else {
198  $this->copyVariablesFromDefault($style);
199  }
200 
201  $this->changeVariablesImport($this->getLessFilePath($style->getId()), $old_style->getCssFile() . "-variables.less", $this->getLessVariablesName($style->getId()));
202 
203  if (file_exists($this->getSkinDirectory() . $old_style->getCssFile() . ".css")) {
204  rename($this->getSkinDirectory() . $old_style->getCssFile() . ".css", $this->getCSSFilePath($style->getId()));
205  } else {
206  try {
207  $this->compileLess($style->getId());
208  } catch (Exception $e) {
209  $this->getMessageStack()->addMessage(
211  $e->getMessage(),
213  )
214  );
215  copy($this->getSystemStylesConf()->getDelosPath() . ".css", $this->getCSSFilePath($style->getId()));
216  }
217  }
218 
219  $this->writeSkinToXML();
220  }
221 
228  protected function resourcesStyleReferences($resource)
229  {
230  $references_ids = array();
231  foreach ($this->getSkin()->getStyles() as $style) {
232  if ($style->referencesResource($resource)) {
233  $references_ids[] = $style->getId();
234  }
235  }
236  return $references_ids;
237  }
238 
246  protected function createResourceDirectory($source, $target)
247  {
248  $path = $this->getSkinDirectory() . $target;
249 
250  mkdir($path, 0777, true);
251 
252  if ($source != "") {
253  self::xCopy($source, $path);
254  $this->getMessageStack()->addMessage(
256  $this->lng->txt("dir_created") . $path,
258  )
259  );
260  }
261  }
262 
270  protected function changeResourceDirectory($new_dir, $old_dir)
271  {
272  $absolut_new_dir = $this->getSkinDirectory() . $new_dir;
273  $absolut_old_dir = $this->getSkinDirectory() . $old_dir;
274 
275  if (file_exists($absolut_new_dir)) {
276  $this->getMessageStack()->addMessage(
278  $this->lng->txt("dir_changed_to") . " " . $absolut_new_dir,
280  )
281  );
282  $this->getMessageStack()->addMessage(
284  $this->lng->txt("dir_preserved_backup") . " " . $absolut_old_dir,
286  )
287  );
288  } else {
289  mkdir($absolut_new_dir, 0777, true);
290  self::xCopy($absolut_old_dir, $absolut_new_dir);
291  $this->getMessageStack()->addMessage(
293  $this->lng->txt("dir_copied_from") . " " . $absolut_old_dir . " " . $this->lng->txt("sty_copy_to") . " " . $absolut_new_dir,
295  )
296  );
297  if (count($this->resourcesStyleReferences($old_dir)) == 0) {
298  self::recursiveRemoveDir(self::getSkinDirectory() . $old_dir);
299  $this->getMessageStack()->addMessage(
301  $this->lng->txt("dir_deleted") . " " . $absolut_old_dir,
303  )
304  );
305  } else {
306  $this->getMessageStack()->addMessage(
308  $this->lng->txt("dir_preserved_linked") . " " . $absolut_old_dir,
310  )
311  );
312  }
313  }
314  }
315 
321  protected function removeResourceDirectory($dir)
322  {
323  $absolut_dir = $this->getSkinDirectory() . $dir;
324 
325  if (file_exists($absolut_dir)) {
326  if (count($this->resourcesStyleReferences($dir)) == 0) {
327  self::recursiveRemoveDir($this->getSkinDirectory() . $dir);
328  $this->getMessageStack()->addMessage(
330  $this->lng->txt("dir_deleted") . " " . $dir,
332  )
333  );
334  } else {
335  $this->getMessageStack()->addMessage(
337  $this->lng->txt("dir_preserved_linked") . " " . $dir,
339  )
340  );
341  }
342  }
343  }
344 
351  protected function createLessStructure(ilSkinStyleXML $style)
352  {
353  $this->createMainLessFile($style);
354  $this->copyVariablesFromDefault($style);
355  $this->copyCSSFromDefault($style);
356  $this->compileLess($style->getId());
357  }
358 
364  public function createMainLessFile(ilSkinStyleXML $style)
365  {
366  $path = $this->getLessFilePath($style->getId());
367  file_put_contents($path, $this->getLessMainFileDefautContent($style));
368  $this->getMessageStack()->addMessage(
370  $this->lng->txt("main_less_created") . " " . $path,
372  )
373  );
374  }
375 
382  public function copyVariablesFromDefault(ilSkinStyleXML $style)
383  {
384  $less_file = new ilSystemStyleLessFile($this->getSystemStylesConf()->getDefaultVariablesPath());
385  $less_file->setLessVariablesFile($this->getLessVariablesFilePath($style->getId()));
386  $less_file->write();
387  return $less_file;
388  }
389 
395  public function resetImages(ilSkinStyleXML $style)
396  {
397  self::recursiveRemoveDir($this->getSkinDirectory() . $style->getImageDirectory());
398  $this->createResourceDirectory($this->getSystemStylesConf()->getDefaultImagesPath(), $style->getImageDirectory());
399  }
400 
406  public function copyCSSFromDefault(ilSkinStyleXML $style)
407  {
408  copy($this->getSystemStylesConf()->getDelosPath() . ".css", $this->getCSSFilePath($style->getId()));
409  }
410 
418  public static function xCopy($src, $dest)
419  {
420  foreach (scandir($src) as $file) {
421  $src_file = rtrim($src, '/') . '/' . $file;
422  $dest_file = rtrim($dest, '/') . '/' . $file;
423  if (!is_readable($src_file)) {
425  }
426  if (substr($file, 0, 1) != ".") {
427  if (is_dir($src_file)) {
428  if (!file_exists($dest_file)) {
429  try {
430  mkdir($dest_file);
431  } catch (Exception $e) {
432  throw new ilSystemStyleException(ilSystemStyleException::FOLDER_CREATION_FAILED, "Copy " . $src_file . " to " . $dest_file . " Error: " . $e);
433  }
434  }
435  self::xCopy($src_file, $dest_file);
436  } else {
437  try {
438  copy($src_file, $dest_file);
439  } catch (Exception $e) {
440  throw new ilSystemStyleException(ilSystemStyleException::FILE_CREATION_FAILED, "Copy " . $src_file . " to " . $dest_file . " Error: " . $e);
441  }
442  }
443  }
444  }
445  }
446 
452  public static function recursiveRemoveDir($dir)
453  {
454  if (is_dir($dir)) {
455  $objects = scandir($dir);
456  foreach ($objects as $object) {
457  if ($object != "." && $object != "..") {
458  if (is_dir($dir . "/" . $object)) {
459  self::recursiveRemoveDir($dir . "/" . $object);
460  } else {
461  unlink($dir . "/" . $object);
462  }
463  }
464  }
465  rmdir($dir);
466  }
467  }
468 
469 
476  protected function getLessMainFileDefautContent(ilSkinStyleXML $style)
477  {
478  $content = "@import \"" . $this->getSystemStylesConf()->getRelDelosPath() . "\";\n";
479  $content .= "// Import Custom Less Files here\n";
480 
481  $content .= "@import \"" . $this->getLessVariablesName($style->getId()) . "\";\n";
482  return $content;
483  }
484 
491  public function move($from, $to)
492  {
493  rename($from, $to);
494  }
495 
496 
500  public function delete()
501  {
502  self::recursiveRemoveDir(self::getSkinDirectory());
503  $this->getMessageStack()->addMessage(
505  $this->lng->txt("skin_deleted") . $this->getSkinDirectory(),
507  )
508  );
509  }
510 
516  protected function deleteFile($path)
517  {
518  if (file_exists($path)) {
519  unlink($path);
520  $this->getMessageStack()->addMessage(
522  $this->lng->txt("file_deleted") . " " . $path,
524  )
525  );
526  }
527  }
528 
534  public function deleteStyle(ilSkinStyleXML $style)
535  {
536  if ($style->isSubstyle()) {
538  $this->getMessageStack()->prependMessage(
540  $this->lng->txt("style_assignments_deleted") . " " . $style->getName(),
542  )
543  );
544  }
545 
546  $this->deleteFile($this->getLessFilePath($style->getId()));
547  $this->deleteFile($this->getCSSFilePath($style->getId()));
548  $this->deleteFile($this->getLessVariablesFilePath($style->getId()));
549 
550  $this->getSkin()->removeStyle($style->getId());
551 
552  $this->removeResourceDirectory($style->getImageDirectory());
553  $this->removeResourceDirectory($style->getFontDirectory());
554  $this->removeResourceDirectory($style->getSoundDirectory());
555 
556  $this->writeSkinToXML();
557  $this->getMessageStack()->prependMessage(
559  $this->lng->txt("style_deleted") . " " . $style->getName(),
561  )
562  );
563  }
564 
571  public function copy(string $new_skin_txt_addon = "Copy")
572  {
573  $new_skin_id_addon = "";
574  $new_skin_name_addon = "";
575 
576  while (ilStyleDefinition::skinExists($this->getSkin()->getId() . $new_skin_id_addon, $this->getSystemStylesConf())) {
577  $new_skin_id_addon .= $new_skin_txt_addon;
578  $new_skin_name_addon .= " " . $new_skin_txt_addon;
579  }
580 
581  $new_skin_path = rtrim($this->getSkinDirectory(), "/") . $new_skin_id_addon;
582 
583  mkdir($new_skin_path, 0777, true);
584  $this->xCopy($this->getSkinDirectory(), $new_skin_path);
585  $this->getMessageStack()->addMessage(new ilSystemStyleMessage($this->lng->txt("directory_created") . " " . $new_skin_path, ilSystemStyleMessage::TYPE_SUCCESS));
586  $skin_container = self::generateFromId($this->getSkin()->getId() . $new_skin_id_addon, null, $this->getSystemStylesConf());
587  $skin_container->getSkin()->setName($skin_container->getSkin()->getName() . $new_skin_name_addon);
588  $skin_container->getSkin()->setVersion("0.1");
589  $skin_container->updateSkin($skin_container->getSkin());
590  return $skin_container;
591  }
592 
596  public function export()
597  {
598  ilFileDelivery::deliverFileAttached($this->createTempZip(), $this->getSkin()->getId() . ".zip", '', true);
599  }
600 
606  public function createTempZip()
607  {
608  $rel_tmp_zip = "../" . $this->getSkin()->getId() . ".zip";
609  ilUtil::zip($this->getSkinDirectory(), $rel_tmp_zip, true);
610  return rtrim($this->getSkinDirectory(), "/") . ".zip";
611  }
612 
624  public static function import($import_zip_path, $name, ilSystemStyleMessageStack $message_stack = null, $system_styles_conf = null, $uploaded = true)
625  {
626  if (!$system_styles_conf) {
627  $system_styles_conf = new ilSystemStyleConfig();
628  }
629 
630  $skin_id = preg_replace('/[^A-Za-z0-9\-_]/', '', rtrim($name, ".zip"));
631 
632  while (ilStyleDefinition::skinExists($skin_id, $system_styles_conf)) {
633  $skin_id .= "Copy";
634  }
635 
636  $skin_path = $system_styles_conf->getCustomizingSkinPath() . $skin_id;
637  mkdir($skin_path, 0777, true);
638 
639  $temp_zip_path = $skin_path . "/" . $name;
640  if ($uploaded) {
641  move_uploaded_file($import_zip_path, $temp_zip_path);
642  } else {
643  rename($import_zip_path, $temp_zip_path);
644  }
645  ilUtil::unzip($temp_zip_path);
646  unlink($temp_zip_path);
647 
648  return self::generateFromId($skin_id, $message_stack, $system_styles_conf);
649  }
650 
656  protected function changeVariablesImport($main_path, $old_style_import, $new_style_import)
657  {
658  $main_less_content = file_get_contents($main_path);
659  $main_less_content = str_replace(
660  "@import \"" . $old_style_import,
661  "@import \"" . $new_style_import,
662  $main_less_content
663  );
664  file_put_contents($main_path, $main_less_content);
665  }
666 
671  public function compileLess($style_id)
672  {
673  if (!PATH_TO_LESSC) {
675  }
676 
677  $output = shell_exec(PATH_TO_LESSC . " " . $this->getLessFilePath($style_id));
678  if (!$output) {
679  $less_error = shell_exec(PATH_TO_LESSC . " " . $this->getLessFilePath($style_id) . " 2>&1");
680  if (!$less_error) {
681  throw new ilSystemStyleException(ilSystemStyleException::LESS_COMPILE_FAILED, "Empty css output, unknown error.");
682  }
684  }
685  file_put_contents($this->getCSSFilePath($style_id), $output);
686  }
690  public function getSkin()
691  {
692  return $this->skin;
693  }
694 
698  public function setSkin($skin)
699  {
700  $this->skin = $skin;
701  }
702 
706  public function getSkinDirectory()
707  {
708  return $this->getSystemStylesConf()->getCustomizingSkinPath() . $this->getSkin()->getId() . "/";
709  }
710 
711 
716  public function getCSSFilePath($style_id)
717  {
718  return $this->getSkinDirectory() . $this->getSkin()->getStyle($style_id)->getCssFile() . ".css";
719  }
720 
725  public function getLessFilePath($style_id)
726  {
727  return $this->getSkinDirectory() . $this->getSkin()->getStyle($style_id)->getCssFile() . ".less";
728  }
729 
734  public function getLessVariablesFilePath($style_id)
735  {
736  return $this->getSkinDirectory() . $this->getLessVariablesName($style_id);
737  }
738 
743  public function getLessVariablesName($style_id)
744  {
745  return $this->getSkin()->getStyle($style_id)->getCssFile() . "-variables.less";
746  }
747 
752  public function getImagesSkinPath($style_id)
753  {
754  return $this->getSkinDirectory() . $this->getSkin()->getStyle($style_id)->getImageDirectory();
755  }
756 
760  public static function getMessageStack()
761  {
762  return self::$message_stack;
763  }
764 
768  public static function setMessageStack($message_stack)
769  {
770  self::$message_stack = $message_stack;
771  }
772 
776  public function addStyle(ilSkinStyleXML $style)
777  {
778  $this->getSkin()->addStyle($style);
779  $old_style = new ilSkinStyleXML("", "");
780  $this->updateStyle($style->getId(), $old_style);
781  }
782 
783  protected function writeSkinToXML()
784  {
785  $this->getSkin()->writeToXMLFile($this->getSkinDirectory() . "template.xml");
786  }
787 
791  public function getSystemStylesConf()
792  {
794  }
795 
799  public function setSystemStylesConf($system_styles_conf)
800  {
801  $this->system_styles_conf = $system_styles_conf;
802  }
803 }
move($from, $to)
Used to move a complete directory of a skin.
createLessStructure(ilSkinStyleXML $style)
Creates the less/css structure of a style.
deleteStyle(ilSkinStyleXML $style)
Deletes a style completely.
This class is responsible for all file system related actions related actions of a skin such as copyi...
removeResourceDirectory($dir)
Deletes a resource directory.
create(ilSystemStyleMessageStack $message_stack)
Creates a new skin.
getSubstyleOf()
Returns the parent style of this style if set.
deleteFile($path)
Deletes a given file in the container.
addMessage(ilSystemStyleMessage $message)
Add a message to be displayed by the stack.
ilSkinXml holds an manages the basic data of a skin as provide by the template of the skin...
getLessMainFileDefautContent(ilSkinStyleXML $style)
Returns the main less default content if a new style is created.
createMainLessFile(ilSkinStyleXML $style)
Creates the main less file.
isSubstyle()
Return wheter this style is a substyle of another.
if($format !==null) $name
Definition: metadata.php:230
updateStyle($style_id, ilSkinStyleXML $old_style)
Updates one single style.
static deliverFileAttached($path_to_file, $download_file_name='', $mime_type='', $delete_file=false)
void
createResourceDirectory($source, $target)
Creates a resource directory (sound, images or fonts) by copying from the source (mostly delos) ...
static recursiveRemoveDir($dir)
Recursive delete of a folder.
copyCSSFromDefault(ilSkinStyleXML $style)
Copies (resets) the images from delos.
global $DIC
Definition: goto.php:24
static deleteSubStyleCategoryAssignments($a_skin_id, $a_style_id, $a_substyle)
Delets a sub styles category assignment.
static unzip(string $path_to_zip_file, bool $overwrite_existing=false, bool $unpack_flat=false)
updateSkin(ilSkinXML $old_skin=null)
Updates the skin.
copy(string $new_skin_txt_addon="Copy")
Copies a complete Skin.
Class for advanced editing exception handling in ILIAS.
static zip($a_dir, $a_file, $compress_content=false)
zips given directory/file into given zip.file
static skinExists($skin_id, ilSystemStyleConfig $system_style_config=null)
Check whether a skin exists.
static generateFromId($skin_id, ilSystemStyleMessageStack $message_stack=null, ilSystemStyleConfig $system_styles_conf=null)
Generate the container class by parsing the corresponding XML.
copyVariablesFromDefault(ilSkinStyleXML $style)
Copies (resets) the variables file from delos.
ilSystemStyleConfig wraps all &#39;constants&#39; to ensure the testability of all classes using those &#39;const...
__construct(ilSkinXML $skin, ilSystemStyleMessageStack $message_stack=null, ilSystemStyleConfig $system_styles_conf=null)
ilSystemStyleSkinContainer constructor.
changeResourceDirectory($new_dir, $old_dir)
Alters the name/path of a resource directory.
resourcesStyleReferences($resource)
Checks if a given resource (folder) is still referenced by a style of the containers skin...
Used to stack messages to be shown to the user.
changeVariablesImport($main_path, $old_style_import, $new_style_import)
resetImages(ilSkinStyleXML $style)
Copies (resets) the images from delos.
$source
Definition: metadata.php:76
export()
Exports the complete skin to an zip file.
static xCopy($src, $dest)
Recursive copy of a folder.