19 declare(strict_types=1);
    28     public const REGEXP = 
'%^(/\w+|\w+[\-.]\w+)+$%';
    37         foreach ($assets as $asset) {
    38             $this->
insertInto($this->assets, explode(
"/", $asset->getTarget()), $asset);
    44         $key = array_shift($path);
    45         $key_exists = array_key_exists($key, $assets);
    46         $target_reached = count($path) === 0;
    48         if (!$key_exists && $target_reached) {
    49             $assets[$key] = $asset;
    53         if (!$target_reached && (!$key_exists || is_array($assets[$key]))) {
    57             $this->
insertInto($assets[$key], $path, $asset);
    61         $first_asset = $assets[$key];
    63             $first_asset = array_shift($first_asset);
    66         throw new \LogicException(
    67             "There are (at least) two assets for the same target '{$asset->getTarget()}': " .
    68             "'{$first_asset->getSource()}' and '{$asset->getSource()}'"    78         if (!preg_match(self::REGEXP, $ilias_base)) {
    79             throw new \InvalidArgumentException(
    80                 "'{$ilias_base}' is not a valid path to ILIAS base folder."    83         if (!preg_match(self::REGEXP, $target)) {
    84             throw new \InvalidArgumentException(
    85                 "'{$target}' is not a valid target path for public assets."    89         $this->
purge($target, 
array_map(fn($v) => $target . 
"/" . $v, self::DONT_PURGE));
    96         if (is_array($asset)) {
   100             $targets = explode(
"/", $asset->getTarget());
   101             $this->
copy(
"$ilias_base/{$asset->getSource()}", 
"$target");
   107         foreach ($assets as $key => $asset) {
   112     protected function copy(
string $source, 
string $target): void
   114         if (is_file($source)) {
   115             copy($source, $target);
   116         } elseif (is_dir($source)) {
   117             $dir = new \RecursiveDirectoryIterator($source, \FilesystemIterator::SKIP_DOTS);
   119             foreach ($dir as 
$d) {
   120                 $name = $d->getBasename();
   121                 $this->
copy(
"$source/$name", 
"$target/$name");
   124             throw new \RuntimeException(
   125                 "Cannot copy $source, not a file or directory."   130     protected function purge(
string $path, array $dont_purge): bool
   132         if (in_array($path, $dont_purge)) {
   136         if (!file_exists($path)) {
   140         if (is_file($path)) {
   147             foreach (array_diff(scandir($path), [
'.', 
'..']) as $item) {
   148                 $purged = $this->
purge($path . 
"/" . $item, $dont_purge) && $purged;
   156         throw new \LogicException(
"Don't know how to purge $path");
   161         if (!file_exists($path)) {
 insertInto(array &$assets, array $path, PublicAsset $asset)
 
addAssets(PublicAsset ... $assets)
 
buildPublicFolder(string $ilias_base, string $target)
 
buildPublicFolderRecursivelyArray(string $ilias_base, string $target, array $assets)
 
An public asset is a file or folder that should be served via the web. 
 
buildPublicFolderRecursively(string $ilias_base, string $target, PublicAsset|array $asset)
 
purge(string $path, array $dont_purge)
 
Will take care of the public assets, just like a good manager does. 
 
copy(string $source, string $target)