src/Entity/JournalArticle.php line 185
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM,
Doctrine\DBAL\Types\Types,
Doctrine\Common\Collections\Collection,
Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping\Index;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Serializer\Annotation\Groups,
Symfony\Component\Validator\Constraints as Assert;
use ApiPlatform\Metadata\ApiResource,
ApiPlatform\Metadata\ApiProperty,
ApiPlatform\Metadata\Get,
ApiPlatform\Metadata\GetCollection,
ApiPlatform\Metadata\Post,
ApiPlatform\Metadata\Put,
ApiPlatform\Metadata\Delete,
ApiPlatform\Metadata\ApiFilter,
ApiPlatform\Doctrine\Orm\Filter\SearchFilter,
ApiPlatform\Doctrine\Orm\Filter\DateFilter,
ApiPlatform\Doctrine\Orm\Filter\ExistsFilter,
ApiPlatform\Doctrine\Orm\Filter\OrderFilter,
ApiPlatform\Doctrine\Orm\Filter\BooleanFilter,
ApiPlatform\Doctrine\Orm\Filter\RangeFilter;
use App\Entity\Trait\IdTrait,
App\Entity\Trait\UuidTrait,
App\Entity\Trait\OrdStatTrait,
App\Entity\Trait\TimestampableTrait,
App\Entity\Trait\TranslatableTrait,
App\Entity\Trait\Languages\LanguageableChildTrait,
App\Entity\Trait\ArchivedTrait,
App\Entity\Trait\ImportIdTrait,
App\Entity\Interface\TranslatableInterface,
App\Entity\Interface\OrdStatableInterface,
App\Entity\Interface\LanguageableChildInterface,
App\Entity\Interface\ArchivableInterface,
App\Entity\Interface\CloneableInterface;
use App\Enum\JournalDateFormat,
App\Enum\JournalArticleType,
App\Enum\JournalLicence,
App\Enum\JournalArticleFileType,
App\Enum\AuthorProperty,
App\Enum\JournalArticleAuthorRole,
App\Doctrine\DBAL\Types\AuthorPropertiesType,
App\Repository\JournalArticleRepository,
App\Security\Voter\ArchivableVoter,
App\Lib\Actions,
App\DTO\CloneDTO,
App\StateProcessor\CloneProcessor,
App\Security\Voter\CloneVoter,
App\Filter\IriFilter,
App\Doctrine\DBAL\Types\LanguagesType;
use App\Util\ClassUtils,
App\Enum\Language,
App\Attribute\DenormalizationInject;
use App\Controller\Export\JournalArticle\JournalArticleCrossrefExporter,
App\Controller\Export\JournalArticle\JournalArticleSimcheckCrossrefExporter,
App\Controller\Export\JournalArticle\JournalArticleFundingCrossrefExporter,
App\Controller\Export\JournalArticle\JournalArticleLicenceFulltextCrossrefExporter,
App\Controller\Export\JournalArticle\JournalArticleReferencesCrossrefExporter,
App\Controller\Export\JournalArticle\JournalArticleJATSExporter;
use App\Controller\Stats\JournalArticleStatsCSVGenerator;
use App\StateProvider\JournalArticleStatsProvider;
#[ApiResource(
description: 'Journal articles',
normalizationContext: ['groups' => [
'read',
'read:' . self::class,
'read:' . self::class . 'Translation',
'read:' . self::class . 'MetadataTranslation'
]],
denormalizationContext: ['groups' => ['write']],
security: 'is_granted("' . Journal::class . '")',
order: ['ord' => 'desc'],
operations: [
new GetCollection(),
new GetCollection(
name: 'get_journal_article_stats',
uriTemplate: '/journal_articles/stats',
provider: JournalArticleStatsProvider::class,
security: 'is_granted("ROLE_MODULE_STATS")',
normalizationContext: ['groups' => ['read:stats']],
),
new GetCollection(
name: 'get_journal_article_stats_csv',
uriTemplate: '/journal_articles/stats/csv',
provider: JournalArticleStatsProvider::class,
controller: JournalArticleStatsCSVGenerator::class,
security: 'is_granted("ROLE_MODULE_STATS")',
),
new Post(
uriTemplate: '/journal_articles/clone',
input: CloneDTO::class,
processor: CloneProcessor::class,
security: 'is_granted("' . Actions::CLONE .'")',
securityMessage: CloneVoter::MESSAGE
),
new Post(denormalizationContext: ['groups' => ['write', 'post']]),
new Get(),
new Get(
name: 'get_journal_article_crossref',
uriTemplate: '/journal_articles/{uuid}/export/crossref',
controller: JournalArticleCrossrefExporter::class
),
new Get(
name: 'get_journal_article_jats',
uriTemplate: '/journal_articles/{uuid}/export/jats',
controller: JournalArticleJATSExporter::class
),
new Get(
name: 'get_journal_article_simcheck_crossref',
uriTemplate: '/journal_articles/{uuid}/export/simcheck_crossref',
controller: JournalArticleSimcheckCrossrefExporter::class
),
new Get(
name: 'get_journal_article_funding_crossref',
uriTemplate: '/journal_articles/{uuid}/export/funding_crossref',
controller: JournalArticleFundingCrossrefExporter::class
),
new Get(
name: 'get_journal_article_licence_fulltext_crossref',
uriTemplate: '/journal_articles/{uuid}/export/licence_fulltext_crossref',
controller: JournalArticleLicenceFulltextCrossrefExporter::class
),
new Get(
name: 'get_journal_article_references_crossref',
uriTemplate: '/journal_articles/{uuid}/export/references_crossref',
controller: JournalArticleReferencesCrossrefExporter::class
),
new Put(),
new Delete(
securityPostDenormalize: 'is_granted("' . Actions::DELETE . '", object)',
securityPostDenormalizeMessage: ArchivableVoter::MESSAGE
),
],
extraProperties: ['standard_put' => false],
)]
#[ApiFilter(SearchFilter::class, properties: [
'translations.title' => 'partial',
'nativeTitle' => 'partial',
'workingTitle' => 'partial',
'uuid' => 'exact',
])]
#[ApiFilter(ExistsFilter::class, properties: ['doi'])]
#[ApiFilter(IriFilter::class, properties: [
'parent',
'issue',
'type',
'section'
])]
#[ApiFilter(DateFilter::class, properties: ['updatedAt'])]
#[ApiFilter(BooleanFilter::class, properties: ['isArchived', 'stat'])]
#[ApiFilter(RangeFilter::class, properties: ['statsAmountOfViews', 'statsAmountOfDownloads'])]
#[ApiFilter(OrderFilter::class, properties: [
'nativeTitle',
'doi',
'pageFrom',
'isOpen',
'onlinePublishedAt',
'updatedAt',
'receivedAt',
'acceptedAt',
'nativeMetadataLanguage',
'parent.nativeTitle',
'issue.nativeTitle',
'issue.volume.nativeTitle',
'section.nativeTitle',
'ord',
'statsAmountOfViews',
'statsAmountOfDownloads'
])]
#[Index(fields: ["importId"], name: "import_id_idx")]
#[Index(fields: ["stat"], name: "stat_idx")]
#[ORM\Entity(repositoryClass: JournalArticleRepository::class)]
class JournalArticle implements
TranslatableInterface,
OrdStatableInterface,
LanguageableChildInterface,
ArchivableInterface,
CloneableInterface
{
use IdTrait,
UuidTrait,
OrdStatTrait,
TimestampableTrait,
TranslatableTrait,
LanguageableChildTrait,
ArchivedTrait,
ImportIdTrait;
const DEFAULT_FILES = [
JournalArticleFileType::BIBLIOGRAPHY,
JournalArticleFileType::ABSTRACT_TEXT,
JournalArticleFileType::FULL_TEXT
];
#[ApiProperty(description: 'Parent', writableLink: false)]
#[Groups(['read', 'post'])]
#[ORM\ManyToOne(targetEntity: Journal::class, inversedBy: 'articles')]
#[ORM\JoinColumn(onDelete: 'cascade', nullable: false)]
private Journal $parent;
#[ApiProperty(description: 'Native title')]
#[Groups(['read', 'read:stats'])]
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $nativeTitle = null;
#[ApiProperty(description: 'Native title raw')]
#[Groups(['read'])]
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $nativeTitleRaw = null;
#[ApiProperty(description: 'Working title')]
#[Groups(['read', 'write'])]
#[Assert\NotBlank]
#[ORM\Column(type: Types::STRING, length: 511)]
private string $workingTitle;
#[ApiProperty(description: 'Licence', writableLink: false)]
#[Groups(['read:' . self::class, 'read:stats', 'write'])]
#[ORM\Column(
type: Types::STRING,
enumType: JournalLicence::class,
length: 255,
options: ['default' => JournalLicence::CC_BY]
)]
private JournalLicence $licence = JournalLicence::CC_BY;
#[ApiProperty(description: 'Issue', writableLink: false, fetchEager: false)]
#[Groups(['read', 'write'])]
#[Assert\NotNull]
#[Assert\Expression(
expression: '!this || value.getParent() === this.getParent()',
message: 'Cannot assign issue from the outside of current journal.'
)]
#[ORM\ManyToOne(targetEntity: JournalIssue::class, inversedBy: 'articles')]
#[ORM\JoinColumn(onDelete: 'cascade', nullable: false)]
private JournalIssue $issue;
#[ApiProperty(description: 'Funding number')]
#[Groups(['read:' . self::class, 'write'])]
#[ORM\Column(type: Types::STRING, length: 255, nullable: true)]
private ?string $fundingNumber = null;
#[ApiProperty(description: 'Type', writableLink: false)]
#[Groups(['read', 'read:stats', 'write'])]
#[ORM\Column(
type: Types::STRING,
enumType: JournalArticleType::class,
length: 255,
options: ['default' => JournalArticleType::ORIGINAL_RESEARCH_ARTICLE
])]
private JournalArticleType $type = JournalArticleType::ORIGINAL_RESEARCH_ARTICLE;
#[ApiProperty(description: 'Section', writableLink: false, fetchEager: false)]
#[Groups(['read:' . self::class, 'write'])]
#[ORM\ManyToOne(targetEntity: JournalSection::class)]
#[ORM\JoinColumn(onDelete: 'set null')]
private ?JournalSection $section = null;
#[ApiProperty(description: 'DOI')]
#[Groups(['read:' . self::class, 'read:stats', 'write'])]
#[ORM\Column(type: Types::STRING, length: 255, nullable: true)]
private ?string $doi = null;
#[ApiProperty(description: 'Page from')]
#[Groups(['read:' . self::class, 'read:stats', 'write'])]
// #[Assert\Positive]
#[ORM\Column(type: Types::STRING, nullable: true)] //, options: ['default' => 1])]
private ?string $pageFrom = null;
#[ApiProperty(description: 'Page to')]
#[Groups(['read:' . self::class, 'read:stats', 'write'])]
// #[Assert\Expression(
// expression: 'value >= this.getPageFrom()',
// message: 'Page to must be greater than page from.'
// )]
#[ORM\Column(type: Types::STRING, nullable: true)] //INTEGER, options: ['default' => 1])]
private ?string $pageTo = null;
#[ApiProperty(description: 'Citation type', writableLink: false)]
#[Groups(['read:' . self::class, 'write'])]
#[ORM\ManyToOne(targetEntity: CitationType::class)]
#[ORM\JoinColumn(onDelete: 'set null')]
private ?CitationType $citationType = null;
#[ApiProperty(description: 'Citation')]
#[Groups(['read:' . self::class, 'write'])]
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $citation = null;
#[ApiProperty(description: 'Received at')]
#[Groups(['read:' . self::class, 'read:stats', 'write'])]
#[ORM\Column(type: Types::DATE_IMMUTABLE, nullable: true)]
private ?\DateTimeImmutable $receivedAt = null;
#[ApiProperty(description: 'Received at format', writableLink: false)]
#[Groups(['read:' . self::class, 'write'])]
#[ORM\Column(
type: Types::STRING,
enumType: JournalDateFormat::class,
length: 255,
options: ['default' => JournalDateFormat::COMPLETE]
)]
private JournalDateFormat $receivedAtFormat = JournalDateFormat::COMPLETE;
#[ApiProperty(description: 'Accepted at')]
#[Groups(['read:' . self::class, 'read:stats', 'write'])]
#[ORM\Column(type: Types::DATE_IMMUTABLE, nullable: true)]
private ?\DateTimeImmutable $acceptedAt = null;
#[ApiProperty(description: 'Accepted at format', writableLink: false)]
#[Groups(['read:' . self::class, 'write'])]
#[ORM\Column(
type: Types::STRING,
enumType: JournalDateFormat::class,
length: 255,
options: ['default' => JournalDateFormat::COMPLETE]
)]
private JournalDateFormat $acceptedAtFormat = JournalDateFormat::COMPLETE;
#[ApiProperty(description: 'Corrected at')]
#[Groups(['read:' . self::class, 'write'])]
#[ORM\Column(type: Types::DATE_IMMUTABLE, nullable: true)]
private ?\DateTimeImmutable $correctedAt = null;
#[ApiProperty(description: 'Corrected at format', writableLink: false)]
#[Groups(['read:' . self::class, 'write'])]
#[ORM\Column(
type: Types::STRING,
enumType: JournalDateFormat::class,
length: 255,
options: ['default' => JournalDateFormat::COMPLETE]
)]
private JournalDateFormat $correctedAtFormat = JournalDateFormat::COMPLETE;
#[ApiProperty(description: 'Online published at')]
#[Groups(['read:' . self::class, 'read:stats', 'write'])]
#[ORM\Column(type: Types::DATE_IMMUTABLE, nullable: true)]
private ?\DateTimeImmutable $onlinePublishedAt = null;
#[ApiProperty(description: 'Online published at format', writableLink: false)]
#[Groups(['read:' . self::class, 'write'])]
#[ORM\Column(
type: Types::STRING,
enumType: JournalDateFormat::class,
length: 255,
options: ['default' => JournalDateFormat::COMPLETE]
)]
private JournalDateFormat $onlinePublishedAtFormat = JournalDateFormat::COMPLETE;
#[ApiProperty(description: 'Is open')]
#[Groups(['read:' . self::class, 'read:stats', 'write'])]
#[ORM\Column(type: Types::BOOLEAN, options: ['default' => true])]
private bool $isOpen = true;
#[ApiProperty(description: 'Price')]
#[Groups(['read:' . self::class])]
#[Assert\PositiveOrZero]
#[ORM\Column(type: Types::INTEGER, nullable: true)]
private ?int $price = null;
#[ApiProperty(description: 'Grace date')]
#[Groups(['read:' . self::class, 'write'])]
#[ORM\Column(type: Types::DATE_IMMUTABLE, nullable: true)]
private ?\DateTimeImmutable $graceDate = null;
#[ApiProperty(description: 'Meta link')]
#[Groups(['read:' . self::class, 'write'])]
#[ORM\Column(type: Types::STRING, length: 255, nullable: true)]
private ?string $metaLink = null;
/** @deprecated */
#[ApiProperty(description: 'Language', writableLink: false)]
#[Groups(['read:' . self::class, 'write'])]
#[ORM\Column(
type: Types::STRING,
enumType: Language::class,
length: 255,
options: ['default' => Language::PL]
)]
private Language $language = Language::PL;
#[ApiProperty(description: 'Visible author properties', writableLink: false)]
#[Groups(['read:' . self::class, 'write'])]
#[Assert\Choice(callback: [AuthorProperty::class, 'cases'], multiple: true)]
#[Assert\Unique]
#[Assert\Count(min: 1)]
#[ORM\Column(type: AuthorPropertiesType::NAME)]
private array $visibleAuthorProperties = [
AuthorProperty::PREFIX,
AuthorProperty::NAME,
AuthorProperty::SURNAME,
AuthorProperty::AFFILIATION
];
#[ApiProperty(description: 'Publication languages', writableLink: false)]
#[Groups(['read:' . self::class, 'write'])]
#[Assert\Choice(callback: [Language::class, 'cases'], multiple: true)]
#[Assert\Unique]
#[Assert\Count(min: 1)]
#[ORM\Column(type: LanguagesType::NAME)]
private array $publicationLanguages = [Language::EN];
#[ApiProperty(description: 'Metadata languages', writableLink: false)]
#[Groups(['read:' . self::class, 'write'])]
#[Assert\Choice(callback: [Language::class, 'cases'], multiple: true)]
#[Assert\Unique]
// #[Assert\Count(min: 1)]
#[ORM\Column(type: LanguagesType::NAME)]
private array $metadataLanguages = [Language::EN, Language::PL];
#[ApiProperty(description: 'Native metadata language')]
#[Groups(['read:' . self::class, 'read:stats'])]
#[ORM\Column(
type: Types::STRING,
enumType: Language::class,
length: 255,
nullable: true,
)]
private ?Language $nativeMetadataLanguage = null;
#[ApiProperty(description: 'Slug')]
#[Groups(['read:' . self::class, 'write'])]
#[Gedmo\Slug(separator: '-', style: 'default', updatable: true, fields: ['nativeTitleRaw'])]
#[ORM\Column(type: Types::STRING, length: 255, nullable: true)]
private ?string $slug = null;
#[ApiProperty(description: 'Statistics: amount of views')]
#[Groups(['read:stats'])]
#[ORM\Column(type: Types::INTEGER)]
private int $statsAmountOfViews = 0;
#[ApiProperty(description: 'Statistics: amount of downloads')]
#[Groups(['read:stats'])]
#[ORM\Column(type: Types::INTEGER)]
private int $statsAmountOfDownloads = 0;
#[ApiProperty(description: 'Metadata translations')]
#[Groups(['read', 'write'])]
#[Assert\Type(Collection::class)]
#[Assert\Valid]
#[DenormalizationInject(method: ['name' => 'getMetadataTranslation', 'key' => 'lang'])]
#[ORM\OneToMany(
targetEntity: JournalArticleMetadataTranslation::class,
mappedBy: 'parent',
cascade: ['persist', 'remove'],
orphanRemoval: true,
indexBy: 'lang'
)]
private Collection $metadataTranslations;
#[ApiProperty(description: 'Classifications')]
#[ORM\OneToMany(targetEntity: JournalArticleClassification::class, mappedBy: 'parent', cascade: ['persist'])]
#[ORM\OrderBy(['ord' => 'desc'])]
private Collection $classifications;
#[ApiProperty(description: 'Research datas')]
#[ORM\OneToMany(targetEntity: JournalArticleResearchData::class, mappedBy: 'parent', cascade: ['persist'])]
#[ORM\OrderBy(['ord' => 'desc'])]
private Collection $researchDatas;
#[ApiProperty(description: 'Relationships')]
#[ORM\OneToMany(targetEntity: JournalArticleRelationship::class, mappedBy: 'parent', cascade: ['persist'])]
#[ORM\OrderBy(['ord' => 'desc'])]
private Collection $relationships;
#[ApiProperty(description: 'Content blocks')]
#[ORM\OneToMany(targetEntity: JournalArticleContentBlock::class, mappedBy: 'parent', cascade: ['persist'])]
#[ORM\OrderBy(['ord' => 'desc'])]
private Collection $contentBlocks;
#[ApiProperty(description: 'Additional blocks')]
#[ORM\OneToMany(targetEntity: JournalArticleAdditionalBlock::class, mappedBy: 'parent')]
#[ORM\OrderBy(['ord' => 'desc'])]
private Collection $additionalBlocks;
#[ApiProperty(description: 'Bibliography entries')]
#[ORM\OneToMany(
targetEntity: JournalArticleBibliographyEntry::class,
mappedBy: 'parent',
cascade: ['persist', 'remove'],
orphanRemoval: true
)]
#[ORM\OrderBy(['ord' => 'desc'])]
private Collection $bibliographyEntries;
#[ApiProperty(description: 'Files')]
#[ORM\OneToMany(targetEntity: JournalArticleFile::class, mappedBy: 'parent', cascade: ['persist'])]
#[ORM\OrderBy(['ord' => 'desc'])]
private Collection $files;
#[ApiProperty(description: 'Authors')]
#[Groups(['read:' . self::class])]
#[ORM\OneToMany(targetEntity: JournalArticleAuthor::class, mappedBy: 'parent')]
#[ORM\OrderBy(['ord' => 'desc'])]
private Collection $authors;
private ?array $redactors = null;
#[ApiProperty(description: 'View entries')]
#[ORM\OneToMany(targetEntity: JournalArticleViewEntry::class, mappedBy: 'parent', cascade: ['persist'])]
#[ORM\OrderBy(['createdAt' => 'desc'])]
private Collection $viewEntries;
#[ApiProperty(description: 'Download entries')]
#[ORM\OneToMany(targetEntity: JournalArticleDownloadEntry::class, mappedBy: 'parent', cascade: ['persist'])]
#[ORM\OrderBy(['createdAt' => 'desc'])]
private Collection $downloadEntries;
#[ApiProperty(description: 'Slug title language', writableLink: false)]
#[Groups(['read:' . self::class, 'write'])]
#[Assert\Choice(callback: 'getMetadataLanguages', message: 'Można wybrać tylko jeden z języków tekstu.')]
#[ORM\Column(
type: Types::STRING,
enumType: Language::class,
length: 255,
nullable: true,
)]
private ?Language $slugTitleLanguage = null;
#[ORM\OneToMany(mappedBy: 'parent', targetEntity: JournalArticleSlugHistory::class, cascade: ['persist'], orphanRemoval: true,)]
private Collection $slugHistory;
public function __construct(Journal $parent, JournalIssue $issue)
{
$this->setUuid();
$this->parent = $parent;
$this->issue = $issue;
$this->translations = new ArrayCollection();
$this->metadataTranslations = new ArrayCollection();
$this->classifications = new ArrayCollection();
$this->researchDatas = new ArrayCollection();
$this->relationships = new ArrayCollection();
$this->contentBlocks = new ArrayCollection();
$this->additionalBlocks = new ArrayCollection();
$this->bibliographyEntries = new ArrayCollection();
$this->files = new ArrayCollection();
$this->authors = new ArrayCollection();
$this->viewEntries = new ArrayCollection();
$this->downloadEntries = new ArrayCollection();
$this->slugHistory = new ArrayCollection();
foreach ($this->parent->getLanguages() as $lang) {
new JournalArticleTranslation($this, $lang);
}
foreach ($this->metadataLanguages as $lang) {
new JournalArticleMetadataTranslation($this, $lang);
}
foreach (self::DEFAULT_FILES as $type) {
new JournalArticleFile($this, $type);
}
$this->isOpen = $issue->getIsOpen();
$this->price = $issue->getPrice();
$this->citationType = $issue->getSuggestedCitationType();
$this->licence = $issue->getLicence();
$this->createdAt = new \DateTimeImmutable();
$this->updatedAt = new \DateTimeImmutable();
$parent->addArticle($this);
}
public function getParent(): Journal
{
return $this->parent;
}
public function getNativeMetadataLanguage(): ?Language
{
return $this->nativeMetadataLanguage;
}
public function getNativeTitle(): ?string
{
return $this->nativeTitle;
}
public function setNativeTitle(?string $nativeTitle): self
{
$this->nativeTitle = $nativeTitle;
return $this;
}
public function getNativeTitleRaw(): ?string
{
return $this->nativeTitleRaw;
}
public function setNativeTitleRaw(?string $nativeTitleRaw): self
{
$this->nativeTitleRaw = $nativeTitleRaw;
$this->addCurrentSlugToHistory();
return $this;
}
public function getWorkingTitle(): ?string
{
return $this->workingTitle;
}
public function setWorkingTitle(?string $workingTitle): self
{
$this->workingTitle = $workingTitle;
return $this;
}
public function getLicence(): JournalLicence
{
return $this->licence;
}
public function setLicence(JournalLicence $licence): self
{
$this->licence = $licence;
return $this;
}
public function getIssue(): JournalIssue
{
return $this->issue;
}
public function setIssue(JournalIssue $issue): self
{
$this->issue = $issue;
return $this;
}
public function getFundingNumber(): ?string
{
return $this->fundingNumber;
}
public function setFundingNumber(?string $fundingNumber): self
{
$this->fundingNumber = $fundingNumber;
return $this;
}
public function getType(): JournalArticleType
{
return $this->type;
}
public function setType(JournalArticleType $type): self
{
$this->type = $type;
return $this;
}
public function getSection(): ?JournalSection
{
return $this->section;
}
public function setSection(?JournalSection $section): self
{
$this->section = $section;
return $this;
}
public function getDoi(): ?string
{
return $this->doi;
}
public function setDoi(?string $doi): self
{
$this->doi = $doi;
return $this;
}
public function getPageFrom(): ?string
{
return $this->pageFrom;
}
public function setPageFrom(?string $pageFrom): self
{
$this->pageFrom = $pageFrom;
return $this;
}
public function getPageTo(): ?string
{
return $this->pageTo;
}
public function setPageTo(?string $pageTo): self
{
$this->pageTo = $pageTo;
return $this;
}
public function getCitationType(): ?CitationType
{
return $this->citationType;
}
public function setCitationType(?CitationType $citationType): self
{
$this->citationType = $citationType;
return $this;
}
public function getCitation(): ?string
{
return $this->citation;
}
public function setCitation(?string $citation): self
{
$this->citation = $citation;
return $this;
}
public function getReceivedAt(): ?\DateTimeImmutable
{
return $this->receivedAt;
}
public function setReceivedAt(?\DateTimeImmutable $receivedAt): self
{
$this->receivedAt = $receivedAt;
return $this;
}
public function getReceivedAtFormat(): JournalDateFormat
{
return $this->receivedAtFormat;
}
public function setReceivedAtFormat(JournalDateFormat $receivedAtFormat): self
{
$this->receivedAtFormat = $receivedAtFormat;
return $this;
}
public function getAcceptedAt(): ?\DateTimeImmutable
{
return $this->acceptedAt;
}
public function setAcceptedAt(?\DateTimeImmutable $acceptedAt): self
{
$this->acceptedAt = $acceptedAt;
return $this;
}
public function getAcceptedAtFormat(): JournalDateFormat
{
return $this->acceptedAtFormat;
}
public function setAcceptedAtFormat(JournalDateFormat $acceptedAtFormat): self
{
$this->acceptedAtFormat = $acceptedAtFormat;
return $this;
}
public function getCorrectedAt(): ?\DateTimeImmutable
{
return $this->correctedAt;
}
public function setCorrectedAt(?\DateTimeImmutable $correctedAt): self
{
$this->correctedAt = $correctedAt;
return $this;
}
public function getCorrectedAtFormat(): JournalDateFormat
{
return $this->correctedAtFormat;
}
public function setCorrectedAtFormat(JournalDateFormat $correctedAtFormat): self
{
$this->correctedAtFormat = $correctedAtFormat;
return $this;
}
public function getOnlinePublishedAt(): ?\DateTimeImmutable
{
return $this->onlinePublishedAt;
}
public function setOnlinePublishedAt(?\DateTimeImmutable $onlinePublishedAt): self
{
if ($this->onlinePublishedAt === $onlinePublishedAt) {
return $this;
}
$this->onlinePublishedAt = $onlinePublishedAt;
if (! $onlinePublishedAt) {
return $this;
}
$period = $this->parent->getData()->getOpenAccessGrantedAfterPeriod();
if (! $period) {
return $this;
}
$graceDate = new \DateTime("@{$this->onlinePublishedAt->getTimestamp()}");
$graceDate->modify($period);
$this->graceDate = new \DateTimeImmutable("@{$graceDate->getTimestamp()}");
return $this;
}
public function getOnlinePublishedAtFormat(): JournalDateFormat
{
return $this->onlinePublishedAtFormat;
}
public function setOnlinePublishedAtFormat(JournalDateFormat $onlinePublishedAtFormat): self
{
$this->onlinePublishedAtFormat = $onlinePublishedAtFormat;
return $this;
}
public function getAllDatesFormatted(): array
{
$properties = ['ReceivedAt', 'AcceptedAt', 'CorrectedAt', 'OnlinePublishedAt'];
$dates = [];
foreach ($properties as $property) {
$date = $this->{'get' . $property}();
$dates[$property] = null;
if (! $date) {
continue;
}
$dates[$property] = match($this->{'get' . $property . 'Format'}()) {
JournalDateFormat::YEAR => $date->format('Y'),
JournalDateFormat::YEAR_AND_MONTH => $date->format('m.Y'),
JournalDateFormat::COMPLETE => $date->format('d.m.Y'),
default => null,
};
}
return $dates;
}
public function getIsOpen(): bool
{
return $this->isOpen;
}
public function setIsOpen(bool $isOpen): self
{
$this->isOpen = $isOpen;
return $this;
}
public function getPrice(): ?int
{
return $this->price;
}
#[Groups(['read:' . self::class, 'read:' . Journal::class])]
public function getPriceReal(): ?float
{
return $this->price ? round($this->price / 1000, 2) : null;
}
public function setPrice(?int $price): self
{
$this->price = $price;
return $this;
}
#[Groups(['write'])]
public function setPriceReal(?float $priceReal): self
{
$this->price = (int) ($priceReal * 1000);
return $this;
}
public function getGraceDate(): ?\DateTimeImmutable
{
return $this->graceDate;
}
public function setGraceDate(?\DateTimeImmutable $graceDate): self
{
$this->graceDate = $graceDate;
return $this;
}
public function getMetaLink(): ?string
{
return $this->metaLink;
}
public function setMetaLink(?string $metaLink): self
{
$this->metaLink = $metaLink;
return $this;
}
/** @deprecated */
public function getLanguage(): Language
{
return $this->language;
}
/** @deprecated */
public function setLanguage(Language $language): self
{
$this->language = $language;
return $this;
}
public function getVisibleAuthorProperties(): array
{
return $this->visibleAuthorProperties;
}
public function setVisibleAuthorProperties(array $visibleAuthorProperties): self
{
$this->visibleAuthorProperties = $visibleAuthorProperties;
return $this;
}
public function getPublicationLanguages(): array
{
return $this->publicationLanguages;
}
public function setPublicationLanguages(array $publicationLanguages): self
{
$this->publicationLanguages = $publicationLanguages;
return $this;
}
public function getMetadataLanguages(): array
{
return $this->metadataLanguages;
}
public function setMetadataLanguages(array $metadataLanguages): self
{
$this->metadataLanguages = $metadataLanguages;
/** @var JournalArticleMetadataTranslation */
foreach ($this->metadataTranslations as $metadataTranslation) {
if (in_array($metadataTranslation->getLang(), $this->metadataLanguages)) {
continue;
}
$this->deleteMetadataTranslation($metadataTranslation);
}
foreach ($this->metadataLanguages as $lang) {
if (! $lang instanceof Language || isset($this->metadataTranslations[$lang->value])) {
continue;
}
$class = JournalArticleMetadataTranslation::class;
new $class($this, $lang);
}
if (count($metadataLanguages) < 1) {
$this->nativeMetadataLanguage = null;
return $this;
}
$this->nativeMetadataLanguage = $this->metadataLanguages[array_key_first($this->metadataLanguages)];
return $this;
}
public function getAvailableMetadataLanguages(string $property): array
{
$langs = [];
foreach($this->metadataLanguages as $lang) {
/** @var JournalArticleMetadataTranslation */
$metadataTranslation = $this->getMetadataTranslation($lang);
switch($property) {
case 'abstract':
if (! empty($metadataTranslation->getAbstract())) {
$langs[] = $lang;
}
break;
case 'keywords':
if (! empty($metadataTranslation->getKeywords())) {
$langs[] = $lang;
}
break;
case 'title':
if (! empty($metadataTranslation->getTitle())) {
$langs[] = $lang;
}
default:
break;
}
}
return $langs;
}
public function getSlug(): ?string
{
return $this->slug;
}
public function setSlug(?string $slug): self
{
$this->slug = $slug;
return $this;
}
public function getStatsAmountOfViews(): int
{
return $this->statsAmountOfViews;
}
public function hitStatsView(): int
{
return $this->statsAmountOfViews++;
}
/*
public function updateStatsView(int $amount): self
{
$this->statsAmountOfViews += $amount;
return $this;
}*/
public function getStatsAmountOfDownloads(): int
{
return $this->statsAmountOfDownloads;
}
public function hitStatsDownload(): int
{
return $this->statsAmountOfDownloads++;
}
/*
public function updateStatsDownload(int $amount): self
{
$this->statsAmountOfDownloads += $amount;
return $this;
}*/
/**
* @return Collection|JournalArticleMetadataTranslation[]
*/
public function getMetadataTranslations(): Collection
{
return $this->metadataTranslations;
}
public function getMetadataTranslation(Language $lang): mixed
{
return $this->metadataTranslations[$lang->value] ?? null;
}
public function addMetadataTranslation(JournalArticleMetadataTranslation $metadataTranslation): self
{
if ($this->metadataTranslations->contains($metadataTranslation)) {
return $this;
}
$this->metadataTranslations[
$metadataTranslation->getLang()->value
] = $metadataTranslation;
return $this;
}
public function deleteMetadataTranslation(JournalArticleMetadataTranslation $metadataTranslation): self
{
$this->metadataTranslations->removeElement($metadataTranslation);
return $this;
}
public function resetMetadataTranslations(): self
{
$this->metadataTranslations = new ArrayCollection();
return $this;
}
public function readMetadataTranslation(null|string|Language $lang, string $property): mixed
{
if (! $lang) {
return null;
}
$lang = is_string($lang)
? Language::from($lang)
: $lang;
if (! isset($this->metadataTranslations[$lang->value])) {
return null;
}
if (! str_contains($property, '.')) {
return $this->metadataTranslations[$lang->value]->{'get' . ucfirst($property)}();
}
$path = explode('.', $property);
$current = array_shift($path);
return $this->readProperty(
object: $this->metadataTranslations[$lang->value]->{'get'. ucfirst($current)}(),
path: $path
);
}
public function readAvailableMetadataTranslation(
string|Language $lang,
string $property,
bool $isNotEmpty = true
): mixed {
$lang = is_string($lang)
? Language::from($lang)
: $lang;
if (! $this->isLanguageAvailable($lang, $this->metadataLanguages)) {
return $this->readMetadataTranslation($this->nativeMetadataLanguage, $property);
}
$value = $this->readMetadataTranslation($lang, $property);
if ($isNotEmpty && empty($value)) {
return $this->readMetadataTranslation($this->nativeMetadataLanguage, $property);
}
return $value;
}
private function isLanguageAvailable(Language $lang, ?array $languages): bool
{
return ! $languages || in_array($lang, $languages);
}
/**
* @return Collection|JournalArticleClassification[]
*/
public function getClassifications(): Collection
{
return $this->classifications;
}
public function getVisibleClassifications(): Collection
{
return $this->getClassifications()->filter(
fn(JournalArticleClassification $classification) => $classification->getType()->getStat() === true
);
}
public function addClassification(JournalArticleClassification $classification): self
{
if ($this->classifications->contains($classification)) {
return $this;
}
$this->classifications[] = $classification;
return $this;
}
public function removeClassification(JournalArticleClassification $classification): self
{
$this->classifications->removeElement($classification);
return $this;
}
public function resetClassifications(): self
{
$this->classifications = new ArrayCollection();
return $this;
}
/**
* @return Collection|JournalArticleResearchData[]
*/
public function getResearchDatas(): Collection
{
return $this->researchDatas;
}
public function addResearchData(JournalArticleResearchData $researchData): self
{
if ($this->researchDatas->contains($researchData)) {
return $this;
}
$this->researchDatas[] = $researchData;
return $this;
}
public function removeResearchData(JournalArticleResearchData $researchData): self
{
$this->researchDatas->removeElement($researchData);
return $this;
}
public function resetResearchDatas(): self
{
$this->researchDatas = new ArrayCollection();
return $this;
}
/**
* @return Collection|JournalArticleRelationship[]
*/
public function getRelationships(): Collection
{
return $this->relationships;
}
public function addRelationship(JournalArticleRelationship $relationship): self
{
if ($this->relationships->contains($relationship)) {
return $this;
}
$this->relationships[] = $relationship;
return $this;
}
public function removeRelationship(JournalArticleRelationship $relationship): self
{
$this->relationships->removeElement($relationship);
return $this;
}
public function resetRelationships(): self
{
$this->relationships = new ArrayCollection();
return $this;
}
/**
* @return Collection|JournalArticleContentBlock[]
*/
public function getContentBlocks(): Collection
{
return $this->contentBlocks;
}
public function getVisibleContentBlocks(): Collection
{
return $this->contentBlocks->filter(
fn (JournalArticleContentBlock $block) => $block->getStat() === true
);
}
public function addContentBlock(JournalArticleContentBlock $contentBlock): self
{
if ($this->contentBlocks->contains($contentBlock)) {
return $this;
}
$this->contentBlocks[] = $contentBlock;
return $this;
}
public function removeContentBlock(JournalArticleContentBlock $contentBlock): self
{
$this->contentBlocks->removeElement($contentBlock);
return $this;
}
public function resetContentBlocks(): self
{
$this->contentBlocks = new ArrayCollection();
return $this;
}
/**
* @return Collection|JournalArticleAddditionalBlock[]
*/
public function getAdditionalBlocks(): Collection
{
return $this->additionalBlocks;
}
public function getVisibleAdditionalBlocks(): Collection
{
return $this->additionalBlocks->filter(
fn (JournalArticleAdditionalBlock $block) => $block->getStat() === true
);
}
public function addAdditionalBlock(JournalArticleAdditionalBlock $additionalBlock): self
{
if ($this->additionalBlocks->contains($additionalBlock)) {
return $this;
}
$this->additionalBlocks[] = $additionalBlock;
return $this;
}
public function removeAdditionalBlock(JournalArticleAdditionalBlock $additionalBlock): self
{
$this->additionalBlocks->removeElement($additionalBlock);
return $this;
}
public function resetAdditionalBlocks(): self
{
$this->additionalBlocks = new ArrayCollection();
return $this;
}
/**
* @return Collection|JournalArticleBibliographyEntry[]
*/
public function getBibliographyEntries(): Collection
{
return $this->bibliographyEntries;
}
public function addBibliographyEntry(JournalArticleBibliographyEntry $bibliographyEntry): self
{
if ($this->bibliographyEntries->contains($bibliographyEntry)) {
return $this;
}
$this->bibliographyEntries[] = $bibliographyEntry;
return $this;
}
public function removeBibliographyEntry(JournalArticleBibliographyEntry $bibliographyEntry): self
{
$this->bibliographyEntries->removeElement($bibliographyEntry);
return $this;
}
public function resetBibliographyEntries(): self
{
$this->bibliographyEntries = new ArrayCollection();
return $this;
}
public function importBibliography(): self
{
$nativeLanguage = $this->getParentNativeLanguage();
$nativeTranslation = $this->getTranslation($nativeLanguage);
if (! $nativeTranslation?->getImportedBibliography()) {
return $this;
}
$otherLanguages = array_filter(
$this->getParentLanguages(),
fn(Language $lang) => $nativeLanguage !== $lang
);
$imported = [];
foreach([$nativeLanguage] + $otherLanguages as $lang) {
$imported[$lang->value] = $this->getImportedBibliographyEntries($lang);
}
$this->resetBibliographyEntries();
$ord = count($imported[$nativeLanguage->value]);
foreach($imported[$nativeLanguage->value] as $key => $title) {
preg_match('/10.\d{4,9}\/[-._;()\/:A-Z0-9]+$/i', $title, $doi);
$entry = new JournalArticleBibliographyEntry($this);
$entry
->setDoi($doi[0] ?? null)
->setOrd($ord--);
$translation = $entry->getTranslation($nativeLanguage);
$translation->setTitle($title);
$this->fillBibliographyEntryTranslations(
entry: $entry,
languages: $otherLanguages,
imported: $imported,
key: $key
);
}
return $this;
}
private function getImportedBibliographyEntries(Language $lang): array
{
$importedBibliography = $this->getTranslation($lang)?->getImportedBibliography() ?? '';
$bibliographyEntries = array_map(
fn(string $bibliograpyEntry) => trim($bibliograpyEntry),
preg_split('/\r\n|\r|\n|<br>|<br \/>|<br\/>/', $importedBibliography)
);
$bibliographyEntries = array_filter(
$bibliographyEntries,
fn(string $bibliograpyEntry) => ! empty($bibliograpyEntry)
);
return $bibliographyEntries;
}
private function fillBibliographyEntryTranslations(
JournalArticleBibliographyEntry $entry,
array $languages,
array $imported,
int $key
): self {
foreach($languages as $language) {
$translation = $entry->getTranslation($language);
$translation->setTitle($imported[$language->value][$key] ?? null);
}
return $this;
}
/**
* @return Collection|JournalArticleFile[]
*/
public function getFiles(): Collection
{
return $this->files;
}
public function addFile(JournalArticleFile $file): self
{
if ($this->files->contains($file)) {
return $this;
}
$this->files[] = $file;
return $this;
}
public function removeFile(JournalArticleFile $file): self
{
$this->files->removeElement($file);
return $this;
}
public function resetFiles(): self
{
$this->files = new ArrayCollection();
return $this;
}
#[Groups(['read:' . self::class])]
public function getHasFiles(): bool
{
foreach($this->files as $file) {
if (! $file->getHasFiles()) {
continue;
}
return true;
}
return false;
}
public function getFullTextFile(): ?JournalArticleFile
{
foreach($this->files as $file) {
if (! $file->getStat() || $file->getType() !== JournalArticleFileType::FULL_TEXT) {
continue;
}
return $file;
}
return null;
}
public function getFullTextTranslationFile(string|Language $lang): ?JournalArticleFileTranslationFile
{
$fullText = $this->getFullTextFile();
if (! $fullText) {
return null;
}
$lang = is_string($lang)
? Language::from($lang)
: $lang;
$files = $fullText->readAvailableTranslation($lang, 'files');
return ($first = $files->first()) === false ? null : $first;
}
/** @return <int, JournalArticleFileTranslationFile> */
public function getAdditionalFiles(string|Language $lang): array
{
$lang = is_string($lang)
? Language::from($lang)
: $lang;
$files = [];
foreach($this->files as $file) {
if (!$file->getStat() || $file->getType() === JournalArticleFileType::FULL_TEXT) {
continue;
}
$files[] = $file;
}
$finalFiles = [];
/** @var JournalArticleFile $file */
foreach ($files as $file) {
/** @var JournalArticleFileTranslation $trans */
$files = $file->readAvailableTranslation($lang, 'files');
if (!$files) {
continue;
}
foreach ($files as $finalFile) {
if (!$finalFile->getMedia() || !$finalFile->getTitle()) {
continue;
}
$finalFiles[] = $finalFile;
}
}
return $finalFiles;
}
public function getFileByType(JournalArticleFileType $type): ?JournalArticleFile
{
return $this->files->findFirst(
fn(int $key, JournalArticleFile $file) => $file->getType() === $type
);
}
/**
* @return Collection|JournalArticleAuthor[]
*/
public function getAuthors(): Collection
{
return $this->authors;
}
public function setAuthors(array $authors): self
{
foreach ($authors as $author) {
$this->authors[] = $author;
}
return $this;
}
public function addAuthor(JournalArticleAuthor $author): self
{
if ($this->authors->contains($author)) {
return $this;
}
$this->authors[] = $author;
return $this;
}
public function removeAuthor(JournalArticleAuthor $author): self
{
$this->authors->removeElement($author);
return $this;
}
public function resetAuthors(): self
{
$this->authors = new ArrayCollection();
return $this;
}
public function getVisibleAuthors(string|Language $lang, ?Author $highlightAuthor = null): array
{
$lang = ! is_string($lang)
? $lang
: Language::from($lang);
$authors = $this->getVisibleAuthorsByRole($lang, JournalArticleAuthorRole::AUTHOR);
if (null !== $highlightAuthor) {
$authors = [
$highlightAuthor,
...array_filter(
$authors,
fn(JournalArticleAuthor $author) => $author->getAuthor()->getUuid() === $highlightAuthor->getUuid()
)
];
}
return $authors;
}
public function getVisibleAuthorsByRole(string|Language $lang, JournalArticleAuthorRole|string $type): array
{
$lang = ! is_string($lang)
? $lang
: Language::from($lang);
$type = is_string($type)
? JournalArticleAuthorRole::from($type)
: $type;
$isNameVisible = in_array(AuthorProperty::NAME, $this->visibleAuthorProperties);
$isSurnameVisible = in_array(AuthorProperty::SURNAME, $this->visibleAuthorProperties);
if (! $isNameVisible && ! $isSurnameVisible) {
return [];
}
return $this->getAuthors()->filter(
fn(JournalArticleAuthor $author) => $author->getRole() === $type
)->toArray();
}
public function getIssueRedactors(): array
{
if ($this->redactors) {
return $this->redactors;
}
$this->redactors = [];
foreach($this->issue?->getEditorialGroups() as $group) {
foreach($group->getMembers() as $member) {
if (in_array($member, $this->redactors)) {
continue;
}
$this->redactors[] = $member;
}
}
return $this->redactors;
}
// -----
// STATS
// -----
/**
* @return Collection|JournalArticleViewEntry[]
*/
public function getViewEntries(): Collection
{
return $this->viewEntries;
}
public function addViewEntry(JournalArticleViewEntry $viewEntry): self
{
if ($this->viewEntries->contains($viewEntry)) {
return $this;
}
$this->viewEntries[] = $viewEntry;
return $this;
}
public function removeViewEntry(JournalArticleViewEntry $viewEntry): self
{
$this->viewEntries->removeElement($viewEntry);
return $this;
}
public function resetViewEntries(): self
{
$this->viewEntries = new ArrayCollection();
return $this;
}
/**
* @return Collection|JournalArticleDownloadEntry[]
*/
public function getDownloadEntries(): Collection
{
return $this->downloadEntries;
}
public function addDownloadEntry(JournalArticleDownloadEntry $downloadEntry): self
{
if ($this->downloadEntries->contains($downloadEntry)) {
return $this;
}
$this->downloadEntries[] = $downloadEntry;
return $this;
}
public function removeDownloadEntry(JournalArticleDownloadEntry $downloadEntry): self
{
$this->downloadEntries->removeElement($downloadEntry);
return $this;
}
public function resetDownloadEntries(): self
{
$this->downloadEntries = new ArrayCollection();
return $this;
}
public function getSlugTitleLanguage(): ?Language
{
if (!$this->slugTitleLanguage) {
if (isset($this->getPublicationLanguages()[0]) && in_array($this->getPublicationLanguages()[0], $this->getMetadataLanguages())) {
return $this->getPublicationLanguages()[0];
}
return $this->nativeMetadataLanguage;
}
return $this->slugTitleLanguage;
}
public function setSlugTitleLanguage(?Language $slugTitleLanguage): self
{
if ($this->slugTitleLanguage !== $slugTitleLanguage && $slugTitleLanguage !== null) {
$this->slugTitleLanguage = $slugTitleLanguage;
foreach ($this->getMetadataTranslations() as $metadataTranslation) {
$metadataTranslation->setTitle($metadataTranslation->getTitle());
}
} else {
$this->slugTitleLanguage = $slugTitleLanguage;
}
return $this;
}
/**
* @return Collection<int, JournalArticleSlugHistory>
*/
public function getSlugHistory(): Collection
{
return $this->slugHistory;
}
public function addCurrentSlugToHistory(): void
{
// check if already in history
foreach ($this->slugHistory as $entry) {
if ($entry->getSlug() === $this->slug) {
return;
}
}
$entry = new JournalArticleSlugHistory($this, $this->slug);
$this->addSlugHistory($entry);
}
public function addSlugHistory(JournalArticleSlugHistory $slugHistory): self
{
if (!$this->slugHistory->contains($slugHistory)) {
$this->slugHistory->add($slugHistory);
}
return $this;
}
public function removeSlugHistory(JournalArticleSlugHistory $slugHistory): self
{
$this->slugHistory->removeElement($slugHistory);
return $this;
}
#[Groups(['read:stats'])]
public function getStatsAuthors(): ?string
{
$authors = [];
/** @var JournalArticleAuthor */
foreach($this->authors as $entry) {
if ($entry->getRole() !== JournalArticleAuthorRole::AUTHOR) {
continue;
}
$author = $entry->getAuthor();
$authors[] = $author->getFullName();
}
return implode(', ', $authors);
}
#[Groups(['read:stats'])]
public function getStatsAuthorsAffiliations(): ?string
{
$affiliations = [];
/** @var JournalArticleAuthor */
foreach($this->authors as $entry) {
if ($entry->getRole() !== JournalArticleAuthorRole::AUTHOR) {
continue;
}
$author = $entry->getAuthor();
/** @var Affiliation */
foreach($author->getAffiliations() as $affiliation) {
if(isset($affiliations[$affiliation->getUuid()->toString()])) {
continue;
}
$affiliations[$affiliation->getUuid()->toString()] = $affiliation->readNativeLanguageTranslation('title');
}
}
return implode(', ', $affiliations);
}
#[Groups(['read:stats'])]
public function getStatsAuthorsCountries(): ?string
{
$countries = [];
/** @var JournalArticleAuthor */
foreach($this->authors as $entry) {
if ($entry->getRole() !== JournalArticleAuthorRole::AUTHOR) {
continue;
}
$author = $entry->getAuthor();
/** @var Affiliation */
foreach($author->getAffiliations() as $affiliation) {
if (! $affiliation->getCountry()) {
continue;
}
if(isset($countries[$affiliation->getCountry()->value])) {
continue;
}
$countries[$affiliation->getCountry()->value] = $affiliation->getCountry()->value;
}
}
return implode(', ', $countries);
}
#[Groups(['read:stats'])]
public function getStatsTranslators(): ?string
{
$authors = [];
/** @var JournalArticleAuthor */
foreach($this->authors as $entry) {
if ($entry->getRole() !== JournalArticleAuthorRole::TRANSLATOR) {
continue;
}
$author = $entry->getAuthor();
$authors[] = $author->getFullName();
}
return implode(', ', $authors);
}
#[Groups(['read:stats'])]
public function getStatsJournal(): string
{
return $this->parent->readNativeLanguageTranslation('title');
}
#[Groups(['read:stats'])]
public function getStatsJournalAffiliations(): string
{
$affiliations = [];
/** @var JournalAffiliation */
foreach($this->parent->getAffiliations() as $entry) {
if (isset($affiliations[$entry->getAffiliation()->getUuid()->toString()])) {
continue;
}
$affiliations[$entry->getAffiliation()->getUuid()->toString()] =
$entry->getAffiliation()->readNativeLanguageTranslation('title');
}
return implode(', ', $affiliations);
}
#[Groups(['read:stats'])]
public function getStatsIssue(): string
{
return $this->issue->readNativeLanguageTranslation('title');
}
#[Groups(['read:stats'])]
public function getStatsVolume(): string
{
return $this->issue->getVolume()->readNativeLanguageTranslation('title');
}
#[Groups(['read:stats'])]
public function getStatsIssueFundingDescription(): ?string
{
return $this->issue->readNativeLanguageTranslation('fundingDescription');
}
#[Groups(['read:stats'])]
public function getStatsVolumeFundingDescription(): ?string
{
return $this->issue->getVolume()->readNativeLanguageTranslation('fundingDescription');
}
#[Groups(['read:stats'])]
public function getStatsSection(): ?string
{
return $this->section?->readNativeLanguageTranslation('title');
}
#[Groups(['read:stats'])]
public function getStatsKeywords(): ?string
{
$keywords = [];
$entries = $this->readMetadataTranslation($this->nativeMetadataLanguage, 'keywords');
/** @var JournalArticleMetadataTranslationKeyword */
foreach($entries as $entry) {
$keywords[] = $entry->getTitle();
}
return implode(', ', $keywords);
}
public function clone(): self
{
$clone = clone $this;
$clone->id = null;
$clone->setUuid();
$clone->ord = 0;
$clone->stat = false;
$clone->importId = null;
ClassUtils::cloneCollection($this, $clone, 'translations');
$clone->synchronizeTranslations();
$nativeLanguage = $clone->parent->getNativeLanguage();
$nativeTranslation = $clone->getTranslation($nativeLanguage);
$nativeTranslation->setTitle($nativeTranslation->getTitle() . ' [KOPIA]');
ClassUtils::cloneCollection($this, $clone, 'classifications');
ClassUtils::cloneCollection($this, $clone, 'researchDatas');
ClassUtils::cloneCollection($this, $clone, 'contentBlocks');
$clone->statsAmountOfViews = 0;
$clone->statsAmountOfDownloads = 0;
$clone
->resetAdditionalBlocks()
->resetBibliographyEntries()
->resetFiles()
->resetAuthors()
->resetViewEntries()
->resetDownloadEntries();
$clone->createdAt = new \DateTimeImmutable();
$clone->updatedAt = new \DateTimeImmutable();
return $clone;
}
}