diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc5728c..9e29a75 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,14 +1,46 @@ -name: CI +name: "CI Tests" -on: [push] +on: [push, pull_request] jobs: - build-test: - runs-on: ubuntu-latest - + test: + runs-on: 'ubuntu-20.04' + strategy: + fail-fast: false + matrix: + php: ['8.2', '8.3'] + symfony: ['6.0.*', '6.1.*', '6.2.*', '6.3.*', '6.4.*', '7.0.*', '7.1.*'] + composer-flags: ['--prefer-stable'] + extensions: ['curl, iconv, mbstring, pdo, pdo_sqlite, sqlite, zip'] + include: + - php: '8.2' + symfony: '6.0.*' + composer-flags: '--prefer-stable --prefer-lowest' + extensions: 'curl, iconv, mbstring, pdo, pdo_sqlite, sqlite, zip' + exclude: + - php: '8.2' + symfony: '6.0.*' + name: "PHP ${{ matrix.php }} - Symfony ${{ matrix.symfony }}${{ matrix.composer-flags != '' && format(' - Composer {0}', matrix.composer-flags) || '' }}" steps: - - uses: actions/checkout@v3 - - uses: php-actions/composer@v6 - - uses: php-actions/phpstan@v3 + - name: Checkout Code + uses: actions/checkout@v4 + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: ~/.composer/cache/files + key: dependencies-symfony-${{ matrix.symfony }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}-flags-${{ matrix.composer-flags }} + - name: Setup PHP + uses: shivammathur/setup-php@v2 with: - memory_limit: -1 + php-version: ${{ matrix.php }} + tools: composer:v2, flex + extensions: ${{ matrix.extensions }} + coverage: none + - name: Install dependencies + run: composer update ${{ matrix.composer-flags }} --prefer-dist --no-suggest + env: + SYMFONY_REQUIRE: ${{ matrix.symfony }} + + - name: Run PHPUnit + run: vendor/bin/phpunit + diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml new file mode 100644 index 0000000..9a52c27 --- /dev/null +++ b/.github/workflows/coding-standards.yml @@ -0,0 +1,13 @@ +name: "CI Tests" + +on: [push, pull_request] +jobs: + build-lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: php-actions/composer@v6 + - uses: php-actions/phpstan@v3 + with: + memory_limit: -1 \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..eca4067 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,49 @@ +name: Publish and release +on: + push: + branches: + - master + - main +jobs: + publish: + runs-on: ubuntu-latest + + permissions: + contents: write + id-token: write + + steps: + - uses: actions/checkout@v4 + - name: Read version from composer.json + id: get_version + run: | + VERSION=$(cat composer.json | jq -r '.version') + echo "version=$VERSION" >> $GITHUB_ENV + echo "::set-output name=version::$VERSION" + - name: Check if tag exists + id: check_tag + run: | + TAG_EXISTS=$(git tag -l "${{ steps.get_version.outputs.version }}") + echo "tag_exists=$TAG_EXISTS" >> $GITHUB_ENV + echo "::set-output name=tag_exists::$TAG_EXISTS" + - name: Create GitHub Tag + if: steps.check_tag.outputs.tag_exists == '' + uses: actions/github-script@v7 + with: + script: | + const tag = `${process.env.version}`; + const latestCommitSha = context.sha; + await github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `refs/tags/${tag}`, + sha: latestCommitSha, + }); + - name: Create a Release + if: steps.check_tag.outputs.tag_exists == '' + uses: elgohr/Github-Release-Action@v5 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag: "${{ steps.get_version.outputs.version }}" + title: "${{ steps.get_version.outputs.version }}" diff --git a/.gitignore b/.gitignore index 80ac4f8..cb61e58 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ public/index.php composer.lock .DS_Store .thumbs +.phpunit.cache \ No newline at end of file diff --git a/Command/H5pBundleCleanUpFilesCommand.php b/Command/H5pBundleCleanUpFilesCommand.php index ea534b5..63c8090 100644 --- a/Command/H5pBundleCleanUpFilesCommand.php +++ b/Command/H5pBundleCleanUpFilesCommand.php @@ -13,7 +13,7 @@ class H5pBundleCleanUpFilesCommand extends Command /** * @var H5POptions $h5POptions */ - private $h5POptions; + private H5POptions $h5POptions; public function __construct(H5POptions $h5POptions) { diff --git a/Command/H5pBundleIncludeAssetsCommand.php b/Command/H5pBundleIncludeAssetsCommand.php index 13d4fca..18ac1c3 100644 --- a/Command/H5pBundleIncludeAssetsCommand.php +++ b/Command/H5pBundleIncludeAssetsCommand.php @@ -3,19 +3,16 @@ namespace Emmedy\H5PBundle\Command; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Style\SymfonyStyle; -use Symfony\Component\Config\FileLocator; use Symfony\Component\HttpKernel\KernelInterface; class H5pBundleIncludeAssetsCommand extends Command { protected static $defaultName = 'h5p-bundle:IncludeAssetsCommand'; /** KernelInterface $appKernel */ - private $appKernel; + private KernelInterface $appKernel; /** * @param KernelInterface $appKernel @@ -26,7 +23,7 @@ public function __construct(KernelInterface $appKernel) parent::__construct(); } - protected function configure() + protected function configure(): void { $this ->setDescription( @@ -39,16 +36,18 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output): int { $this->includeAssets($input->getOption('copy') ?? false); - return 0; + return Command::SUCCESS; } private function includeAssets(bool $copy): void { + $projectDir = $this->appKernel->getProjectDir(); + //get dir of vendor H5P + $fromDir = $projectDir . "/vendor/h5p/"; - $fromDir = $this->appKernel->getProjectDir() . "/vendor/h5p/"; //call service - $toDir = $this->appKernel->getProjectDir() . '/public/bundles/emmedyh5p/h5p/'; + $toDir = $projectDir . '/public/bundles/emmedyh5p/h5p/'; $coreSubDir = "h5p-core/"; $coreDirs = ["fonts", "images", "js", "styles"]; @@ -59,7 +58,7 @@ private function includeAssets(bool $copy): void $this->createFiles($fromDir, $toDir, $editorSubDir, $editorDirs, $copy); } - private function createFiles($fromDir, $toDir, $subDir, $subDirs, $copy) + private function createFiles(string $fromDir, string $toDir, string $subDir, array $subDirs, bool $copy): void { foreach ($subDirs as $dir) { $src = $fromDir . $subDir . $dir; @@ -71,7 +70,7 @@ private function createFiles($fromDir, $toDir, $subDir, $subDirs, $copy) } } - private function recurseCopy($src, $dst) + private function recurseCopy(string $src, string $dst): void { $dir = opendir($src); @mkdir($dst); diff --git a/Controller/H5PAJAXController.php b/Controller/H5PAJAXController.php index d4cc67c..5a1689f 100644 --- a/Controller/H5PAJAXController.php +++ b/Controller/H5PAJAXController.php @@ -7,15 +7,13 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; -/** - * @Route("/h5p/ajax") - */ +#[Route('/h5p/ajax')] class H5PAJAXController extends AbstractController { protected \H5peditor $h5peditor; - protected H5POptions $h5POptions; + protected H5POptions $serviceh5poptions; public function __construct(\H5peditor $h5peditor, H5POptions $h5poption) { @@ -23,11 +21,12 @@ public function __construct(\H5peditor $h5peditor, H5POptions $h5poption) $this->h5POptions = $h5poption; } + #[Route('/libraries/')] + /** * Callback that lists all h5p libraries. * - * @Route("/libraries/") - * @param Request $request + * @param Request $request Current request * @return JsonResponse */ public function librariesCallback(Request $request): JsonResponse @@ -37,6 +36,7 @@ public function librariesCallback(Request $request): JsonResponse if ($request->get('machineName')) { return $this->libraryCallback($request); } + //get editor $editor = $this->h5peditor; $editor->ajax->action(\H5PEditorEndpoints::LIBRARIES); @@ -47,9 +47,11 @@ public function librariesCallback(Request $request): JsonResponse return $this->json(json_decode($output, true)); } + #[Route('/content-type-cache/')] + /** - * Callback that returns the content type cache - * @Route("/content-type-cache/") + * Callback that returns the content type cache. + * @return JsonResponse */ public function contentTypeCacheCallback(): JsonResponse { @@ -63,15 +65,16 @@ public function contentTypeCacheCallback(): JsonResponse return $this->json(json_decode($output, true)); } + #[Route('/content-hub-metadata-cache')] + /** - * Callback that return the content hub metadata cache - * @Route("/content-hub-metadata-cache") - * @param Request $request + * Callback that return the content hub metadata cache. + * @param Request $request Current Request * @return JsonResponse */ public function contentHubMetadataCache(Request $request): JsonResponse { - $locale = $request->getLocale() != null ? $request->getLocale() : 'en'; + $locale = $request->getLocale() !== null ? $request->getLocale() : 'en'; ob_start(); $editor = $this->h5peditor; @@ -83,11 +86,11 @@ public function contentHubMetadataCache(Request $request): JsonResponse return $this->json(json_decode($output, true)); } + #[Route('/translations/')] + /** - * Callback for translations - * + * Callback for translations. * @param Request $request - * @Route("/translations/") * * @return JsonResponse */ @@ -105,13 +108,13 @@ public function TranslationsCallback(Request $request): JsonResponse return $this->json(json_decode($output, true)); } + #[Route('/library-install/')] + /** - * Callback Install library from external file - * - * @param Request $request + * Callback Install library from external file. + * @param Request $request Current request * * @return JsonResponse - * @Route("/library-install/") */ public function libraryInstallCallback(Request $request): JsonResponse { @@ -131,9 +134,9 @@ public function libraryInstallCallback(Request $request): JsonResponse } /** - * Callback that returns data for a given library + * Callback that returns data for a given library. * - * @param Request $request + * @param Request $request Current Request * @return JsonResponse */ private function libraryCallback(Request $request): JsonResponse @@ -142,7 +145,7 @@ private function libraryCallback(Request $request): JsonResponse //$machineName, $majorVersion, $minorVersion, $languageCode, $prefix = '', $fileDir = '', $defaultLanguage $editor = $this->h5peditor; - $locale = $request->getLocale() != null ? $request->getLocale() : 'en'; + $locale = $request->getLocale() !== null ? $request->getLocale() : 'en'; $editor->ajax->action( \H5PEditorEndpoints::SINGLE_LIBRARY, $request->get('machineName'), @@ -160,14 +163,15 @@ private function libraryCallback(Request $request): JsonResponse return $this->json(json_decode($output, true)); } + #[Route('/library-upload/')] + /** - * Callback for uploading a library + * Callback for uploading a library. * - * @param Request $request + * @param Request $request Current Request * * @return JsonResponse * @throws Exception - * @Route("/library-upload/") */ public function libraryUploadCallback(Request $request): JsonResponse { @@ -195,19 +199,20 @@ public function libraryUploadCallback(Request $request): JsonResponse return $this->json(json_decode($output, true)); } + #[Route('/files/')] + /** * Callback for file uploads. * - * @param Request $request + * @param Request $request Current request * @return JsonResponse - * @Route("/files/") */ public function filesCallback(Request $request): JsonResponse { ob_start(); $editor = $this->h5peditor; - $id = $request->get('id') != null ? $request->get('id') : $request->get('contentId'); + $id = $request->get('id') !== null ? $request->get('id') : $request->get('contentId'); $editor->ajax->action( \H5PEditorEndpoints::FILES, $request->get('token', 1), @@ -220,12 +225,13 @@ public function filesCallback(Request $request): JsonResponse return $this->json(json_decode($output, true)); } + #[Route('/filter/')] + /** * Callback for filtering. * - * @param Request $request + * @param Request $request Current request * @return JsonResponse - * @Route("/filter/") */ public function filterCallback(Request $request): JsonResponse { diff --git a/Controller/H5PController.php b/Controller/H5PController.php index e45b3fb..d4b2561 100644 --- a/Controller/H5PController.php +++ b/Controller/H5PController.php @@ -11,18 +11,16 @@ use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; use Emmedy\H5PBundle\Core\H5PIntegration; use Emmedy\H5PBundle\Form\Type\H5PType; -/** - * @Route("/h5p/") - */ +#[Route('/h5p/')] class H5PController extends AbstractController { - protected $h5PIntegrations; - protected $libraryStorage; - protected $entityManager; + protected H5PIntegration $h5PIntegrations; + protected LibraryStorage $libraryStorage; + protected EntityManagerInterface $entityManager; public function __construct( H5PIntegration $h5PIntegration, @@ -34,9 +32,10 @@ public function __construct( $this->entityManager = $entityManager; } + #[Route('list')] + /** - * List of all H5P content - * @Route("list") + * List of all H5P content. */ public function listAction(): Response { @@ -44,9 +43,10 @@ public function listAction(): Response return $this->render('@EmmedyH5P/list.html.twig', ['contents' => $contents]); } + #[Route('show/{content}')] + /** - * Show content of H5P created by user - * @Route("show/{content}") + * Show content of H5P created by user. * @param Content $content * @param \H5PCore $h5PCore * @param H5POptions $h5POptions @@ -78,13 +78,14 @@ public function showAction(Content $content, \H5PCore $h5PCore, H5POptions $h5PO 'contentId' => $content->getId(), 'isFrame' => $content->getLibrary()->isFrame(), 'h5pIntegration' => $h5pIntegration, - 'files' => $files + 'files' => $files, ] ); } + #[Route('new')] + /** - * @Route("new") * @param Request $request * @return RedirectResponse|Response */ @@ -93,8 +94,9 @@ public function newAction(Request $request) return $this->handleRequest($request); } + #[Route('edit/{content}')] + /** - * @Route("edit/{content}") * @param Request $request * @param Content $content * @return RedirectResponse|Response @@ -136,8 +138,9 @@ private function handleRequest(Request $request, Content $content = null) ); } + #[Route("delete/{contentId}")] + /** - * @Route("delete/{contentId}") * @param integer $contentId * @param \H5PStorage $h5PStorage * @return RedirectResponse diff --git a/Controller/H5PInteractionController.php b/Controller/H5PInteractionController.php index b636515..9facea1 100644 --- a/Controller/H5PInteractionController.php +++ b/Controller/H5PInteractionController.php @@ -17,23 +17,21 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\KernelInterface; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Serializer\SerializerInterface; -/** - * @Route("/h5p/interaction") - */ +#[Route('/h5p/interaction')] class H5PInteractionController extends AbstractController { - protected $entityManager; - protected $resultService; - protected $serializer; - protected $assetsPaths; - protected $options; - protected $h5PIntegration; - protected $h5PCore; - protected $kernel; + protected EntityManagerInterface $entityManager; + protected ResultService $resultService; + protected SerializerInterface $serializer; + protected Packages $assetsPaths; + protected H5POptions $options; + protected H5PIntegration $h5PIntegration; + protected H5PCore $h5PCore; + protected KernelInterface $kernel; public function __construct( EntityManagerInterface $entityManager, @@ -55,11 +53,12 @@ public function __construct( $this->kernel = $kernel; } + #[Route("/set-finished/{token}")] + /** - * Access callback for the setFinished feature + * Access callback for the setFinished feature. * - * @Route("/set-finished/{token}") - * @param Request $request + * @param Request $request Current request * @param $token * @return JsonResponse */ @@ -77,11 +76,12 @@ public function setFinished(Request $request, $token): JsonResponse return new JsonResponse(['success' => true]); } + #[Route("/content-user-data/{contentId}/{dataType}/{subContentId}")] + /** * Handles insert, updating and deleting content user data through AJAX. * - * @Route("/content-user-data/{contentId}/{dataType}/{subContentId}") - * @param Request $request + * @param Request $request Current request * @param $contentId * @param $dataType * @param $subContentId @@ -103,6 +103,7 @@ public function contentUserData(Request $request, $contentId, $dataType, $subCon if (!\H5PCore::validToken('contentuserdata', $request->get("token"))) { return new JsonResponse(['success' => false, 'message' => 'No content']); } + //remove data if data = 0 if ($data === '0') { //remove data here @@ -111,6 +112,7 @@ public function contentUserData(Request $request, $contentId, $dataType, $subCon // Wash values to ensure 0 or 1. $preload = ($preload === '0' ? 0 : 1); $invalidate = ($invalidate === '0' ? 0 : 1); + //get if exists /** * @var ContentUserData $update @@ -136,6 +138,7 @@ public function contentUserData(Request $request, $contentId, $dataType, $subCon $contentUserData->setPreloaded($preload); $contentUserData->setDeleteOnContentChange($invalidate); $contentUserData->setTimestamp(time()); + /** @var Content|null $content */ $content = $em->getRepository('Emmedy\H5PBundle\Entity\Content')->findOneBy(['id' => $contentId]); $contentUserData->setMainContent($content); @@ -153,7 +156,7 @@ public function contentUserData(Request $request, $contentId, $dataType, $subCon return new JsonResponse(['success' => true]); } else { - $data = $em->getRepository("Studit\H5PBundle\Entity\ContentUserData")->findOneBy([ + $data = $em->getRepository("Emmedy\H5PBundle\Entity\ContentUserData")->findOneBy([ 'subContentId' => $subContentId, 'mainContent' => $contentId, 'dataId' => $dataType, @@ -168,9 +171,10 @@ public function contentUserData(Request $request, $contentId, $dataType, $subCon } } + #[Route("/embed/{content}")] + /** - * @Route("/embed/{content}") - * @param Request $request + * @param Request $request Current request * @param Content $content * @return Response */ @@ -215,7 +219,7 @@ public function embedAction(Request $request, Content $content): Response 'title' => "H5P Content $id", ]; //include the embed file (provide in h5p-core) - include $this->kernel->getProjectDir() . '/vendor/h5p/h5p-core/embed.php'; + include_once $this->kernel->getProjectDir() . '/vendor/h5p/h5p-core/embed.php'; $response['#markup'] = ob_get_clean(); //return nes Response HTML return new Response($response['#markup']); diff --git a/Core/H5PIntegration.php b/Core/H5PIntegration.php index 75332bd..69511f8 100644 --- a/Core/H5PIntegration.php +++ b/Core/H5PIntegration.php @@ -19,31 +19,37 @@ class H5PIntegration extends H5PUtils /** * @var EntityManager */ - private $entityManager; + private EntityManager $entityManager; + /** * @var \H5PCore */ - private $core; + private \H5PCore $core; + /** * @var RouterInterface */ - private $router; + private RouterInterface $router; + /** * @var H5POptions */ - private $options; + private H5POptions $options; + /** * @var RequestStack */ - private $requestStack; + private RequestStack $requestStack; + /** * @var Packages */ - private $assetsPaths; + private Packages $assetsPaths; + /** * @var \H5PContentValidator */ - private $contentValidator; + private \H5PContentValidator $contentValidator; /** * H5PContent constructor. @@ -77,20 +83,25 @@ public function __construct( } /** - * Prepares the generic H5PIntegration settings + * Prepares the generic H5PIntegration settings. + * @return array|null */ - public function getGenericH5PIntegrationSettings() + public function getGenericH5PIntegrationSettings(): ?array { static $settings; if (!empty($settings)) { - return $settings; // Only needs to be generated the first time + // Only needs to be generated the first time + return $settings; } + // Load current user $user = $this->getCurrentOrAnonymousUser(); + // Load configuration settings $saveContentState = $this->options->getOption('save_content_state', false); $saveContentFrequency = $this->options->getOption('save_content_frequency', 30); $hubIsEnabled = $this->options->getOption('hub_is_enabled', true); + // Create AJAX URLs $setFinishedUrl = $this->router->generate('emmedy_h5p_h5pinteraction_setfinished', [ 'token' => \H5PCore::createToken('result') @@ -101,6 +112,7 @@ public function getGenericH5PIntegrationSettings() 'subContentId' => ':subContentId', 'token' => \H5PCore::createToken('contentuserdata') ]); + // Define the generic H5PIntegration settings $settings = [ 'baseUrl' => "/", @@ -179,7 +191,9 @@ public function getH5PContentIntegrationSettings(Content $content): array 'jsonContent' => $filteredParameters, 'fullScreen' => $content->getLibrary()->isFullscreen(), 'exportUrl' => $this->getExportUrl($content), - 'embedCode' => '', + 'embedCode' => '', 'resizeCode' => '', 'url' => $embedUrl, 'title' => 'Not Available', @@ -188,7 +202,7 @@ public function getH5PContentIntegrationSettings(Content $content): array ); } - public function getFilteredParameters(Content $content): ?string + public function getFilteredParameters(Content $content): string|object|null { $params = json_decode($content->getParameters()); $contentData = [ @@ -220,7 +234,7 @@ protected function getExportUrl(Content $content): string } } - public function getEditorIntegrationSettings($contentId = null) + public function getEditorIntegrationSettings($contentId = null): array { $editorSettings = [ 'filesPath' => $this->options->getRelativeH5PPath(), @@ -267,7 +281,7 @@ private function getEditorAssets(): array } /** - * Extracts assets from a collection of assets + * Extracts assets from a collection of assets. * * @param array $collection Collection of assets * @param string $prefix Prefix needed for constructing the file-path of the assets @@ -290,7 +304,7 @@ private function getAssets($collection, $prefix, $exceptions = null): array } /** - * Get cache buster + * Get cache buster. * * @return string A cache buster that may be applied to resources */ @@ -301,7 +315,7 @@ public function getCacheBuster(): string } /** - * Translation file path for the editor. Defaults to English if chosen + * Translation file path for the editor. Defaults to English if chosen. * language is not available. * * @return string Path to translation file for editor @@ -330,7 +344,7 @@ private function getH5PAssetUrl(): string } /** - * Access to direct access to the configuration to save time + * Access to direct access to the configuration to save time. * @return H5POptions */ public function getOptions(): H5POptions diff --git a/Core/H5POptions.php b/Core/H5POptions.php index 5b2501c..f57fa05 100644 --- a/Core/H5POptions.php +++ b/Core/H5POptions.php @@ -12,19 +12,21 @@ class H5POptions /** * @var array */ - private $config; + private array|null $config; + /** * @var array */ - private $storedConfig = null; + private array|null $storedConfig = null; private $h5pPath; private $folderPath; private $projectRootDir; + /** * @var EntityManagerInterface */ - private $manager; + private EntityManagerInterface $manager; /** * H5POptions constructor. @@ -40,15 +42,23 @@ public function __construct(?array $config, $projectRootDir, EntityManagerInterf } /** - * @param $name - * @param $default - * @return mixed|null + * Retrieves the value of a configuration option. + * + * This method fetches the specified configuration option's value. If the option is found in the cached + * `storedConfig`, it returns that value. If not, it checks the local `config` array. If the option is + * not found in either, it returns the provided default value. + * + * @param string $name The name of the configuration option. + * @param mixed $default The default value to return if the option is not found in either `storedConfig` or `config`. + * + * @return mixed|null The value of the configuration option, or the default value if the option is not set. */ public function getOption($name, $default = null) { try { $this->retrieveStoredConfig(); - } catch (DriverException $e) { + } catch (DriverException) { + // Suppress database errors and continue } if (isset($this->storedConfig[$name])) { @@ -61,9 +71,20 @@ public function getOption($name, $default = null) } /** - * @throws InvalidArgumentException + * Sets or updates a configuration option in the database. + * + * This method updates the value of a specified configuration option. If the option already exists + * and its current value differs from the provided value, the method updates it. If the option does + * not exist, it creates a new one. Changes are persisted to the database. + * + * @param string $name The name of the configuration option. + * @param string|int|null $value The value to set for the configuration option. + * + * @throws InvalidArgumentException If the provided option name or value is invalid. + * + * @return void */ - public function setOption($name, $value): void + public function setOption(string $name, string|int|null $value): void { $this->retrieveStoredConfig(); @@ -80,6 +101,12 @@ public function setOption($name, $value): void } /** + * Retrieves and caches configuration options from the database. + * + * This method loads all configuration options from the database if they haven't been loaded yet. + * The options are stored as key-value pairs in the `$storedConfig` property for easy access. + * If `storedConfig` is already populated, the method does nothing to avoid redundant database queries. + * * @return void */ private function retrieveStoredConfig(): void @@ -87,8 +114,10 @@ private function retrieveStoredConfig(): void if ($this->storedConfig === null) { $this->storedConfig = []; $options = $this->manager->getRepository('Emmedy\H5PBundle\Entity\Option')->findAll(); - foreach ($options as $option) { - $this->storedConfig[$option->getName()] = $option->getValue(); + if (!empty($options)) { + foreach ($options as $option) { + $this->storedConfig[$option->getName()] = $option->getValue(); + } } } } @@ -120,27 +149,33 @@ public function getUploadedH5pPath($set = null) } /** - * @return mixed|string|null + * Helper function to ensure storage_dir always starts with a '/'. + * + * @return string */ - public function getRelativeH5PPath() + private function formatStorageDir(): string { - $dir = $this->getOption('storage_dir'); - return $dir[0] === '/' ? $dir : '/' . $dir; + // Setup the default value to empty string + $dir = $this->getOption('storage_dir', [""]); + return $dir[0] === '/' ? $dir : "/{$dir}"; } - public function getAbsoluteH5PPathWithSlash(): string + /** + * @return string + */ + public function getRelativeH5PPath(): string { - $dir = $this->getOption('storage_dir'); - $dir = $dir[0] === '/' ? $dir : '/' . $dir; + return $this->formatStorageDir(); + } - return $this->getAbsoluteWebPath() . $dir . '/'; + public function getAbsoluteH5PPathWithSlash(): string + { + return $this->getAbsoluteWebPath() . $this->formatStorageDir() . '/'; } + public function getAbsoluteH5PPath(): string { - $dir = $this->getOption('storage_dir'); - $dir = $dir[0] === '/' ? $dir : '/' . $dir; - - return $this->getAbsoluteWebPath() . $dir; + return rtrim($this->getAbsoluteWebPath(), '/') . $this->formatStorageDir(); } public function getAbsoluteWebPath(): string diff --git a/Core/H5PSymfony.php b/Core/H5PSymfony.php index be5516d..22c0fc1 100644 --- a/Core/H5PSymfony.php +++ b/Core/H5PSymfony.php @@ -543,16 +543,16 @@ public function saveLibraryData(&$libraryData, $new = true) } /** - * Convert list of file paths to csv + * Convert list of file paths to csv. * - * @param array $libraryData * Library data as found in library.json files - * @param string $key * Key that should be found in $libraryData - * @return string * file paths separated by ', ' + * @param array $libraryData + * @param string $key + * @return string */ - private function pathsToCsv($libraryData, $key) + private function pathsToCsv(array $libraryData, string $key): string { if (isset($libraryData[$key])) { $paths = array(); diff --git a/Core/H5PUtils.php b/Core/H5PUtils.php index 058e54a..8443ef9 100644 --- a/Core/H5PUtils.php +++ b/Core/H5PUtils.php @@ -36,7 +36,7 @@ protected function getCurrentOrAnonymousUser() * @param UserInterface|null $user * @return string|null|integer */ - protected function getUserId(?UserInterface $user) + public function getUserId(?UserInterface $user) { if ($user !== null) { if (method_exists($user, 'getId')) { diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 20d080a..a75d61a 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -13,7 +13,7 @@ class Configuration implements ConfigurationInterface * version of Symfony H5P bundle * @return string */ - const H5P_VERSION = '2.1.0'; + const H5P_VERSION = '3.0.0'; /** * Generates the configuration tree. diff --git a/DependencyInjection/EmmedyH5PExtension.php b/DependencyInjection/EmmedyH5PExtension.php index 38a73dc..244f824 100644 --- a/DependencyInjection/EmmedyH5PExtension.php +++ b/DependencyInjection/EmmedyH5PExtension.php @@ -5,8 +5,7 @@ use Exception; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\Config\FileLocator; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\HttpKernel\DependencyInjection\Extension; +use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Loader; @@ -16,8 +15,9 @@ class EmmedyH5PExtension extends Extension /** * @inheritDoc * @throws Exception + * @return void */ - public function load(array $configs, ContainerBuilder $container) + public function load(array $configs, ContainerBuilder $container): void { $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); diff --git a/Editor/EditorAjax.php b/Editor/EditorAjax.php index 936417e..a7a88b1 100644 --- a/Editor/EditorAjax.php +++ b/Editor/EditorAjax.php @@ -46,7 +46,7 @@ public function getLatestLibraryVersions(): array /** - * Get locally stored Content Type Cache. If machine name is provided + * Get locally stored Content Type Cache. If machine name is provided. * it will only get the given content type from the cache * * @param $machineName diff --git a/Editor/EditorStorage.php b/Editor/EditorStorage.php index 71154a6..f35537d 100644 --- a/Editor/EditorStorage.php +++ b/Editor/EditorStorage.php @@ -115,11 +115,11 @@ public function getAvailableLanguages($machineName, $majorVersion, $minorVersion * "Callback" for mark the given file as a permanent file. * Used when saving content that has new uploaded files. * - * @param string $path To new file + * @param int $fileId To new file */ - public function keepFile($path) + public function keepFile($fileId) { - var_dump($path); + var_dump($fileId); } /** diff --git a/Editor/Utilities.php b/Editor/Utilities.php index 6862036..65ef5a2 100644 --- a/Editor/Utilities.php +++ b/Editor/Utilities.php @@ -9,12 +9,12 @@ class Utilities { /** - * Extract library information from library string + * Extract library information from library string. * * @param string $library Library string with versioning, e.g. H5P.MultiChoice 1.9 * @return array|bool */ - public static function getLibraryProperties($library) + public static function getLibraryProperties($library): array|bool { $matches = []; preg_match_all('/(.+)\s(\d+)\.(\d+)$/', $library, $matches); diff --git a/Entity/Content.php b/Entity/Content.php index 78af0c7..ab52423 100644 --- a/Entity/Content.php +++ b/Entity/Content.php @@ -4,49 +4,50 @@ use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity(repositoryClass="ContentRepository") - * @ORM\Table(name="h5p_content") - */ +#[ORM\Entity(repositoryClass: ContentRepository::class)] +#[ORM\Table(name: 'h5p_content')] class Content { + #[ORM\Id] + #[ORM\Column(type: "integer")] + #[ORM\GeneratedValue(strategy:"AUTO")] /** * @var int - * - * @ORM\Id - * @ORM\Column(type="integer") - * @ORM\GeneratedValue(strategy="AUTO") */ - private $id; + private ?int $id; + + #[ORM\ManyToOne(targetEntity: Library::class)] + #[ORM\JoinColumn(name: "library_id", referencedColumnName: "id", onDelete: "CASCADE")] /** * @var Library - * * @ORM\ManyToOne(targetEntity="\Emmedy\H5PBundle\Entity\Library") - * @ORM\JoinColumn(name="library_id", referencedColumnName="id", onDelete="CASCADE") */ - private $library; + private ?Library $library; + /** - * @var string - * - * @ORM\Column(name="parameters", type="text", nullable=true) + * @var string|null */ - private $parameters; + #[ORM\Column(name: "parameters", type: "text", nullable: true)] + private ?string $parameters; + + #[ORM\Column(name: "filtered_parameters", type: "text", nullable: true)] /** * @var string|null - * - * @ORM\Column(name="filtered_parameters", type="text", nullable=true) */ - private $filteredParameters; + private ?string $filteredParameters; + + #[ORM\Column(name: "disabled_features", type: "integer", nullable: true)] + /** - * @var int - * - * @ORM\Column(name="disabled_features", type="integer", nullable=true) + * @var int|null */ - private $disabledFeatures; - public function __clone() + private ?int $disabledFeatures; + + public function __clone(): void { $this->id = null; } + /** * @return int */ @@ -57,9 +58,10 @@ public function getId(): int /** * @param int $id */ - public function setId(int $id) + public function setId(int $id): self { $this->id = $id; + return $this; } /** * @return Library @@ -71,9 +73,10 @@ public function getLibrary(): Library /** * @param Library $library */ - public function setLibrary(Library $library) + public function setLibrary(Library $library): self { $this->library = $library; + return $this; } /** * @return string @@ -84,10 +87,12 @@ public function getParameters(): string } /** * @param string $parameters + * @return self */ - public function setParameters(string $parameters) + public function setParameters(string $parameters): self { $this->parameters = $parameters; + return $this; } /** * @return string|null @@ -100,9 +105,10 @@ public function getFilteredParameters(): ?string /** * @param string|null $filteredParameters */ - public function setFilteredParameters(?string $filteredParameters) + public function setFilteredParameters(?string $filteredParameters): self { $this->filteredParameters = $filteredParameters; + return $this; } /** * @return int @@ -113,9 +119,11 @@ public function getDisabledFeatures(): int } /** * @param int $disabledFeatures + * @return self */ - public function setDisabledFeatures(int $disabledFeatures) + public function setDisabledFeatures(int $disabledFeatures): self { $this->disabledFeatures = $disabledFeatures; + return $this; } } diff --git a/Entity/ContentLibraries.php b/Entity/ContentLibraries.php index 0dab310..bb3b1a7 100644 --- a/Entity/ContentLibraries.php +++ b/Entity/ContentLibraries.php @@ -5,115 +5,125 @@ use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity() - * @ORM\Table(name="h5p_content_libraries") - */ +#[ORM\Entity()] +#[ORM\Table(name: "h5p_content_libraries")] class ContentLibraries { + #[ORM\Id] + #[ORM\ManyToOne(targetEntity: Content::class)] + #[ORM\JoinColumn(name: "content_id", referencedColumnName: "id", onDelete: "CASCADE")] /** - * @var Content - * - * @ORM\Id - * @ORM\ManyToOne(targetEntity="\Emmedy\H5PBundle\Entity\Content") - * @ORM\JoinColumn(name="content_id", referencedColumnName="id", onDelete="CASCADE") + * @var Content|null */ - private $content; + private ?Content $content; + + #[ORM\Id] + #[ORM\ManyToOne(targetEntity: Library::class, inversedBy: "contentLibraries")] + #[ORM\JoinColumn(name: "library_id", referencedColumnName: "id", onDelete: "CASCADE")] + /** * @var Library - * - * @ORM\Id - * @ORM\ManyToOne(targetEntity="\Emmedy\H5PBundle\Entity\Library", inversedBy="contentLibraries") - * @ORM\JoinColumn(name="library_id", referencedColumnName="id", onDelete="CASCADE") */ - private $library; + private ?Library $library; + + #[ORM\Id()] + #[ORM\Column(name: "dependency_type", type: "string", length: 31)] + /** - * @var int - * - * @ORM\Id - * @ORM\Column(name="dependency_type", type="string", length=31) + * @var null|string */ - private $dependencyType; + private null|string $dependencyType; + + #[ORM\Column(name: "drop_css", type: "boolean", length: 1)] /** - * @var bool - * - * @ORM\Column(name="drop_css", type="string", length=1) + * @var bool|null */ - private $dropCss; + private ?bool $dropCss; /** - * @var int - * - * @ORM\Column(name="weight", type="integer") + * @var int|null */ - private $weight; + #[ORM\Column(name: "weight", type: "integer")] + private ?int $weight; + /** - * @return Content + * @return Content|null */ - public function getContent() + public function getContent(): ?Content { return $this->content; } /** - * @param Content $content + * @param Content|null $content + * @return self */ - public function setContent($content) + public function setContent(?Content $content): self { $this->content = $content; + return $this; } + /** * @return Library */ - public function getLibrary() + public function getLibrary(): Library { return $this->library; } + /** * @param Library $library + * @return self */ - public function setLibrary($library) + public function setLibrary($library): self { $this->library = $library; + return $this; } + /** - * @return int + * @return string|null */ - public function getDependencyType() + public function getDependencyType(): ?string { return $this->dependencyType; } /** - * @param int $dependencyType + * @param null|string $dependencyType + * @return self */ - public function setDependencyType($dependencyType) + public function setDependencyType(?string $dependencyType): self { $this->dependencyType = $dependencyType; + return $this; } /** * @return bool */ - public function isDropCss() + public function isDropCss(): ?bool { return $this->dropCss; } /** * @param bool $dropCss */ - public function setDropCss($dropCss) + public function setDropCss($dropCss): self { $this->dropCss = $dropCss; + return $this; } /** * @return int */ - public function getWeight() + public function getWeight(): ?int { return $this->weight; } /** * @param int $weight */ - public function setWeight($weight) + public function setWeight($weight): self { $this->weight = $weight; + return $this; } } diff --git a/Entity/ContentResult.php b/Entity/ContentResult.php index 225f121..f35364b 100644 --- a/Entity/ContentResult.php +++ b/Entity/ContentResult.php @@ -5,63 +5,54 @@ use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity() - * @ORM\Table(name="h5p_content_result") - */ +#[ORM\Entity()] +#[ORM\Table(name: "h5p_content_result")] class ContentResult { /** * @var integer - * - * @ORM\Id - * @ORM\Column(type="integer") - * @ORM\GeneratedValue(strategy="AUTO") */ - private $id; + #[ORM\Id] + #[ORM\Column(type: 'integer')] + #[ORM\GeneratedValue(strategy:"AUTO")] + private ?int $id; /** - * @var Content - * - * @ORM\ManyToOne(targetEntity="Emmedy\H5PBundle\Entity\Content") - * @ORM\JoinColumn(onDelete="CASCADE") + * @var Content|null */ - private $content; + #[ORM\ManyToOne(targetEntity: Content::class)] + #[ORM\JoinColumn(onDelete:"CASCADE")] + private ?Content $content; /** - * @var string - * - * @ORM\Column(type="string", nullable=false) + * @var string|int|null */ - private $userId; + #[ORM\Column(type: "string", nullable: false)] + private string|int|null $userId; + /** - * @var integer|null - * - * @ORM\Column(type="integer", nullable=true) + * @var int|null */ - private $score; + #[ORM\Column(type: "integer", nullable: true)] + private ?int $score; /** - * @var integer|null - * - * @ORM\Column(type="integer", nullable=true) + * @var int|null */ + #[ORM\Column(type: "integer", nullable: true)] private $maxScore; /** - * @var integer|null - * - * @ORM\Column(type="integer", nullable=true) + * @var int|null */ - private $opened; + #[ORM\Column(type: "integer", nullable: true)] + private ?int $opened; /** - * @var integer|null - * - * @ORM\Column(type="integer", nullable=true) + * @var int|null */ - private $finished; + #[ORM\Column(type: "integer", nullable: true)] + private ?int $finished; /** - * @var integer|null - * - * @ORM\Column(type="integer", nullable=true) + * @var int|null */ - private $time; + #[ORM\Column(type: "integer", nullable: true)] + private ?int $time; /** * ContentResult constructor. * @param string $userId diff --git a/Entity/ContentUserData.php b/Entity/ContentUserData.php index cd6e625..db99120 100644 --- a/Entity/ContentUserData.php +++ b/Entity/ContentUserData.php @@ -5,175 +5,189 @@ use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity() - * @ORM\Table(name="h5p_content_user_data") - */ + #[ORM\Entity()] + #[ORM\Table(name: "h5p_content_user_data")] class ContentUserData { + #[ORM\Id] + #[ORM\Column(name: "user_id", type: "integer")] /** - * @var integer - * - * @ORM\Id - * @ORM\Column(name="user_id", type="integer") + * @var int|null */ - private $user; + private ?int $user; /** - * @var Content - * - * @ORM\Id - * @ORM\ManyToOne(targetEntity="\Emmedy\H5PBundle\Entity\Content") - * @ORM\JoinColumn(name="content_main_id", referencedColumnName="id", onDelete="CASCADE") + * @var Content|null */ - private $mainContent; + #[ORM\Id] + #[ORM\ManyToOne(targetEntity: Content::class)] + #[ORM\JoinColumn(name: "content_main_id", referencedColumnName:"id", onDelete: 'CASCADE')] + private ?Content $mainContent; + + #[ORM\Id] + #[ORM\Column(name: "sub_content_id", type: "integer", length: 10)] + /** - * @var integer - * - * @ORM\Id - * @ORM\Column(name="sub_content_id", type="integer", length=10) + * @var int|null */ - private $subContentId; + private ?int $subContentId; + + #[ORM\Id] + #[ORM\Column(name: "data_id", type: "string", length: 127)] /** - * @var integer - * - * @ORM\Id - * @ORM\Column(name="data_id", type="string", length=127) + * @var string|null */ - private $dataId; + private ?string $dataId; + /** - * @var integer - * - * @ORM\Column(name="timestamp", type="integer", length=10) + * @var int|null */ - private $timestamp; + #[ORM\Column(name: "timestamp", type: "integer", length: 10)] + private ?int $timestamp; + + #[ORM\Column(name: "data", type: "text")] /** - * @var string - * - * @ORM\Column(name="data", type="text") + * @var string|null */ - private $data; + private ?string $data; + /** - * @var boolean - * - * @ORM\Column(name="preloaded", type="boolean", nullable=true) + * @var bool|null */ - private $preloaded; + #[ORM\Column(name: "preloaded", type: "boolean", nullable: true)] + private ?bool $preloaded; + + #[ORM\Column(name: "delete_on_content_change", type: "boolean", nullable: true)] /** - * @var boolean - * - * @ORM\Column(name="delete_on_content_change", type="boolean", nullable=true) + * @var bool|null */ - private $deleteOnContentChange; + private ?bool $deleteOnContentChange; + /** - * @return integer + * @return int|null */ - public function getUser() + public function getUser(): ?int { return $this->user; } + /** - * @param integer $user + * @param null|int $user + * @return self */ - public function setUser($user) + public function setUser(?int $user): self { $this->user = $user; + return $this; } /** - * @return Content + * @return Content|null */ - public function getMainContent() + public function getMainContent(): ?Content { return $this->mainContent; } /** * @param Content $mainContent + * @return self */ - public function setMainContent($mainContent) + public function setMainContent(?Content $mainContent): self { $this->mainContent = $mainContent; + return $this; } + /** - * @return int + * @return int|null */ - public function getSubContentId() + public function getSubContentId(): ?int { return $this->subContentId; } + /** * @param int $subContentId */ - public function setSubContentId($subContentId) + public function setSubContentId($subContentId): self { $this->subContentId = $subContentId; + return $this; } + /** - * @return int + * @return int|string|null */ public function getDataId() { return $this->dataId; } + /** * @param int $dataId */ - public function setDataId($dataId) + public function setDataId(null|int|string $dataId): self { $this->dataId = $dataId; + return $this; } + /** * @return int */ - public function getTimestamp() + public function getTimestamp(): ?int { return $this->timestamp; } /** * @param int $timestamp */ - public function setTimestamp($timestamp) + public function setTimestamp($timestamp): self { $this->timestamp = $timestamp; + return $this; } /** * @return string */ - public function getData() + public function getData(): ?string { return $this->data; } /** * @param string $data */ - public function setData($data) + public function setData($data): self { $this->data = $data; + return $this; } /** - * @return bool + * @return bool|null */ - public function isPreloaded() + public function isPreloaded(): ?bool { return $this->preloaded; } /** * @param bool $preloaded */ - public function setPreloaded($preloaded) + public function setPreloaded(bool $preloaded): self { $this->preloaded = $preloaded; + return $this; } /** * @return bool */ - public function isDeleteOnContentChange() + public function isDeleteOnContentChange(): ?bool { return $this->deleteOnContentChange; } /** * @param bool $deleteOnContentChange */ - public function setDeleteOnContentChange($deleteOnContentChange) + public function setDeleteOnContentChange($deleteOnContentChange): self { $this->deleteOnContentChange = $deleteOnContentChange; + return $this; } } diff --git a/Entity/Counters.php b/Entity/Counters.php index 7b116c7..b96541b 100644 --- a/Entity/Counters.php +++ b/Entity/Counters.php @@ -5,39 +5,36 @@ use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity() - * @ORM\Table(name="h5p_counters") - */ +#[ORM\Entity()] +#[ORM\Table(name: "h5p_counters")] class Counters { + #[ORM\Id] + #[ORM\Column(name: "type", type: "string", length: 63)] /** - * @var string - * - * @ORM\Id - * @ORM\Column(name="type", type="string", length=63) + * @var string|null */ - private $type; + private ?string $type; + /** - * @var string - * - * @ORM\Id - * @ORM\Column(name="library_name", type="string", length=127) + * @var string|null */ - private $libraryName; + #[ORM\Id] + #[ORM\Column(name: "library_name", type: "string", length: 127)] + private ?string $libraryName; + /** - * @var string - * - * @ORM\Id - * @ORM\Column(name="library_version", type="string", length=31) + * @var string|null */ - private $libraryVersion; + #[ORM\Id] + #[ORM\Column(name: "library_version", type: "string", length: 31)] + private ?string $libraryVersion; + /** - * @var integer - * - * @ORM\Column(name="num", type="integer") + * @var int|null */ - private $num; + #[ORM\Column(name: "num", type: "integer")] + private ?int $num; /** * @return string */ @@ -87,11 +84,14 @@ public function getNum() { return $this->num; } + /** - * @param int $num + * @param int $num + * @return self */ - public function setNum($num) + public function setNum($num): self { $this->num = $num; + return $this; } } diff --git a/Entity/Event.php b/Entity/Event.php index b6b13a4..0fad16a 100644 --- a/Entity/Event.php +++ b/Entity/Event.php @@ -5,193 +5,222 @@ use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity(repositoryClass="EventRepository") - * @ORM\Table(name="h5p_event") - */ +#[ORM\Entity(repositoryClass: EventRepository::class)] +#[ORM\Table('h5p_event')] class Event { + #[ORM\Id] + #[ORM\Column(type:"integer")] + #[ORM\GeneratedValue(strategy: "AUTO")] + /** * @var integer - * - * @ORM\Id - * @ORM\Column(type="integer") - * @ORM\GeneratedValue(strategy="AUTO") */ - private $id; + private ?int $id; + + #[ORM\Column(name: 'user_id', type: "integer")] /** * @var integer - * - * @ORM\Column(name="user_id", type="integer") */ - private $user; + private ?int $user; + + #[ORM\Column(name: 'created_at', type: "integer")] /** * @var integer - * - * @ORM\Column(name="created_at", type="integer") */ - private $createdAt; + private ?int $createdAt; + + #[ORM\Column(name: "type", type: "string", length: 63)] /** * @var string - * - * @ORM\Column(name="type", type="string", length=63) */ - private $type; + private ?string $type; + /** * @var string - * - * @ORM\Column(name="sub_type", type="string", length=63) */ - private $subType; + #[ORM\Column(name: "sub_type", type: "string", length: 63)] + private ?string $subType; + + #[ORM\ManyToOne(targetEntity: Content::class)] + #[ORM\JoinColumn(name: "content_id", referencedColumnName: "id", onDelete: 'CASCADE')] /** * @var Content - * - * @ORM\ManyToOne(targetEntity="\Emmedy\H5PBundle\Entity\Content") - * @ORM\JoinColumn(name="content_id", referencedColumnName="id", onDelete="CASCADE") */ - private $content; + private ?Content $content; + + #[ORM\Column(name: "content_title", type: "string", length: 255)] + /** * @var string - * - * @ORM\Column(name="content_title", type="string", length=255) */ - private $contentTitle; + private ?string $contentTitle; + + #[ORM\Column(name: "library_name", type: "string", length: 127)] + /** * @var string - * - * @ORM\Column(name="library_name", type="string", length=127) */ - private $libraryName; + private ?string $libraryName; + + #[ORM\Column(name: "library_version", type: "string", length: 31)] + /** * @var string - * - * @ORM\Column(name="library_version", type="string", length=31) */ - private $libraryVersion; + private ?string $libraryVersion; + /** - * @return integer + * @return integer|null */ - public function getId() + public function getId(): ?int { return $this->id; } /** - * @param integer $id + * @param int|null $id + * @return self */ - public function setId($id) + public function setId(?int $id): self { $this->id = $id; + return $this; } + /** - * @return integer + * @return int|null */ - public function getUser() + public function getUser(): ?int { return $this->user; } /** - * @param integer $user + * @param int|null $user Current user */ - public function setUser($user) + public function setUser(?int $user): self { $this->user = $user; + return $this; } /** - * @return integer + * @return int|null */ - public function getCreatedAt() + public function getCreatedAt(): ?int { return $this->createdAt; } + /** - * @param integer $createdAt + * @param int|null $createdAt */ - public function setCreatedAt($createdAt) + public function setCreatedAt(?int $createdAt): self { $this->createdAt = $createdAt; + return $this; } + /** - * @return string + * @return string|null */ - public function getType() + public function getType(): ?string { return $this->type; } /** * @param string $type + * @return self */ - public function setType($type) + public function setType($type): self { $this->type = $type; + return $this; } + /** - * @return string + * @return string|null */ - public function getSubType() + public function getSubType(): ?string { return $this->subType; } /** - * @param string $subType + * @param string|null $subType + * @return self */ - public function setSubType($subType) + public function setSubType(?string $subType): self { $this->subType = $subType; + return $this; } + /** - * @return Content + * @return Content|null */ - public function getContent() + public function getContent(): ?Content { return $this->content; } + /** * @param Content $content + * @return self */ - public function setContent($content) + public function setContent(Content $content): self { $this->content = $content; + return $this; } + /** - * @return string + * @return string|null */ - public function getContentTitle() + public function getContentTitle(): ?string { return $this->contentTitle; } + /** - * @param string $contentTitle + * @param string|null $contentTitle + * @return self */ - public function setContentTitle($contentTitle) + public function setContentTitle(?string $contentTitle): self { $this->contentTitle = $contentTitle; + return $this; } + /** * @return string */ - public function getLibraryName() + public function getLibraryName(): ?string { return $this->libraryName; } /** * @param string $libraryName + * @return self */ - public function setLibraryName($libraryName) + public function setLibraryName(string $libraryName): self { $this->libraryName = $libraryName; + return $this; } + /** - * @return string + * @return string|null */ - public function getLibraryVersion() + public function getLibraryVersion(): ?string { return $this->libraryVersion; } + /** * @param string $libraryVersion + * @return self */ - public function setLibraryVersion($libraryVersion) + public function setLibraryVersion(string $libraryVersion): self { $this->libraryVersion = $libraryVersion; + return $this; } } diff --git a/Entity/EventRepository.php b/Entity/EventRepository.php index f4e5000..9d1325b 100644 --- a/Entity/EventRepository.php +++ b/Entity/EventRepository.php @@ -16,7 +16,7 @@ public function __construct(ManagerRegistry $registry) parent::__construct($registry, Event::class); } - public function findRecentlyUsedLibraries($userId) + public function findRecentlyUsedLibraries($userId): array { $qb = $this->createQueryBuilder('e') ->select('e.libraryName, MAX(e.createdAt) as max_created_at') diff --git a/Entity/LibrariesHubCache.php b/Entity/LibrariesHubCache.php index c1b3779..97ff4d6 100644 --- a/Entity/LibrariesHubCache.php +++ b/Entity/LibrariesHubCache.php @@ -5,146 +5,136 @@ use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity() - * @ORM\Table(name="h5p_libraries_hub_cache") - */ +#[ORM\Entity()] +#[ORM\Table('h5p_libraries_hub_cache')] class LibrariesHubCache { /** - * @var integer - * - * @ORM\Id - * @ORM\Column(name="id", type="integer") - * @ORM\GeneratedValue(strategy="AUTO") + * @var int|null */ - private $id; + #[ORM\Id] + #[ORM\Column(name: "id", type: 'integer')] + #[ORM\GeneratedValue(strategy:"AUTO")] + + private ?int $id; /** - * @var string - * - * @ORM\Column(name="machine_name", type="string", length=127) + * @var string|null */ - private $machineName; + #[ORM\Column(name: "machine_name", type: "string", length: 127)] + private ?string $machineName; /** - * @var int - * - * @ORM\Column(name="major_version", type="integer") + * @var int|null */ - private $majorVersion; + #[ORM\Column(name: "major_version", type: "integer")] + private ?int $majorVersion; + /** - * @var int - * - * @ORM\Column(name="minor_version", type="integer") + * @var int|null */ - private $minorVersion; + #[ORM\Column(name: "minor_version", type: "integer")] + private ?int $minorVersion; /** - * @var int - * - * @ORM\Column(name="patch_version", type="integer") + * @var int|null */ - private $patchVersion; + #[ORM\Column(name: "patch_version", type: "integer")] + private ?int $patchVersion; /** - * @var int - * - * @ORM\Column(name="h5p_major_version", type="integer", nullable=true) + * @var int|null */ - private $h5pMajorVersion; + #[ORM\Column(name: "h5p_major_version", type: "integer", nullable: true)] + private ?int $h5pMajorVersion; + /** - * @var int - * - * @ORM\Column(name="h5p_minor_version", type="integer", nullable=true) + * @var int|null */ - private $h5pMinorVersion; + #[ORM\Column(name: "h5p_minor_version", type: "integer", nullable: true)] + private ?int $h5pMinorVersion; /** - * @var string - * - * @ORM\Column(name="title", type="string", length=255) + * @var string|null */ - private $title; + #[ORM\Column(name: "title", type: "string", length: 255)] + private ?string $title; /** - * @var string - * - * @ORM\Column(name="summary", type="text") + * @var string|null */ - private $summary; + #[ORM\Column(name: "summary", type: "text")] + private ?string $summary; + /** - * @var string - * - * @ORM\Column(name="description", type="text") + * @var string|null */ - private $description; + #[ORM\Column(name: "description", type: "text")] + private ?string $description; /** - * @var string - * - * @ORM\Column(name="icon", type="text") + * @var string|null */ - private $icon; + #[ORM\Column(name: "icon", type: "text")] + private ?string $icon; /** - * @var integer - * - * @ORM\Column(name="created_at", type="integer") + * @var int|null */ - private $createdAt; + #[ORM\Column(name: "created_at", type: "integer")] + private ?int $createdAt; /** - * @var integer - * - * @ORM\Column(name="updated_at", type="integer") + * @var int|null */ - private $updatedAt; + #[ORM\Column(name: "updated_at", type: "integer")] + private ?int $updatedAt; + /** - * @var boolean - * - * @ORM\Column(name="is_recommended", type="boolean", options={"default": 1}) + * @var bool */ - private $isRecommended = true; + #[ORM\Column(name: "is_recommended", type: "boolean", options: ["default" => 1])] + private bool $isRecommended = true; + /** - * @var integer - * - * @ORM\Column(name="popularity", type="integer") + * @var int|null */ - private $popularity = false; + #[ORM\Column(name: "popularity", type: "integer")] + private ?int $popularity = 0; + + #[ORM\Column(name: "screenshots", type: "text", nullable: true)] + /** - * @var string - * - * @ORM\Column(name="screenshots", type="text", nullable=true) + * @var string|null */ - private $screenshots; + private ?string $screenshots; + #[ORM\Column(name: "license", type: "text", nullable: true)] /** - * @var string - * - * @ORM\Column(name="license", type="text", nullable=true) + * @var string|null */ - private $license; + private ?string $license; + + #[ORM\Column(name: "example", type: "text")] /** - * @var string - * - * @ORM\Column(name="example", type="text") + * @var string|null */ - private $example; + private ?string $example; + + #[ORM\Column(name: "tutorial", type: "text", nullable: true)] + /** - * @var string - * - * @ORM\Column(name="tutorial", type="text", nullable=true) + * @var string|null */ - private $tutorial; + private ?string $tutorial; /** - * @var string - * - * @ORM\Column(name="keywords", type="text", nullable=true) + * @var string|null */ - private $keywords; + #[ORM\Column(name: "keywords", type: "text", nullable: true)] + private ?string $keywords; + + #[ORM\Column(name: "categories", type: "text", nullable: true)] /** - * @var string - * - * @ORM\Column(name="categories", type="text", nullable=true) + * @var string|null */ - private $categories; + private ?string $categories; + + #[ORM\Column(name: "owner", type: "text", nullable: true)] /** - * @var string - * - * @ORM\Column(name="owner", type="text", nullable=true) + * @var string|null */ - private $owner; + private ?string $owner; + public function __get($name) { $name = \H5PCore::snakeToCamel([$name => 1]); diff --git a/Entity/LibrariesLanguages.php b/Entity/LibrariesLanguages.php index 54e435b..ccd357f 100644 --- a/Entity/LibrariesLanguages.php +++ b/Entity/LibrariesLanguages.php @@ -5,33 +5,28 @@ use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity(repositoryClass="LibrariesLanguagesRepository") - * @ORM\Table(name="h5p_libraries_languages") - */ +#[ORM\Entity(repositoryClass: LibrariesLanguagesRepository::class)] +#[ORM\Table(name: "h5p_libraries_languages")] class LibrariesLanguages { /** - * @var Library - * - * @ORM\Id - * @ORM\ManyToOne(targetEntity="\Emmedy\H5PBundle\Entity\Library") - * @ORM\JoinColumn(name="library_id", referencedColumnName="id", onDelete="CASCADE") + * @var Library|null */ - private $library; + #[ORM\Id] + #[ORM\ManyToOne(targetEntity: Library::class)] + #[ORM\JoinColumn(name: "library_id", referencedColumnName: "id", onDelete: "CASCADE")] + private ?Library $library; /** - * @var string - * - * @ORM\Id - * @ORM\Column(name="language_code", type="string", length=31) + * @var string|null */ - private $languageCode; + #[ORM\Id] + #[ORM\Column(name: "language_code", type: "string", length: 31)] + private ?string $languageCode; /** - * @var string - * - * @ORM\Column(name="language_json", type="text") + * @var string|null */ - private $languageJson; + #[ORM\Column(name: "language_json", type: "text")] + private ?string $languageJson; /** * @return Library */ diff --git a/Entity/Library.php b/Entity/Library.php index f9669c1..9efd8d5 100644 --- a/Entity/Library.php +++ b/Entity/Library.php @@ -4,137 +4,133 @@ namespace Emmedy\H5PBundle\Entity; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity(repositoryClass="LibraryRepository") - * @ORM\Table(name="h5p_library") - */ +#[ORM\Entity(repositoryClass: LibraryRepository::class)] +#[ORM\Table(name: 'h5p_library')] class Library { + #[ORM\Id] + #[ORM\Column(type:"integer")] + #[ORM\GeneratedValue(strategy: "AUTO")] + /** - * @var int - * - * @ORM\Id - * @ORM\Column(type="integer") - * @ORM\GeneratedValue(strategy="AUTO") + * @var int|null */ - private $id; + private ?int $id; /** - * @var string - * - * @ORM\Column(name="machine_name", type="string", length=127) + * @var string|null */ - private $machineName; + #[ORM\Column(name: "machine_name", type: "string", length: 127)] + private ?string $machineName; + + #[ORM\Column(name: "title", type: "string", length: 255)] + /** - * @var string - * - * @ORM\Column(name="title", type="string", length=255) + * @var string|null */ - private $title; + private ?string $title; + + #[ORM\Column(name: "major_version", type: "integer")] /** - * @var int - * - * @ORM\Column(name="major_version", type="integer") + * @var int|null */ - private $majorVersion; + private ?int $majorVersion; + + #[ORM\Column(name: "minor_version", type: "integer")] /** - * @var int - * - * @ORM\Column(name="minor_version", type="integer") + * @var int|null */ - private $minorVersion; + private ?int $minorVersion; + + #[ORM\Column(name: "patch_version", type: "integer")] + /** - * @var int - * - * @ORM\Column(name="patch_version", type="integer") + * @var int|null */ - private $patchVersion; + private ?int $patchVersion; /** - * @var boolean - * @ORM\Column(name="patch_version_in_folder_name", type="boolean", options={"default": 0}) + * @var bool */ - private $patchVersionInFolderName = false; + #[ORM\Column(name: "patch_version_in_folder_name", type: "boolean", options: [ "default" => 0])] + private bool $patchVersionInFolderName = false; + + #[ORM\Column(name: "runnable", type: "boolean", options: [ "default" => 1])] + /** - * @var boolean - * - * @ORM\Column(name="runnable", type="boolean", options={"default": 1}) + * @var bool */ - private $runnable = true; + private bool $runnable = true; + + #[ORM\Column(name: "fullscreen", type: "boolean", options: [ "default" => 0])] /** * @var boolean - * - * @ORM\Column(name="fullscreen", type="boolean", options={"default": 0}) */ - private $fullscreen = false; + private bool $fullscreen = false; + + #[ORM\Column(name: "embed_types", type: "string", length: 255)] /** - * @var string - * - * @ORM\Column(name="embed_types", type="string", length=255) + * @var string|null */ - private $embedTypes; + private ?string $embedTypes; + /** - * @var string - * - * @ORM\Column(name="preloaded_js", type="text", nullable=true) + * @var string|null */ - private $preloadedJs; + #[ORM\Column(name: "preloaded_js", type: "text", nullable: true)] + private ?string $preloadedJs; /** - * @var string - * - * @ORM\Column(name="preloaded_css", type="text", nullable=true) + * @var string|null */ - private $preloadedCss; + #[ORM\Column(name: "preloaded_css", type: "text", nullable: true)] + private ?string $preloadedCss; /** - * @var string - * - * @ORM\Column(name="drop_library_css", type="text", nullable=true) + * @var string|null */ - private $dropLibraryCss; + #[ORM\Column(name: "drop_library_css", type: "text", nullable: true)] + private ?string $dropLibraryCss; /** - * @var string - * - * @ORM\Column(name="semantics", type="text") + * @var string|null */ - private $semantics; + #[ORM\Column(name: "semantics", type: "text")] + private ?string $semantics; + + #[ORM\Column(name: "restricted", type: "boolean", options: ['default' => 0])] /** - * @var boolean - * - * @ORM\Column(name="restricted", type="boolean", options={"default": 0}) + * @var bool */ - private $restricted = false; + private bool $restricted = false; + /** - * @var string - * - * @ORM\Column(name="tutorial_url", type="string", length=1000, nullable=true) + * @var string|null */ - private $tutorialUrl; + #[ORM\Column(name: "tutorial_url", type: "string", length: 1000, nullable: true)] + private ?string $tutorialUrl; + /** * @var boolean - * - * @ORM\Column(name="has_icon", type="boolean", options={"default": 0}) */ - private $hasIcon = false; + #[ORM\Column(name: "has_icon", type: "boolean", options: ['default' => 0])] + private bool $hasIcon = false; + + #[ORM\OneToMany(targetEntity: ContentLibraries::class, mappedBy: "library")] /** - * @var ArrayCollection - * - * @ORM\OneToMany(targetEntity="Emmedy\H5PBundle\Entity\ContentLibraries", mappedBy="library") + * @var ArrayCollection|Collection */ - private $contentLibraries; + private ArrayCollection|Collection $contentLibraries; /** - * @var string - * - * @ORM\Column(name="metadata_settings", type="text", nullable=true) + * @var string|null */ - private $metadataSettings; + #[ORM\Column(name: "metadata_settings", type: "text", nullable: true)] + private ?string $metadataSettings; /** - * @var string - * - * @ORM\Column(name="add_to", type="text", nullable=true) + * @var string|null */ - private $addTo; + #[ORM\Column(name: "add_to", type: "text", nullable: true)] + private ?string $addTo; public function __get($name) { @@ -171,230 +167,256 @@ public function __toString(): string return "{$this->machineName} {$this->majorVersion}.{$this->minorVersion}"; } /** - * @return int + * @return int|null */ - public function getId() + public function getId(): ?int { return $this->id; } /** * @param int $id + * @return self */ - public function setId($id) + public function setId(?int $id): self { $this->id = $id; + return $this; } + /** - * @return string + * @return string|null */ - public function getMachineName() + public function getMachineName(): ?string { return $this->machineName; } /** * @param string $machineName + * @return self */ - public function setMachineName($machineName) + public function setMachineName($machineName): self { $this->machineName = $machineName; + return $this; } /** - * @return string + * @return string|null */ - public function getTitle() + public function getTitle(): ?string { return $this->title; } /** * @param string $title + * @return self */ - public function setTitle($title) + public function setTitle($title): self { $this->title = $title; + return $this; } /** - * @return int + * @return int|null */ - public function getMajorVersion() + public function getMajorVersion(): ?int { return $this->majorVersion; } + /** * @param int $majorVersion + * @return self */ - public function setMajorVersion($majorVersion) + public function setMajorVersion($majorVersion): self { $this->majorVersion = $majorVersion; + return $this; } /** - * @return int + * @return int|null */ - public function getMinorVersion() + public function getMinorVersion(): ?int { return $this->minorVersion; } /** - * @param int $minorVersion + * @param int|null $minorVersion + * @return self */ - public function setMinorVersion($minorVersion) + public function setMinorVersion(?int $minorVersion): self { $this->minorVersion = $minorVersion; + return $this; } /** * @return int */ - public function getPatchVersion() + public function getPatchVersion(): ?int { return $this->patchVersion; } /** * @param int $patchVersion + * @return self */ - public function setPatchVersion($patchVersion) + public function setPatchVersion(?int $patchVersion): self { $this->patchVersion = $patchVersion; + return $this; } /** * @return bool */ - public function isRunnable() + public function isRunnable(): bool { return $this->runnable; } /** * @param bool $runnable */ - public function setRunnable($runnable) + public function setRunnable($runnable): self { $this->runnable = $runnable; + return $this; } /** * @return bool */ - public function isFullscreen() + public function isFullscreen(): bool { return $this->fullscreen; } /** * @param bool $fullscreen */ - public function setFullscreen($fullscreen) + public function setFullscreen($fullscreen): self { $this->fullscreen = $fullscreen; + return $this; } /** * @return string */ - public function getEmbedTypes() + public function getEmbedTypes(): ?string { return $this->embedTypes; } /** * @param string $embedTypes */ - public function setEmbedTypes($embedTypes) + public function setEmbedTypes($embedTypes): self { $this->embedTypes = $embedTypes; + return $this; } /** * @return string */ - public function getPreloadedJs() + public function getPreloadedJs(): ?string { return $this->preloadedJs; } /** * @param string $preloadedJs */ - public function setPreloadedJs($preloadedJs) + public function setPreloadedJs($preloadedJs): self { $this->preloadedJs = $preloadedJs; + return $this; } /** * @return string */ - public function getPreloadedCss() + public function getPreloadedCss(): ?string { return $this->preloadedCss; } /** * @param string $preloadedCss */ - public function setPreloadedCss($preloadedCss) + public function setPreloadedCss($preloadedCss): self { $this->preloadedCss = $preloadedCss; + return $this; } /** * @return string */ - public function getDropLibraryCss() + public function getDropLibraryCss(): ?string { return $this->dropLibraryCss; } /** * @param string $dropLibraryCss */ - public function setDropLibraryCss($dropLibraryCss) + public function setDropLibraryCss($dropLibraryCss): self { $this->dropLibraryCss = $dropLibraryCss; + return $this; } /** - * @return string + * @return string|null */ - public function getSemantics() + public function getSemantics(): ?string { return $this->semantics; } /** * @param string $semantics + * @return self */ - public function setSemantics($semantics) + public function setSemantics($semantics): self { $this->semantics = $semantics; + return $this; } /** * @return bool */ - public function isRestricted() + public function isRestricted(): bool { return $this->restricted; } /** * @param bool $restricted */ - public function setRestricted($restricted) + public function setRestricted($restricted): self { $this->restricted = $restricted; + return $this; } /** * @return string */ - public function getTutorialUrl() + public function getTutorialUrl(): ?string { return $this->tutorialUrl; } /** * @param string $tutorialUrl + * @return self */ - public function setTutorialUrl($tutorialUrl) + public function setTutorialUrl($tutorialUrl): self { $this->tutorialUrl = $tutorialUrl; + return $this; } /** * @return bool */ - public function isHasIcon() + public function isHasIcon(): bool { return $this->hasIcon; } /** * @param bool $hasIcon */ - public function setHasIcon($hasIcon) + public function setHasIcon(bool $hasIcon): self { $this->hasIcon = $hasIcon; + return $this; } - public function isFrame() + public function isFrame(): bool { return (strpos($this->embedTypes, 'iframe') !== false); } @@ -402,7 +424,7 @@ public function isFrame() /** * @return string */ - public function getMetadataSettings() + public function getMetadataSettings(): ?string { return $this->metadataSettings; } @@ -410,15 +432,16 @@ public function getMetadataSettings() /** * @param string $metadataSettings */ - public function setMetadataSettings($metadataSettings) + public function setMetadataSettings(string $metadataSettings): ?self { $this->metadataSettings = $metadataSettings; + return $this; } /** * @return string */ - public function getAddTo() + public function getAddTo(): ?string { return $this->addTo; } diff --git a/Entity/LibraryLibraries.php b/Entity/LibraryLibraries.php index 6ab4448..e31d060 100644 --- a/Entity/LibraryLibraries.php +++ b/Entity/LibraryLibraries.php @@ -5,35 +5,29 @@ use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity(repositoryClass="LibraryLibrariesRepository") - * @ORM\Table(name="h5p_library_libraries") - */ - +#[ORM\Entity(repositoryClass: LibraryLibrariesRepository::class)] +#[ORM\Table(name: "h5p_library_libraries")] class LibraryLibraries { /** - * @var integer - * - * @ORM\Id - * @ORM\ManyToOne(targetEntity="\Emmedy\H5PBundle\Entity\Library") - * @ORM\JoinColumn(name="library_id", referencedColumnName="id", onDelete="CASCADE") + * @var int|Library|null */ - private $library; + #[ORM\Id] + #[ORM\ManyToOne(targetEntity: Library::class)] + #[ORM\JoinColumn(name: "library_id", referencedColumnName: "id", onDelete: 'CASCADE')] + private null|Library|int $library; /** - * @var Library - * - * @ORM\Id - * @ORM\ManyToOne(targetEntity="\Emmedy\H5PBundle\Entity\Library") - * @ORM\JoinColumn(name="required_library_id", referencedColumnName="id", onDelete="CASCADE") + * @var Library|null */ - private $requiredLibrary; + #[ORM\Id] + #[ORM\ManyToOne(targetEntity: Library::class)] + #[ORM\JoinColumn(name: "required_library_id", referencedColumnName: "id", onDelete: 'CASCADE')] + private ?Library $requiredLibrary; /** - * @var string - * - * @ORM\Column(name="dependency_type", type="string", length=31) + * @var string|null */ - private $dependencyType; + #[ORM\Column(name: "dependency_type", type: "string", length: 31)] + private ?string $dependencyType; /** * @return string */ @@ -56,14 +50,14 @@ public function getRequiredLibrary() return $this->requiredLibrary; } /** - * @param Library $requiredLibrary + * @param null|Library|int $requiredLibrary */ public function setRequiredLibrary($requiredLibrary) { $this->requiredLibrary = $requiredLibrary; } /** - * @return Library + * @return null|Library|int */ public function getLibrary() { diff --git a/Entity/Option.php b/Entity/Option.php index 683ef20..9117f87 100644 --- a/Entity/Option.php +++ b/Entity/Option.php @@ -5,39 +5,38 @@ use Doctrine\DBAL\Exception\InvalidArgumentException; use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity(repositoryClass="OptionRepository") - * @ORM\Table(name="h5p_option") - */ +#[ORM\Entity(repositoryClass: OptionRepository::class)] +#[ORM\Table('h5p_option')] class Option { private const INTEGER = "integer"; private const BOOLEAN = "boolean"; private const STRING = "string"; + #[ORM\Id] + #[ORM\Column(name: "name", type: "string", length: 255)] + /** * @var string - * - * @ORM\Id - * @ORM\Column(name="name", type="string", length=255) */ - private $name; + private ?string $name; + + #[ORM\Column(name: "value", type: "text")] /** - * @var string - * - * @ORM\Column(name="value", type="text") + * @var string|null $value */ - private $value; + private ?string $value; + + #[ORM\Column(name: "type", type: "string", length: 255)] /** * @var string - * - * @ORM\Column(name="type", type="string", length=255) */ - private $type; + private ?string $type; /** + * Constructor of current class. * @param string $name */ public function __construct(string $name) diff --git a/Entity/OptionRepository.php b/Entity/OptionRepository.php index 134145b..85ab697 100644 --- a/Entity/OptionRepository.php +++ b/Entity/OptionRepository.php @@ -3,8 +3,6 @@ namespace Emmedy\H5PBundle\Entity; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; -use Doctrine\ORM\AbstractQuery; -use Doctrine\ORM\NoResultException; use Doctrine\Persistence\ManagerRegistry; /** diff --git a/Entity/Points.php b/Entity/Points.php index 8b30429..2e1da2e 100644 --- a/Entity/Points.php +++ b/Entity/Points.php @@ -5,49 +5,41 @@ use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity() - * @ORM\Table(name="h5p_points") - */ +#[ORM\Entity()] +#[ORM\Table(name: "h5p_points")] class Points { /** - * @var integer - * - * @ORM\Column(name="user_id", type="integer") + * @var int|null */ - private $user; + #[ORM\Column(name: "user_id", type: "integer")] + private ?int $user; /** - * @var Content - * - * @ORM\Id - * @ORM\ManyToOne(targetEntity="\Emmedy\H5PBundle\Entity\Content") - * @ORM\JoinColumn(name="content_main_id", referencedColumnName="id", onDelete="CASCADE") + * @var Content|null */ - private $content; + #[ORM\Id] + #[ORM\ManyToOne(targetEntity: Content::class)] + #[ORM\JoinColumn(name: "content_main_id", referencedColumnName: "id", onDelete: "CASCADE")] + private ?Content $content; /** - * @var integer - * - * @ORM\Column(name="started", type="integer") + * @var int|null */ - private $started; + #[ORM\Column(name: "started", type: "integer")] + private ?int $started; /** - * @var integer - * - * @ORM\Column(name="finished", type="integer") + * @var int */ - private $finished = 0; + #[ORM\Column(name: "finished", type: "integer")] + private int $finished = 0; /** - * @var integer - * - * @ORM\Column(name="points", type="integer", nullable=true) + * @var int|null */ - private $points; + #[ORM\Column(name: "points", type: "integer", nullable: true)] + private ?int $points; /** - * @var integer - * - * @ORM\Column(name="max_points", type="integer", nullable=true) + * @var int|null */ + #[ORM\Column(name: "max_points", type: "integer", nullable: true)] private $maxPoints; /** * @return integer diff --git a/Event/H5PEvents.php b/Event/H5PEvents.php index d04bd9f..17d2c07 100644 --- a/Event/H5PEvents.php +++ b/Event/H5PEvents.php @@ -22,7 +22,8 @@ class H5PEvents extends \H5PEventBase /** * @var EntityManagerInterface $em */ - private $em; + private EntityManagerInterface $em; + /** * H5PEvents constructor. * @param $type diff --git a/Event/LibrarySemanticsEvent.php b/Event/LibrarySemanticsEvent.php index b976549..e2c6fa0 100644 --- a/Event/LibrarySemanticsEvent.php +++ b/Event/LibrarySemanticsEvent.php @@ -7,49 +7,54 @@ class LibrarySemanticsEvent extends Event { - private $semantics; - private $name; - private $majorVersion; - private $minorVersion; + private array $semantics; + private string $name; + private int $majorVersion; + private int $minorVersion; + /** * LibrarySemanticsEvent constructor. - * @param $semantics - * @param $name - * @param $majorVersion - * @param $minorVersion + * @param array $semantics array of semantics + * @param string $name Nom of package + * @param int $majorVersion number of major version + * @param int $minorVersion number of minor version */ - public function __construct($semantics, $name, $majorVersion, $minorVersion) + public function __construct(array $semantics, string $name, int $majorVersion, int $minorVersion) { $this->semantics = $semantics; $this->name = $name; $this->majorVersion = $majorVersion; $this->minorVersion = $minorVersion; } + /** - * @return mixed + * @return array */ - public function getSemantics() + public function getSemantics(): array { return $this->semantics; } + /** - * @return mixed + * @return string */ - public function getName() + public function getName(): string { return $this->name; } + /** - * @return mixed + * @return int */ - public function getMajorVersion() + public function getMajorVersion(): int { return $this->majorVersion; } + /** - * @return mixed + * @return int */ - public function getMinorVersion() + public function getMinorVersion(): int { return $this->minorVersion; } diff --git a/Form/Type/H5PType.php b/Form/Type/H5PType.php index e1abe05..9106db1 100644 --- a/Form/Type/H5PType.php +++ b/Form/Type/H5PType.php @@ -10,11 +10,11 @@ class H5PType extends AbstractType { - public function buildForm(FormBuilderInterface $builder, array $options) + public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('library', HiddenType::class) ->add('parameters', HiddenType::class) - ->add('save', SubmitType::class, array('label' => 'Save')); + ->add('save', SubmitType::class, ['label' => 'Save']); } } diff --git a/README.MD b/README.MD index 800432b..375ef7c 100644 --- a/README.MD +++ b/README.MD @@ -12,7 +12,8 @@ This bundle was tested on : | Version Supported | Symfony 3 | Symfony 4 | Symfony 5 | Symfony 6 | Symfony 7 | |-------------------|---------------------------------------------------------------------------|-----------|-----------|-----------|-----------| -| 2.X | ❌ | ❌ | ✅ | ✅ | ✅ | +| 3.X | ❌ | ❌ | ❌ | ✅ | ✅ | +| 2.X | ❌ | ❌ | ✅ | ✅ | ❌ | | 1.X | [H5PBundle for Symfony 2.X and 3.X](https://github.com/Emmedy/h5p-bundle) | ✅ | ✅ | ❌ | ❌ | Prerequisite diff --git a/Resources/config/routes.yaml b/Resources/config/routes.yaml index c23e890..ace428e 100644 --- a/Resources/config/routes.yaml +++ b/Resources/config/routes.yaml @@ -1,7 +1,7 @@ emmedy_h5p.ajax: resource: "@EmmedyH5PBundle/Controller/H5PAJAXController.php" - type: annotation + type: attribute emmedy_h5p.interaction: resource: "@EmmedyH5PBundle/Controller/H5PInteractionController.php" - type: annotation + type: attribute diff --git a/Resources/config/routing_demo.yml b/Resources/config/routing_demo.yml index 343f9be..c394d01 100644 --- a/Resources/config/routing_demo.yml +++ b/Resources/config/routing_demo.yml @@ -1,3 +1,3 @@ emmedy_h5p.test: resource: "@EmmedyH5PBundle/Controller/H5PController.php" - type: annotation \ No newline at end of file + type: attribute diff --git a/Service/ResultService.php b/Service/ResultService.php index 81635df..deca676 100644 --- a/Service/ResultService.php +++ b/Service/ResultService.php @@ -6,6 +6,7 @@ use Doctrine\ORM\EntityManagerInterface; use Emmedy\H5PBundle\Entity\ContentResult; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Core\User\UserInterface; class ResultService { @@ -16,6 +17,7 @@ class ResultService /** * ResultService constructor. + * @param EntityManagerInterface $em */ public function __construct(EntityManagerInterface $em) { @@ -27,7 +29,7 @@ public function __construct(EntityManagerInterface $em) * @param $userId * @return ContentResult */ - public function handleRequestFinished(Request $request, $userId) + public function handleRequestFinished(Request $request, $userId): ContentResult { $contentId = $request->get('contentId', false); if (!$contentId) { @@ -50,20 +52,20 @@ public function handleRequestFinished(Request $request, $userId) } /** - * remove data in content User Data + * remove data in content User Data. * @param integer $contentId * @param string $dataType - * @param $user + * @param UserInterface $user Current user * @param integer $subContentId */ - public function removeData($contentId, $dataType, $user, $subContentId) + public function removeData(int $contentId, string $dataType, $user, int $subContentId): void { $ContentUserData = $this->em->getRepository('Emmedy\H5PBundle\Entity\ContentUserData')->findBy( [ 'subContentId' => $subContentId, 'mainContent' => $contentId, 'dataId' => $dataType, - 'user' => $user->getId() + 'user' => $user->getUserIdentifier() ] ); if (count($ContentUserData) > 0) { diff --git a/Tests/Core/H5PIntegrationTest.php b/Tests/Core/H5PIntegrationTest.php new file mode 100644 index 0000000..103eba1 --- /dev/null +++ b/Tests/Core/H5PIntegrationTest.php @@ -0,0 +1,116 @@ +core = $this->createMock(H5PCore::class); + $this->options = $this->createMock(H5POptions::class); + $tokenStorage = $this->createMock(TokenStorageInterface::class); + $this->entityManager = $this->createMock(EntityManager::class); + $this->router = $this->createMock(RouterInterface::class); + $this->requestStack = $this->createMock(RequestStack::class); + $this->assetsPaths = $this->createMock(Packages::class); + $this->contentValidator = $this->createMock(H5PContentValidator::class); + + // Création de l'instance de H5PIntegration pour les tests + $this->h5pIntegration = new H5PIntegration( + $this->core, + $this->options, + $tokenStorage, + $this->entityManager, + $this->router, + $this->requestStack, + $this->assetsPaths, + $this->contentValidator + ); + } + + public function testGetGenericH5PIntegrationSettings() + { + $request = new Request(); + $this->requestStack->method('getMainRequest')->willReturn($request); + + $this->options->method('getOption')->willReturnMap([ + ['save_content_state', false, true], + ['save_content_frequency', 30, 30], + ['hub_is_enabled', true, true] + ]); + $h5pFrameworkMock = $this->createMock(H5PFrameworkInterface::class); + $h5pFrameworkMock->method('getLibraryConfig')->willReturn(['someKey' => 'someValue']); + + // Injectez le mock H5PFramework dans H5PCore + $this->core->h5pF = $h5pFrameworkMock; + + $settings = $this->h5pIntegration->getGenericH5PIntegrationSettings(); + + $this->assertIsArray($settings); + $this->assertArrayHasKey('baseUrl', $settings); + $this->assertArrayHasKey('ajax', $settings); + $this->assertArrayHasKey('l10n', $settings); + } + + public function testGetCoreAssets() + { + $this->options->method('getH5PAssetPath')->willReturn('/assets/h5p'); + H5PCore::$scripts = ['script1.js', 'script2.js']; + H5PCore::$styles = ['style1.css', 'style2.css']; + + $assets = $this->h5pIntegration->getCoreAssets(); + + $this->assertIsArray($assets); + $this->assertArrayHasKey('scripts', $assets); + $this->assertArrayHasKey('styles', $assets); + $this->assertCount(2, $assets['scripts']); + $this->assertCount(2, $assets['styles']); + } + + public function testGetCacheBuster() + { + H5PCore::$coreApi = ['majorVersion' => 1, 'minorVersion' => 2]; + $cacheBuster = $this->h5pIntegration->getCacheBuster(); + + $this->assertEquals('?=1.2', $cacheBuster); + } + + public function testGetTranslationFilePath() + { + $request = new Request(); + $request->setLocale('en'); + $this->requestStack->method('getCurrentRequest')->willReturn($request); + + $this->options->method('getAbsoluteWebPath')->willReturn('/web'); + + $translationFilePath = $this->h5pIntegration->getTranslationFilePath(); + + $this->assertStringContainsString('/h5p-editor/language/en.js', $translationFilePath); + } + +} diff --git a/Tests/Core/H5POptionsTest.php b/Tests/Core/H5POptionsTest.php new file mode 100644 index 0000000..a55ee18 --- /dev/null +++ b/Tests/Core/H5POptionsTest.php @@ -0,0 +1,111 @@ +entityManager = $this->createMock(EntityManagerInterface::class); + // Créez un mock pour l'EntityRepository + $this->repository = $this->createMock(EntityRepository::class); + + // Configurez l'EntityManager pour retourner un mock de repository + $this->entityManager->method('getRepository')->willReturn($this->repository); + + // Initialisez H5POptions avec les dépendances mockées + $this->h5pOptions = new H5POptions( + ['storage_dir' => '/var/www/html'], // Config de test + '/var/www', // projectRootDir de test + $this->entityManager + ); + } + + public function testGetOptionReturnsStoredConfigValue() + { + // Simule la méthode findAll() du repository pour retourner une option + $option = $this->createMock(Option::class); + $option->method('getName')->willReturn('storage_dir'); + $option->method('getValue')->willReturn('/tmp/h5p'); + + // Configurez le repository pour retourner cette option + $this->repository->method('findAll')->willReturn([$option]); + + // Testez la méthode getOption + $result = $this->h5pOptions->getOption('storage_dir'); + $this->assertEquals('/tmp/h5p', $result); + } + + public function testSetOptionStoresNewOptionValue() + { + // Créez un mock de l'option à persister + $option = $this->createMock(Option::class); + $option->method('getName')->willReturn('storage_dir'); + + // Simulez la recherche de l'option dans le repository + $this->repository->method('find')->willReturn(null); // Aucun option trouvée, il faut créer une nouvelle + + // Configurez l'EntityManager pour simuler les méthodes persist et flush + $this->entityManager->expects($this->once())->method('persist')->with($this->isInstanceOf(Option::class)); + $this->entityManager->expects($this->once())->method('flush'); + + // Appelez setOption et vérifiez que persist et flush sont bien appelées + $this->h5pOptions->setOption('storage_dir', '/new/path/h5p'); + } + + public function testGetOptionReturnsDefaultIfOptionNotFound() + { + // Configurez le mock pour retourner une liste vide d'options + $this->repository->method('findAll')->willReturn([]); + + // Testez la méthode getOption avec une option qui n'existe pas + $result = $this->h5pOptions->getOption('non_existent_option', 'default_value'); + $this->assertEquals('default_value', $result); + } + + public function testRetrieveStoredConfigHandlesDriverException() + { + // Testez la gestion de l'exception dans la méthode retrieveStoredConfig + $this->expectNotToPerformAssertions(); + try { + $this->h5pOptions->getOption('storage_dir'); + } catch (DriverException $e) { + // Vérifiez que l'exception est bien attrapée + $this->assertEquals('Database error', $e->getMessage()); + } + } + + public function testGetUploadedH5pFolderPath() + { + // Testez le getter et setter de folderPath + $this->h5pOptions->getUploadedH5pFolderPath('/custom/folder'); + $this->assertEquals('/custom/folder', $this->h5pOptions->getUploadedH5pFolderPath()); + } + + public function testGetRelativeH5PPath() + { + // Testez la méthode getRelativeH5PPath pour obtenir le chemin relatif + $this->h5pOptions->setOption('storage_dir', 'var/h5p'); + $this->assertEquals('/var/h5p', $this->h5pOptions->getRelativeH5PPath()); + } + + public function testGetAbsoluteH5PPath() + { + // Testez la méthode getAbsoluteH5PPath pour obtenir le chemin absolu + $this->h5pOptions->setOption('storage_dir', 'var/h5p'); + $this->assertStringContainsString('/var/www/var/h5p', $this->h5pOptions->getAbsoluteH5PPath()); + } +} diff --git a/Tests/Event/LibraryFileEventTest.php b/Tests/Event/LibraryFileEventTest.php new file mode 100644 index 0000000..3733554 --- /dev/null +++ b/Tests/Event/LibraryFileEventTest.php @@ -0,0 +1,51 @@ +assertSame($files, $event->getFiles()); + } + + public function testGetLibraryList() + { + // Arrange + $files = ['file1.js', 'file2.css']; + $libraryList = ['library1', 'library2']; + $mode = 'production'; + + // Act + $event = new LibraryFileEvent($files, $libraryList, $mode); + + // Assert + $this->assertSame($libraryList, $event->getLibraryList()); + } + + public function testGetMode() + { + // Arrange + $files = ['file1.js', 'file2.css']; + $libraryList = ['library1', 'library2']; + $mode = 'production'; + + // Act + $event = new LibraryFileEvent($files, $libraryList, $mode); + + // Assert + $this->assertSame($mode, $event->getMode()); + } +} diff --git a/Tests/Event/LibrarySemanticsEvent.php b/Tests/Event/LibrarySemanticsEvent.php new file mode 100644 index 0000000..b51ffe4 --- /dev/null +++ b/Tests/Event/LibrarySemanticsEvent.php @@ -0,0 +1,45 @@ +semantics = ['title' => 'Example', 'description' => 'Example description']; + $this->name = 'TestPackage'; + $this->majorVersion = 1; + $this->minorVersion = 0; + + $this->event = new LibrarySemanticsEvent($this->semantics, $this->name, $this->majorVersion, $this->minorVersion); + } + + public function testGetSemantics() + { + $this->assertEquals($this->semantics, $this->event->getSemantics(), 'The semantics should match the initialized value.'); + } + + public function testGetName() + { + $this->assertEquals($this->name, $this->event->getName(), 'The name should match the initialized value.'); + } + + public function testGetMajorVersion() + { + $this->assertEquals($this->majorVersion, $this->event->getMajorVersion(), 'The major version should match the initialized value.'); + } + + public function testGetMinorVersion() + { + $this->assertEquals($this->minorVersion, $this->event->getMinorVersion(), 'The minor version should match the initialized value.'); + } +} diff --git a/composer.json b/composer.json index 629eddf..31a0934 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,6 @@ { "name": "emmedy/h5p-bundle", + "version": "3.0.0", "type": "symfony-bundle", "description": "H5P Bundle for Symfony 5, 6 and Symfony 7", "keywords": [ @@ -27,20 +28,20 @@ } ], "require": { - "php": ">= 7.4", - "doctrine/orm": "^2.14.1", - "guzzlehttp/guzzle": "^7.8", - "h5p/h5p-core": "1.26", + "php": ">= 8.1", + "doctrine/orm": "~2.0|~3.0", + "guzzlehttp/guzzle": "^7.9", + "h5p/h5p-core": "1.27", "h5p/h5p-editor": "^1.25", - "symfony/framework-bundle": "~5.0|~6.0|~7.0", - "symfony/serializer": "~5.0|~6.0|~7.0", + "symfony/framework-bundle": "~6.0|~7.0", + "symfony/serializer": "~6.0|~7.0", "twig/extra-bundle": "^3.0", - "doctrine/doctrine-bundle": "^2.0", - "symfony/security-bundle": "~5.0|~6.0|~7.0", - "symfony/asset": "~5.0|~6.0|~7.0", - "symfony/form": "~5.0|~6.0|~7.0", + "doctrine/doctrine-bundle": "^2.13", + "symfony/security-bundle": "~6.0|~7.0", + "symfony/asset": "~6.0|~7.0", + "symfony/form": "~6.0|~7.0", "ext-json": "*", - "symfony/intl": "~5.0|~6.0|~7.0" + "symfony/intl": "~6.0|~7.0" }, "autoload": { "psr-4": { @@ -48,6 +49,7 @@ } }, "require-dev": { - "phpstan/phpstan": "^1.10" + "phpstan/phpstan": "^1.12", + "phpunit/phpunit": "^11.4" } } diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..4b3179a --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,26 @@ + + + + + Tests + + + + + + . + + +