ILIAS  release_7 Revision v7.30-3-g800a261c036
class.ilSystemStyleSkinContainer.php
Go to the documentation of this file.
1<?php
2include_once("Services/Style/System/classes/Utilities/class.ilSkinStyleXML.php");
3include_once("Services/Style/System/classes/class.ilStyleDefinition.php");
4include_once("Services/Style/System/classes/Exceptions/class.ilSystemStyleException.php");
5include_once("Services/Style/System/classes/Utilities/class.ilSystemStyleMessageStack.php");
6include_once("Services/Style/System/classes/Utilities/class.ilSystemStyleMessage.php");
7include_once("Services/Style/System/classes/Less/class.ilSystemStyleLessFile.php");
8include_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
71 } else {
73 }
74 }
75
86 {
87 if (!$skin_id) {
89 }
90
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) {
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
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 {
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
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
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) {
628 }
629
630 $skin_id = preg_replace('/[^A-Za-z0-9\-_]/', '', rtrim($name, ".zip"));
631
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
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 {
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
800 {
801 $this->system_styles_conf = $system_styles_conf;
802 }
803}
An exception for terminatinating execution or to throw for unit testing.
static deliverFileAttached($path_to_file, $download_file_name='', $mime_type='', $delete_file=false)
void
getSubstyleOf()
Returns the parent style of this style if set.
isSubstyle()
Return wheter this style is a substyle of another.
ilSkinXml holds an manages the basic data of a skin as provide by the template of the skin.
static skinExists($skin_id, ilSystemStyleConfig $system_style_config=null)
Check whether a skin exists.
ilSystemStyleConfig wraps all 'constants' to ensure the testability of all classes using those 'const...
Class for advanced editing exception handling in ILIAS.
Used to stack messages to be shown to the user.
static deleteSubStyleCategoryAssignments($a_skin_id, $a_style_id, $a_substyle)
Delets a sub styles category assignment.
This class is responsible for all file system related actions related actions of a skin such as copyi...
static recursiveRemoveDir($dir)
Recursive delete of a folder.
getLessMainFileDefautContent(ilSkinStyleXML $style)
Returns the main less default content if a new style is created.
deleteFile($path)
Deletes a given file in the container.
changeResourceDirectory($new_dir, $old_dir)
Alters the name/path of a resource directory.
createResourceDirectory($source, $target)
Creates a resource directory (sound, images or fonts) by copying from the source (mostly delos)
copyCSSFromDefault(ilSkinStyleXML $style)
Copies (resets) the images from delos.
removeResourceDirectory($dir)
Deletes a resource directory.
static generateFromId($skin_id, ilSystemStyleMessageStack $message_stack=null, ilSystemStyleConfig $system_styles_conf=null)
Generate the container class by parsing the corresponding XML.
static xCopy($src, $dest)
Recursive copy of a folder.
changeVariablesImport($main_path, $old_style_import, $new_style_import)
copyVariablesFromDefault(ilSkinStyleXML $style)
Copies (resets) the variables file from delos.
resourcesStyleReferences($resource)
Checks if a given resource (folder) is still referenced by a style of the containers skin.
export()
Exports the complete skin to an zip file.
deleteStyle(ilSkinStyleXML $style)
Deletes a style completely.
copy(string $new_skin_txt_addon="Copy")
Copies a complete Skin.
move($from, $to)
Used to move a complete directory of a skin.
updateSkin(ilSkinXML $old_skin=null)
Updates the skin.
__construct(ilSkinXML $skin, ilSystemStyleMessageStack $message_stack=null, ilSystemStyleConfig $system_styles_conf=null)
ilSystemStyleSkinContainer constructor.
updateStyle($style_id, ilSkinStyleXML $old_style)
Updates one single style.
resetImages(ilSkinStyleXML $style)
Copies (resets) the images from delos.
createMainLessFile(ilSkinStyleXML $style)
Creates the main less file.
create(ilSystemStyleMessageStack $message_stack)
Creates a new skin.
createLessStructure(ilSkinStyleXML $style)
Creates the less/css structure of a style.
static zip($a_dir, $a_file, $compress_content=false)
zips given directory/file into given zip.file
static unzip(string $path_to_zip_file, bool $overwrite_existing=false, bool $unpack_flat=false)
global $DIC
Definition: goto.php:24
if($format !==null) $name
Definition: metadata.php:230
$source
Definition: metadata.php:76