276 lines
8.1 KiB
PHP
276 lines
8.1 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @file classes/institution/DAO.php
|
|
*
|
|
* Copyright (c) 2022 Simon Fraser University
|
|
* Copyright (c) 2022 John Willinsky
|
|
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
|
*
|
|
* @class DAO
|
|
*
|
|
* @ingroup institution
|
|
*
|
|
* @see Institution
|
|
*
|
|
* @brief Operations for retrieving and modifying Institution objects.
|
|
*/
|
|
|
|
namespace PKP\institution;
|
|
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\App;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\LazyCollection;
|
|
use PKP\core\EntityDAO;
|
|
use PKP\core\SoftDeleteTrait;
|
|
use PKP\core\traits\EntityWithParent;
|
|
use PKP\services\PKPSchemaService;
|
|
|
|
/**
|
|
* @template T of Institution
|
|
* @extends EntityDAO<T>
|
|
*/
|
|
class DAO extends EntityDAO
|
|
{
|
|
use EntityWithParent;
|
|
use SoftDeleteTrait;
|
|
|
|
/** @copydoc EntityDAO::$schema */
|
|
public $schema = PKPSchemaService::SCHEMA_INSTITUTION;
|
|
|
|
/** @copydoc EntityDAO::$table */
|
|
public $table = 'institutions';
|
|
|
|
/** @copydoc EntityDAO::$settingsTable */
|
|
public $settingsTable = 'institution_settings';
|
|
|
|
/** @copydoc EntityDAO::$primaryKeyColumn */
|
|
public $primaryKeyColumn = 'institution_id';
|
|
|
|
/** @copydoc EntityDAO::$primaryTableColumns */
|
|
public $primaryTableColumns = [
|
|
'id' => 'institution_id',
|
|
'contextId' => 'context_id',
|
|
'ror' => 'ror',
|
|
'deletedAt' => 'deleted_at'
|
|
];
|
|
|
|
/**
|
|
* Get the parent object ID column name
|
|
*/
|
|
public function getParentColumn(): string
|
|
{
|
|
return 'context_id';
|
|
}
|
|
|
|
/**
|
|
* Instantiate a new DataObject
|
|
*/
|
|
public function newDataObject(): Institution
|
|
{
|
|
return App::make(Institution::class);
|
|
}
|
|
|
|
/**
|
|
* Get the number of institutions matching the configured query
|
|
*/
|
|
public function getCount(Collector $query): int
|
|
{
|
|
return $query
|
|
->getQueryBuilder()
|
|
->select('i.' . $this->primaryKeyColumn)
|
|
->count();
|
|
}
|
|
|
|
/**
|
|
* Get a list of institution ids matching the configured query
|
|
*
|
|
* @return Collection<int,int>
|
|
*/
|
|
public function getIds(Collector $query): Collection
|
|
{
|
|
return $query
|
|
->getQueryBuilder()
|
|
->select('i.' . $this->primaryKeyColumn)
|
|
->pluck('i.' . $this->primaryKeyColumn);
|
|
}
|
|
|
|
/**
|
|
* Get a collection of institutions matching the configured query
|
|
* @return LazyCollection<int,T>
|
|
*/
|
|
public function getMany(Collector $query): LazyCollection
|
|
{
|
|
$rows = $query
|
|
->getQueryBuilder()
|
|
->select(['i.*'])
|
|
->get();
|
|
|
|
return LazyCollection::make(function () use ($rows) {
|
|
foreach ($rows as $row) {
|
|
yield $row->institution_id => $this->fromRow($row);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get a collection of deleted institutions matching the configured query
|
|
*/
|
|
public function getSoftDeleted(Collector $query): LazyCollection
|
|
{
|
|
$rows = $query
|
|
->includeSoftDeletes(true)
|
|
->getQueryBuilder()
|
|
->whereNotNull('deleted_at')
|
|
->select(['i.*'])
|
|
->get();
|
|
|
|
return LazyCollection::make(function () use ($rows) {
|
|
foreach ($rows as $row) {
|
|
yield $row->institution_id => $this->fromRow($row);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @copydoc EntityDAO::fromRow()
|
|
*/
|
|
public function fromRow(object $row): Institution
|
|
{
|
|
/** @var Institution */
|
|
$institution = parent::fromRow($row);
|
|
|
|
$ipRanges = DB::table('institution_ip')
|
|
->where($this->primaryKeyColumn, '=', $institution->getId())
|
|
->pluck('ip_string')
|
|
->toArray();
|
|
|
|
$institution->setIPRanges($ipRanges);
|
|
|
|
return $institution;
|
|
}
|
|
|
|
/**
|
|
* @copydoc EntityDAO::insert()
|
|
*/
|
|
public function insert(Institution $institution): int
|
|
{
|
|
if (isset($institution->_data['ipRanges'])) {
|
|
$ipRanges = $institution->getData('ipRanges');
|
|
unset($institution->_data['ipRanges']);
|
|
}
|
|
$institutionId = parent::_insert($institution);
|
|
if (isset($ipRanges)) {
|
|
$this->insertIPRanges($institutionId, $ipRanges);
|
|
}
|
|
return $institutionId;
|
|
}
|
|
|
|
/**
|
|
* @copydoc EntityDAO::update()
|
|
*/
|
|
public function update(Institution $institution): void
|
|
{
|
|
if (isset($institution->_data['ipRanges'])) {
|
|
$ipRanges = $institution->getData('ipRanges');
|
|
unset($institution->_data['ipRanges']);
|
|
}
|
|
parent::_update($institution);
|
|
if (isset($ipRanges)) {
|
|
$this->deleteIPRanges($institution->getId());
|
|
$this->insertIPRanges($institution->getId(), $ipRanges);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @copydoc EntityDAO::delete()
|
|
*/
|
|
public function delete(Institution $institution): void
|
|
{
|
|
// If the reference in the table institutional_subscriptions exists, soft delete the institution
|
|
$shouldSoftDelete = DB::table('institutional_subscriptions')
|
|
->where('institution_id', '=', $institution->getId())
|
|
->exists();
|
|
if ($shouldSoftDelete) {
|
|
$this->_softDelete($institution);
|
|
} else {
|
|
$this->deleteIPRanges($institution->getId());
|
|
parent::_delete($institution);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Insert institution IP ranges.
|
|
*/
|
|
protected function insertIPRanges(int $institutionId, array $ipRanges): void
|
|
{
|
|
if (empty($ipRanges) || empty($institutionId)) {
|
|
return;
|
|
}
|
|
foreach ($ipRanges as $ipRange) {
|
|
$ipStart = null;
|
|
$ipEnd = null;
|
|
|
|
$ipRange = trim($ipRange);
|
|
// Parse and check single IP string
|
|
if (strpos($ipRange, Institution::IP_RANGE_RANGE) === false) {
|
|
// Check for wildcards in IP
|
|
if (strpos($ipRange, Institution::IP_RANGE_WILDCARD) === false) {
|
|
// Get non-CIDR IP
|
|
if (strpos($ipRange, '/') === false) {
|
|
$ipStart = sprintf('%u', ip2long($ipRange));
|
|
|
|
// Convert CIDR IP to IP range
|
|
} else {
|
|
[$cidrIPString, $cidrBits] = explode('/', $ipRange);
|
|
|
|
if ($cidrBits == 0) {
|
|
$cidrMask = 0;
|
|
} else {
|
|
$cidrMask = (0xffffffff << (32 - $cidrBits));
|
|
}
|
|
|
|
$ipStart = sprintf('%u', ip2long($cidrIPString) & $cidrMask);
|
|
|
|
if ($cidrBits != 32) {
|
|
$ipEnd = sprintf('%u', ip2long($cidrIPString) | (~$cidrMask & 0xffffffff));
|
|
}
|
|
}
|
|
|
|
// Convert wildcard IP to IP range
|
|
} else {
|
|
$ipStart = sprintf('%u', ip2long(str_replace(Institution::IP_RANGE_WILDCARD, '0', $ipRange)));
|
|
$ipEnd = sprintf('%u', ip2long(str_replace(Institution::IP_RANGE_WILDCARD, '255', $ipRange)));
|
|
}
|
|
|
|
// Convert wildcard IP range to IP range
|
|
} else {
|
|
[$ipStart, $ipEnd] = explode(Institution::IP_RANGE_RANGE, $ipRange);
|
|
|
|
// Replace wildcards in start and end of range
|
|
$ipStart = sprintf('%u', ip2long(str_replace(Institution::IP_RANGE_WILDCARD, '0', trim($ipStart))));
|
|
$ipEnd = sprintf('%u', ip2long(str_replace(Institution::IP_RANGE_WILDCARD, '255', trim($ipEnd))));
|
|
}
|
|
|
|
// Insert IP or IP range
|
|
if ($ipStart != null) {
|
|
DB::table('institution_ip')->insert([
|
|
'institution_id' => $institutionId,
|
|
'ip_string' => $ipRange,
|
|
'ip_start' => $ipStart,
|
|
'ip_end' => $ipEnd
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete institution IP ranges by institution ID.
|
|
*/
|
|
private function deleteIPRanges(int $institutionId): void
|
|
{
|
|
DB::table('institution_ip')->where('institution_id', '=', $institutionId)->delete();
|
|
}
|
|
}
|