elabftw/elabftw

View on GitHub
src/Make/MakeStreamZip.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php

/**
 * @author Nicolas CARPi <nico-git@deltablot.email>
 * @copyright 2012 Nicolas CARPi
 * @see https://www.elabftw.net Official website
 * @license AGPL-3.0
 * @package elabftw
 */

declare(strict_types=1);

namespace Elabftw\Make;

use DateTimeImmutable;
use Elabftw\Elabftw\App;
use Elabftw\Exceptions\IllegalActionException;
use Elabftw\Models\AbstractEntity;
use League\Flysystem\UnableToReadFile;
use ZipStream\ZipStream;

use function array_walk;
use function count;
use function json_encode;

/**
 * Make a zip archive from experiment or db item
 */
class MakeStreamZip extends AbstractMakeZip
{
    // data array (entries) that will be converted to json
    protected array $dataArr = array();

    public function __construct(protected ZipStream $Zip, AbstractEntity $entity, protected array $idArr, protected bool $usePdfa = false, bool $includeChangelog = false)
    {
        parent::__construct(
            entity: $entity,
            includeChangelog: $includeChangelog
        );
        array_walk($this->idArr, function (&$id) {
            $id = (int) $id;
        });
    }

    /**
     * Get the name of the generated file
     */
    public function getFileName(): string
    {
        if (count($this->idArr) === 1) {
            $this->Entity->setId($this->idArr[0]);
            $this->Entity->canOrExplode('read');
            return $this->getBaseFileName() . $this->extension;
        }
        return 'export.elabftw' . $this->extension;
    }

    /**
     * Loop on each id and add it to our zip archive
     * This could be called the main function.
     */
    public function getStreamZip(): void
    {
        foreach ($this->idArr as $id) {
            try {
                $this->addToZip((int) $id);
            } catch (IllegalActionException) {
                continue;
            }
        }

        // add the (hidden) .elabftw.json file useful for reimport
        $this->Zip->addFile('.elabftw.json', json_encode(array('data' => $this->dataArr, 'meta' => $this->getMeta()), JSON_THROW_ON_ERROR, 512));

        $this->Zip->finish();
    }

    /**
     * Produce metadata for the "meta" key of the json file
     */
    protected function getMeta(): array
    {
        $creationDateTime = new DateTimeImmutable();
        return array(
            'elabftw_producer_version' => App::INSTALLED_VERSION,
            'elabftw_producer_version_int' => App::INSTALLED_VERSION_INT,
            'dateCreated' => $creationDateTime->format(DateTimeImmutable::ATOM),
            'count' => count($this->dataArr),
        );
    }

    /**
     * This is where the magic happens
     * Note the different try catch blocks to skip issues that would stop the zip generation
     *
     * @param int $id The id of the item we are zipping
     */
    private function addToZip(int $id): void
    {
        $this->Entity->setId($id);
        try {
            $permissions = $this->Entity->getPermissions();
        } catch (IllegalActionException) {
            return;
        }
        if ($permissions['read']) {
            $entityArr = $this->Entity->entityData;
            $uploadedFilesArr = $entityArr['uploads'];
            $this->folder = $this->getBaseFileName();

            if (!empty($uploadedFilesArr)) {
                try {
                    // we overwrite the uploads array with what the function returns so we have correct real_names
                    $entityArr['uploads'] = $this->addAttachedFiles($uploadedFilesArr);
                } catch (UnableToReadFile) {
                    return;
                }
            }
            $this->addPdf();
            // add an entry to the json file
            $this->dataArr[] = $entityArr;
        }
    }
}