chamilo/chamilo-lms

View on GitHub
src/CoreBundle/Migrations/Schema/V200/Version20240519210000.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php

declare(strict_types=1);

/* For licensing terms, see /license.txt */

namespace Chamilo\CoreBundle\Migrations\Schema\V200;

use Chamilo\CoreBundle\Entity\Asset;
use Chamilo\CoreBundle\Entity\AttemptFile;
use Chamilo\CoreBundle\Entity\TrackEAttempt;
use Chamilo\CoreBundle\Migrations\AbstractMigrationChamilo;
use Doctrine\DBAL\Schema\Schema;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use Symfony\Component\HttpFoundation\File\UploadedFile;

final class Version20240519210000 extends AbstractMigrationChamilo
{
    public function getDescription(): string
    {
        return 'Migrate exercise audio files';
    }

    public function up(Schema $schema): void
    {
        $attemptRepo = $this->entityManager->getRepository(TrackEAttempt::class);

        // Migrate exercise audio files
        $sql = "SELECT ta.exe_id, ta.question_id, ta.user_id, ta.session_id, te.exe_exo_id, ta.filename
                FROM track_e_attempt ta
                INNER JOIN track_e_exercises te ON te.exe_id = ta.exe_id
                WHERE (ta.filename IS NOT NULL AND ta.filename != '')";
        $result = $this->connection->executeQuery($sql);
        $attempts = $result->fetchAllAssociative();

        foreach ($attempts as $attemptData) {
            $sessionId = (int) $attemptData['session_id'];
            $exerciseId = (int) $attemptData['exe_exo_id'];
            $questionId = (int) $attemptData['question_id'];
            $userId = (int) $attemptData['user_id'];
            $filename = $attemptData['filename'];

            $pathPattern = "{$sessionId}/{$exerciseId}/{$questionId}/{$userId}/{$filename}";
            $courseDir = $this->findCourseDirectory($pathPattern);

            if ($courseDir) {
                $filePath = $this->getUpdateRootPath()."app/courses/{$courseDir}/exercises/{$pathPattern}";
                $this->processFile($filePath, $attemptRepo, $attemptData);
            } else {
                error_log('MIGRATIONS :: File not found for pattern: '.$pathPattern);
            }
        }

        $this->entityManager->flush();
    }

    private function findCourseDirectory(string $pathPattern): ?string
    {
        $kernel = $this->container->get('kernel');
        $rootPath = $this->getUpdateRootPath().'/app/courses/';
        $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($rootPath));

        foreach ($iterator as $file) {
            if (str_contains($file->getPathname(), $pathPattern)) {
                $relativePath = str_replace($rootPath, '', $file->getPath());

                return explode('/', $relativePath)[0];
            }
        }

        return null;
    }

    private function processFile(string $filePath, $attemptRepo, array $attemptData): void
    {
        if (file_exists($filePath)) {
            $fileName = basename($filePath);

            /** @var TrackEAttempt $attempt */
            $attempt = $attemptRepo->findOneBy([
                'user' => $attemptData['user_id'],
                'questionId' => $attemptData['question_id'],
                'filename' => $fileName,
            ]);

            if (null !== $attempt) {
                if ($attempt->getAttemptFiles()->count() > 0) {
                    return;
                }

                $mimeType = mime_content_type($filePath);
                $file = new UploadedFile($filePath, $fileName, $mimeType, null, true);

                $asset = (new Asset())
                    ->setCategory(Asset::EXERCISE_ATTEMPT)
                    ->setTitle($fileName)
                    ->setFile($file)
                ;
                $this->entityManager->persist($asset);
                $this->entityManager->flush();

                $attemptFile = (new AttemptFile())
                    ->setAsset($asset)
                ;
                $attempt->addAttemptFile($attemptFile);
                $this->entityManager->persist($attemptFile);
                $this->entityManager->flush();

                error_log('MIGRATIONS :: File processed and inserted as asset and attempt file: '.$filePath);
            }
        }
    }

    public function down(Schema $schema): void
    {
        // This migration is not reversible
    }
}