Add pages entities + tests

pull/4020/head^2
Julio 3 years ago
parent 4356348bf1
commit 4eb21c1005
  1. 11
      src/CoreBundle/Controller/Admin/SettingsController.php
  2. 28
      src/CoreBundle/DataFixtures/PageFixtures.php
  3. 66
      src/CoreBundle/DataProvider/Extension/PageExtension.php
  4. 255
      src/CoreBundle/Entity/Page.php
  5. 148
      src/CoreBundle/Entity/PageCategory.php
  6. 33
      src/CoreBundle/Repository/PageRepository.php
  7. 5
      tests/ChamiloTestTrait.php
  8. 18
      tests/CoreBundle/Repository/CourseCategoryRepositoryTest.php
  9. 273
      tests/CoreBundle/Repository/PageRepositoryTest.php

@ -7,7 +7,6 @@ declare(strict_types=1);
namespace Chamilo\CoreBundle\Controller\Admin;
use Chamilo\CoreBundle\Controller\BaseController;
use Chamilo\CoreBundle\Entity\AccessUrl;
use Chamilo\CoreBundle\Traits\ControllerTrait;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
@ -106,9 +105,7 @@ class SettingsController extends BaseController
public function updateSettingAction(Request $request, string $namespace): Response
{
$manager = $this->getSettingsManager();
// @todo improve get the current url entity
$urlId = $request->getSession()->get('access_url_id');
$url = $this->getDoctrine()->getRepository(AccessUrl::class)->find($urlId);
$url = $this->getAccessUrl();
$manager->setUrl($url);
$schemaAlias = $manager->convertNameSpaceToService($namespace);
$searchForm = $this->getSearchForm();
@ -188,12 +185,10 @@ class SettingsController extends BaseController
*/
#[IsGranted('ROLE_ADMIN')]
#[Route('/settings_sync', name: 'admin_settings')]
public function syncSettings(Request $request): Response
public function syncSettings(): Response
{
$manager = $this->getSettingsManager();
// @todo improve get the current url entity
$urlId = $request->getSession()->get('access_url_id');
$url = $this->getDoctrine()->getRepository(AccessUrl::class)->find($urlId);
$url = $this->getAccessUrl();
$manager->setUrl($url);
$manager->installSchemas($url);

@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\DataFixtures;
use Chamilo\CoreBundle\Entity\PageCategory;
use Chamilo\CoreBundle\Entity\User;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
class PageFixtures extends Fixture
{
public function load(ObjectManager $manager): void
{
/** @var User $admin */
$admin = $this->getReference(AccessUserFixtures::ADMIN_USER_REFERENCE);
$category = (new PageCategory())
->setTitle('home')
->setType('grid')
->setCreator($admin)
;
$manager->persist($category);
$manager->flush();
}
}

@ -0,0 +1,66 @@
<?php
/* For licensing terms, see /license.txt */
declare(strict_types=1);
namespace Chamilo\CoreBundle\DataProvider\Extension;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
//use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface;
//use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Chamilo\CoreBundle\Entity\Page;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Security;
final class PageExtension implements QueryCollectionExtensionInterface //, QueryItemExtensionInterface
{
private Security $security;
private RequestStack $requestStack;
public function __construct(Security $security, RequestStack $request)
{
$this->security = $security;
$this->requestStack = $request;
}
public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null): void
{
$this->addWhere($queryBuilder, $resourceClass);
}
public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, string $operationName = null, array $context = []): void
{
//$this->addWhere($queryBuilder, $resourceClass);
}
private function addWhere(QueryBuilder $qb, string $resourceClass): void
{
if (Page::class !== $resourceClass) {
return;
}
$alias = $qb->getRootAliases()[0];
$request = $this->requestStack->getCurrentRequest();
$urlId = $request->getSession()->get('access_url_id');
// Url filter by default.
$qb
->andWhere("$alias.url = :url")
->setParameter('url', $urlId)
;
$locale = $request->query->get('locale');
// By default, load the locale elements.
if (empty($locale)) {
$qb
->andWhere("$alias.locale = :locale")
->setParameter('locale', $request->getLocale())
;
}
}
}

@ -0,0 +1,255 @@
<?php
declare(strict_types=1);
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Entity;
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use Chamilo\CoreBundle\Traits\TimestampableTypedEntity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Table(
* name="page",
* indexes={
* }
* )
* @ORM\Entity
*/
#[ApiResource(
collectionOperations: [
'get' => [
'security' => "is_granted('ROLE_USER')",
],
'post' => [
'security' => "is_granted('ROLE_ADMIN')",
],
],
itemOperations: [
'get' => [
'security' => "is_granted('ROLE_USER')",
],
'put' => [
'security' => "is_granted('ROLE_ADMIN')",
],
'delete' => [
'security' => "is_granted('ROLE_ADMIN')",
],
],
denormalizationContext: [
'groups' => ['page:write'],
],
normalizationContext: [
'groups' => ['page:read'],
],
)]
#[ApiFilter(SearchFilter::class, properties: [
'locale' => 'exact',
'url' => 'exact',
'category' => 'exact',
'category.title' => 'partial',
])]
class Page
{
use TimestampableTypedEntity;
/**
* @ORM\Column(name="id", type="bigint")
* @ORM\Id
* @ORM\GeneratedValue()
*/
protected int $id;
/**
* @ORM\Column(name="title", type="string", length=255)
*/
#[Assert\NotBlank]
#[Groups(['page:read', 'page:write'])]
protected string $title;
/**
* @ORM\Column(name="content", type="text")
*/
#[Groups(['page:read', 'page:write'])]
#[Assert\NotBlank]
protected string $content;
/**
* @Gedmo\Slug(
* fields={"title"},
* updatable=true,
* unique=true,
* )
* @ORM\Column(name="slug", type="string", length=255)
*/
protected string $slug;
/**
* @ORM\Column(name="enabled", type="boolean", nullable=false)
*/
#[Groups(['page:read', 'page:write'])]
protected bool $enabled;
/**
* @Gedmo\SortablePosition
* @ORM\Column(name="position", type="integer")
*/
#[Groups(['page:read', 'page:write'])]
protected int $position;
/**
* @ORM\Column(name="locale", type="string", length=10)
*/
#[Groups(['page:read', 'page:write'])]
protected string $locale;
/**
* @ORM\ManyToOne(targetEntity="AccessUrl", cascade={"persist"})
* @ORM\JoinColumn(name="access_url_id", referencedColumnName="id")
*/
#[Assert\NotNull]
#[Groups(['page:read', 'page:write'])]
protected AccessUrl $url;
/**
* @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\User")
* @ORM\JoinColumn(name="creator_id", referencedColumnName="id", nullable=true, onDelete="CASCADE")
*/
#[Assert\NotNull]
#[Groups(['page:read', 'page:write'])]
protected User $creator;
/**
* @Gedmo\SortableGroup
* @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\PageCategory", inversedBy="pages")
* @ORM\JoinColumn(name="category_id", referencedColumnName="id", onDelete="SET NULL")
*/
#[Groups(['page:read', 'page:write'])]
protected ?PageCategory $category = null;
public function __construct()
{
$this->enabled = false;
}
public function getId(): int
{
return $this->id;
}
public function getTitle(): string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getContent(): string
{
return $this->content;
}
public function setContent(string $content): self
{
$this->content = $content;
return $this;
}
public function getSlug(): string
{
return $this->slug;
}
public function setSlug(string $slug): self
{
$this->slug = $slug;
return $this;
}
public function isEnabled(): bool
{
return $this->enabled;
}
public function setEnabled(bool $enabled): self
{
$this->enabled = $enabled;
return $this;
}
public function getLocale(): string
{
return $this->locale;
}
public function setLocale(string $locale): self
{
$this->locale = $locale;
return $this;
}
public function getUrl(): AccessUrl
{
return $this->url;
}
public function setUrl(AccessUrl $url): self
{
$this->url = $url;
return $this;
}
public function getCreator(): User
{
return $this->creator;
}
public function setCreator(User $creator): self
{
$this->creator = $creator;
return $this;
}
public function getPosition(): int
{
return $this->position;
}
public function setPosition(int $position): self
{
$this->position = $position;
return $this;
}
public function getCategory(): ?PageCategory
{
return $this->category;
}
public function setCategory(PageCategory $category): self
{
$this->category = $category;
return $this;
}
}

@ -0,0 +1,148 @@
<?php
declare(strict_types=1);
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Chamilo\CoreBundle\Traits\TimestampableTypedEntity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Table(
* name="page_category",
* indexes={
* }
* )
* @ORM\Entity
*/
#[ApiResource(
collectionOperations: [
'get' => [
'security' => "is_granted('ROLE_USER')",
],
'post' => [
'security' => "is_granted('ROLE_ADMIN')",
],
],
itemOperations: [
'get' => [
'security' => "is_granted('ROLE_USER')",
],
'put' => [
'security' => "is_granted('ROLE_ADMIN')",
],
'delete' => [
'security' => "is_granted('ROLE_ADMIN')",
],
],
denormalizationContext: [
'groups' => ['page_category:write'],
],
normalizationContext: [
'groups' => ['page_category:read'],
],
)]
class PageCategory
{
use TimestampableTypedEntity;
/**
* @ORM\Column(name="id", type="bigint")
* @ORM\Id
* @ORM\GeneratedValue()
*/
#[Groups(['page_category:read', 'page_category:write'])]
protected ?int $id = null;
/**
* @ORM\Column(name="title", type="string", length=255)
*/
#[Assert\NotBlank]
#[Groups(['page_category:read', 'page_category:write'])]
protected string $title;
/**
* @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\User")
* @ORM\JoinColumn(name="creator_id", referencedColumnName="id", nullable=true, onDelete="CASCADE")
*/
#[Assert\NotNull]
protected User $creator;
/**
* @ORM\Column(name="type", type="string")
*/
#[Groups(['page_category:read', 'page_category:write', 'page:read'])]
#[Assert\NotBlank]
protected string $type;
/**
* @var Collection|Page[]
* @ORM\OneToMany(targetEntity="Chamilo\CoreBundle\Entity\Page", mappedBy="category", cascade={"persist"})
*/
protected Collection $pages;
public function __construct()
{
$this->pages = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getCreator(): User
{
return $this->creator;
}
public function setCreator(User $creator): self
{
$this->creator = $creator;
return $this;
}
public function getType(): string
{
return $this->type;
}
public function setType(string $type): self
{
$this->type = $type;
return $this;
}
public function getPages()
{
return $this->pages;
}
public function setPages($pages): self
{
$this->pages = $pages;
return $this;
}
}

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Repository;
use Chamilo\CoreBundle\Entity\Page;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class PageRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Page::class);
}
public function update(Page $page): void
{
$this->getEntityManager()->persist($page);
$this->getEntityManager()->flush();
}
public function delete(Page $page = null): void
{
if (null !== $page) {
$this->getEntityManager()->remove($page);
$this->getEntityManager()->flush();
}
}
}

@ -126,6 +126,11 @@ trait ChamiloTestTrait
return $repo->findByUsername($username);
}
public function getAdmin(): User
{
return $this->getUser('admin');
}
public function getCourse($courseId): ?Course
{
$repo = static::getContainer()->get(CourseRepository::class);

@ -20,8 +20,6 @@ class CourseCategoryRepositoryTest extends AbstractApiTest
public function testCreate(): void
{
self::bootKernel();
$em = $this->getEntityManager();
$repo = self::getContainer()->get(CourseCategoryRepository::class);
$defaultCount = $repo->count([]);
@ -44,8 +42,6 @@ class CourseCategoryRepositoryTest extends AbstractApiTest
public function testCreateWithParent(): void
{
self::bootKernel();
$em = $this->getEntityManager();
$repo = self::getContainer()->get(CourseCategoryRepository::class);
$defaultCount = $repo->count([]);
@ -71,8 +67,6 @@ class CourseCategoryRepositoryTest extends AbstractApiTest
public function testCreateWithAsset(): void
{
self::bootKernel();
$em = $this->getEntityManager();
/** @var CourseCategoryRepository $repoCourseCategory */
@ -164,8 +158,6 @@ class CourseCategoryRepositoryTest extends AbstractApiTest
public function testEditAndDeleteAsset(): void
{
self::bootKernel();
$em = $this->getEntityManager();
$repoCourseCategory = self::getContainer()->get(CourseCategoryRepository::class);
@ -209,13 +201,13 @@ class CourseCategoryRepositoryTest extends AbstractApiTest
$categories = $repoCourseCategory->findAllInAccessUrl($urlId);
$this->assertSame(3, \count($categories));
$this->assertCount(3, $categories);
$categories = $repoCourseCategory->findAllInAccessUrl($urlId, false);
$this->assertSame(3, \count($categories));
$this->assertCount(3, $categories);
$categories = $repoCourseCategory->findAllInAccessUrl($urlId, false, 99);
$this->assertSame(0, \count($categories));
$this->assertCount(0, $categories);
}
public function testGetCategoriesByCourseIdAndAccessUrlId(): void
@ -245,9 +237,9 @@ class CourseCategoryRepositoryTest extends AbstractApiTest
$em->flush();
$categories = $repoCourseCategory->getCategoriesByCourseIdAndAccessUrlId($urlId, $course->getId());
$this->assertSame(1, \count($categories));
$this->assertCount(1, $categories);
$categories = $repoCourseCategory->getCategoriesByCourseIdAndAccessUrlId($urlId, $course->getId(), true);
$this->assertSame(1, \count($categories));
$this->assertCount(1, $categories);
}
}

@ -0,0 +1,273 @@
<?php
declare(strict_types=1);
/* For licensing terms, see /license.txt */
namespace Chamilo\Tests\CoreBundle\Repository;
use Chamilo\CoreBundle\Entity\AccessUrl;
use Chamilo\CoreBundle\Entity\Page;
use Chamilo\CoreBundle\Entity\PageCategory;
use Chamilo\CoreBundle\Repository\PageRepository;
use Chamilo\Tests\AbstractApiTest;
use Chamilo\Tests\ChamiloTestTrait;
use DateTime;
class PageRepositoryTest extends AbstractApiTest
{
use ChamiloTestTrait;
public function testCreate(): Page
{
$em = $this->getEntityManager();
$pageRepo = self::getContainer()->get(PageRepository::class);
$user = $this->getAdmin();
$url = $this->getAccessUrl();
$category = (new PageCategory())
->setCreator($user)
->setTitle('category1')
->setType('simple')
->setCreatedAt(new DateTime())
->setUpdatedAt(new DateTime())
;
$this->assertHasNoEntityViolations($category);
$em->persist($category);
$page = (new Page())
->setTitle('page1')
->setContent('page1 content')
->setCreator($user)
->setUrl($url)
->setPosition(0)
->setCategory($category)
->setSlug('english')
->setLocale('en')
->setEnabled(true)
->setCreatedAt(new DateTime())
->setUpdatedAt(new DateTime())
;
$this->assertHasNoEntityViolations($page);
$em->persist($page);
$em->flush();
$this->assertSame(0, $page->getPosition());
$this->assertSame(1, $pageRepo->count([]));
$category2 = (new PageCategory())
->setCreator($user)
->setTitle('category2')
->setType('simple')
->setCreatedAt(new DateTime())
->setUpdatedAt(new DateTime())
;
$this->assertHasNoEntityViolations($category2);
$em->persist($category2);
$pageFrench = (new Page())
->setTitle("l'êtê")
->setContent('french content')
->setCreator($user)
->setUrl($url)
->setCategory($category2)
->setLocale('fr')
->setEnabled(true)
->setCreatedAt(new DateTime())
->setUpdatedAt(new DateTime())
;
$this->assertHasNoEntityViolations($pageFrench);
$em->persist($pageFrench);
$em->flush();
$this->assertSame(0, $pageFrench->getPosition());
$this->assertSame('fr', $pageFrench->getLocale());
$this->assertSame('lete', $pageFrench->getSlug());
$this->assertSame(2, $pageRepo->count([]));
return $page;
}
public function testAddAnotherPage(): void
{
$page = $this->testCreate();
$em = $this->getEntityManager();
$pageRepo = self::getContainer()->get(PageRepository::class);
/** @var Page $page */
$page = $pageRepo->find($page->getId());
$url = $this->getAccessUrl();
$user = $this->getAdmin();
$anotherPage = (new Page())
->setTitle('page2')
->setContent('page2 content')
->setUrl($url)
->setCreator($user)
->setLocale('en')
->setEnabled(true)
->setCategory($page->getCategory())
;
$this->assertHasNoEntityViolations($anotherPage);
$em->persist($anotherPage);
$em->flush();
$this->assertSame(3, $pageRepo->count([]));
$this->assertSame(1, $anotherPage->getPosition());
$this->assertNotNull($anotherPage->getCategory());
}
public function testUpdate(): void
{
$page = $this->testCreate();
$pageRepo = self::getContainer()->get(PageRepository::class);
$this->assertSame(2, $pageRepo->count([]));
$page->setLocale('fr');
$pageRepo->update($page);
$this->assertSame('fr', $page->getLocale());
$this->assertSame(2, $pageRepo->count([]));
}
public function testDelete(): void
{
$page = $this->testCreate();
$pageRepo = self::getContainer()->get(PageRepository::class);
$pageRepo->delete($page);
$this->assertSame(1, $pageRepo->count([]));
}
public function testGetPages(): void
{
$this->testAddAnotherPage();
$token = $this->getUserToken([]);
$this->createClientWithCredentials($token)->request('GET', '/api/pages');
$this->assertResponseIsSuccessful();
$response = $this->createClientWithCredentials($token)->request(
'GET',
'/api/pages',
[
'query' => [
'locale' => 'en',
],
]
);
$this->assertResponseIsSuccessful();
// Asserts that the returned content type is JSON-LD (the default)
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
// Asserts that the returned JSON is a superset of this one
$this->assertJsonContains([
'@context' => '/api/contexts/Page',
'@id' => '/api/pages',
'@type' => 'hydra:Collection',
'hydra:totalItems' => 2,
]);
$this->assertCount(2, $response->toArray()['hydra:member']);
$this->assertMatchesResourceCollectionJsonSchema(Page::class);
$response = $this->createClientWithCredentials($token)->request(
'GET',
'/api/pages',
[
'query' => [
'locale' => 'en',
'category.title' => 'category1',
],
]
);
$this->assertCount(2, $response->toArray()['hydra:member']);
$this->assertJsonContains([
'@context' => '/api/contexts/Page',
'@id' => '/api/pages',
'@type' => 'hydra:Collection',
'hydra:member' => [
[
'@type' => 'Page',
'title' => 'page1',
],
[
'@type' => 'Page',
'title' => 'page2',
],
],
]);
$response = $this->createClientWithCredentials($token)->request(
'GET',
'/api/pages',
[
'query' => [
'locale' => 'fr',
],
]
);
$this->assertCount(1, $response->toArray()['hydra:member']);
}
public function testAddPage(): void
{
$user = $this->getAdmin();
$url = $this->getAccessUrl();
$url = $this->findIriBy(AccessUrl::class, ['id' => $url->getId()]);
$token = $this->getUserToken([]);
$this->createClientWithCredentials($token)->request(
'POST',
'/api/pages',
[
'json' => [
'creator' => $user->getIri(),
'url' => $url,
'locale' => 'en',
'title' => 'my post',
'content' => 'hello',
],
]
);
$this->assertResponseStatusCodeSame(201);
}
public function testGetPage(): void
{
$page = $this->testCreate();
$iri = $this->findIriBy(Page::class, ['id' => $page->getId()]);
$token = $this->getUserToken([]);
$this->createClientWithCredentials($token)->request('GET', $iri);
$this->assertResponseIsSuccessful();
$this->assertJsonContains([
'@id' => $iri,
'@type' => 'Page',
'title' => 'english',
'content' => 'english content',
'@context' => '/api/contexts/Page',
]);
}
public function testDeletePage(): void
{
$page = $this->testCreate();
$iri = $this->findIriBy(Page::class, ['id' => $page->getId()]);
$token = $this->getUserToken([]);
$this->createClientWithCredentials($token)->request(
'DELETE',
$iri
);
$this->assertResponseStatusCodeSame(204);
$iri = $this->findIriBy(Page::class, ['id' => $page->getId()]);
$this->assertNull($iri);
}
}
Loading…
Cancel
Save