src/Entity/Journal.php line 146

  1. <?php
  2. namespace App\Entity;
  3. use Doctrine\ORM\Mapping as ORM,
  4.     Doctrine\Common\Collections\Collection,
  5.     Doctrine\Common\Collections\ArrayCollection,
  6.     Doctrine\DBAL\Types\Types,
  7.     Doctrine\Common\Collections\Criteria;
  8. use Doctrine\ORM\Mapping\Index;
  9. use Gedmo\Mapping\Annotation as Gedmo;
  10. use Symfony\Component\Serializer\Annotation\Groups,
  11.     Symfony\Component\Validator\Constraints as Assert;
  12. use ApiPlatform\Metadata\ApiResource,
  13.     ApiPlatform\Metadata\ApiProperty,
  14.     ApiPlatform\Metadata\Get,
  15.     ApiPlatform\Metadata\GetCollection,
  16.     ApiPlatform\Metadata\Post,
  17.     ApiPlatform\Metadata\Put,
  18.     ApiPlatform\Metadata\Delete,
  19.     ApiPlatform\Metadata\ApiFilter,
  20.     ApiPlatform\Doctrine\Orm\Filter\SearchFilter,
  21.     ApiPlatform\Doctrine\Orm\Filter\RangeFilter,
  22.     ApiPlatform\Doctrine\Orm\Filter\DateFilter,
  23.     ApiPlatform\Doctrine\Orm\Filter\BooleanFilter,
  24.     ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
  25. use App\Entity\Trait\IdTrait,
  26.     App\Entity\Trait\UuidTrait,
  27.     App\Entity\Trait\OrdStatTrait,
  28.     App\Entity\Trait\TimestampableTrait,
  29.     App\Entity\Trait\TranslatableTrait,
  30.     App\Entity\Trait\Languages\JournalLanguagesTrait,
  31.     App\Entity\Trait\ArchivedTrait,
  32.     App\Entity\Trait\OwnerTrait,
  33.     App\Entity\Trait\EditorialGroupableTrait,
  34.     App\Entity\Trait\ImportIdTrait,
  35.     App\Entity\Interface\TranslatableInterface,
  36.     App\Entity\Interface\OrdStatableInterface,
  37.     App\Entity\Interface\LanguageableInterface,
  38.     App\Entity\Interface\EditorialGroupableInterface,
  39.     App\Entity\Interface\ArchivableInterface,
  40.     App\Entity\Interface\OwnerableInterface,
  41.     App\Entity\Interface\CloneableInterface,
  42.     App\Repository\JournalRepository;
  43. use App\Enum\Language,
  44.     App\Enum\JournalCoverType,
  45.     App\Enum\JournalDefaultPage,
  46.     App\Entity\Admin,
  47.     App\Security\Voter\ArchivableVoter,
  48.     App\Lib\Actions,
  49.     App\DTO\CloneDTO,
  50.     App\StateProcessor\CloneProcessor,
  51.     App\Security\Voter\CloneVoter;
  52. use App\Attribute\DenormalizationInject,
  53.     App\Util\ClassUtils,
  54.     App\Filter\IriFilter;
  55. use App\Controller\Export\Journal\JournalCrossrefExporter,
  56.     App\Controller\Export\Journal\JournalSimcheckCrossrefExporter,
  57.     App\Controller\Export\Journal\JournalLicenceFulltextCrossrefExporter;
  58. #[ApiResource(
  59.     description'Journals',
  60.     normalizationContext: ['groups' => [
  61.         'read',
  62.         'read:' self::class,
  63.         'read:' self::class . 'Translation'
  64.     ]],
  65.     denormalizationContext: ['groups' => ['write']],
  66.     security'is_granted("' self::class . '")',
  67.     order: ['ord' => 'desc'],
  68.     operations: [
  69.         new GetCollection(),
  70.         new GetCollection(
  71.             uriTemplate'/journals/list',
  72.             normalizationContext: [ 'groups' => ['read''read:list' ]],
  73.         ),
  74.         new Post(
  75.             uriTemplate'/journals/clone',
  76.             inputCloneDTO::class,
  77.             processorCloneProcessor::class,
  78.             security'is_granted("' Actions::CLONE .'")',
  79.             securityMessageCloneVoter::MESSAGE
  80.         ),
  81.         new Post(),
  82.         new Get(),
  83.         new Get(
  84.             name'get_journal_crossref',
  85.             uriTemplate'/journals/{uuid}/export/crossref',
  86.             controllerJournalCrossrefExporter::class
  87.         ),
  88.         new Get(
  89.             name'get_journal_simcheck_crossref',
  90.             uriTemplate'/journals/{uuid}/export/simcheck_crossref',
  91.             controllerJournalSimcheckCrossrefExporter::class
  92.         ),
  93.         new Get(
  94.             name'get_journal_licence_fulltext_crossref',
  95.             uriTemplate'/journals/{uuid}/export/licence_fulltext_crossref',
  96.             controllerJournalLicenceFulltextCrossrefExporter::class
  97.         ),
  98.         new Put(),
  99.         new Delete(
  100.             securityPostDenormalize'is_granted("' Actions::DELETE '", object)',
  101.             securityPostDenormalizeMessageArchivableVoter::MESSAGE
  102.         ),
  103.     ],
  104.     extraProperties: ['standard_put' => false],
  105. )]
  106. #[ApiFilter(SearchFilter::class, properties: [
  107.     'translations.title' => 'partial',
  108.     'nativeTitle' => 'partial',
  109.     'data.workingTitle' => 'partial',
  110.     'data.issn' => 'exact',
  111.     'data.eIssn' => 'exact',
  112. ])]
  113. #[ApiFilter(RangeFilter::class, properties: ['meinScore'])]
  114. #[ApiFilter(DateFilter::class, properties: ['updatedAt'])]
  115. #[ApiFilter(IriFilter::class, properties: [
  116.     'nativeLanguage',
  117.     'domains.domain',
  118.     'affiliations.affiliation',
  119.     'data.periodicity',
  120.     'data.type',
  121.     'data.licence',
  122.     'data.state'
  123. ])]
  124. #[ApiFilter(BooleanFilter::class, properties: ['isArchived''stat'])]
  125. #[ApiFilter(OrderFilter::class, properties: [
  126.     'nativeTitle',
  127.     'nativeLanguage',
  128.     'data.workingTitle',
  129.     'data.periodicity',
  130.     'updatedAt',
  131.     'stat',
  132.     'ord'
  133. ])]
  134. #[Index(fields: ["nativeLanguage"], name"native_language_idx")]
  135. #[Index(fields: ["stat"], name"stat_idx")]
  136. #[ORM\Entity(repositoryClassJournalRepository::class)]
  137. class Journal implements
  138.     TranslatableInterface,
  139.     OrdStatableInterface,
  140.     LanguageableInterface,
  141.     EditorialGroupableInterface,
  142.     ArchivableInterface,
  143.     OwnerableInterface,
  144.     CloneableInterface
  145. {
  146.     use IdTrait,
  147.         UuidTrait,
  148.         OrdStatTrait,
  149.         TimestampableTrait,
  150.         TranslatableTrait,
  151.         JournalLanguagesTrait,
  152.         ArchivedTrait,
  153.         OwnerTrait,
  154.         EditorialGroupableTrait,
  155.         ImportIdTrait;
  156.     #[ApiProperty(description'Native title sort key')]
  157.     #[Groups(['read:' self::class])]
  158.     #[ORM\Column(typeTypes::STRINGlength255nullabletrue)]
  159.     private ?string $nativeTitleSortKey null;
  160.     #[ApiProperty(description'Data subresource'writabletrue)]
  161.     #[Groups(['read:'self::class, 'read:list''write'])]
  162.     #[Assert\Valid]
  163.     #[DenormalizationInject(method: ['name' => 'getData'])]
  164.     #[ORM\OneToOne(targetEntityJournalData::class, mappedBy'parent'cascade: ['persist''remove'])]
  165.     private JournalData $data;
  166.     #[ApiProperty(description'View subresource'writabletrue)]
  167.     #[Groups(['read:' self::class, 'write'])]
  168.     #[Assert\Valid]
  169.     #[DenormalizationInject(method: ['name' => 'getView'])]
  170.     #[ORM\OneToOne(targetEntityJournalView::class, mappedBy'parent'cascade: ['persist''remove'])]
  171.     private JournalView $view;
  172.     #[ApiProperty(description'Slug')]
  173.     #[Groups(['read:' self::class, 'write'])]
  174.     #[Gedmo\Slug(separator'-'style'default'updatabletruefields: ['nativeTitle'])]
  175.     #[ORM\Column(typeTypes::STRINGlength255nullabletrue)]
  176.     private ?string $slug null;
  177.     #[ApiProperty(description'Slug')]
  178.     #[Groups(['read:' self::class, 'write'])]
  179.     #[ORM\Column(typeTypes::STRINGlength255nullabletrue)]
  180.     private ?string $importSlug null;
  181.     #[ApiProperty(description'Slug')]
  182.     #[Groups(['read:' self::class, 'write'])]
  183.     #[ORM\Column(typeTypes::STRINGlength255nullabletrue)]
  184.     private ?string $importSlugEn null;
  185.     #[ApiProperty(description'Scientific council members'writableLinkfalse)]
  186.     #[ORM\OneToMany(targetEntityJournalScientificCouncilMember::class, mappedBy'parent'cascade: ['persist'])]
  187.     #[ORM\OrderBy(['ord' => 'desc'])]
  188.     private Collection $scientificCouncilMembers;
  189.     #[ApiProperty(description'Domains'fetchEagerfalse)]
  190.     #[Groups(['read''read:list'])]
  191.     #[ORM\OneToMany(targetEntityJournalDomain::class, mappedBy'parent'cascade: ['persist''remove'])]
  192.     #[ORM\OrderBy(['ord' => 'desc'])]
  193.     private Collection $domains;
  194.     #[ApiProperty(description'Indexation collections')]
  195.     #[ORM\OneToMany(targetEntityJournalIndexationCollection::class, mappedBy'parent'cascade: ['persist''remove'])]
  196.     #[ORM\OrderBy(['ord' => 'desc'])]
  197.     private Collection $indexationCollections;
  198.     #[ApiProperty(description'Indicators')]
  199.     #[ORM\OneToMany(targetEntityJournalIndicator::class, mappedBy'parent'cascade: ['persist''remove'])]
  200.     #[ORM\OrderBy(['ord' => 'desc'])]
  201.     private Collection $indicators;
  202.     #[ApiProperty(description'Affiliations'fetchEagerfalse)]
  203.     #[Groups(['read','read:list'])]
  204.     #[ORM\OneToMany(targetEntityJournalAffiliation::class, mappedBy'parent'cascade: ['persist''remove'])]
  205.     #[ORM\OrderBy(['ord' => 'desc'])]
  206.     private Collection $affiliations;
  207.     #[ApiProperty(description'Publishers')]
  208.     #[ORM\OneToMany(targetEntityJournalPublisher::class, mappedBy'parent'cascade: ['persist''remove'])]
  209.     #[ORM\OrderBy(['ord' => 'desc'])]
  210.     private Collection $publishers;
  211.     #[ApiProperty(description'Partners')]
  212.     #[ORM\OneToMany(targetEntityJournalPartner::class, mappedBy'parent'cascade: ['persist''remove'])]
  213.     #[ORM\OrderBy(['ord' => 'desc'])]
  214.     private Collection $partners;
  215.     #[ApiProperty(description'Slides')]
  216.     #[ORM\OneToMany(targetEntityJournalSlide::class, mappedBy'parent'cascade: ['persist''remove'])]
  217.     #[ORM\OrderBy(['ord' => 'desc'])]
  218.     private Collection $slides;
  219.     #[ApiProperty(description'Sections')]
  220.     #[ORM\OneToMany(targetEntityJournalSection::class, mappedBy'parent'cascade: ['persist''remove'])]
  221.     #[ORM\OrderBy(['ord' => 'desc'])]
  222.     private Collection $sections;
  223.     #[ApiProperty(description'Menu items')]
  224.     #[ORM\OneToMany(targetEntityJournalMenuItem::class, mappedBy'parent'cascade: ['persist''remove'])]
  225.     #[ORM\OrderBy(['ord' => 'desc'])]
  226.     private Collection $menuItems;
  227.     #[ApiProperty(description'Submenu groups')]
  228.     #[ORM\OneToMany(targetEntityJournalSubmenuGroup::class, mappedBy'parent'cascade: ['persist''remove'])]
  229.     #[ORM\OrderBy(['ord' => 'desc'])]
  230.     private Collection $submenuGroups;
  231.     #[ApiProperty(description'Sidemenu groups')]
  232.     #[ORM\OneToMany(targetEntityJournalSidemenuGroup::class, mappedBy'parent'cascade: ['persist''remove'])]
  233.     #[ORM\OrderBy(['ord' => 'desc'])]
  234.     private Collection $sidemenuGroups;
  235.     #[ApiProperty(description'Banners')]
  236.     #[ORM\OneToMany(targetEntityJournalBanner::class, mappedBy'parent'cascade: ['persist''remove'])]
  237.     #[ORM\OrderBy(['ord' => 'desc'])]
  238.     private Collection $banners;
  239.     #[ApiProperty(description'Volumes')]
  240.     #[ORM\OneToMany(targetEntityJournalVolume::class, mappedBy'parent'cascade: ['persist''remove'])]
  241.     #[ORM\OrderBy(['ord' => 'desc'])]
  242.     private Collection $volumes;
  243.     #[ApiProperty(description'Issues')]
  244.     #[ORM\OneToMany(targetEntityJournalIssue::class, mappedBy'parent'cascade: ['persist''remove'])]
  245.     #[ORM\OrderBy(['ord' => 'desc'])]
  246.     private Collection $issues;
  247.     #[ApiProperty(description'Articles')]
  248.     #[ORM\OneToMany(targetEntityJournalArticle::class, mappedBy'parent'cascade: ['persist''remove'])]
  249.     #[ORM\OrderBy(['ord' => 'desc'])]
  250.     private Collection $articles;
  251.     #[ApiProperty(description'Pages')]
  252.     #[ORM\OneToMany(targetEntityJournalPage::class, mappedBy'parent'cascade: ['persist''remove'])]
  253.     #[ORM\OrderBy(['ord' => 'desc'])]
  254.     private Collection $pages;
  255.     #[ApiProperty(description'News')]
  256.     #[ORM\OneToMany(targetEntityJournalNews::class, mappedBy'parent'cascade: ['persist''remove'])]
  257.     #[ORM\OrderBy(['ord' => 'desc'])]
  258.     private Collection $news;
  259.     #[ApiProperty(description'Collections')]
  260.     #[ORM\OneToMany(targetEntityJournalCollection::class, mappedBy'parent'cascade: ['persist''remove'])]
  261.     #[ORM\OrderBy(['ord' => 'desc'])]
  262.     private Collection $collections;
  263.     #[ApiProperty(description'Sort article by ord')]
  264.     #[Groups(['read:' self::class, 'write'])]
  265.     #[ORM\Column(typeTypes::BOOLEANoptions: ['default' => false])]
  266.     private bool $sortArticlesByOrd false;
  267.     #[ORM\OneToMany(mappedBy'parent'targetEntityJournalFooter::class, orphanRemovaltrue)]
  268.     private Collection $smallFooters;
  269.     public function __construct(Admin $createdBy, ?array $languages)
  270.     {
  271.         $this->setUuid();
  272.         $this->data = new JournalData($this);
  273.         $this->view = new JournalView($this);
  274.         $this->createdBy $createdBy;
  275.         $this->updatedBy $createdBy;
  276.         $this->translations = new ArrayCollection();
  277.         $this->domains = new ArrayCollection();
  278.         $this->indexationCollections = new ArrayCollection();
  279.         $this->indicators = new ArrayCollection();
  280.         $this->affiliations = new ArrayCollection();
  281.         $this->publishers = new ArrayCollection();
  282.         $this->partners = new ArrayCollection();
  283.         $this->slides = new ArrayCollection();
  284.         $this->editorialGroups = new ArrayCollection();
  285.         $this->scientificCouncilMembers = new ArrayCollection();
  286.         $this->sections = new ArrayCollection();
  287.         $this->menuItems = new ArrayCollection();
  288.         $this->submenuGroups = new ArrayCollection();
  289.         $this->sidemenuGroups = new ArrayCollection();
  290.         $this->banners = new ArrayCollection();
  291.         $this->volumes = new ArrayCollection();
  292.         $this->issues = new ArrayCollection();
  293.         $this->articles = new ArrayCollection();
  294.         $this->pages = new ArrayCollection();
  295.         $this->news = new ArrayCollection();
  296.         $this->collections = new ArrayCollection();
  297.         $this->setLanguages($languages ?? Language::DEFAULT_JOURNAL);
  298.         foreach (array_reverse(JournalDefaultPage::cases()) as $index => $idName) {
  299.             new JournalPage(
  300.                 parent$this,
  301.                 workingTitle$idName->value,
  302.                 idName$idName->value,
  303.                 ord$index 1,
  304.                 stattrue
  305.             );
  306.         }
  307.         $this->createdAt = new \DateTimeImmutable();
  308.         $this->updatedAt = new \DateTimeImmutable();
  309.         $this->smallFooters = new ArrayCollection();
  310.     }
  311.     public function getTitle(): string
  312.     {
  313.         return $this->data->getWorkingTitle();
  314.     }
  315.     public function setNativeTitleSortKey(string $nativeTitleSortKey): self
  316.     {
  317.         $this->nativeTitleSortKey $nativeTitleSortKey;
  318.         return $this;
  319.     }
  320.     public function getNativeTitleSortKey(): ?string
  321.     {
  322.         return $this->nativeTitleSortKey;
  323.     }
  324.     public function getData(): JournalData
  325.     {
  326.         return $this->data;
  327.     }
  328.     public function getView(): JournalView
  329.     {
  330.         return $this->view;
  331.     }
  332.     public function getCover(Language $lang): ?Media
  333.     {
  334.         if ($this->view->getCoverType() === JournalCoverType::CHOSEN) {
  335.             return $this->readAvailableTranslation($lang'cover');
  336.         }
  337.         if ($cover $this->getNewestIssue()?->readAvailableTranslation($lang'cover')) {
  338.             return $cover;
  339.         }
  340.         return $this->view->getCoverType() === JournalCoverType::CURRENT_ISSUE_OR_CHOSEN
  341.             $this->readAvailableTranslation($lang'cover')
  342.             : null;
  343.     }
  344.     public function getCoverAlt(Language $lang): ?string
  345.     {
  346.         if ($this->view->getCoverType() === JournalCoverType::CHOSEN) {
  347.             return $this->readAvailableTranslation($lang'coverAlt');
  348.         }
  349.         if ($this->getNewestIssue()?->readAvailableTranslation($lang'cover')) {
  350.             return $this->getNewestIssue()?->readAvailableTranslation($lang'coverAlt');
  351.         }
  352.         return $this->view->getCoverType() === JournalCoverType::CURRENT_ISSUE_OR_CHOSEN
  353.             $this->readAvailableTranslation($lang'coverAlt')
  354.             : null;
  355.     }
  356.     public function getSlug(): ?string
  357.     {
  358.         return $this->slug;
  359.     }
  360.     public function setSlug(?string $slug): self
  361.     {
  362.         $this->slug $slug;
  363.         return $this;
  364.     }
  365.     public function getImportSlug(): ?string
  366.     {
  367.         return $this->importSlug;
  368.     }
  369.     public function setImportSlug(?string $importSlug): self
  370.     {
  371.         $this->importSlug $importSlug;
  372.         return $this;
  373.     }
  374.     public function getImportSlugEn(): ?string
  375.     {
  376.         return $this->importSlugEn;
  377.     }
  378.     public function setImportSlugEn(?string $importSlugEn): self
  379.     {
  380.         $this->importSlugEn $importSlugEn;
  381.         return $this;
  382.     }
  383.     /**
  384.      * @return Collection|JournalScientificCouncilMember[]
  385.      */
  386.     public function getScientificCouncilMembers(): Collection
  387.     {
  388.         return $this->scientificCouncilMembers;
  389.     }
  390.     public function addScientificCouncilMember(JournalScientificCouncilMember $scientificCouncilMember): self
  391.     {
  392.         if ($this->scientificCouncilMembers->contains($scientificCouncilMember)) {
  393.             return $this;
  394.         }
  395.         $this->scientificCouncilMembers[] = $scientificCouncilMember;
  396.         return $this;
  397.     }
  398.     public function removeScientificCouncilMember(JournalScientificCouncilMember $scientificCouncilMember): self
  399.     {
  400.         $this->scientificCouncilMembers->removeElement($scientificCouncilMember);
  401.         return $this;
  402.     }
  403.     public function resetScientificCouncilMembers(): self
  404.     {
  405.         $this->scientificCouncilMembers = new ArrayCollection();
  406.         return $this;
  407.     }
  408.     /**
  409.      * @return Collection|JournalDomain[]
  410.      */
  411.     public function getDomains(): Collection
  412.     {
  413.         return $this->domains;
  414.     }
  415.     public function addDomain(JournalDomain $domain): self
  416.     {
  417.         if ($this->domains->contains($domain)) {
  418.             return $this;
  419.         }
  420.         $this->domains[] = $domain;
  421.         return $this;
  422.     }
  423.     public function removeDomain(JournalDomain $domain): self
  424.     {
  425.         $this->domains->removeElement($domain);
  426.         return $this;
  427.     }
  428.     public function resetDomains(): self
  429.     {
  430.         $this->domains = new ArrayCollection();
  431.         return $this;
  432.     }
  433.     /**
  434.      * @return Collection|JournalIndexationCollection[]
  435.      */
  436.     public function getIndexationCollections(): Collection
  437.     {
  438.         return $this->indexationCollections;
  439.     }
  440.     public function addIndexationCollection(JournalIndexationCollection $indexationCollection): self
  441.     {
  442.         if ($this->indexationCollections->contains($indexationCollection)) {
  443.             return $this;
  444.         }
  445.         $this->indexationCollections[] = $indexationCollection;
  446.         return $this;
  447.     }
  448.     public function removeIndexationCollection(JournalIndexationCollection $indexationCollection): self
  449.     {
  450.         $this->indexationCollections->removeElement($indexationCollection);
  451.         return $this;
  452.     }
  453.     public function resetIndexationCollections(): self
  454.     {
  455.         $this->indexationCollections = new ArrayCollection();
  456.         return $this;
  457.     }
  458.     /**
  459.      * @return Collection|JournalIndicator[]
  460.      */
  461.     public function getIndicators(): Collection
  462.     {
  463.         return $this->indicators;
  464.     }
  465.     public function addIndicator(JournalIndicator $indicator): self
  466.     {
  467.         if ($this->indicators->contains($indicator)) {
  468.             return $this;
  469.         }
  470.         $this->indicators[] = $indicator;
  471.         return $this;
  472.     }
  473.     public function removeIndicator(JournalIndicator $indicator): self
  474.     {
  475.         $this->indicators->removeElement($indicator);
  476.         return $this;
  477.     }
  478.     public function resetIndicators(): self
  479.     {
  480.         $this->indicators = new ArrayCollection();
  481.         return $this;
  482.     }
  483.     /**
  484.      * @return Collection|JournalAffiliation[]
  485.      */
  486.     public function getAffiliations(): Collection
  487.     {
  488.         return $this->affiliations;
  489.     }
  490.     public function addAffiliation(JournalAffiliation $affiliation): self
  491.     {
  492.         if ($this->affiliations->contains($affiliation)) {
  493.             return $this;
  494.         }
  495.         $this->affiliations[] = $affiliation;
  496.         return $this;
  497.     }
  498.     public function removeAffiliation(JournalAffiliation $affiliation): self
  499.     {
  500.         $this->affiliations->removeElement($affiliation);
  501.         return $this;
  502.     }
  503.     public function resetAffiliations(): self
  504.     {
  505.         $this->affiliations = new ArrayCollection();
  506.         return $this;
  507.     }
  508.     /**
  509.      * @return Collection|JournalPublisher[]
  510.      */
  511.     public function getPublishers(): Collection
  512.     {
  513.         return $this->publishers;
  514.     }
  515.     public function addPublisher(JournalPublisher $publisher): self
  516.     {
  517.         if ($this->publishers->contains($publisher)) {
  518.             return $this;
  519.         }
  520.         $this->publishers[] = $publisher;
  521.         return $this;
  522.     }
  523.     public function removePublisher(JournalPublisher $publisher): self
  524.     {
  525.         $this->publishers->removeElement($publisher);
  526.         return $this;
  527.     }
  528.     public function resetPublishers(): self
  529.     {
  530.         $this->publishers = new ArrayCollection();
  531.         return $this;
  532.     }
  533.     public function getVisiblePublishers(): Collection
  534.     {
  535.         return $this->publishers->filter(
  536.             fn (JournalPublisher $publisher) =>
  537.                 $publisher->getStat() === true &&
  538.                 $publisher->getPublisher()->getStat() === true
  539.         );
  540.     }
  541.     /**
  542.      * @return Collection|JournalPartner[]
  543.      */
  544.     public function getPartners(): Collection
  545.     {
  546.         return $this->partners;
  547.     }
  548.     public function addPartner(JournalPartner $partner): self
  549.     {
  550.         if ($this->partners->contains($partner)) {
  551.             return $this;
  552.         }
  553.         $this->partners[] = $partner;
  554.         return $this;
  555.     }
  556.     public function removePartner(JournalPartner $partner): self
  557.     {
  558.         $this->partners->removeElement($partner);
  559.         return $this;
  560.     }
  561.     public function resetPartners(): self
  562.     {
  563.         $this->partners = new ArrayCollection();
  564.         return $this;
  565.     }
  566.     /**
  567.      * @return Collection|JournalSlide[]
  568.      */
  569.     public function getSlides(): Collection
  570.     {
  571.         return $this->slides;
  572.     }
  573.     public function addSlide(JournalSlide $slide): self
  574.     {
  575.         if ($this->slides->contains($slide)) {
  576.             return $this;
  577.         }
  578.         $this->slides[] = $slide;
  579.         return $this;
  580.     }
  581.     public function removeSlide(JournalSlide $slide): self
  582.     {
  583.         $this->slides->removeElement($slide);
  584.         return $this;
  585.     }
  586.     public function resetSlides(): self
  587.     {
  588.         $this->slides = new ArrayCollection();
  589.         return $this;
  590.     }
  591.     /**
  592.      * @return Collection|JournalSection[]
  593.      */
  594.     public function getSections(): Collection
  595.     {
  596.         return $this->sections;
  597.     }
  598.     public function addSection(JournalSection $section): self
  599.     {
  600.         if ($this->sections->contains($section)) {
  601.             return $this;
  602.         }
  603.         $this->sections[] = $section;
  604.         return $this;
  605.     }
  606.     public function removeSection(JournalSection $section): self
  607.     {
  608.         $this->sections->removeElement($section);
  609.         return $this;
  610.     }
  611.     public function resetSections(): self
  612.     {
  613.         $this->sections = new ArrayCollection();
  614.         return $this;
  615.     }
  616.     /**
  617.      * @return Collection|JournalMenuItem[]
  618.      */
  619.     public function getMenuItems(): Collection
  620.     {
  621.         return $this->menuItems;
  622.     }
  623.     public function addMenuItem(JournalMenuItem $menuItem): self
  624.     {
  625.         if ($this->menuItems->contains($menuItem)) {
  626.             return $this;
  627.         }
  628.         $this->menuItems[] = $menuItem;
  629.         return $this;
  630.     }
  631.     public function removeMenuItem(JournalMenuItem $menuItem): self
  632.     {
  633.         $this->menuItems->removeElement($menuItem);
  634.         return $this;
  635.     }
  636.     public function resetMenuItems(): self
  637.     {
  638.         $this->menuItems = new ArrayCollection();
  639.         return $this;
  640.     }
  641.     /**
  642.      * @return Collection|JournalSubmenuGroup[]
  643.      */
  644.     public function getSubmenuGroups(): Collection
  645.     {
  646.         return $this->submenuGroups;
  647.     }
  648.     public function addSubmenuGroup(JournalSubmenuGroup $submenuGroup): self
  649.     {
  650.         if ($this->submenuGroups->contains($submenuGroup)) {
  651.             return $this;
  652.         }
  653.         $this->submenuGroups[] = $submenuGroup;
  654.         return $this;
  655.     }
  656.     public function removeSubmenuGroup(JournalSubmenuGroup $submenuGroup): self
  657.     {
  658.         $this->submenuGroups->removeElement($submenuGroup);
  659.         return $this;
  660.     }
  661.     public function resetSubmenuGroups(): self
  662.     {
  663.         $this->submenuGroups = new ArrayCollection();
  664.         return $this;
  665.     }
  666.     /**
  667.      * @return Collection|JournalSidemenuGroup[]
  668.      */
  669.     public function getSidemenuGroups(): Collection
  670.     {
  671.         return $this->sidemenuGroups;
  672.     }
  673.     public function addSidemenuGroup(JournalSidemenuGroup $sidemenuGroup): self
  674.     {
  675.         if ($this->sidemenuGroups->contains($sidemenuGroup)) {
  676.             return $this;
  677.         }
  678.         $this->sidemenuGroups[] = $sidemenuGroup;
  679.         return $this;
  680.     }
  681.     public function removeSidemenuGroup(JournalSidemenuGroup $sidemenuGroup): self
  682.     {
  683.         $this->sidemenuGroups->removeElement($sidemenuGroup);
  684.         return $this;
  685.     }
  686.     public function resetSidemenuGroups(): self
  687.     {
  688.         $this->sidemenuGroups = new ArrayCollection();
  689.         return $this;
  690.     }
  691.     /**
  692.      * @return Collection|JournalBanner[]
  693.      */
  694.     public function getBanners(): Collection
  695.     {
  696.         return $this->banners;
  697.     }
  698.     public function addBanner(JournalBanner $banner): self
  699.     {
  700.         if ($this->banners->contains($banner)) {
  701.             return $this;
  702.         }
  703.         $this->banners[] = $banner;
  704.         return $this;
  705.     }
  706.     public function removeBanner(JournalBanner $banner): self
  707.     {
  708.         $this->banners->removeElement($banner);
  709.         return $this;
  710.     }
  711.     public function resetBanners(): self
  712.     {
  713.         $this->banners = new ArrayCollection();
  714.         return $this;
  715.     }
  716.     /**
  717.      * @return Collection|JournalVolume[]
  718.      */
  719.     public function getVolumes(): Collection
  720.     {
  721.         return $this->volumes;
  722.     }
  723.     public function addVolume(JournalVolume $volume): self
  724.     {
  725.         if ($this->volumes->contains($volume)) {
  726.             return $this;
  727.         }
  728.         $this->volumes[] = $volume;
  729.         return $this;
  730.     }
  731.     public function removeVolume(JournalVolume $volume): self
  732.     {
  733.         $this->volumes->removeElement($volume);
  734.         return $this;
  735.     }
  736.     public function resetVolumes(): self
  737.     {
  738.         $this->volumes = new ArrayCollection();
  739.         return $this;
  740.     }
  741.     /**
  742.      * @return Collection<int, JournalIssue>
  743.      */
  744.     public function getIssues(): Collection
  745.     {
  746.         return $this->issues;
  747.     }
  748.     /**
  749.      * @return Collection<int, JournalIssue>
  750.      */
  751.     public function getVisibleIssues(): Collection
  752.     {
  753.         return $this->issues->filter(fn (JournalIssue $issue) => $issue->getStat());
  754.     }
  755.     public function addIssue(JournalIssue $issue): self
  756.     {
  757.         if ($this->issues->contains($issue)) {
  758.             return $this;
  759.         }
  760.         $this->issues[] = $issue;
  761.         return $this;
  762.     }
  763.     public function removeIssue(JournalIssue $issue): self
  764.     {
  765.         $this->issues->removeElement($issue);
  766.         return $this;
  767.     }
  768.     public function resetIssues(): self
  769.     {
  770.         $this->issues = new ArrayCollection();
  771.         return $this;
  772.     }
  773.     public function getNewestIssue(): ?JournalIssue
  774.     {
  775.         foreach ($this->getIssues() as $issue) {
  776.             if ($issue->getStat() && $issue->getIsNewestIssue()) {
  777.                 return $issue;
  778.             }
  779.         }
  780.         return null;
  781.     }
  782.     public function getOldestIssue(): ?JournalIssue
  783.     {
  784.         $filtered = new ArrayCollection();
  785.         foreach ($this->getIssues() as $issue) {
  786.             if ($issue->getStat() && $issue->getPublishedAt()) {
  787.                 $filtered->add($issue);
  788.             }
  789.         }
  790.         if (count($filtered) === 0) {
  791.             return null;
  792.         }
  793.         $criteria Criteria::create()->orderBy(['publishedAt' => Criteria::ASC]);
  794.         return $filtered
  795.             ->matching($criteria)
  796.             ->first();
  797.     }
  798.     /**
  799.      * @return Collection|JournalArticle[]
  800.      */
  801.     public function getArticles(): Collection
  802.     {
  803.         return $this->articles;
  804.     }
  805.     /**
  806.      * @return Collection<int, JournalArticle>
  807.      */
  808.     public function getArticlesVisible(): Collection
  809.     {
  810.         return $this->articles->filter(fn (JournalArticle $article) => $article->getStat());
  811.     }
  812.     public function addArticle(JournalArticle $article): self
  813.     {
  814.         if ($this->articles->contains($article)) {
  815.             return $this;
  816.         }
  817.         $this->articles[] = $article;
  818.         return $this;
  819.     }
  820.     public function removeArticle(JournalArticle $article): self
  821.     {
  822.         $this->articles->removeElement($article);
  823.         return $this;
  824.     }
  825.     public function resetArticles(): self
  826.     {
  827.         $this->articles = new ArrayCollection();
  828.         return $this;
  829.     }
  830.     /**
  831.      * @return Collection|JournalPage[]
  832.      */
  833.     public function getPages(): Collection
  834.     {
  835.         return $this->pages;
  836.     }
  837.     public function addPage(JournalPage $page): self
  838.     {
  839.         if ($this->pages->contains($page)) {
  840.             return $this;
  841.         }
  842.         $this->pages[] = $page;
  843.         return $this;
  844.     }
  845.     public function removePage(JournalPage $page): self
  846.     {
  847.         $this->pages->removeElement($page);
  848.         return $this;
  849.     }
  850.     public function resetPages(): self
  851.     {
  852.         $this->pages = new ArrayCollection();
  853.         return $this;
  854.     }
  855.     /**
  856.      * @return Collection|JournalNews[]
  857.      */
  858.     public function getNews(): Collection
  859.     {
  860.         return $this->news;
  861.     }
  862.     public function addNews(JournalNews $news): self
  863.     {
  864.         if ($this->news->contains($news)) {
  865.             return $this;
  866.         }
  867.         $this->news[] = $news;
  868.         return $this;
  869.     }
  870.     public function removeNews(JournalNews $news): self
  871.     {
  872.         $this->news->removeElement($news);
  873.         return $this;
  874.     }
  875.     public function resetNews(): self
  876.     {
  877.         $this->news = new ArrayCollection();
  878.         return $this;
  879.     }
  880.     /**
  881.      * @return Collection|JournalCollection[]
  882.      */
  883.     public function getCollections(): Collection
  884.     {
  885.         return $this->collections;
  886.     }
  887.     public function addCollection(JournalCollection $collection): self
  888.     {
  889.         if ($this->collections->contains($collection)) {
  890.             return $this;
  891.         }
  892.         $this->collections[] = $collection;
  893.         return $this;
  894.     }
  895.     public function removeCollection(JournalCollection $news): self
  896.     {
  897.         $this->news->removeElement($news);
  898.         return $this;
  899.     }
  900.     public function resetCollections(): self
  901.     {
  902.         $this->collections = new ArrayCollection();
  903.         return $this;
  904.     }
  905.     public function clone(Admin $createdBy null): self
  906.     {
  907.         $clone = clone $this;
  908.         $clone->id null;
  909.         $clone->setUuid();
  910.         $clone->ord 0;
  911.         $clone->stat false;
  912.         $clone->importId null;
  913.         $clone->data $this->data->clone($clone);
  914.         $clone->view $this->view->clone($clone);
  915.         $nativeLanguage $clone->getNativeLanguage();
  916.         $nativeTranslation $clone->getTranslation($nativeLanguage);
  917.         $nativeTranslation->setTitle($nativeTranslation->getTitle() . ' [KOPIA]');
  918.         ClassUtils::cloneCollection($this$clone'translations');
  919.         $clone
  920.             ->resetDomains()
  921.             ->resetIndexationCollections()
  922.             ->resetIndicators()
  923.             ->resetAffiliations()
  924.             ->resetPublishers()
  925.             ->resetPartners()
  926.             ->resetSlides()
  927.             ->resetSections()
  928.             ->resetMenuItems()
  929.             ->resetSubmenuGroups()
  930.             ->resetBanners()
  931.             ->resetVolumes()
  932.             ->resetIssues()
  933.             ->resetArticles()
  934.             ->resetPages()
  935.             ->resetNews()
  936.             ->resetCollections()
  937.             ->resetEditorialGroups()
  938.             ->resetScientificCouncilMembers();
  939.         $clone->createdBy $createdBy ?? $clone->createdBy;
  940.         $clone->updatedBy $createdBy ?? $clone->updatedBy;
  941.         $clone->createdAt = new \DateTimeImmutable();
  942.         $clone->updatedAt = new \DateTimeImmutable();
  943.         return $clone;
  944.     }
  945.     public function isSortArticlesByOrd(): bool
  946.     {
  947.         return $this->sortArticlesByOrd;
  948.     }
  949.     public function setSortArticlesByOrd(bool $sortArticlesByOrd): self
  950.     {
  951.         $this->sortArticlesByOrd $sortArticlesByOrd;
  952.         return $this;
  953.     }
  954.     /**
  955.      * @return Collection<int, JournalFooter>
  956.      */
  957.     public function getSmallFooters(): Collection
  958.     {
  959.         return $this->smallFooters;
  960.     }
  961.     public function addSmallFooter(JournalFooter $smallFooter): self
  962.     {
  963.         if (!$this->smallFooters->contains($smallFooter)) {
  964.             $this->smallFooters->add($smallFooter);
  965.             $smallFooter->setParent($this);
  966.         }
  967.         return $this;
  968.     }
  969.     public function removeSmallFooter(JournalFooter $smallFooter): self
  970.     {
  971.         if ($this->smallFooters->removeElement($smallFooter)) {
  972.             // set the owning side to null (unless already changed)
  973.             if ($smallFooter->getParent() === $this) {
  974.                 $smallFooter->setParent(null);
  975.             }
  976.         }
  977.         return $this;
  978.     }
  979.     public function getVisibleSmallFooters(): Collection
  980.     {
  981.         return $this->smallFooters->filter(fn (JournalFooter $smallFooter) => $smallFooter->getStat());
  982.     }
  983. }