Platform: Refactor global events management - refs #5270
parent
a1f04ee3b1
commit
6096110fd0
@ -1,166 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
/* For licensing terms, see /license.txt */ |
|
||||||
|
|
||||||
namespace Chamilo\CoreBundle\Entity; |
|
||||||
|
|
||||||
use DateTime; |
|
||||||
use Doctrine\ORM\Mapping as ORM; |
|
||||||
|
|
||||||
/** |
|
||||||
* SysCalendar. |
|
||||||
*/ |
|
||||||
#[ORM\Table(name: 'sys_calendar')] |
|
||||||
#[ORM\Entity] |
|
||||||
class SysCalendar |
|
||||||
{ |
|
||||||
public const COLOR_SYSTEM_EVENT = '#FF0000'; |
|
||||||
|
|
||||||
#[ORM\Column(name: 'id', type: 'integer')] |
|
||||||
#[ORM\Id] |
|
||||||
#[ORM\GeneratedValue(strategy: 'IDENTITY')] |
|
||||||
protected ?int $id = null; |
|
||||||
|
|
||||||
#[ORM\Column(name: 'title', type: 'string', length: 255, nullable: false)] |
|
||||||
protected string $title; |
|
||||||
|
|
||||||
#[ORM\Column(name: 'content', type: 'text', nullable: true)] |
|
||||||
protected ?string $content = null; |
|
||||||
|
|
||||||
#[ORM\Column(name: 'start_date', type: 'datetime', nullable: true)] |
|
||||||
protected ?DateTime $startDate = null; |
|
||||||
|
|
||||||
#[ORM\Column(name: 'end_date', type: 'datetime', nullable: true)] |
|
||||||
protected ?DateTime $endDate = null; |
|
||||||
|
|
||||||
#[ORM\ManyToOne(targetEntity: AccessUrl::class)] |
|
||||||
#[ORM\JoinColumn(name: 'access_url_id', referencedColumnName: 'id', onDelete: 'CASCADE')] |
|
||||||
protected AccessUrl $url; |
|
||||||
|
|
||||||
#[ORM\Column(name: 'all_day', type: 'integer', nullable: false)] |
|
||||||
protected int $allDay; |
|
||||||
|
|
||||||
#[ORM\Column(name: 'color', type: 'string', length: 20, nullable: true)] |
|
||||||
protected ?string $color = null; |
|
||||||
|
|
||||||
public function setTitle(string $title): self |
|
||||||
{ |
|
||||||
$this->title = $title; |
|
||||||
|
|
||||||
return $this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Get title. |
|
||||||
* |
|
||||||
* @return string |
|
||||||
*/ |
|
||||||
public function getTitle() |
|
||||||
{ |
|
||||||
return $this->title; |
|
||||||
} |
|
||||||
|
|
||||||
public function setContent(string $content): self |
|
||||||
{ |
|
||||||
$this->content = $content; |
|
||||||
|
|
||||||
return $this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Get content. |
|
||||||
* |
|
||||||
* @return string |
|
||||||
*/ |
|
||||||
public function getContent() |
|
||||||
{ |
|
||||||
return $this->content; |
|
||||||
} |
|
||||||
|
|
||||||
public function setStartDate(DateTime $startDate): self |
|
||||||
{ |
|
||||||
$this->startDate = $startDate; |
|
||||||
|
|
||||||
return $this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Get startDate. |
|
||||||
* |
|
||||||
* @return DateTime |
|
||||||
*/ |
|
||||||
public function getStartDate() |
|
||||||
{ |
|
||||||
return $this->startDate; |
|
||||||
} |
|
||||||
|
|
||||||
public function setEndDate(DateTime $endDate): self |
|
||||||
{ |
|
||||||
$this->endDate = $endDate; |
|
||||||
|
|
||||||
return $this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Get endDate. |
|
||||||
* |
|
||||||
* @return DateTime |
|
||||||
*/ |
|
||||||
public function getEndDate() |
|
||||||
{ |
|
||||||
return $this->endDate; |
|
||||||
} |
|
||||||
|
|
||||||
public function setAllDay(int $allDay): self |
|
||||||
{ |
|
||||||
$this->allDay = $allDay; |
|
||||||
|
|
||||||
return $this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Get allDay. |
|
||||||
* |
|
||||||
* @return int |
|
||||||
*/ |
|
||||||
public function getAllDay() |
|
||||||
{ |
|
||||||
return $this->allDay; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Get id. |
|
||||||
* |
|
||||||
* @return int |
|
||||||
*/ |
|
||||||
public function getId() |
|
||||||
{ |
|
||||||
return $this->id; |
|
||||||
} |
|
||||||
|
|
||||||
public function getColor(): ?string |
|
||||||
{ |
|
||||||
return $this->color; |
|
||||||
} |
|
||||||
|
|
||||||
public function setColor(string $color): self |
|
||||||
{ |
|
||||||
$this->color = $color; |
|
||||||
|
|
||||||
return $this; |
|
||||||
} |
|
||||||
|
|
||||||
public function getUrl(): AccessUrl |
|
||||||
{ |
|
||||||
return $this->url; |
|
||||||
} |
|
||||||
|
|
||||||
public function setUrl(AccessUrl $url): self |
|
||||||
{ |
|
||||||
$this->url = $url; |
|
||||||
|
|
||||||
return $this; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,82 @@ |
|||||||
|
<?php |
||||||
|
/* For licensing terms, see /license.txt */ |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Chamilo\CoreBundle\Filter; |
||||||
|
|
||||||
|
use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter; |
||||||
|
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; |
||||||
|
use ApiPlatform\Metadata\Operation; |
||||||
|
use Chamilo\CoreBundle\Entity\ResourceNode; |
||||||
|
use Doctrine\ORM\QueryBuilder; |
||||||
|
use Doctrine\Persistence\ManagerRegistry; |
||||||
|
use Psr\Log\LoggerInterface; |
||||||
|
use Symfony\Component\Serializer\NameConverter\NameConverterInterface; |
||||||
|
|
||||||
|
class GlobalEventFilter extends AbstractFilter |
||||||
|
{ |
||||||
|
public function __construct( |
||||||
|
ManagerRegistry $managerRegistry, |
||||||
|
?LoggerInterface $logger = null, |
||||||
|
?array $properties = null, |
||||||
|
?NameConverterInterface $nameConverter = null |
||||||
|
) { |
||||||
|
parent::__construct($managerRegistry, $logger, $properties, $nameConverter); |
||||||
|
} |
||||||
|
|
||||||
|
protected function filterProperty( |
||||||
|
string $property, |
||||||
|
$value, |
||||||
|
QueryBuilder $queryBuilder, |
||||||
|
QueryNameGeneratorInterface $queryNameGenerator, |
||||||
|
string $resourceClass, |
||||||
|
?Operation $operation = null, |
||||||
|
array $context = [] |
||||||
|
): void { |
||||||
|
$isGlobalType = isset($context['filters']['type']) && $context['filters']['type'] === 'global'; |
||||||
|
|
||||||
|
$rootAlias = $queryBuilder->getRootAliases()[0]; |
||||||
|
$resourceNodeAlias = $queryNameGenerator->generateJoinAlias('resourceNode'); |
||||||
|
$resourceLinkAlias = $queryNameGenerator->generateJoinAlias('resourceLink'); |
||||||
|
if ($isGlobalType) { |
||||||
|
$queryBuilder |
||||||
|
->innerJoin("$rootAlias.resourceNode", $resourceNodeAlias) |
||||||
|
->innerJoin("$resourceNodeAlias.resourceLinks", $resourceLinkAlias) |
||||||
|
->andWhere("$resourceLinkAlias.course IS NULL") |
||||||
|
->andWhere("$resourceLinkAlias.session IS NULL") |
||||||
|
->andWhere("$resourceLinkAlias.group IS NULL") |
||||||
|
->andWhere("$resourceLinkAlias.user IS NULL"); |
||||||
|
|
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (!$isGlobalType) { |
||||||
|
$subQueryBuilder = $queryBuilder->getEntityManager()->createQueryBuilder(); |
||||||
|
$subRN = $queryNameGenerator->generateJoinAlias('subResourceNode'); |
||||||
|
$subRL = $queryNameGenerator->generateJoinAlias('subResourceLink'); |
||||||
|
$subQueryBuilder->select('1') |
||||||
|
->from(ResourceNode::class, $subRN) |
||||||
|
->innerJoin("$subRN.resourceLinks", $subRL) |
||||||
|
->where("$subRL.course IS NULL") |
||||||
|
->andWhere("$subRL.session IS NULL") |
||||||
|
->andWhere("$subRL.group IS NULL") |
||||||
|
->andWhere("$subRL.user IS NULL") |
||||||
|
->andWhere("$subRN.id = $rootAlias.resourceNode"); |
||||||
|
|
||||||
|
$queryBuilder->andWhere($queryBuilder->expr()->not($queryBuilder->expr()->exists($subQueryBuilder->getDQL()))); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public function getDescription(string $resourceClass): array |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'type' => [ |
||||||
|
'property' => 'type', |
||||||
|
'type' => 'string', |
||||||
|
'required' => false, |
||||||
|
'description' => 'Filter events by type. Use "global" to get global events.', |
||||||
|
], |
||||||
|
]; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,102 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
/* For licensing terms, see /license.txt */ |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Chamilo\CoreBundle\Migrations\Schema\V200; |
||||||
|
|
||||||
|
use Chamilo\CoreBundle\Entity\ResourceLink; |
||||||
|
use Chamilo\CoreBundle\Entity\User; |
||||||
|
use Chamilo\CoreBundle\Migrations\AbstractMigrationChamilo; |
||||||
|
use Chamilo\CourseBundle\Entity\CCalendarEvent; |
||||||
|
use DateTime; |
||||||
|
use DateTimeZone; |
||||||
|
use Doctrine\DBAL\Schema\Schema; |
||||||
|
|
||||||
|
class Version20240323181500 extends AbstractMigrationChamilo |
||||||
|
{ |
||||||
|
public function getDescription(): string |
||||||
|
{ |
||||||
|
return 'Migrate sys_calendar to c_calendar_event'; |
||||||
|
} |
||||||
|
|
||||||
|
public function up(Schema $schema): void |
||||||
|
{ |
||||||
|
$em = $this->getEntityManager(); |
||||||
|
$sysCalendars = $this->connection->fetchAllAssociative('SELECT * FROM sys_calendar'); |
||||||
|
|
||||||
|
$utc = new DateTimeZone('UTC'); |
||||||
|
$admin = $this->getAdmin(); |
||||||
|
foreach ($sysCalendars as $sysCalendar) { |
||||||
|
|
||||||
|
$calendarEvent = $this->createCCalendarEvent( |
||||||
|
$sysCalendar['title'] ?: '-', |
||||||
|
$sysCalendar['content'], |
||||||
|
$sysCalendar['start_date'] ? new DateTime($sysCalendar['start_date'], $utc) : null, |
||||||
|
$sysCalendar['end_date'] ? new DateTime($sysCalendar['end_date'], $utc) : null, |
||||||
|
(bool) $sysCalendar['all_day'], |
||||||
|
$sysCalendar['color'] ?? '', |
||||||
|
$admin |
||||||
|
); |
||||||
|
|
||||||
|
$em->persist($calendarEvent); |
||||||
|
$this->addGlobalResourceLinkToNode($em, $calendarEvent->getResourceNode()); |
||||||
|
} |
||||||
|
|
||||||
|
$em->flush(); |
||||||
|
} |
||||||
|
|
||||||
|
private function createCCalendarEvent( |
||||||
|
string $title, |
||||||
|
string $content, |
||||||
|
?DateTime $startDate, |
||||||
|
?DateTime $endDate, |
||||||
|
bool $allDay, |
||||||
|
string $color, |
||||||
|
User $creator |
||||||
|
): CCalendarEvent { |
||||||
|
$calendarEvent = new CCalendarEvent(); |
||||||
|
$calendarEvent |
||||||
|
->setTitle($title) |
||||||
|
->setContent($content) |
||||||
|
->setStartDate($startDate) |
||||||
|
->setEndDate($endDate) |
||||||
|
->setAllDay($allDay) |
||||||
|
->setColor($color) |
||||||
|
->setCreator($creator) |
||||||
|
->setResourceName($title) |
||||||
|
->setParentResourceNode($creator->getResourceNode()->getId()) |
||||||
|
; |
||||||
|
|
||||||
|
return $calendarEvent; |
||||||
|
} |
||||||
|
|
||||||
|
private function addGlobalResourceLinkToNode($em, $resourceNode): void |
||||||
|
{ |
||||||
|
$globalLink = new ResourceLink(); |
||||||
|
$globalLink->setCourse(null) |
||||||
|
->setSession(null) |
||||||
|
->setGroup(null) |
||||||
|
->setUser(null); |
||||||
|
|
||||||
|
$alreadyHasGlobalLink = false; |
||||||
|
foreach ($resourceNode->getResourceLinks() as $existingLink) { |
||||||
|
if (null === $existingLink->getCourse() && null === $existingLink->getSession() && |
||||||
|
null === $existingLink->getGroup() && null === $existingLink->getUser()) { |
||||||
|
$alreadyHasGlobalLink = true; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!$alreadyHasGlobalLink) { |
||||||
|
$resourceNode->addResourceLink($globalLink); |
||||||
|
$em->persist($globalLink); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public function down(Schema $schema): void |
||||||
|
{ |
||||||
|
// Down migration is not defined, as data migration cannot be easily reverted |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,29 @@ |
|||||||
|
<?php |
||||||
|
/* For licensing terms, see /license.txt */ |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Chamilo\CoreBundle\Migrations\Schema\V200; |
||||||
|
|
||||||
|
use Chamilo\CoreBundle\Migrations\AbstractMigrationChamilo; |
||||||
|
use Doctrine\DBAL\Schema\Schema; |
||||||
|
|
||||||
|
final class Version20240323222700 extends AbstractMigrationChamilo |
||||||
|
{ |
||||||
|
public function getDescription(): string |
||||||
|
{ |
||||||
|
return 'Remove the sys_calendar table'; |
||||||
|
} |
||||||
|
|
||||||
|
public function up(Schema $schema): void |
||||||
|
{ |
||||||
|
$this->addSql('DROP TABLE IF EXISTS sys_calendar'); |
||||||
|
} |
||||||
|
|
||||||
|
public function down(Schema $schema): void |
||||||
|
{ |
||||||
|
if (!$schema->hasTable('sys_calendar')) { |
||||||
|
$this->addSql('CREATE TABLE sys_calendar (id INT AUTO_INCREMENT NOT NULL, title VARCHAR(255) NOT NULL, content LONGTEXT DEFAULT NULL, start_date DATETIME DEFAULT NULL, end_date DATETIME DEFAULT NULL, access_url_id INT DEFAULT NULL, all_day INT NOT NULL, color VARCHAR(20) DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -1,19 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
/* For licensing terms, see /license.txt */ |
|
||||||
|
|
||||||
namespace Chamilo\CoreBundle\Repository; |
|
||||||
|
|
||||||
use Chamilo\CoreBundle\Entity\SysCalendar; |
|
||||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; |
|
||||||
use Doctrine\Persistence\ManagerRegistry; |
|
||||||
|
|
||||||
class SysCalendarRepository extends ServiceEntityRepository |
|
||||||
{ |
|
||||||
public function __construct(ManagerRegistry $registry) |
|
||||||
{ |
|
||||||
parent::__construct($registry, SysCalendar::class); |
|
||||||
} |
|
||||||
} |
|
||||||
Loading…
Reference in new issue