芝麻web文件管理V1.00
编辑当前文件:/home/mgatv524/cms.mgaplay.com.br/lib/Middleware/LayoutLock.php
. */ namespace Xibo\Middleware; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Server\MiddlewareInterface as Middleware; use Psr\Http\Server\RequestHandlerInterface as RequestHandler; use Slim\App as App; use Slim\Routing\RouteContext; use Stash\Invalidation; use Stash\Item; use Stash\Pool; use Xibo\Helper\DateFormatHelper; use Xibo\Support\Exception\AccessDeniedException; use Xibo\Support\Exception\GeneralException; class LayoutLock implements Middleware { /* @var App $app */ private $app; /** @var Item */ private $lock; private $ttl = 300; private $layoutId; private $userId; private $entryPoint; public function __construct($app, $ttl = 300) { $this->app = $app; $this->ttl = $ttl; } /** * This Middleware will Lock the Layout for the specific User and entry point * It is not added on the whole Application stack, instead it's added to selected groups of routes in routes.php * * For a User designing a Layout there will be no change in the way that User interacts with it * However if the same Layout will be accessed by different User or Entry Point then this middleware will throw an Exception with suitable message. * * * @param Request $request * @param RequestHandler $handler * @return Response * @throws GeneralException */ public function process(Request $request, RequestHandler $handler): Response { $routeContext = RouteContext::fromRequest($request); $route = $routeContext->getRoute(); // what route are we in? $resource = $route->getPattern(); // skip for test suite if ($request->getAttribute('name') === 'test' && $this->app->getContainer()->get('name') === 'test') { return $handler->handle($request); } if (strpos($resource,'layout') !== false) { // Layout route, we can get the Layout id from route argument. $this->layoutId = (int)$route->getArgument('id'); } elseif (strpos($resource,'region') !== false) { // Region route, we need to get the Layout Id from layoutFactory by Region Id // if it's POST request or positionAll then id in route is already LayoutId we can use if (strpos($resource, 'position') !== false || $route->getMethods()[0] === 'POST') { $this->layoutId = (int)$route->getArgument('id'); } else { $regionId = (int)$route->getArgument('id'); $this->layoutId = $this->app->getContainer()->get('layoutFactory')->getByRegionId($regionId)->layoutId; } } elseif (strpos($route->getName(),'playlist') !== false || $route->getName() === 'module.widget.add') { // Playlist Route, we need to get to LayoutId, Widget add the same behaviour. $playlistId = (int)$route->getArgument('id'); $regionId = $this->app->getContainer()->get('playlistFactory')->getById($playlistId)->regionId; // if we are assigning media or ordering Region Playlist, then we will have regionId // otherwise it's non Region specific Playlist, in which case we are not interested in locking anything. if ($regionId != null) { $this->layoutId = $this->app->getContainer()->get('layoutFactory')->getByRegionId($regionId)->layoutId; } } elseif (strpos($route->getName(), 'widget') !== false) { // Widget route, the id route argument will be Widget Id $widgetId = (int)$route->getArgument('id'); // get the Playlist Id for this Widget $playlistId = $this->app->getContainer()->get('widgetFactory')->getById($widgetId)->playlistId; $regionId = $this->app->getContainer()->get('playlistFactory')->getById($playlistId)->regionId; // check if it's Region specific Playlist, otherwise we don't lock anything. if ($regionId != null) { $this->layoutId = $this->app->getContainer()->get('layoutFactory')->getByRegionId($regionId)->layoutId; } } else { // this should never happen throw new GeneralException(sprintf(__('Layout Lock Middleware called with incorrect route %s'), $route->getPattern())); } // run only if we have layout id, that will exclude non Region specific Playlist requests. if ($this->layoutId !== null) { $this->userId = $this->app->getContainer()->get('user')->userId; $this->entryPoint = $this->app->getContainer()->get('name'); $key = $this->getKey(); $this->lock = $this->getPool()->getItem('locks/layout/' . $key); $objectToCache = new \stdClass(); $objectToCache->layoutId = $this->layoutId; $objectToCache->userId = $this->userId; $objectToCache->entryPoint = $this->entryPoint; $this->app->getContainer()->get('logger')->debug('Layout Lock middleware for LayoutId ' . $this->layoutId . ' userId ' . $this->userId . ' emtrypoint ' . $this->entryPoint); $this->lock->setInvalidationMethod(Invalidation::OLD); // Get the lock // other requests will wait here until we're done, or we've timed out $locked = $this->lock->get(); $this->app->getContainer()->get('logger')->debug('$locked is ' . var_export($locked, true) . ', key = ' . $key); if ($this->lock->isMiss() || $locked === []) { $this->app->getContainer()->get('logger')->debug('Lock miss or false. Locking for ' . $this->ttl . ' seconds. $locked is ' . var_export($locked, true) . ', key = ' . $key); // so lock now $this->lock->expiresAfter($this->ttl); $objectToCache->expires = $this->lock->getExpiration()->format(DateFormatHelper::getSystemFormat()); $this->lock->set($objectToCache); $this->lock->save(); } else { // We are a hit - we must be locked $this->app->getContainer()->get('logger')->debug('LOCK hit for ' . $key . ' expires ' . $this->lock->getExpiration()->format(DateFormatHelper::getSystemFormat()) . ', created ' . $this->lock->getCreation()->format(DateFormatHelper::getSystemFormat())); if ($locked->userId == $this->userId && $locked->entryPoint == $this->entryPoint) { // the same user in the same entry point is editing the same layoutId $this->lock->expiresAfter($this->ttl); $objectToCache->expires = $this->lock->getExpiration()->format(DateFormatHelper::getSystemFormat()); $this->lock->set($objectToCache); $this->lock->save(); $this->app->getContainer()->get('logger')->debug('Lock extended to ' . $this->lock->getExpiration()->format(DateFormatHelper::getSystemFormat())); } else { // different user or entry point $this->app->getContainer()->get('logger')->debug('Sorry Layout is locked by another User!'); throw new AccessDeniedException(sprintf(__('Layout ID %d is locked by another User! Lock expires on: %s'), $locked->layoutId, $locked->expires)); } } } return $handler->handle($request); } /** * @return Pool */ private function getPool() { return $this->app->getContainer()->get('pool'); } private function getKey() { return $this->layoutId; } }