ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
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)
137  {
138  $old_customizing_skin_directory = $this->getSystemStylesConf()->getCustomizingSkinPath() . $old_skin->getId() . "/";
139 
140  //Move if skin id has been changed
141  if ($old_skin->getId() != $this->getSkin()->getId()) {
142  $this->move($old_customizing_skin_directory, $this->getSkinDirectory());
143  }
144 
145  //Delete old template.xml and write a new one
146  unlink($this->getSkinDirectory() . "template.xml");
147  $this->writeSkinToXML();
148  }
149 
156  public function updateStyle($style_id, ilSkinStyleXML $old_style)
157  {
158  $style = $this->getSkin()->getStyle($style_id);
159 
160  if ($style->getImageDirectory() != $old_style->getImageDirectory()) {
161  if (file_exists($this->getSkinDirectory() . $old_style->getImageDirectory())) {
162  $this->changeResourceDirectory($style->getImageDirectory(), $old_style->getImageDirectory());
163  } else {
164  $this->createResourceDirectory($this->getSystemStylesConf()->getDefaultImagesPath(), $style->getImageDirectory());
165  }
166  }
167 
168  if ($style->getFontDirectory() != $old_style->getFontDirectory()) {
169  if (file_exists($this->getSkinDirectory() . $old_style->getFontDirectory())) {
170  $this->changeResourceDirectory($style->getFontDirectory(), $old_style->getFontDirectory());
171  } else {
172  $this->createResourceDirectory($this->getSystemStylesConf()->getDefaultFontsPath(), $style->getFontDirectory());
173  }
174  }
175 
176  if ($style->getSoundDirectory() != $old_style->getSoundDirectory()) {
177  if (file_exists($this->getSkinDirectory() . $old_style->getSoundDirectory())) {
178  $this->changeResourceDirectory($style->getSoundDirectory(), $old_style->getSoundDirectory());
179  } else {
180  $this->createResourceDirectory($this->getSystemStylesConf()->getDefaultSoundsPath(), $style->getSoundDirectory());
181  }
182  }
183 
184 
185 
186  if (file_exists($this->getSkinDirectory() . $old_style->getCssFile() . ".less")) {
187  rename($this->getSkinDirectory() . $old_style->getCssFile() . ".less", $this->getLessFilePath($style->getId()));
188  } else {
189  $this->createMainLessFile($style);
190  }
191 
192  if (file_exists($this->getSkinDirectory() . $old_style->getCssFile() . "-variables.less")) {
193  rename($this->getSkinDirectory() . $old_style->getCssFile() . "-variables.less", $this->getLessVariablesFilePath($style->getId()));
194  } else {
196  }
197 
198  $this->changeVariablesImport($this->getLessFilePath($style->getId()), $old_style->getCssFile() . "-variables.less", $this->getLessVariablesName($style->getId()));
199 
200  if (file_exists($this->getSkinDirectory() . $old_style->getCssFile() . ".css")) {
201  rename($this->getSkinDirectory() . $old_style->getCssFile() . ".css", $this->getCSSFilePath($style->getId()));
202  } else {
203  try {
204  $this->compileLess($style->getId());
205  } catch (Exception $e) {
206  $this->getMessageStack()->addMessage(
208  $e->getMessage(),
210  )
211  );
212  copy($this->getSystemStylesConf()->getDelosPath() . ".css", $this->getCSSFilePath($style->getId()));
213  }
214  }
215 
216  $this->writeSkinToXML();
217  }
218 
225  protected function resourcesStyleReferences($resource)
226  {
227  $references_ids = array();
228  foreach ($this->getSkin()->getStyles() as $style) {
229  if ($style->referencesResource($resource)) {
230  $references_ids[] = $style->getId();
231  }
232  }
233  return $references_ids;
234  }
235 
244  {
245  $path = $this->getSkinDirectory() . $target;
246 
247  mkdir($path, 0777, true);
248 
249  if ($source != "") {
250  self::xCopy($source, $path);
251  $this->getMessageStack()->addMessage(
253  $this->lng->txt("dir_created") . $path,
255  )
256  );
257  }
258  }
259 
267  protected function changeResourceDirectory($new_dir, $old_dir)
268  {
269  $absolut_new_dir = $this->getSkinDirectory() . $new_dir;
270  $absolut_old_dir = $this->getSkinDirectory() . $old_dir;
271 
272  if (file_exists($absolut_new_dir)) {
273  $this->getMessageStack()->addMessage(
275  $this->lng->txt("dir_changed_to") . " " . $absolut_new_dir,
277  )
278  );
279  $this->getMessageStack()->addMessage(
281  $this->lng->txt("dir_preserved_backup") . " " . $absolut_old_dir,
283  )
284  );
285  } else {
286  mkdir($absolut_new_dir, 0777, true);
287  self::xCopy($absolut_old_dir, $absolut_new_dir);
288  $this->getMessageStack()->addMessage(
290  $this->lng->txt("dir_copied_from") . " " . $absolut_old_dir . " " . $this->lng->txt("to") . " " . $absolut_new_dir,
292  )
293  );
294  if (count($this->resourcesStyleReferences($old_dir)) == 0) {
295  self::recursiveRemoveDir(self::getSkinDirectory() . $old_dir);
296  $this->getMessageStack()->addMessage(
298  $this->lng->txt("dir_deleted") . " " . $absolut_old_dir,
300  )
301  );
302  } else {
303  $this->getMessageStack()->addMessage(
305  $this->lng->txt("dir_preserved_linked") . " " . $absolut_old_dir,
307  )
308  );
309  }
310  }
311  }
312 
318  protected function removeResourceDirectory($dir)
319  {
320  $absolut_dir = $this->getSkinDirectory() . $dir;
321 
322  if (file_exists($absolut_dir)) {
323  if (count($this->resourcesStyleReferences($dir)) == 0) {
324  self::recursiveRemoveDir($this->getSkinDirectory() . $dir);
325  $this->getMessageStack()->addMessage(
327  $this->lng->txt("dir_deleted") . " " . $dir,
329  )
330  );
331  } else {
332  $this->getMessageStack()->addMessage(
334  $this->lng->txt("dir_preserved_linked") . " " . $dir,
336  )
337  );
338  }
339  }
340  }
341 
349  {
350  $this->createMainLessFile($style);
351  $this->copyVariablesFromDefault($style);
352  $this->copyCSSFromDefault($style);
353  $this->compileLess($style->getId());
354  }
355 
362  {
363  $path = $this->getLessFilePath($style->getId());
364  file_put_contents($path, $this->getLessMainFileDefautContent($style));
365  $this->getMessageStack()->addMessage(
367  $this->lng->txt("main_less_created") . " " . $path,
369  )
370  );
371  }
372 
380  {
381  $less_file = new ilSystemStyleLessFile($this->getSystemStylesConf()->getDefaultVariablesPath());
382  $less_file->setLessVariablesFile($this->getLessVariablesFilePath($style->getId()));
383  $less_file->write();
384  return $less_file;
385  }
386 
393  {
394  self::recursiveRemoveDir($this->getSkinDirectory() . $style->getImageDirectory());
395  $this->createResourceDirectory($this->getSystemStylesConf()->getDefaultImagesPath(), $style->getImageDirectory());
396  }
397 
404  {
405  copy($this->getSystemStylesConf()->getDelosPath() . ".css", $this->getCSSFilePath($style->getId()));
406  }
407 
415  public static function xCopy($src, $dest)
416  {
417  foreach (scandir($src) as $file) {
418  $src_file = rtrim($src, '/') . '/' . $file;
419  $dest_file = rtrim($dest, '/') . '/' . $file;
420  if (!is_readable($src_file)) {
422  }
423  if (substr($file, 0, 1) != ".") {
424  if (is_dir($src_file)) {
425  if (!file_exists($dest_file)) {
426  try {
427  mkdir($dest_file);
428  } catch (Exception $e) {
429  throw new ilSystemStyleException(ilSystemStyleException::FOLDER_CREATION_FAILED, "Copy " . $src_file . " to " . $dest_file . " Error: " . $e);
430  }
431  }
432  self::xCopy($src_file, $dest_file);
433  } else {
434  try {
435  copy($src_file, $dest_file);
436  } catch (Exception $e) {
437  throw new ilSystemStyleException(ilSystemStyleException::FILE_CREATION_FAILED, "Copy " . $src_file . " to " . $dest_file . " Error: " . $e);
438  }
439  }
440  }
441  }
442  }
443 
449  public static function recursiveRemoveDir($dir)
450  {
451  if (is_dir($dir)) {
452  $objects = scandir($dir);
453  foreach ($objects as $object) {
454  if ($object != "." && $object != "..") {
455  if (is_dir($dir . "/" . $object)) {
456  self::recursiveRemoveDir($dir . "/" . $object);
457  } else {
458  unlink($dir . "/" . $object);
459  }
460  }
461  }
462  rmdir($dir);
463  }
464  }
465 
466 
474  {
475  $content = "@import \"" . $this->getSystemStylesConf()->getRelDelosPath() . "\";\n";
476  $content .= "// Import Custom Less Files here\n";
477 
478  $content .= "@import \"" . $this->getLessVariablesName($style->getId()) . "\";\n";
479  return $content;
480  }
481 
488  public function move($from, $to)
489  {
490  rename($from, $to);
491  }
492 
493 
497  public function delete()
498  {
499  self::recursiveRemoveDir(self::getSkinDirectory());
500  $this->getMessageStack()->addMessage(
502  $this->lng->txt("skin_deleted") . $this->getSkinDirectory(),
504  )
505  );
506  }
507 
513  protected function deleteFile($path)
514  {
515  if (file_exists($path)) {
516  unlink($path);
517  $this->getMessageStack()->addMessage(
519  $this->lng->txt("file_deleted") . " " . $path,
521  )
522  );
523  }
524  }
525 
532  {
533  if ($style->isSubstyle()) {
535  $this->getMessageStack()->prependMessage(
537  $this->lng->txt("style_assignments_deleted") . " " . $style->getName(),
539  )
540  );
541  }
542 
543  $this->deleteFile($this->getLessFilePath($style->getId()));
544  $this->deleteFile($this->getCSSFilePath($style->getId()));
545  $this->deleteFile($this->getLessVariablesFilePath($style->getId()));
546 
547  $this->getSkin()->removeStyle($style->getId());
548 
549  $this->removeResourceDirectory($style->getImageDirectory());
550  $this->removeResourceDirectory($style->getFontDirectory());
551  $this->removeResourceDirectory($style->getSoundDirectory());
552 
553  $this->writeSkinToXML();
554  $this->getMessageStack()->prependMessage(
556  $this->lng->txt("style_deleted") . " " . $style->getName(),
558  )
559  );
560  }
561 
568  public function copy()
569  {
570  $new_skin_id_addon = "";
571 
572  while (ilStyleDefinition::skinExists($this->getSkin()->getId() . $new_skin_id_addon, $this->getSystemStylesConf())) {
573  $new_skin_id_addon .= "Copy";
574  }
575 
576  $new_skin_path = rtrim($this->getSkinDirectory(), "/") . $new_skin_id_addon;
577 
578  mkdir($new_skin_path, 0777, true);
579  $this->xCopy($this->getSkinDirectory(), $new_skin_path);
580  $this->getMessageStack()->addMessage(new ilSystemStyleMessage($this->lng->txt("directory_created") . " " . $new_skin_path, ilSystemStyleMessage::TYPE_SUCCESS));
581  return self::generateFromId($this->getSkin()->getId() . $new_skin_id_addon, null, $this->getSystemStylesConf());
582  }
583 
587  public function export()
588  {
589  ilFileDelivery::deliverFileAttached($this->createTempZip(), $this->getSkin()->getId() . ".zip", '', true);
590  }
591 
597  public function createTempZip()
598  {
599  $rel_tmp_zip = "../" . $this->getSkin()->getId() . ".zip";
600  ilUtil::zip($this->getSkinDirectory(), $rel_tmp_zip, true);
601  return rtrim($this->getSkinDirectory(), "/") . ".zip";
602  }
603 
615  public static function import($import_zip_path, $name, ilSystemStyleMessageStack $message_stack = null, $system_styles_conf = null, $uploaded = true)
616  {
617  if (!$system_styles_conf) {
618  $system_styles_conf = new ilSystemStyleConfig();
619  }
620 
621  $skin_id = preg_replace('/[^A-Za-z0-9\-_]/', '', rtrim($name, ".zip"));
622 
623  while (ilStyleDefinition::skinExists($skin_id, $system_styles_conf)) {
624  $skin_id .= "Copy";
625  }
626 
627  $skin_path = $system_styles_conf->getCustomizingSkinPath() . $skin_id;
628  mkdir($skin_path, 0777, true);
629 
630  $temp_zip_path = $skin_path . "/" . $name;
631  if ($uploaded) {
632  move_uploaded_file($import_zip_path, $temp_zip_path);
633  } else {
634  rename($import_zip_path, $temp_zip_path);
635  }
636  ilUtil::unzip($temp_zip_path);
637  unlink($temp_zip_path);
638 
639  return self::generateFromId($skin_id, $message_stack, $system_styles_conf);
640  }
641 
647  protected function changeVariablesImport($main_path, $old_style_import, $new_style_import)
648  {
649  $main_less_content = file_get_contents($main_path);
650  $main_less_content = str_replace(
651  "@import \"" . $old_style_import,
652  "@import \"" . $new_style_import,
653  $main_less_content
654  );
655  file_put_contents($main_path, $main_less_content);
656  }
657 
662  public function compileLess($style_id)
663  {
664  if (!PATH_TO_LESSC) {
666  }
667 
668  $output = shell_exec(PATH_TO_LESSC . " " . $this->getLessFilePath($style_id));
669  if (!$output) {
670  $less_error = shell_exec(PATH_TO_LESSC . " " . $this->getLessFilePath($style_id) . " 2>&1");
671  if (!$less_error) {
672  throw new ilSystemStyleException(ilSystemStyleException::LESS_COMPILE_FAILED, "Empty css output, unknown error.");
673  }
675  }
676  file_put_contents($this->getCSSFilePath($style_id), $output);
677  }
681  public function getSkin()
682  {
683  return $this->skin;
684  }
685 
689  public function setSkin($skin)
690  {
691  $this->skin = $skin;
692  }
693 
697  public function getSkinDirectory()
698  {
699  return $this->getSystemStylesConf()->getCustomizingSkinPath() . $this->getSkin()->getId() . "/";
700  }
701 
702 
707  public function getCSSFilePath($style_id)
708  {
709  return $this->getSkinDirectory() . $this->getSkin()->getStyle($style_id)->getCssFile() . ".css";
710  }
711 
716  public function getLessFilePath($style_id)
717  {
718  return $this->getSkinDirectory() . $this->getSkin()->getStyle($style_id)->getCssFile() . ".less";
719  }
720 
725  public function getLessVariablesFilePath($style_id)
726  {
727  return $this->getSkinDirectory() . $this->getLessVariablesName($style_id);
728  }
729 
734  public function getLessVariablesName($style_id)
735  {
736  return $this->getSkin()->getStyle($style_id)->getCssFile() . "-variables.less";
737  }
738 
743  public function getImagesSkinPath($style_id)
744  {
745  return $this->getSkinDirectory() . $this->getSkin()->getStyle($style_id)->getImageDirectory();
746  }
747 
751  public static function getMessageStack()
752  {
753  return self::$message_stack;
754  }
755 
759  public static function setMessageStack($message_stack)
760  {
761  self::$message_stack = $message_stack;
762  }
763 
767  public function addStyle(ilSkinStyleXML $style)
768  {
769  $this->getSkin()->addStyle($style);
770  $old_style = new ilSkinStyleXML("", "");
771  $this->updateStyle($style->getId(), $old_style);
772  }
773 
774  protected function writeSkinToXML()
775  {
776  $this->getSkin()->writeToXMLFile($this->getSkinDirectory() . "template.xml");
777  }
778 
782  public function getSystemStylesConf()
783  {
785  }
786 
790  public function setSystemStylesConf($system_styles_conf)
791  {
792  $this->system_styles_conf = $system_styles_conf;
793  }
794 }
move($from, $to)
Used to move a complete directory of a skin.
createLessStructure(ilSkinStyleXML $style)
Creates the less/css structure of a style.
updateSkin(ilSkinXML $old_skin)
Updates the skin.
$path
Definition: aliased.php:25
$style
Definition: example_012.php:70
deleteStyle(ilSkinStyleXML $style)
Deletes a style completely.
global $DIC
Definition: saml.php:7
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.
static unzip($a_file, $overwrite=false, $a_flat=false)
unzip file
$from
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.
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.
static deleteSubStyleCategoryAssignments($a_skin_id, $a_style_id, $a_substyle)
Delets a sub styles category assignment.
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: linkback.php:22
$target
Definition: test.php:19
export()
Exports the complete skin to an zip file.
static xCopy($src, $dest)
Recursive copy of a folder.