Laminas \ Cache \ Exception \ RuntimeException
Error opening file '/usr/local/vufind/local/cache/objects/object-65/object-KohaRest-2b31482982489f36383117d9d34d67ce.dat'
Previous exceptions
  • fopen(/usr/local/vufind/local/cache/objects/object-65/object-KohaRest-2b31482982489f36383117d9d34d67ce.dat): failed to open stream: No space left on device (0)
Laminas\Cache\Exception\RuntimeException thrown with message "Error opening file '/usr/local/vufind/local/cache/objects/object-65/object-KohaRest-2b31482982489f36383117d9d34d67ce.dat'" Stacktrace: #29 Laminas\Cache\Exception\RuntimeException in /usr/local/vufind/vendor/laminas/laminas-cache-storage-adapter-filesystem/src/Filesystem.php:1581 #28 ErrorException in /usr/local/vufind/vendor/laminas/laminas-cache-storage-adapter-filesystem/src/Filesystem.php:1573 #27 fopen in /usr/local/vufind/vendor/laminas/laminas-cache-storage-adapter-filesystem/src/Filesystem.php:1573 #26 Laminas\Cache\Storage\Adapter\Filesystem:putFileContent in /usr/local/vufind/vendor/laminas/laminas-cache-storage-adapter-filesystem/src/Filesystem.php:970 #25 Laminas\Cache\Storage\Adapter\Filesystem:internalSetItem in /usr/local/vufind/vendor/laminas/laminas-cache/src/Storage/Adapter/AbstractAdapter.php:667 #24 Laminas\Cache\Storage\Adapter\AbstractAdapter:setItem in /usr/local/vufind/vendor/laminas/laminas-cache-storage-adapter-filesystem/src/Filesystem.php:844 #23 Laminas\Cache\Storage\Adapter\Filesystem:setItem in /usr/local/vufind/module/VuFind/src/VuFind/Cache/CacheTrait.php:123 #22 VuFind\ILS\Driver\KohaRest:putCachedData in /usr/local/vufind/module/VuFind/src/VuFind/ILS/Driver/KohaRest.php:1804 #21 VuFind\ILS\Driver\KohaRest:getOAuth2Token in /usr/local/vufind/module/VuFind/src/VuFind/ILS/Driver/KohaRest.php:1678 #20 VuFind\ILS\Driver\KohaRest:makeRequest in /usr/local/vufind/module/VuFind/src/VuFind/ILS/Driver/KohaRest.php:1827 #19 VuFind\ILS\Driver\KohaRest:getItemStatusesForBiblio in /usr/local/vufind/module/VuFind/src/VuFind/ILS/Driver/KohaRest.php:365 #18 VuFind\ILS\Driver\KohaRest:getHolding in /usr/local/vufind/module/VuFind/src/VuFind/ILS/Connection.php:1109 #17 call_user_func_array in /usr/local/vufind/module/VuFind/src/VuFind/ILS/Connection.php:1109 #16 VuFind\ILS\Connection:__call in /usr/local/vufind/module/VuFind/src/VuFind/ILS/Connection.php:1071 #15 VuFind\ILS\Connection:getHolding in /usr/local/vufind/module/VuFind/src/VuFind/ILS/Logic/Holds.php:215 #14 VuFind\ILS\Logic\Holds:getHoldings in /usr/local/vufind/module/VuFind/src/VuFind/RecordDriver/Feature/IlsAwareTrait.php:114 #13 VuFind\RecordDriver\SolrMarc:getRealTimeHoldings in /usr/local/vufind/themes/bootstrap3/templates/RecordTab/holdingsils.phtml:13 #12 include in /usr/local/vufind/vendor/laminas/laminas-view/src/Renderer/PhpRenderer.php:505 #11 Laminas\View\Renderer\PhpRenderer:render in /usr/local/vufind/module/VuFind/src/VuFind/View/Helper/Root/Record.php:361 #10 VuFind\View\Helper\Root\Record:getTab in /usr/local/vufind/themes/bootstrap3/templates/record/view.phtml:74 #9 include in /usr/local/vufind/vendor/laminas/laminas-view/src/Renderer/PhpRenderer.php:505 #8 Laminas\View\Renderer\PhpRenderer:render in /usr/local/vufind/vendor/laminas/laminas-view/src/View.php:206 #7 Laminas\View\View:render in /usr/local/vufind/vendor/laminas/laminas-view/src/View.php:235 #6 Laminas\View\View:renderChildren in /usr/local/vufind/vendor/laminas/laminas-view/src/View.php:199 #5 Laminas\View\View:render in /usr/local/vufind/vendor/laminas/laminas-mvc/src/View/Http/DefaultRenderingStrategy.php:104 #4 Laminas\Mvc\View\Http\DefaultRenderingStrategy:render in /usr/local/vufind/vendor/laminas/laminas-eventmanager/src/EventManager.php:331 #3 Laminas\EventManager\EventManager:triggerListeners in /usr/local/vufind/vendor/laminas/laminas-eventmanager/src/EventManager.php:180 #2 Laminas\EventManager\EventManager:triggerEvent in /usr/local/vufind/vendor/laminas/laminas-mvc/src/Application.php:366 #1 Laminas\Mvc\Application:completeRequest in /usr/local/vufind/vendor/laminas/laminas-mvc/src/Application.php:347 #0 Laminas\Mvc\Application:run in /usr/local/vufind/public/index.php:71
29
Laminas\Cache\Exception\RuntimeException
/vendor/laminas/laminas-cache-storage-adapter-filesystem/src/Filesystem.php1581
28
ErrorException
/vendor/laminas/laminas-cache-storage-adapter-filesystem/src/Filesystem.php1573
27
fopen
/vendor/laminas/laminas-cache-storage-adapter-filesystem/src/Filesystem.php1573
26
Laminas\Cache\Storage\Adapter\Filesystem putFileContent
/vendor/laminas/laminas-cache-storage-adapter-filesystem/src/Filesystem.php970
25
Laminas\Cache\Storage\Adapter\Filesystem internalSetItem
/vendor/laminas/laminas-cache/src/Storage/Adapter/AbstractAdapter.php667
24
Laminas\Cache\Storage\Adapter\AbstractAdapter setItem
/vendor/laminas/laminas-cache-storage-adapter-filesystem/src/Filesystem.php844
23
Laminas\Cache\Storage\Adapter\Filesystem setItem
/module/VuFind/src/VuFind/Cache/CacheTrait.php123
22
VuFind\ILS\Driver\KohaRest putCachedData
/module/VuFind/src/VuFind/ILS/Driver/KohaRest.php1804
21
VuFind\ILS\Driver\KohaRest getOAuth2Token
/module/VuFind/src/VuFind/ILS/Driver/KohaRest.php1678
20
VuFind\ILS\Driver\KohaRest makeRequest
/module/VuFind/src/VuFind/ILS/Driver/KohaRest.php1827
19
VuFind\ILS\Driver\KohaRest getItemStatusesForBiblio
/module/VuFind/src/VuFind/ILS/Driver/KohaRest.php365
18
VuFind\ILS\Driver\KohaRest getHolding
/module/VuFind/src/VuFind/ILS/Connection.php1109
17
call_user_func_array
/module/VuFind/src/VuFind/ILS/Connection.php1109
16
VuFind\ILS\Connection __call
/module/VuFind/src/VuFind/ILS/Connection.php1071
15
VuFind\ILS\Connection getHolding
/module/VuFind/src/VuFind/ILS/Logic/Holds.php215
14
VuFind\ILS\Logic\Holds getHoldings
/module/VuFind/src/VuFind/RecordDriver/Feature/IlsAwareTrait.php114
13
VuFind\RecordDriver\SolrMarc getRealTimeHoldings
/themes/bootstrap3/templates/RecordTab/holdingsils.phtml13
12
include
/vendor/laminas/laminas-view/src/Renderer/PhpRenderer.php505
11
Laminas\View\Renderer\PhpRenderer render
/module/VuFind/src/VuFind/View/Helper/Root/Record.php361
10
VuFind\View\Helper\Root\Record getTab
/themes/bootstrap3/templates/record/view.phtml74
9
include
/vendor/laminas/laminas-view/src/Renderer/PhpRenderer.php505
8
Laminas\View\Renderer\PhpRenderer render
/vendor/laminas/laminas-view/src/View.php206
7
Laminas\View\View render
/vendor/laminas/laminas-view/src/View.php235
6
Laminas\View\View renderChildren
/vendor/laminas/laminas-view/src/View.php199
5
Laminas\View\View render
/vendor/laminas/laminas-mvc/src/View/Http/DefaultRenderingStrategy.php104
4
Laminas\Mvc\View\Http\DefaultRenderingStrategy render
/vendor/laminas/laminas-eventmanager/src/EventManager.php331
3
Laminas\EventManager\EventManager triggerListeners
/vendor/laminas/laminas-eventmanager/src/EventManager.php180
2
Laminas\EventManager\EventManager triggerEvent
/vendor/laminas/laminas-mvc/src/Application.php366
1
Laminas\Mvc\Application completeRequest
/vendor/laminas/laminas-mvc/src/Application.php347
0
Laminas\Mvc\Application run
/public/index.php71
        $perm  = $options->getFilePermission();
        if ($umask !== false && $perm !== false) {
            $perm = $perm & ~$umask;
        }
 
        ErrorHandler::start();
 
        // if locking and non blocking is enabled -> file_put_contents can't used
        if ($locking && $nonBlocking) {
            $umask = ($umask !== false) ? umask($umask) : false;
 
            $fp = fopen($file, 'cb');
 
            if ($umask) {
                umask($umask);
            }
 
            if (! $fp) {
                $err = ErrorHandler::stop();
                throw new Exception\RuntimeException("Error opening file '{$file}'", 0, $err);
            }
 
            if ($perm !== false && ! chmod($file, $perm)) {
                fclose($fp);
                $oct = decoct($perm);
                $err = ErrorHandler::stop();
                throw new Exception\RuntimeException("chmod('{$file}', 0{$oct}) failed", 0, $err);
            }
 
            if (! flock($fp, LOCK_EX | LOCK_NB, $wouldblock)) {
                fclose($fp);
                $err = ErrorHandler::stop();
                if ($wouldblock) {
                    return;
                } else {
                    throw new Exception\RuntimeException("Error locking file '{$file}'", 0, $err);
                }
            }
 
            if (fwrite($fp, $data) === false) {
        }
 
        $options     = $this->getOptions();
        $locking     = $options->getFileLocking();
        $nonBlocking = $locking && $nonBlocking;
        $wouldblock  = null;
 
        $umask = $options->getUmask();
        $perm  = $options->getFilePermission();
        if ($umask !== false && $perm !== false) {
            $perm = $perm & ~$umask;
        }
 
        ErrorHandler::start();
 
        // if locking and non blocking is enabled -> file_put_contents can't used
        if ($locking && $nonBlocking) {
            $umask = ($umask !== false) ? umask($umask) : false;
 
            $fp = fopen($file, 'cb');
 
            if ($umask) {
                umask($umask);
            }
 
            if (! $fp) {
                $err = ErrorHandler::stop();
                throw new Exception\RuntimeException("Error opening file '{$file}'", 0, $err);
            }
 
            if ($perm !== false && ! chmod($file, $perm)) {
                fclose($fp);
                $oct = decoct($perm);
                $err = ErrorHandler::stop();
                throw new Exception\RuntimeException("chmod('{$file}', 0{$oct}) failed", 0, $err);
            }
 
            if (! flock($fp, LOCK_EX | LOCK_NB, $wouldblock)) {
                fclose($fp);
                $err = ErrorHandler::stop();
Exception message: fopen(/usr/local/vufind/local/cache/objects/object-65/object-KohaRest-2b31482982489f36383117d9d34d67ce.dat): failed to open stream: No space left on device
        }
 
        $options     = $this->getOptions();
        $locking     = $options->getFileLocking();
        $nonBlocking = $locking && $nonBlocking;
        $wouldblock  = null;
 
        $umask = $options->getUmask();
        $perm  = $options->getFilePermission();
        if ($umask !== false && $perm !== false) {
            $perm = $perm & ~$umask;
        }
 
        ErrorHandler::start();
 
        // if locking and non blocking is enabled -> file_put_contents can't used
        if ($locking && $nonBlocking) {
            $umask = ($umask !== false) ? umask($umask) : false;
 
            $fp = fopen($file, 'cb');
 
            if ($umask) {
                umask($umask);
            }
 
            if (! $fp) {
                $err = ErrorHandler::stop();
                throw new Exception\RuntimeException("Error opening file '{$file}'", 0, $err);
            }
 
            if ($perm !== false && ! chmod($file, $perm)) {
                fclose($fp);
                $oct = decoct($perm);
                $err = ErrorHandler::stop();
                throw new Exception\RuntimeException("chmod('{$file}', 0{$oct}) failed", 0, $err);
            }
 
            if (! flock($fp, LOCK_EX | LOCK_NB, $wouldblock)) {
                fclose($fp);
                $err = ErrorHandler::stop();
        return parent::replaceItems($keyValuePairs);
    }
 
    /**
     * Internal method to store an item.
     *
     * @param  string $normalizedKey
     * @param  mixed  $value
     * @return bool
     * @throws Exception\ExceptionInterface
     */
    protected function internalSetItem(& $normalizedKey, & $value)
    {
        $filespec = $this->getFileSpec($normalizedKey);
        $file     = $this->formatFilename($filespec);
        $this->prepareDirectoryStructure($filespec);
 
        // write data in non-blocking mode
        $wouldblock = null;
        $this->putFileContent($file, $value, true, $wouldblock);
 
        // delete related tag file (if present)
        $this->unlink($this->formatTagFilename($filespec));
 
        // Retry writing data in blocking mode if it was blocked before
        if ($wouldblock) {
            $this->putFileContent($file, $value);
        }
 
        return true;
    }
 
    /**
     * Internal method to store multiple items.
     *
     * @param  array $normalizedKeyValuePairs
     * @return array Array of not stored keys
     * @throws Exception\ExceptionInterface
     */
    protected function internalSetItems(array & $normalizedKeyValuePairs)
     * @triggers setItem.exception(ExceptionEvent)
     */
    public function setItem($key, $value)
    {
        if (! $this->getOptions()->getWritable()) {
            return false;
        }
 
        $this->normalizeKey($key);
        $args = new ArrayObject([
            'key'   => & $key,
            'value' => & $value,
        ]);
 
        try {
            $eventRs = $this->triggerPre(__FUNCTION__, $args);
 
            $result = $eventRs->stopped()
                ? $eventRs->last()
                : $this->internalSetItem($args['key'], $args['value']);
 
            return $this->triggerPost(__FUNCTION__, $args, $result);
        } catch (\Exception $e) {
            $result = false;
            return $this->triggerException(__FUNCTION__, $args, $result, $e);
        }
    }
 
    /**
     * Internal method to store an item.
     *
     * @param  string $normalizedKey
     * @param  mixed  $value
     * @return bool
     * @throws Exception\ExceptionInterface
     */
    abstract protected function internalSetItem(& $normalizedKey, & $value);
 
    /**
     * Store multiple items.
 
    /**
     * Store an item.
     *
     * @param  string $key
     * @param  mixed  $value
     * @return bool
     * @throws Exception\ExceptionInterface
     *
     * @triggers setItem.pre(PreEvent)
     * @triggers setItem.post(PostEvent)
     * @triggers setItem.exception(ExceptionEvent)
     */
    public function setItem($key, $value)
    {
        $options = $this->getOptions();
        if ($options->getWritable() && $options->getClearStatCache()) {
            clearstatcache();
        }
        return parent::setItem($key, $value);
    }
 
    /**
     * Store multiple items.
     *
     * @param  array $keyValuePairs
     * @return array Array of not stored keys
     * @throws Exception\ExceptionInterface
     *
     * @triggers setItems.pre(PreEvent)
     * @triggers setItems.post(PostEvent)
     * @triggers setItems.exception(ExceptionEvent)
     */
    public function setItems(array $keyValuePairs)
    {
        $options = $this->getOptions();
        if ($options->getWritable() && $options->getClearStatCache()) {
            clearstatcache();
        }
 
     * Data is cached for up to $this->cacheLifetime seconds.
     *
     * @param string $key      Cache entry key
     * @param mixed  $entry    Entry to be cached
     * @param int    $lifetime Optional lifetime for the entry in seconds
     *
     * @return void
     */
    protected function putCachedData($key, $entry, $lifetime = null)
    {
        // Don't write to cache if we don't have a cache!
        if (null === $this->cache) {
            return;
        }
        $item = [
            'time' => time(),
            'lifetime' => $lifetime,
            'entry' => $entry,
        ];
        $this->cache->setItem($this->getCacheKey($key), $item);
    }
 
    /**
     * Helper function for removing cached data.
     *
     * @param string $key Cache entry key
     *
     * @return void
     */
    protected function removeCachedData($key)
    {
        // Don't write to cache if we don't have a cache!
        if (null === $this->cache) {
            return;
        }
        $this->cache->removeItem($this->getCacheKey($key));
    }
}
 
 
        $url = $this->config['Catalog']['host'] . '/v1/oauth/token';
 
        try {
            $token = $this->getNewOAuth2Token(
                $url,
                $this->config['Catalog']['clientId'],
                $this->config['Catalog']['clientSecret'],
                $this->config['Catalog']['grantType'] ?? 'client_credentials'
            );
        } catch (AuthTokenException $exception) {
            throw new ILSException(
                'Problem with Koha REST API: ' . $exception->getMessage()
            );
        }
 
        $this->putCachedData(
            $cacheKey,
            $token->getHeaderValue(),
            $token->getExpiresIn()
        );
 
        return $token->getHeaderValue();
    }
 
    /**
     * Get Item Statuses
     *
     * This is responsible for retrieving the status information of a certain
     * record.
     *
     * @param string $id     The record id to retrieve the holdings for
     * @param array  $patron Patron information, if available
     *
     * @return array An associative array with the following keys:
     * id, availability (boolean), status, location, reserve, callnumber.
     */
    protected function getItemStatusesForBiblio($id, $patron = null)
    {
        $result = $this->makeRequest(
    {
        // Set up the request
        $apiUrl = $this->config['Catalog']['host'] . '/';
 
        // Handle the simple case of just a path in $request
        if (is_string($request) || !isset($request['path'])) {
            $request = [
                'path' => $request
            ];
        }
 
        if (is_array($request['path'])) {
            $apiUrl .= implode('/', array_map('urlencode', $request['path']));
        } else {
            $apiUrl .= $request['path'];
        }
 
        $client = $this->createHttpClient($apiUrl);
        $client->getRequest()->getHeaders()
            ->addHeaderLine('Authorization', $this->getOAuth2Token());
 
        // Add params
        if (!empty($request['query'])) {
            $client->setParameterGet($request['query']);
        }
        if (!empty($request['form'])) {
            $client->setParameterPost($request['form']);
        } elseif (!empty($request['json'])) {
            $client->getRequest()->setContent(json_encode($request['json']));
            $client->getRequest()->getHeaders()->addHeaderLine(
                'Content-Type',
                'application/json'
            );
        }
 
        if (!empty($request['headers'])) {
            $requestHeaders = $client->getRequest()->getHeaders();
            foreach ($request['headers'] as $name => $value) {
                $requestHeaders->addHeaderLine($name, [$value]);
            }
    }
 
    /**
     * Get Item Statuses
     *
     * This is responsible for retrieving the status information of a certain
     * record.
     *
     * @param string $id     The record id to retrieve the holdings for
     * @param array  $patron Patron information, if available
     *
     * @return array An associative array with the following keys:
     * id, availability (boolean), status, location, reserve, callnumber.
     */
    protected function getItemStatusesForBiblio($id, $patron = null)
    {
        $result = $this->makeRequest(
            [
                'path' => [
                    'v1', 'contrib', 'kohasuomi', 'availability', 'biblios', $id,
                    'search'
                ],
                'errors' => true
            ]
        );
        if (404 == $result['code']) {
            return [];
        }
        /**if (200 != $result['code']) {
            throw new ILSException('Problem with Koha REST API.');
    }**/
 
        if (empty($result['data']['item_availabilities'])) {
            return [];
        }
 
        $statuses = [];
        foreach ($result['data']['item_availabilities'] as $i => $item) {
            $avail = $item['availability'];
            $available = $avail['available'];
    /**
     * Get Holding
     *
     * This is responsible for retrieving the holding information of a certain
     * record.
     *
     * @param string $id      The record id to retrieve the holdings for
     * @param array  $patron  Patron data
     * @param array  $options Extra options
     *
     * @throws ILSException
     * @return array         On success, an associative array with the following
     * keys: id, availability (boolean), status, location, reserve, callnumber,
     * duedate, number, barcode.
     *
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function getHolding($id, array $patron = null, array $options = [])
    {
        return $this->getItemStatusesForBiblio($id, $patron);
    }
 
    /**
     * Get Purchase History
     *
     * This is responsible for retrieving the acquisitions history data for the
     * specific record (usually recently received issues of a serial).
     *
     * @param string $id The record id to retrieve the info for
     *
     * @return mixed     An array with the acquisitions data on success.
     *
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function getPurchaseHistory($id)
    {
        return [];
    }
 
    /**
        return $holdings;
    }
 
    /**
     * Default method -- pass along calls to the driver if available; return
     * false otherwise.  This allows custom functions to be implemented in
     * the driver without constant modification to the connection class.
     *
     * @param string $methodName The name of the called method.
     * @param array  $params     Array of passed parameters.
     *
     * @throws ILSException
     * @return mixed             Varies by method (false if undefined method)
     */
    public function __call($methodName, $params)
    {
        try {
            if ($this->checkCapability($methodName, $params)) {
                return call_user_func_array(
                    [$this->getDriver(), $methodName],
                    $params
                );
            }
        } catch (\Exception $e) {
            if ($this->failOverToNoILS($e)) {
                return call_user_func_array([$this, __METHOD__], func_get_args());
            }
            throw $e;
        }
        throw new ILSException(
            'Cannot call method: ' . $this->getDriverClass() . '::' . $methodName
        );
    }
}
 
        return $holdings;
    }
 
    /**
     * Default method -- pass along calls to the driver if available; return
     * false otherwise.  This allows custom functions to be implemented in
     * the driver without constant modification to the connection class.
     *
     * @param string $methodName The name of the called method.
     * @param array  $params     Array of passed parameters.
     *
     * @throws ILSException
     * @return mixed             Varies by method (false if undefined method)
     */
    public function __call($methodName, $params)
    {
        try {
            if ($this->checkCapability($methodName, $params)) {
                return call_user_func_array(
                    [$this->getDriver(), $methodName],
                    $params
                );
            }
        } catch (\Exception $e) {
            if ($this->failOverToNoILS($e)) {
                return call_user_func_array([$this, __METHOD__], func_get_args());
            }
            throw $e;
        }
        throw new ILSException(
            'Cannot call method: ' . $this->getDriverClass() . '::' . $methodName
        );
    }
}
 
        $params = compact('id', 'patron');
        $config = $this->checkCapability('getConfig', ['Holdings', $params])
            ? $this->getDriver()->getConfig('Holdings', $params) : [];
        if (empty($config['itemLimit'])) {
            // Use itemLimit in Holds as fallback for backward compatibility:
            $config
                = $this->checkCapability('getConfig', ['Holds', $params])
                ? $this->getDriver()->getConfig('Holds', $params) : [];
        }
        $itemLimit = !empty($config['itemLimit']) ? $config['itemLimit'] : null;
 
        $page = $this->request ? $this->request->getQuery('page', 1) : 1;
        $offset = ($itemLimit && is_numeric($itemLimit))
            ? ($page * $itemLimit) - $itemLimit
            : null;
        $defaultOptions = compact('page', 'itemLimit', 'offset');
        $finalOptions = $options + $defaultOptions;
 
        // Get the holdings from the ILS
        $holdings = $this->__call('getHolding', [$id, $patron, $finalOptions]);
 
        // Return all the necessary details:
        if (!isset($holdings['holdings'])) {
            $holdings = [
                'total' => count($holdings),
                'holdings' => $holdings,
                'electronic_holdings' => [],
            ];
        } else {
            if (!isset($holdings['total'])) {
                $holdings['total'] = count($holdings['holdings']);
            }
            if (!isset($holdings['electronic_holdings'])) {
                $holdings['electronic_holdings'] = [];
            }
        }
        $holdings['page'] = $finalOptions['page'];
        $holdings['itemLimit'] = $finalOptions['itemLimit'];
        return $holdings;
    }
 
            // Does this ILS Driver handle consortial holdings?
            $config = $this->catalog->checkFunction(
                'Holds',
                compact('id', 'patron')
            );
        } catch (ILSException $e) {
            $patron = false;
            $config = [];
        }
 
        if (isset($config['consortium']) && $config['consortium'] == true) {
            $result = $this->catalog->getConsortialHoldings(
                $id,
                $patron ? $patron : null,
                $ids
            );
        } else {
            $result = $this->catalog
                ->getHolding($id, $patron ? $patron : null, $options);
        }
 
        $grb = 'getRequestBlocks'; // use variable to shorten line below:
        $blocks
            = $patron && $this->catalog->checkCapability($grb, compact('patron'))
            ? $this->catalog->getRequestBlocks($patron) : false;
 
        $mode = $this->catalog->getHoldsMode();
 
        if ($mode == "disabled") {
            $holdings = $this->standardHoldings($result);
        } elseif ($mode == "driver") {
            $holdings = $this->driverHoldings($result, $config, !empty($blocks));
        } else {
            $holdings = $this->generateHoldings($result, $mode, $config);
        }
 
        $holdings = $this->processStorageRetrievalRequests(
            $holdings,
            $id,
     *
     * @return bool
     */
    protected function hasILS()
    {
        return null !== $this->ils
            && in_array($this->getSourceIdentifier(), $this->ilsBackends);
    }
 
    /**
     * Get an array of information about record holdings, obtained in real-time
     * from the ILS.
     *
     * @return array
     */
    public function getRealTimeHoldings()
    {
        return $this->hasILS() ? $this->holdLogic->getHoldings(
            $this->getUniqueID(),
            $this->tryMethod('getConsortialIDs')
        ) : [];
    }
 
    /**
     * Get an array of information about record history, obtained in real-time
     * from the ILS.
     *
     * @return array
     */
    public function getRealTimeHistory()
    {
        // Get Acquisitions Data
        if (!$this->hasILS()) {
            return [];
        }
        try {
            return $this->ils->getPurchaseHistory($this->getUniqueID());
        } catch (ILSException $e) {
            return [];
        }
<?php
    // Set up convenience variables:
    $account = $this->auth()->getManager();
    $user = $account->isLoggedIn();
    $openUrl = $this->openUrl($this->driver, 'holdings');
    $openUrlActive = $openUrl->isActive();
    $doi = $this->doi($this->driver, 'holdings');
    $doiActive = $doi->isActive();
    // Account for replace_other_urls setting
    $urls = $this->record($this->driver)->getLinkDetails($openUrlActive);
    $offlineMode = $this->ils()->getOfflineMode();
    try {
        $holdings = $this->driver->getRealTimeHoldings();
    } catch (\VuFind\Exception\ILS $e) {
        $holdings = [
          'holdings' => [],
          'electronic_holdings' => [],
          'total' => 0,
          'page' => 0,
          'itemLimit' => 0
        ];
        $offlineMode = 'ils-offline';
    }
    // Set page title.
    $this->headTitle($this->translate('Holdings') . ': ' . $this->driver->getBreadcrumb());
?>
 
<?=$this->context($this)->renderInContext('librarycards/selectcard.phtml', ['user' => $this->auth()->isLoggedIn()]); ?>
 
<?php if (!empty($holdings['blocks'])):?>
  <div id="account-block-msg" class="alert alert-danger">
    <?=$this->transEsc('account_block_options_missing', ['%%details%%' => implode('; ', $holdings['blocks'])]) ?>
  </div>
<?php endif; ?>
 
<?=($offlineMode == "ils-offline") ? $this->render('Helpers/ils-offline.phtml', ['offlineModeMsg' => 'ils_offline_holdings_message']) : ''?>
 
<?php if (($this->ils()->getHoldsMode() == 'driver' && !empty($holdings['holdings'])) || $this->ils()->getTitleHoldsMode() == 'driver'): ?>
  <?php if ($account->loginEnabled() && $offlineMode != 'ils-offline'): ?>
    <?php if (!$user): ?>
        $__vars = $this->vars()->getArrayCopy();
        if (array_key_exists('this', $__vars)) {
            unset($__vars['this']);
        }
        extract($__vars);
        unset($__vars); // remove $__vars from local scope
 
        $this->__content = '';
        while ($this->__template = array_pop($this->__templates)) {
            $this->__file = $this->resolver($this->__template);
            if (! $this->__file) {
                throw new Exception\RuntimeException(sprintf(
                    '%s: Unable to render template "%s"; resolver could not resolve to a file',
                    __METHOD__,
                    $this->__template
                ));
            }
            try {
                ob_start();
                $includeReturn = include $this->__file;
                $this->__content = ob_get_clean();
            } catch (\Throwable $ex) {
                ob_end_clean();
                throw $ex;
            } catch (\Exception $ex) { // @TODO clean up once PHP 7 requirement is enforced
                ob_end_clean();
                throw $ex;
            }
            if ($includeReturn === false && empty($this->__content)) {
                throw new Exception\UnexpectedValueException(sprintf(
                    '%s: Unable to render template "%s"; file include failed',
                    __METHOD__,
                    $this->__file
                ));
            }
        }
 
        $this->setVars(array_pop($this->__varsCache));
 
        if ($this->__filterChain instanceof FilterChain) {
        );
        $link .= $this->getView()->plugin('searchTabs')
            ->getCurrentHiddenFilterParams($this->driver->getSourceIdentifier());
        return $link;
    }
 
    /**
     * Render the contents of the specified record tab.
     *
     * @param \VuFind\RecordTab\TabInterface $tab Tab to display
     *
     * @return string
     */
    public function getTab(\VuFind\RecordTab\TabInterface $tab)
    {
        $context = ['driver' => $this->driver, 'tab' => $tab];
        $classParts = explode('\\', get_class($tab));
        $template = 'RecordTab/' . strtolower(array_pop($classParts)) . '.phtml';
        $oldContext = $this->contextHelper->apply($context);
        $html = $this->view->render($template);
        $this->contextHelper->restore($oldContext);
        return $html;
    }
 
    /**
     * Render a toolbar for use on the record view.
     *
     * @return string
     */
    public function getToolbar()
    {
        return $this->renderTemplate('toolbar.phtml');
    }
 
    /**
     * Render a search result for the specified view mode.
     *
     * @param string $view View mode to use.
     *
     * @return string
                  $tabClasses[] = 'active';
                }
                $tabClasses[] = 'initiallyActive';
                $activeTabObj = $obj;
              }
              if (!$obj->isVisible()) { $tabClasses[] = 'hidden'; }
              if (!$obj->supportsAjax()) { $tabClasses[] = 'noajax'; }
            ?>
            <li class="<?=implode(' ', $tabClasses)?>" data-tab="<?=$this->escapeHtmlAttr($tabName)?>"<?php if ($obj->supportsAjax() && in_array($tab, $this->backgroundTabs)):?> data-background<?php endif ?>>
              <a href="<?=$this->escapeHtmlAttr($this->recordLinker()->getTabUrl($this->driver, $tab))?>#tabnav" data-lightbox-ignore>
                <?=$this->transEsc($desc)?>
              </a>
            </li>
          <?php endforeach; ?>
        </ul>
 
        <div class="tab-content">
          <?php if (!$this->loadInitialTabWithAjax || !isset($activeTabObj) || !$activeTabObj->supportsAjax()): ?>
            <div class="tab-pane active <?=$this->escapeHtmlAttr($this->activeTab) ?>-tab">
              <?=isset($activeTabObj) ? $this->record($this->driver)->getTab($activeTabObj) : '' ?>
            </div>
          <?php endif; ?>
        </div>
      </div>
    <?php endif; ?>
 
    <?=$this->driver->supportsCoinsOpenURL()?'<span class="Z3988" title="' . $this->escapeHtmlAttr($this->driver->getCoinsOpenURL()) . '"></span>':''?>
  </div>
 
  <div class="<?=$this->layoutClass('sidebar')?>">
    <?php foreach ($sidebarList as $current): ?>
      <?=$this->related()->render($current)?>
    <?php endforeach; ?>
  </div>
</div>
<?=$this->inlineScript(\Laminas\View\Helper\HeadScript::SCRIPT, '$(document).ready(recordDocReady);', 'SET'); ?>
 
        $__vars = $this->vars()->getArrayCopy();
        if (array_key_exists('this', $__vars)) {
            unset($__vars['this']);
        }
        extract($__vars);
        unset($__vars); // remove $__vars from local scope
 
        $this->__content = '';
        while ($this->__template = array_pop($this->__templates)) {
            $this->__file = $this->resolver($this->__template);
            if (! $this->__file) {
                throw new Exception\RuntimeException(sprintf(
                    '%s: Unable to render template "%s"; resolver could not resolve to a file',
                    __METHOD__,
                    $this->__template
                ));
            }
            try {
                ob_start();
                $includeReturn = include $this->__file;
                $this->__content = ob_get_clean();
            } catch (\Throwable $ex) {
                ob_end_clean();
                throw $ex;
            } catch (\Exception $ex) { // @TODO clean up once PHP 7 requirement is enforced
                ob_end_clean();
                throw $ex;
            }
            if ($includeReturn === false && empty($this->__content)) {
                throw new Exception\UnexpectedValueException(sprintf(
                    '%s: Unable to render template "%s"; file include failed',
                    __METHOD__,
                    $this->__file
                ));
            }
        }
 
        $this->setVars(array_pop($this->__varsCache));
 
        if ($this->__filterChain instanceof FilterChain) {
 
        // If EVENT_RENDERER or EVENT_RENDERER_POST changed the model, make sure
        // we use this new model instead of the current $model
        $model   = $event->getModel();
 
        // If we have children, render them first, but only if:
        // a) the renderer does not implement TreeRendererInterface, or
        // b) it does, but canRenderTrees() returns false
        if ($model->hasChildren()
            && (! $renderer instanceof TreeRendererInterface
                || ! $renderer->canRenderTrees())
        ) {
            $this->renderChildren($model);
        }
 
        // Reset the model, in case it has changed, and set the renderer
        $event->setModel($model);
        $event->setRenderer($renderer);
 
        $rendered = $renderer->render($model);
 
        // If this is a child model, return the rendered content; do not
        // invoke the response strategy.
        $options = $model->getOptions();
        if (array_key_exists('has_parent', $options) && $options['has_parent']) {
            return $rendered;
        }
 
        $event->setResult($rendered);
        $event->setName(ViewEvent::EVENT_RESPONSE);
 
        $events->triggerEvent($event);
    }
 
    /**
     * Loop through children, rendering each
     *
     * @param  Model $model
     * @throws Exception\DomainException
     * @return void
        $event->setName(ViewEvent::EVENT_RESPONSE);
 
        $events->triggerEvent($event);
    }
 
    /**
     * Loop through children, rendering each
     *
     * @param  Model $model
     * @throws Exception\DomainException
     * @return void
     */
    protected function renderChildren(Model $model)
    {
        foreach ($model as $child) {
            if ($child->terminate()) {
                throw new Exception\DomainException('Inconsistent state; child view model is marked as terminal');
            }
            $child->setOption('has_parent', true);
            $result  = $this->render($child);
            $child->setOption('has_parent', null);
            $capture = $child->captureTo();
            if (! empty($capture)) {
                if ($child->isAppend()) {
                    $oldResult = $model->{$capture};
                    $model->setVariable($capture, $oldResult . $result);
                } else {
                    $model->setVariable($capture, $result);
                }
            }
        }
    }
 
    /**
     * Create and return ViewEvent used by render()
     *
     * @return ViewEvent
     */
    protected function getEvent()
    {
                __METHOD__
            ));
        }
 
        $event->setRenderer($renderer);
        $event->setName(ViewEvent::EVENT_RENDERER_POST);
        $events->triggerEvent($event);
 
        // If EVENT_RENDERER or EVENT_RENDERER_POST changed the model, make sure
        // we use this new model instead of the current $model
        $model   = $event->getModel();
 
        // If we have children, render them first, but only if:
        // a) the renderer does not implement TreeRendererInterface, or
        // b) it does, but canRenderTrees() returns false
        if ($model->hasChildren()
            && (! $renderer instanceof TreeRendererInterface
                || ! $renderer->canRenderTrees())
        ) {
            $this->renderChildren($model);
        }
 
        // Reset the model, in case it has changed, and set the renderer
        $event->setModel($model);
        $event->setRenderer($renderer);
 
        $rendered = $renderer->render($model);
 
        // If this is a child model, return the rendered content; do not
        // invoke the response strategy.
        $options = $model->getOptions();
        if (array_key_exists('has_parent', $options) && $options['has_parent']) {
            return $rendered;
        }
 
        $event->setResult($rendered);
        $event->setName(ViewEvent::EVENT_RESPONSE);
 
        $events->triggerEvent($event);
    }
        if ($result instanceof Response) {
            return $result;
        }
 
        // Martial arguments
        $request   = $e->getRequest();
        $response  = $e->getResponse();
        $viewModel = $e->getViewModel();
        if (! $viewModel instanceof ViewModel) {
            return;
        }
 
        $view = $this->view;
        $view->setRequest($request);
        $view->setResponse($response);
 
        $caughtException = null;
 
        try {
            $view->render($viewModel);
        } catch (\Throwable $ex) {
            $caughtException = $ex;
        } catch (\Exception $ex) {  // @TODO clean up once PHP 7 requirement is enforced
            $caughtException = $ex;
        }
 
        if ($caughtException !== null) {
            if ($e->getName() === MvcEvent::EVENT_RENDER_ERROR) {
                throw $caughtException;
            }
 
            $application = $e->getApplication();
            $events      = $application->getEventManager();
 
            $e->setError(Application::ERROR_EXCEPTION);
            $e->setParam('exception', $caughtException);
            $e->setName(MvcEvent::EVENT_RENDER_ERROR);
            $events->triggerEvent($e);
        }
 
        }
 
        if ($this->sharedManager) {
            foreach ($this->sharedManager->getListeners($this->identifiers, $name) as $priority => $listeners) {
                $listOfListenersByPriority[$priority][] = $listeners;
            }
        }
 
        // Sort by priority in reverse order
        krsort($listOfListenersByPriority);
 
        // Initial value of stop propagation flag should be false
        $event->stopPropagation(false);
 
        // Execute listeners
        $responses = new ResponseCollection();
        foreach ($listOfListenersByPriority as $listOfListeners) {
            foreach ($listOfListeners as $listeners) {
                foreach ($listeners as $listener) {
                    $response = $listener($event);
                    $responses->push($response);
 
                    // If the event was asked to stop propagating, do so
                    if ($event->propagationIsStopped()) {
                        $responses->setStopped(true);
                        return $responses;
                    }
 
                    // If the result causes our validation callback to return true,
                    // stop propagation
                    if ($callback && $callback($response)) {
                        $responses->setStopped(true);
                        return $responses;
                    }
                }
            }
        }
 
        return $responses;
    }
        $event = clone $this->eventPrototype;
        $event->setName($eventName);
 
        if ($target !== null) {
            $event->setTarget($target);
        }
 
        if ($argv) {
            $event->setParams($argv);
        }
 
        return $this->triggerListeners($event, $callback);
    }
 
    /**
     * @inheritDoc
     */
    public function triggerEvent(EventInterface $event)
    {
        return $this->triggerListeners($event);
    }
 
    /**
     * @inheritDoc
     */
    public function triggerEventUntil(callable $callback, EventInterface $event)
    {
        return $this->triggerListeners($event, $callback);
    }
 
    /**
     * @inheritDoc
     */
    public function attach($eventName, callable $listener, $priority = 1)
    {
        if (! is_string($eventName)) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects a string for the event; received %s',
                __METHOD__,
                (is_object($eventName) ? get_class($eventName) : gettype($eventName))
        return $this->completeRequest($event);
    }
 
    /**
     * Complete the request
     *
     * Triggers "render" and "finish" events, and returns response from
     * event object.
     *
     * @param  MvcEvent $event
     * @return Application
     */
    protected function completeRequest(MvcEvent $event)
    {
        $events = $this->events;
        $event->setTarget($this);
 
        $event->setName(MvcEvent::EVENT_RENDER);
        $event->stopPropagation(false); // Clear before triggering
        $events->triggerEvent($event);
 
        $event->setName(MvcEvent::EVENT_FINISH);
        $event->stopPropagation(false); // Clear before triggering
        $events->triggerEvent($event);
 
        return $this;
    }
}
 
        // Trigger dispatch event
        $event->setName(MvcEvent::EVENT_DISPATCH);
        $event->stopPropagation(false); // Clear before triggering
        $result = $events->triggerEventUntil($shortCircuit, $event);
 
        // Complete response
        $response = $result->last();
        if ($response instanceof ResponseInterface) {
            $event->setName(MvcEvent::EVENT_FINISH);
            $event->setTarget($this);
            $event->setResponse($response);
            $event->stopPropagation(false); // Clear before triggering
            $events->triggerEvent($event);
            $this->response = $response;
            return $this;
        }
 
        $response = $this->response;
        $event->setResponse($response);
        return $this->completeRequest($event);
    }
 
    /**
     * Complete the request
     *
     * Triggers "render" and "finish" events, and returns response from
     * event object.
     *
     * @param  MvcEvent $event
     * @return Application
     */
    protected function completeRequest(MvcEvent $event)
    {
        $events = $this->events;
        $event->setTarget($this);
 
        $event->setName(MvcEvent::EVENT_RENDER);
        $event->stopPropagation(false); // Clear before triggering
        $events->triggerEvent($event);
 
$pathParts[] = APPLICATION_PATH . '/vendor';
$pathParts[] = get_include_path();
set_include_path(implode(PATH_SEPARATOR, $pathParts));
 
// Composer autoloading
if (file_exists('vendor/autoload.php')) {
    $loader = include 'vendor/autoload.php';
}
 
if (!class_exists('Laminas\Loader\AutoloaderFactory')) {
    throw new RuntimeException('Unable to load Laminas autoloader.');
}
 
// Run the application!
$app = Laminas\Mvc\Application::init(require 'config/application.config.php');
if (PHP_SAPI === 'cli') {
    return $app->getServiceManager()
        ->get(\VuFindConsole\ConsoleRunner::class)->run();
} else {
    $app->run();
}
 

Environment & details:

empty
empty
empty
empty
Key Value
__Laminas Array ( [_REQUEST_ACCESS_TIME] => 1711620429.0256 [_VALID] => Array ( [Laminas\Session\Validator\Id] => pddr9hv1tqcdb10m92r70e3av7 ) )
SessionState Laminas\Stdlib\ArrayObject Object ( [storage:protected] => Array ( [cookiePath] => / ) [flag:protected] => 2 [iteratorClass:protected] => ArrayIterator [protectedProperties:protected] => Array ( [0] => storage [1] => flag [2] => iteratorClass [3] => protectedProperties ) )
FlashMessenger Laminas\Stdlib\ArrayObject Object ( [storage:protected] => Array ( ) [flag:protected] => 2 [iteratorClass:protected] => ArrayIterator [protectedProperties:protected] => Array ( [0] => storage [1] => flag [2] => iteratorClass [3] => protectedProperties ) )
Key Value
REDIRECT_VUFIND_ENV development
REDIRECT_VUFIND_LOCAL_DIR /usr/local/vufind/local
REDIRECT_STATUS 200
VUFIND_ENV development
VUFIND_LOCAL_DIR /usr/local/vufind/local
HTTP_HOST vufind.umc.cl
HTTP_ACCEPT */*
HTTP_USER_AGENT claudebot
HTTP_X_FORWARDED_FOR 52.91.84.219
HTTP_X_FORWARDED_HOST busca.umc.cl
HTTP_X_FORWARDED_SERVER busca.umc.cl
HTTP_CONNECTION Keep-Alive
PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SERVER_SIGNATURE <address>Apache/2.4.51 (Debian) Server at vufind.umc.cl Port 80</address>
SERVER_SOFTWARE Apache/2.4.51 (Debian)
SERVER_NAME vufind.umc.cl
SERVER_ADDR 10.111.120.20
SERVER_PORT 80
REMOTE_ADDR 10.111.120.170
DOCUMENT_ROOT /usr/local/vufind/public
REQUEST_SCHEME http
CONTEXT_PREFIX
CONTEXT_DOCUMENT_ROOT /usr/local/vufind/public
SERVER_ADMIN [no address given]
SCRIPT_FILENAME /usr/local/vufind/public/index.php
REMOTE_PORT 52002
REDIRECT_URL /Record/ebs698448e
GATEWAY_INTERFACE CGI/1.1
SERVER_PROTOCOL HTTP/1.1
REQUEST_METHOD GET
QUERY_STRING
REQUEST_URI /Record/ebs698448e
SCRIPT_NAME /index.php
PHP_SELF /index.php
REQUEST_TIME_FLOAT 1711620429.0024
REQUEST_TIME 1711620429
empty
0. Whoops\Handler\PrettyPageHandler