334 lines
9.9 KiB
PHP
334 lines
9.9 KiB
PHP
<?php
|
|
|
|
namespace App\Benzina;
|
|
|
|
use App\Entity\Project\Project;
|
|
use App\Entity\Project\ProjectCalendar;
|
|
use App\Entity\Project\ProjectDeadline;
|
|
use App\Entity\Project\ProjectStatus;
|
|
use App\Entity\Project\ProjectVideo;
|
|
use App\Entity\Project\Update;
|
|
use App\Entity\Territory;
|
|
use App\Entity\User\User;
|
|
use App\Repository\Project\ProjectRepository;
|
|
use App\Repository\User\UserRepository;
|
|
use App\Service\Embed\EmbedService;
|
|
use App\Service\Project\TerritoryService;
|
|
use Doctrine\Common\Collections\ArrayCollection;
|
|
use Goteo\Benzina\Pump\ArrayPumpTrait;
|
|
use Goteo\Benzina\Pump\DoctrinePumpTrait;
|
|
use Goteo\Benzina\Pump\PumpInterface;
|
|
|
|
class ProjectsPump implements PumpInterface
|
|
{
|
|
use ArrayPumpTrait;
|
|
use DoctrinePumpTrait;
|
|
use DatabasePumpTrait;
|
|
use ProjectsPumpTrait;
|
|
use LocalizedPumpTrait;
|
|
|
|
public function __construct(
|
|
private ProjectRepository $projectRepository,
|
|
private UserRepository $userRepository,
|
|
private TerritoryService $territoryService,
|
|
private EmbedService $embedService,
|
|
) {}
|
|
|
|
public function supports(mixed $sample): bool
|
|
{
|
|
if ($this->hasAllKeys($sample, self::PROJECT_KEYS)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public function pump(mixed $record, array $context): void
|
|
{
|
|
if (empty($record['name'])) {
|
|
return;
|
|
}
|
|
|
|
$status = $this->getProjectStatus($record);
|
|
if (\in_array($status, [ProjectStatus::CampaignReviewRejected])) {
|
|
return;
|
|
}
|
|
|
|
$created = new \DateTime($record['created']);
|
|
if (\in_array($status, [ProjectStatus::InDraft, ProjectStatus::InDraft]) && $created < new \DateTime('2024-01-01')) {
|
|
return;
|
|
}
|
|
|
|
$owner = $this->getProjectOwner($record);
|
|
if ($owner === null) {
|
|
return;
|
|
}
|
|
|
|
$project = $this->getProject($record);
|
|
if ($project === null) {
|
|
$project = new Project();
|
|
}
|
|
|
|
$project->setSlug($record['id']);
|
|
$project->setTerritory($this->getProjectTerritory($record));
|
|
$project->setVideo($this->getProjectVideo($record));
|
|
$project->setOwner($owner);
|
|
$project->setStatus($status);
|
|
$project->setMigrated(true);
|
|
$project->setMigratedId($record['id']);
|
|
$project->setDateCreated($created);
|
|
$project->setDateUpdated(new \DateTime());
|
|
$project->setTranslatableLocale($record['lang']);
|
|
$project->setUpdates(new ArrayCollection($this->getProjectUpdates($project, $context)));
|
|
|
|
$conf = $this->getProjectConf($project, $context);
|
|
|
|
$project->setDeadline($this->getProjectDeadline($conf));
|
|
$project->setCalendar($this->getProjectCalendar($record));
|
|
|
|
$project->addLocale($record['lang']);
|
|
$project->setTitle($record['name'] ?? '');
|
|
$project->setSubtitle($record['subtitle'] ?? '');
|
|
$project->setDescription($this->getProjectDescription($record));
|
|
|
|
$this->setPreventFlushAndClear(true);
|
|
$this->persist($project, $context);
|
|
|
|
$localizations = $this->getProjectLocalizations($project, $context);
|
|
|
|
$this->setPreventFlushAndClear(false);
|
|
$this->localize($project, $localizations, $context, [
|
|
'title' => fn($l) => $l['name'],
|
|
'subtitle' => fn($l) => $l['subtitle'],
|
|
'description' => fn($l) => $this->getProjectDescription($l),
|
|
]);
|
|
}
|
|
|
|
private function getProject(array $record): ?Project
|
|
{
|
|
return $this->projectRepository->findOneBy(['migratedId' => $record['id']]);
|
|
}
|
|
|
|
private function getProjectOwner(array $record): ?User
|
|
{
|
|
return $this->userRepository->findOneBy(['migratedId' => $record['owner']]);
|
|
}
|
|
|
|
private function getProjectDescription(array $record): string
|
|
{
|
|
$lang = $record['lang'];
|
|
$hasTitles = \array_key_exists($lang, self::PROJECT_DESC_TITLES);
|
|
|
|
$description = $record['description'];
|
|
|
|
if ($hasTitles) {
|
|
$description .= \sprintf("\n\n## %s", self::PROJECT_DESC_TITLES[$lang]['about']);
|
|
}
|
|
|
|
$description .= \sprintf("\n%s", $record['about']);
|
|
|
|
if ($hasTitles) {
|
|
$description .= \sprintf("\n\n## %s", self::PROJECT_DESC_TITLES[$lang]['motivation']);
|
|
}
|
|
|
|
$description .= \sprintf("\n\n%s", $record['motivation']);
|
|
|
|
if ($hasTitles) {
|
|
$description .= \sprintf("\n\n## %s", self::PROJECT_DESC_TITLES[$lang]['related']);
|
|
}
|
|
|
|
$description .= \sprintf("\n%s", $record['related']);
|
|
|
|
return $description;
|
|
}
|
|
|
|
private function getProjectLocalizations(Project $project, array $context): array
|
|
{
|
|
$query = $this->getDbConnection($context)->prepare(
|
|
'SELECT * FROM `project_lang` l WHERE l.id = :project'
|
|
);
|
|
|
|
$query->execute(['project' => $project->getMigratedId()]);
|
|
|
|
return $query->fetchAll();
|
|
}
|
|
|
|
private function getProjectCalendar(array $record): ProjectCalendar
|
|
{
|
|
$calendar = new ProjectCalendar();
|
|
$calendar->release = new \DateTimeImmutable($record['published']);
|
|
$calendar->minimum = new \DateTimeImmutable($record['passed'] ?? $record['closed']);
|
|
$calendar->optimum = new \DateTimeImmutable($record['success'] ?? $record['closed']);
|
|
|
|
return $calendar;
|
|
}
|
|
|
|
private function getProjectStatus(array $record): ProjectStatus
|
|
{
|
|
switch ($record['status']) {
|
|
case 1:
|
|
return ProjectStatus::InDraft;
|
|
case 2:
|
|
return ProjectStatus::InCampaignReview;
|
|
case 3:
|
|
return ProjectStatus::InCampaign;
|
|
case 6:
|
|
return ProjectStatus::CampaignFailed;
|
|
case 4:
|
|
case 5:
|
|
return ProjectStatus::FundingPaid;
|
|
case 0:
|
|
default:
|
|
return ProjectStatus::CampaignReviewRejected;
|
|
}
|
|
}
|
|
|
|
private function getProjectTerritory(array $record): Territory
|
|
{
|
|
if ($record['project_location'] === null) {
|
|
return Territory::unknown();
|
|
}
|
|
|
|
$cleanAddress = $this->cleanProjectLocation($record['project_location'], 2);
|
|
|
|
if ($cleanAddress === '') {
|
|
return Territory::unknown();
|
|
}
|
|
|
|
return $this->territoryService->search($cleanAddress);
|
|
}
|
|
|
|
private function getProjectVideoSource(array $record): ?string
|
|
{
|
|
if ($record['video'] !== null) {
|
|
return \trim($record['video']);
|
|
}
|
|
|
|
if ($record['media'] !== null) {
|
|
return \trim($record['media']);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private function getProjectVideo(array $record): ?ProjectVideo
|
|
{
|
|
$url = $this->getProjectVideoSource($record);
|
|
|
|
if ($url === '') {
|
|
return null;
|
|
}
|
|
|
|
if (!\str_contains($url, '.')) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
$video = $this->embedService->getVideo($url);
|
|
|
|
return new ProjectVideo($video->src, $video->thumbnail);
|
|
} catch (\Exception $e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return Update[]
|
|
*/
|
|
private function getProjectUpdates(Project $project, array $context): array
|
|
{
|
|
$updates = [];
|
|
|
|
$milestones = $this->getProjectMilestones($project, $context);
|
|
foreach ($milestones as $milestone) {
|
|
$update = new Update();
|
|
$update->setProject($project);
|
|
$update->setTranslatableLocale($project->getLocales()[0]);
|
|
$update->setTitle($milestone['title']);
|
|
$update->setSubtitle('');
|
|
$update->setBody('');
|
|
$update->setDate(new \DateTime($milestone['date']));
|
|
|
|
$updates[] = $update;
|
|
}
|
|
|
|
$posts = $this->getProjectBlogPosts($project, $context);
|
|
foreach ($posts as $post) {
|
|
if ($post['publish'] == 0) {
|
|
continue;
|
|
}
|
|
|
|
$update = new Update();
|
|
$update->setProject($project);
|
|
$update->setTranslatableLocale($project->getLocales()[0]);
|
|
$update->setTitle($post['title']);
|
|
$update->setSubtitle($post['subtitle'] ?? '');
|
|
$update->setBody($post['text'] ?? '');
|
|
$update->setDate(new \DateTime($post['date']));
|
|
|
|
$updates[] = $update;
|
|
}
|
|
|
|
return $updates;
|
|
}
|
|
|
|
private function getProjectMilestones(Project $project, array $context): array
|
|
{
|
|
$query = $this->getDbConnection($context)->prepare(
|
|
'SELECT p.description AS title, p.image, m.date FROM `milestone` p
|
|
INNER JOIN `project_milestone` m ON m.milestone = p.id
|
|
WHERE m.project = :project
|
|
'
|
|
);
|
|
|
|
$query->execute(['project' => $project->getMigratedId()]);
|
|
|
|
return $query->fetchAll();
|
|
}
|
|
|
|
private function getProjectBlogPosts(Project $project, array $context): array
|
|
{
|
|
$query = $this->getDbConnection($context)->prepare(
|
|
"SELECT * FROM `post` p
|
|
INNER JOIN `blog` b ON b.id = p.blog
|
|
WHERE b.type = 'project'
|
|
AND b.owner = :project
|
|
"
|
|
);
|
|
|
|
$query->execute(['project' => $project->getMigratedId()]);
|
|
|
|
return $query->fetchAll();
|
|
}
|
|
|
|
private function getProjectConf(Project $project, array $context): array
|
|
{
|
|
$query = $this->getDbConnection($context)->prepare(
|
|
'SELECT * FROM `project_conf` WHERE `project` = :project'
|
|
);
|
|
|
|
$query->execute(['project' => $project->getMigratedId()]);
|
|
|
|
$conf = $query->fetch();
|
|
|
|
if (!\is_array($conf)) {
|
|
return [
|
|
'one_round' => 0,
|
|
'days_round1' => 40,
|
|
'days_round2' => 40,
|
|
];
|
|
}
|
|
|
|
return $conf;
|
|
}
|
|
|
|
private function getProjectDeadline(array $conf): ProjectDeadline
|
|
{
|
|
if ($conf['one_round'] < 1) {
|
|
return ProjectDeadline::Optimum;
|
|
}
|
|
|
|
return ProjectDeadline::Minimum;
|
|
}
|
|
}
|