first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-06-08 17:09:23 -04:00
commit df3a033196
17887 changed files with 8637778 additions and 0 deletions
+181
View File
@@ -0,0 +1,181 @@
<?php
/**
* @file classes/section/Collector.php
*
* Copyright (c) 2014-2023 Simon Fraser University
* Copyright (c) 2003-2023 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class Collector
*
* @brief A helper class to configure a Query Builder to get a collection of sections
*/
namespace PKP\section;
use APP\section\DAO;
use APP\section\Section;
use APP\submission\Submission;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\LazyCollection;
use PKP\core\interfaces\CollectorInterface;
/**
* @template T of Section
*/
class Collector implements CollectorInterface
{
public DAO $dao;
public ?array $contextIds = null;
public ?array $titles = null;
public ?array $abbrevs = null;
public bool $editorOnly = false;
public bool $excludeInactive = false;
public bool $withPublished = false;
public ?int $count = null;
public ?int $offset = null;
public function __construct(DAO $dao)
{
$this->dao = $dao;
}
public function getCount(): int
{
return $this->dao->getCount($this);
}
/**
* @return Collection<int,int>
*/
public function getIds(): Collection
{
return $this->dao->getIds($this);
}
/**
* @copydoc DAO::getMany()
* @return LazyCollection<int,T>
*/
public function getMany(): LazyCollection
{
return $this->dao->getMany($this);
}
/**
* Filter sections by one or more contexts
*/
public function filterByContextIds(?array $contextIds): self
{
$this->contextIds = $contextIds;
return $this;
}
/**
* Filter sections by one or more titles
*/
public function filterByTitles(?array $titles): self
{
$this->titles = $titles;
return $this;
}
/**
* Filter sections by one or more abbreviations
*/
public function filterByAbbrevs(?array $abbrevs): self
{
$this->abbrevs = $abbrevs;
return $this;
}
/**
* Only include sections that all users can submit to
*/
public function excludeEditorOnly(bool $editorOnly = true): self
{
$this->editorOnly = $editorOnly;
return $this;
}
/**
* Only include active sections
*/
public function excludeInactive(bool $excludeInactive = true): self
{
$this->excludeInactive = $excludeInactive;
return $this;
}
/**
* Only include sections that contain published items
*/
public function withPublished(bool $withPublished = true): self
{
$this->withPublished = $withPublished;
return $this;
}
/**
* Limit the number of objects retrieved
*/
public function limit(?int $count): self
{
$this->count = $count;
return $this;
}
/**
* Offset the number of objects retrieved, for example to
* retrieve the second page of contents
*/
public function offset(?int $offset): self
{
$this->offset = $offset;
return $this;
}
public function getQueryBuilder(): Builder
{
return DB::table($this->dao->table, 's')->select('s.*')
->when(!is_null($this->contextIds), function (Builder $qb) {
$qb->whereIn('s.' . $this->dao->getParentColumn(), $this->contextIds);
})
->when(!is_null($this->titles) || !is_null($this->abbrevs), function (Builder $qb) {
$qb->join($this->dao->settingsTable . ' AS ss', 'ss.' . $this->dao->primaryKeyColumn, '=', 's.' . $this->dao->primaryKeyColumn)
->when(!is_null($this->titles), function (Builder $qb) {
$qb->where('ss.setting_name', 'title')
->whereIn('ss.setting_value', $this->titles);
})
->when(!is_null($this->abbrevs), function (Builder $qb) {
$qb->where('setting_name', 'abbrev')
->whereIn('setting_value', $this->abbrevs);
});
})
->when($this->editorOnly, function (Builder $qb) {
$qb->where('s.editor_restricted', 0)
->where('s.is_inactive', 0);
})
->when($this->excludeInactive, function (Builder $qb) {
$qb->where('s.is_inactive', 0);
})
->when($this->withPublished, function (Builder $qb) {
$qb->whereExists(function (Builder $qb) {
$qb->select('p.*')
->from('publications AS p')
->whereNotNull('p.' . $this->dao->primaryKeyColumn)
->whereColumn('p.' . $this->dao->primaryKeyColumn, '=', 's.' . $this->dao->primaryKeyColumn)
->where('p.status', '=', Submission::STATUS_PUBLISHED);
});
})
->orderBy('s.seq')
->when(!is_null($this->count), function (Builder $qb) {
$qb->limit($this->count);
})
->when(!is_null($this->offset), function (Builder $qb) {
$qb->offset($this->offset);
});
}
}
+104
View File
@@ -0,0 +1,104 @@
<?php
/**
* @file classes/section/DAO.php
*
* Copyright (c) 2014-2023 Simon Fraser University
* Copyright (c) 2003-2023 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class DAO
*
* @ingroup section
*
* @see Section
*
* @brief Operations for retrieving and modifying Section objects.
*/
namespace PKP\section;
use APP\section\Section;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\App;
use Illuminate\Support\LazyCollection;
use PKP\core\EntityDAO;
use PKP\core\traits\EntityWithParent;
/**
* @template T of Section
* @extends EntityDAO<T>
*/
abstract class DAO extends EntityDAO
{
use EntityWithParent;
/**
* Get the parent object ID column name
*/
abstract public function getParentColumn(): string;
/**
* Instantiate a new DataObject
*/
public function newDataObject(): Section
{
return App::make(Section::class);
}
/**
* Get the number of sections matching the configured query
*/
public function getCount(Collector $query): int
{
return $query
->getQueryBuilder()
->select($this->primaryKeyColumn)
->count();
}
/**
* Get a list of sections ids matching the configured query
*
* @return Collection<int,int>
*/
public function getIds(Collector $query): Collection
{
return $query
->getQueryBuilder()
->select($this->primaryKeyColumn)
->pluck($this->primaryKeyColumn);
}
/**
* Get a collection of sections matching the configured query
* @return LazyCollection<int,T>
*/
public function getMany(Collector $query): LazyCollection
{
$rows = $query
->getQueryBuilder()
->get();
return LazyCollection::make(function () use ($rows) {
foreach ($rows as $row) {
yield $row->{$this->primaryKeyColumn} => $this->fromRow($row);
}
});
}
public function insert(Section $section): int
{
return parent::_insert($section);
}
public function update(Section $section)
{
parent::_update($section);
}
public function delete(Section $section)
{
parent::_delete($section);
}
}
+111
View File
@@ -0,0 +1,111 @@
<?php
/**
* @file classes/section/Section.php
*
* Copyright (c) 2014-2023 Simon Fraser University
* Copyright (c) 2003-2023 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PKPSection
*
* @ingroup section
*
* @see DAO
*
* @brief Basic class describing a section.
*/
namespace PKP\section;
use PKP\security\Role;
class PKPSection extends \PKP\core\DataObject
{
/**
* What user roles are allowed to submit to sections
* that have restricted submissions to editors
*
* @return int[] One or more ROLE_ID_* constants
*/
public static function getEditorRestrictedRoles(): array
{
return [
Role::ROLE_ID_SITE_ADMIN,
Role::ROLE_ID_MANAGER,
Role::ROLE_ID_SUB_EDITOR
];
}
public function getContextId(): int
{
return $this->getData('contextId');
}
public function setContextId(int $contextId): void
{
$this->setData('contextId', $contextId);
}
public function getSequence(): float
{
return $this->getData('sequence');
}
public function setSequence(float $sequence): void
{
$this->setData('sequence', $sequence);
}
/* Because title is required, there must be at least one title */
public function getLocalizedTitle(): string
{
return $this->getLocalizedData('title');
}
public function getTitle(?string $locale): string|array|null
{
return $this->getData('title', $locale);
}
public function setTitle(string|array $title, string $locale = null): void
{
$this->setData('title', $title, $locale);
}
/**
* Return boolean indicating whether or not submissions are restricted to [sub]Editors.
*/
public function getEditorRestricted(): bool
{
return $this->getData('editorRestricted');
}
/**
* Set whether or not submissions are restricted to [sub]Editors.
*/
public function setEditorRestricted(bool $editorRestricted): void
{
$this->setData('editorRestricted', $editorRestricted);
}
/**
* Return boolean indicating if section is not active.
*/
public function getIsInactive(): bool
{
return $this->getData('isInactive');
}
/**
* Set if section should be inactivated.
*/
public function setIsInactive(bool $isInactive): void
{
$this->setData('isInactive', $isInactive);
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\section\PKPSection', '\PKPSection');
}
+216
View File
@@ -0,0 +1,216 @@
<?php
/**
* @file classes/section/Repository.php
*
* Copyright (c) 2014-2023 Simon Fraser University
* Copyright (c) 2003-2023 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class Repository
*
* @brief A repository to find and manage sections.
*/
namespace PKP\section;
use APP\core\Request;
use APP\core\Services;
use APP\facades\Repo;
use APP\section\DAO;
use APP\section\Section;
use Illuminate\Support\Facades\App;
use PKP\context\Context;
use PKP\plugins\Hook;
use PKP\services\PKPSchemaService;
use PKP\validation\ValidatorFactory;
class Repository
{
public DAO $dao;
public string $schemaMap = maps\Schema::class;
protected Request $request;
protected PKPSchemaService $schemaService;
public function __construct(DAO $dao, Request $request, PKPSchemaService $schemaService)
{
$this->dao = $dao;
$this->request = $request;
$this->schemaService = $schemaService;
}
/** @copydoc DAO::newDataObject() */
public function newDataObject(array $params = []): Section
{
$object = $this->dao->newDataObject();
if (!empty($params)) {
$object->setAllData($params);
}
return $object;
}
/** @copydoc DAO::exists() */
public function exists(int $id, int $contextId = null): bool
{
return $this->dao->exists($id, $contextId);
}
/** @copydoc DAO::get() */
public function get(int $id, int $contextId = null): ?Section
{
return $this->dao->get($id, $contextId);
}
public function getCollector(): Collector
{
return App::make(Collector::class);
}
/**
* Get an instance of the map class for mapping
* sections to their schema
*/
public function getSchemaMap(): maps\Schema
{
return app('maps')->withExtensions($this->schemaMap);
}
/**
* Validate properties for a section
*
* Perform validation checks on data used to add or edit a section.
*
* @param Section|null $object Section being edited. Pass `null` if creating a new section
* @param array $props A key/value array with the new data to validate
*
* @return array A key/value array with validation errors. Empty if no errors
*/
public function validate(?Section $object, array $props, Context $context): array
{
$errors = [];
$allowedLocales = $context->getSupportedSubmissionLocales();
$primaryLocale = $context->getPrimaryLocale();
$validator = ValidatorFactory::make(
$props,
$this->schemaService->getValidationRules($this->dao->schema, $allowedLocales)
);
// Check required fields if we're adding a section
ValidatorFactory::required(
$validator,
$object,
$this->schemaService->getRequiredProps($this->dao->schema),
$this->schemaService->getMultilingualProps($this->dao->schema),
$allowedLocales,
$primaryLocale
);
// Check for input from disallowed locales
ValidatorFactory::allowedLocales($validator, $this->schemaService->getMultilingualProps($this->dao->schema), $allowedLocales);
// The contextId must match an existing context
$validator->after(function ($validator) use ($props) {
if (isset($props['contextId']) && !$validator->errors()->get('contextId')) {
$sectionContext = Services::get('context')->get($props['contextId']);
if (!$sectionContext) {
$validator->errors()->add('contextId', __('manager.sections.noContext'));
}
}
});
if ($validator->fails()) {
$errors = $this->schemaService->formatValidationErrors($validator->errors());
}
Hook::call('Section::validate', [&$errors, $object, $props, $allowedLocales, $primaryLocale]);
return $errors;
}
/** @copydoc DAO::insert() */
public function add(Section $section): int
{
$id = $this->dao->insert($section);
Hook::call('Section::add', [$section]);
return $id;
}
/** @copydoc DAO::update() */
public function edit(Section $section, array $params): void
{
$newSection = clone $section;
$newSection->setAllData(array_merge($newSection->_data, $params));
Hook::call('Section::edit', [$newSection, $section, $params]);
$this->dao->update($newSection);
}
/**
* Deletes all sections for a given context
*/
public function deleteByContextId(int $contextId)
{
$collector = $this->getCollector()->filterByContextIds([$contextId]);
$this->deleteMany($collector);
}
/** @copydoc DAO::delete() */
public function delete(Section $section): void
{
Hook::call('Section::delete::before', [$section]);
$this->dao->delete($section);
Hook::call('Section::delete', [$section]);
}
/**
* Delete a collection of sections
*/
public function deleteMany(Collector $collector): void
{
foreach ($collector->getMany() as $section) {
$this->delete($section);
}
}
/**
* Check if the section has any submissions assigned to it.
*/
public function isEmpty(int $sectionId, int $contextId): bool
{
return Repo::submission()
->getCollector()
->filterByContextIds([$contextId])
->filterBySectionIds([$sectionId])
->getCount() === 0;
}
/**
* Sequentially renumber sections in their sequence order.
*/
public function resequence(int $contextId): void
{
$sections = $this->getCollector()->filterByContextIds([$contextId])->getMany();
$seq = 0;
foreach ($sections as $section) {
$section->setSequence($seq);
$this->dao->update($section);
$seq++;
}
}
/**
* Get array of sections containing id, title and group (isInactive) key
*/
public function getSectionList(int $contextId, bool $excludeInactive = false): array
{
return $this->getCollector()
->filterByContextIds([$contextId])
->excludeInactive($excludeInactive)
->getMany()
->map(fn (Section $section) => [
'id' => $section->getId(),
'title' => $section->getLocalizedTitle(),
'group' => $section->getIsInactive()
])
->all();
}
}
+94
View File
@@ -0,0 +1,94 @@
<?php
/**
* @file classes/section/maps/Schema.php
*
* Copyright (c) 2014-2023 Simon Fraser University
* Copyright (c) 2003-2023 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class Schema
*
* @brief Map sections to the properties defined in the section schema
*/
namespace PKP\section\maps;
use APP\section\Section;
use Illuminate\Support\Enumerable;
use PKP\services\PKPSchemaService;
class Schema extends \PKP\core\maps\Schema
{
/** @copydoc \PKP\core\maps\Schema::$collection */
public Enumerable $collection;
/** @copydoc \PKP\core\maps\Schema::$schema */
public string $schema = PKPSchemaService::SCHEMA_SECTION;
/**
* Map a section
*
* Includes all properties in the section schema.
*/
public function map(Section $item): array
{
return $this->mapByProperties($this->getProps(), $item);
}
/**
* Summarize an section
*
* Includes properties with the apiSummary flag in the section schema.
*/
public function summarize(Section $item): array
{
return $this->mapByProperties($this->getSummaryProps(), $item);
}
/**
* Map a collection of Sections
*
* @see self::map
*/
public function mapMany(Enumerable $collection): Enumerable
{
$this->collection = $collection;
return $collection->map(function ($item) {
return $this->map($item);
});
}
/**
* Summarize a collection of Sections
*
* @see self::summarize
*/
public function summarizeMany(Enumerable $collection): Enumerable
{
$this->collection = $collection;
return $collection->map(function ($item) {
return $this->summarize($item);
});
}
/**
* Map schema properties of an Section to an assoc array
*/
protected function mapByProperties(array $props, Section $item): array
{
$output = [];
foreach ($props as $prop) {
switch ($prop) {
case '_href':
$output[$prop] = $this->getApiUrl('sections/' . $item->getId());
break;
default:
$output[$prop] = $item->getData($prop);
break;
}
}
$output = $this->schemaService->addMissingMultilingualValues($this->schema, $output, $this->context->getSupportedFormLocales());
ksort($output);
return $this->withExtensions($output, $item);
}
}