Merge pull request #58863 from nextcloud/fix/annotation-attributes-fix

This commit is contained in:
Benjamin Gaussorgues 2026-03-18 08:46:31 +01:00 committed by GitHub
commit 1b504bf4ec
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 138 additions and 168 deletions

View file

@ -11,6 +11,7 @@ namespace OCA\Provisioning_API\Middleware;
use OCA\Provisioning_API\Middleware\Exceptions\NotSubAdminException;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Middleware;
use OCP\AppFramework\OCS\OCSException;
@ -40,7 +41,7 @@ class ProvisioningApiMiddleware extends Middleware {
*/
public function beforeController($controller, $methodName) {
// If AuthorizedAdminSetting, the check will be done in the SecurityMiddleware
if (!$this->isAdmin && !$this->reflector->hasAnnotation('NoSubAdminRequired') && !$this->isSubAdmin && !$this->reflector->hasAnnotation('AuthorizedAdminSetting')) {
if (!$this->isAdmin && !$this->reflector->hasAnnotation('NoSubAdminRequired') && !$this->isSubAdmin && !$this->reflector->hasAnnotationOrAttribute('AuthorizedAdminSetting', AuthorizedAdminSetting::class)) {
throw new NotSubAdminException();
}
}

View file

@ -53,10 +53,14 @@ class ProvisioningApiMiddlewareTest extends TestCase {
);
$this->reflector->method('hasAnnotation')
->willReturnCallback(function ($annotation) use ($subadminRequired, $hasSettingAuthorizationAnnotation) {
->willReturnCallback(function ($annotation) use ($subadminRequired) {
if ($annotation === 'NoSubAdminRequired') {
return !$subadminRequired;
}
return false;
});
$this->reflector->method('hasAnnotationOrAttribute')
->willReturnCallback(function ($annotation, $attribute) use ($hasSettingAuthorizationAnnotation) {
if ($annotation === 'AuthorizedAdminSetting') {
return $hasSettingAuthorizationAnnotation;
}

View file

@ -14,6 +14,7 @@ use OC\AppFramework\Http;
use OC\AppFramework\Middleware\Security\Exceptions\NotAdminException;
use OC\AppFramework\Utility\ControllerMethodReflector;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Middleware;
use OCP\Group\ISubAdmin;
@ -44,7 +45,7 @@ class SubadminMiddleware extends Middleware {
#[Override]
public function beforeController(Controller $controller, string $methodName): void {
if (!$this->reflector->hasAnnotation('NoSubAdminRequired') && !$this->reflector->hasAnnotation('AuthorizedAdminSetting')) {
if (!$this->reflector->hasAnnotation('NoSubAdminRequired') && !$this->reflector->hasAnnotationOrAttribute('AuthorizedAdminSetting', AuthorizedAdminSetting::class)) {
if (!$this->isSubAdmin()) {
throw new NotAdminException($this->l10n->t('Logged in account must be a sub admin'));
}

View file

@ -14,6 +14,7 @@ use OC\AppFramework\Middleware\Security\Exceptions\NotAdminException;
use OC\AppFramework\Utility\ControllerMethodReflector;
use OCA\Settings\Middleware\SubadminMiddleware;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\Group\ISubAdmin;
use OCP\IL10N;
@ -62,11 +63,16 @@ class SubadminMiddlewareTest extends \Test\TestCase {
$this->expectException(NotAdminException::class);
$this->reflector
->expects($this->exactly(2))
->expects($this->exactly(1))
->method('hasAnnotation')
->willReturnMap([
['NoSubAdminRequired', false],
['AuthorizedAdminSetting', false],
]);
$this->reflector
->expects($this->exactly(1))
->method('hasAnnotationOrAttribute')
->willReturnMap([
['AuthorizedAdminSetting', AuthorizedAdminSetting::class, false],
]);
$this->subAdminManager
@ -94,11 +100,16 @@ class SubadminMiddlewareTest extends \Test\TestCase {
public function testBeforeControllerAsSubAdminWithoutAnnotation(): void {
$this->reflector
->expects($this->exactly(2))
->expects($this->exactly(1))
->method('hasAnnotation')
->willReturnMap([
['NoSubAdminRequired', false],
['AuthorizedAdminSetting', false],
]);
$this->reflector
->expects($this->exactly(1))
->method('hasAnnotationOrAttribute')
->willReturnMap([
['AuthorizedAdminSetting', AuthorizedAdminSetting::class, false],
]);
$this->subAdminManager

View file

@ -1552,9 +1552,6 @@
</DeprecatedMethod>
</file>
<file src="apps/files_sharing/lib/Middleware/SharingCheckMiddleware.php">
<DeprecatedInterface>
<code><![CDATA[protected]]></code>
</DeprecatedInterface>
<DeprecatedMethod>
<code><![CDATA[getAppValue]]></code>
<code><![CDATA[getAppValue]]></code>
@ -2097,9 +2094,6 @@
</DeprecatedMethod>
</file>
<file src="apps/provisioning_api/lib/Middleware/ProvisioningApiMiddleware.php">
<DeprecatedInterface>
<code><![CDATA[IControllerMethodReflector]]></code>
</DeprecatedInterface>
<DeprecatedMethod>
<code><![CDATA[hasAnnotation]]></code>
<code><![CDATA[hasAnnotation]]></code>

View file

@ -11,7 +11,6 @@ namespace OC\Core\Middleware;
use Exception;
use OC\AppFramework\Http\Attributes\TwoFactorSetUpDoneRequired;
use OC\AppFramework\Middleware\MiddlewareUtils;
use OC\Authentication\Exceptions\TwoFactorAuthRequiredException;
use OC\Authentication\Exceptions\UserAlreadyLoggedInException;
use OC\Authentication\TwoFactorAuth\Manager;
@ -23,6 +22,7 @@ use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\NoTwoFactorRequired;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Middleware;
use OCP\AppFramework\Utility\IControllerMethodReflector;
use OCP\Authentication\TwoFactorAuth\ALoginSetupController;
use OCP\IRequest;
use OCP\ISession;
@ -36,7 +36,7 @@ class TwoFactorMiddleware extends Middleware {
private Session $userSession,
private ISession $session,
private IURLGenerator $urlGenerator,
private MiddlewareUtils $middlewareUtils,
private IControllerMethodReflector $reflector,
private IRequest $request,
) {
}
@ -46,9 +46,7 @@ class TwoFactorMiddleware extends Middleware {
* @param string $methodName
*/
public function beforeController($controller, $methodName) {
$reflectionMethod = new ReflectionMethod($controller, $methodName);
if ($this->middlewareUtils->hasAnnotationOrAttribute($reflectionMethod, 'NoTwoFactorRequired', NoTwoFactorRequired::class)) {
if ($this->reflector->hasAnnotationOrAttribute('NoTwoFactorRequired', NoTwoFactorRequired::class)) {
// Route handler explicitly marked to work without finished 2FA are
// not blocked
return;
@ -59,6 +57,7 @@ class TwoFactorMiddleware extends Middleware {
return;
}
$reflectionMethod = new ReflectionMethod($controller, $methodName);
if ($controller instanceof TwoFactorChallengeController
&& $this->userSession->getUser() !== null
&& !$reflectionMethod->getAttributes(TwoFactorSetUpDoneRequired::class)) {

View file

@ -18,7 +18,6 @@ use OCP\Authentication\TwoFactorAuth\ALoginSetupController;
use OCP\ISession;
use OCP\IUserSession;
use Psr\Log\LoggerInterface;
use ReflectionMethod;
// Will close the session if the user session is ephemeral.
// Happens when the user logs in via the login flow v2.
@ -61,12 +60,7 @@ class FlowV2EphemeralSessionsMiddleware extends Middleware {
return;
}
$reflectionMethod = new ReflectionMethod($controller, $methodName);
if (!empty($reflectionMethod->getAttributes(PublicPage::class))) {
return;
}
if ($this->reflector->hasAnnotation('PublicPage')) {
if ($this->reflector->hasAnnotationOrAttribute('PublicPage', PublicPage::class)) {
return;
}

View file

@ -30,19 +30,10 @@ class MiddlewareUtils {
* @param ReflectionMethod $reflectionMethod
* @param ?string $annotationName
* @param class-string<T> $attributeClass
* @return boolean
* @deprecated 34.0.0 call directly on the reflector
*/
public function hasAnnotationOrAttribute(ReflectionMethod $reflectionMethod, ?string $annotationName, string $attributeClass): bool {
if (!empty($reflectionMethod->getAttributes($attributeClass))) {
return true;
}
if ($annotationName && $this->reflector->hasAnnotation($annotationName)) {
$this->logger->debug($reflectionMethod->getDeclaringClass()->getName() . '::' . $reflectionMethod->getName() . ' uses the @' . $annotationName . ' annotation and should use the #[' . $attributeClass . '] attribute instead');
return true;
}
return false;
return $this->reflector->hasAnnotationOrAttribute($annotationName, $attributeClass);
}
/**

View file

@ -46,9 +46,7 @@ class PasswordConfirmationMiddleware extends Middleware {
* @throws NotConfirmedException
*/
public function beforeController(Controller $controller, string $methodName) {
$reflectionMethod = new ReflectionMethod($controller, $methodName);
if (!$this->needsPasswordConfirmation($reflectionMethod)) {
if (!$this->needsPasswordConfirmation()) {
return;
}
@ -79,6 +77,7 @@ class PasswordConfirmationMiddleware extends Middleware {
return;
}
$reflectionMethod = new ReflectionMethod($controller, $methodName);
if ($this->isPasswordConfirmationStrict($reflectionMethod)) {
$authHeader = $this->request->getHeader('Authorization');
if (!str_starts_with(strtolower($authHeader), 'basic ')) {
@ -101,18 +100,8 @@ class PasswordConfirmationMiddleware extends Middleware {
}
}
private function needsPasswordConfirmation(ReflectionMethod $reflectionMethod): bool {
$attributes = $reflectionMethod->getAttributes(PasswordConfirmationRequired::class);
if (!empty($attributes)) {
return true;
}
if ($this->reflector->hasAnnotation('PasswordConfirmationRequired')) {
$this->logger->debug($reflectionMethod->getDeclaringClass()->getName() . '::' . $reflectionMethod->getName() . ' uses the @' . 'PasswordConfirmationRequired' . ' annotation and should use the #[PasswordConfirmationRequired] attribute instead');
return true;
}
return false;
private function needsPasswordConfirmation(): bool {
return $this->reflector->hasAnnotationOrAttribute('PasswordConfirmationRequired', PasswordConfirmationRequired::class);
}
private function isPasswordConfirmationStrict(ReflectionMethod $reflectionMethod): bool {

View file

@ -14,7 +14,6 @@ use OCP\AppFramework\Http\Attribute\UseSession;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Middleware;
use OCP\ISession;
use ReflectionMethod;
class SessionMiddleware extends Middleware {
public function __construct(
@ -28,18 +27,7 @@ class SessionMiddleware extends Middleware {
* @param string $methodName
*/
public function beforeController($controller, $methodName) {
/**
* Annotation deprecated with Nextcloud 26
*/
$hasAnnotation = $this->reflector->hasAnnotation('UseSession');
if ($hasAnnotation) {
$this->session->reopen();
return;
}
$reflectionMethod = new ReflectionMethod($controller, $methodName);
$hasAttribute = !empty($reflectionMethod->getAttributes(UseSession::class));
if ($hasAttribute) {
if ($this->reflector->hasAnnotationOrAttribute('UseSession', UseSession::class)) {
$this->session->reopen();
}
}
@ -51,18 +39,7 @@ class SessionMiddleware extends Middleware {
* @return Response
*/
public function afterController($controller, $methodName, Response $response) {
/**
* Annotation deprecated with Nextcloud 26
*/
$hasAnnotation = $this->reflector->hasAnnotation('UseSession');
if ($hasAnnotation) {
$this->session->close();
return $response;
}
$reflectionMethod = new ReflectionMethod($controller, $methodName);
$hasAttribute = !empty($reflectionMethod->getAttributes(UseSession::class));
if ($hasAttribute) {
if ($this->reflector->hasAnnotationOrAttribute('UseSession', UseSession::class)) {
$this->session->close();
}

View file

@ -9,28 +9,39 @@ declare(strict_types=1);
namespace OC\AppFramework\Utility;
use OCP\AppFramework\Utility\IControllerMethodReflector;
use Psr\Log\LoggerInterface;
/**
* Reads and parses annotations from doc comments
*/
class ControllerMethodReflector implements IControllerMethodReflector {
public $annotations = [];
private $types = [];
private $parameters = [];
public array $annotations = [];
private array $types = [];
private array $parameters = [];
private array $ranges = [];
private int $startLine = 0;
private string $file = '';
private ?\ReflectionMethod $reflectionMethod = null;
public function __construct(
private readonly LoggerInterface $logger,
) {
}
/**
* @param object $object an object or classname
* @param string $method the method which we want to inspect
*/
public function reflect($object, string $method) {
$reflection = new \ReflectionMethod($object, $method);
$this->startLine = $reflection->getStartLine();
$this->file = $reflection->getFileName();
$this->annotations = [];
$this->types = [];
$this->parameters = [];
$this->ranges = [];
$this->reflectionMethod = new \ReflectionMethod($object, $method);
$this->startLine = $this->reflectionMethod->getStartLine();
$this->file = $this->reflectionMethod->getFileName();
$docs = $reflection->getDocComment();
$docs = $this->reflectionMethod->getDocComment();
if ($docs !== false) {
// extract everything prefixed by @ and first letter uppercase
@ -69,7 +80,7 @@ class ControllerMethodReflector implements IControllerMethodReflector {
}
}
foreach ($reflection->getParameters() as $param) {
foreach ($this->reflectionMethod->getParameters() as $param) {
// extract type information from PHP 7 scalar types and prefer them over phpdoc annotations
$type = $param->getType();
if ($type instanceof \ReflectionNamedType) {
@ -114,6 +125,24 @@ class ControllerMethodReflector implements IControllerMethodReflector {
return $this->parameters;
}
/**
* @template T
*
* @param class-string<T> $attributeClass
*/
public function hasAnnotationOrAttribute(?string $annotationName, string $attributeClass): bool {
if (!empty($this->reflectionMethod->getAttributes($attributeClass))) {
return true;
}
if ($annotationName && $this->hasAnnotation($annotationName)) {
$this->logger->debug($this->reflectionMethod->getDeclaringClass()->getName() . '::' . $this->reflectionMethod->getName() . ' uses the @' . $annotationName . ' annotation and should use the #[' . $attributeClass . '] attribute instead');
return true;
}
return false;
}
/**
* Check if a method contains an annotation
* @param string $name the name of the annotation

View file

@ -11,22 +11,13 @@ namespace OCP\AppFramework\Utility;
/**
* Interface ControllerMethodReflector
*
* Reads and parses annotations from doc comments
* You can inject this interface in your Middleware, and it will be prefilled with information related to the called controller method
*
* Reads and parses annotations from doc comments (deprecated) and PHP attributes
*
* @since 8.0.0
* @deprecated 22.0.0 will be obsolete with native attributes in PHP8
* @see https://help.nextcloud.com/t/how-should-we-use-php8-attributes/104278
*/
interface IControllerMethodReflector {
/**
* @param object $object an object or classname
* @param string $method the method which we want to inspect
* @return void
* @since 8.0.0
* @deprecated 17.0.0 Reflect should not be called multiple times and only be used internally. This will be removed in Nextcloud 18
*/
public function reflect($object, string $method);
/**
* Inspects the PHPDoc parameters for types
*
@ -56,4 +47,15 @@ interface IControllerMethodReflector {
* @see https://help.nextcloud.com/t/how-should-we-use-php8-attributes/104278
*/
public function hasAnnotation(string $name): bool;
/**
* @template T
*
* Check if a method contains an annotation or an attribute.
* Log a debug line if the annotation is used.
*
* @param class-string<T> $attributeClass
* @since 34.0.0
*/
public function hasAnnotationOrAttribute(?string $annotationName, string $attributeClass): bool;
}

View file

@ -10,7 +10,6 @@ namespace Test\Core\Middleware;
use OC\AppFramework\Http\Attributes\TwoFactorSetUpDoneRequired;
use OC\AppFramework\Http\Request;
use OC\AppFramework\Middleware\MiddlewareUtils;
use OC\AppFramework\Utility\ControllerMethodReflector;
use OC\Authentication\Exceptions\TwoFactorAuthRequiredException;
use OC\Authentication\Exceptions\UserAlreadyLoggedInException;
@ -102,7 +101,7 @@ class TwoFactorMiddlewareTest extends TestCase {
$this->createMock(IConfig::class)
);
$this->middleware = new TwoFactorMiddleware($this->twoFactorManager, $this->userSession, $this->session, $this->urlGenerator, new MiddlewareUtils($this->reflector, $this->logger), $this->request);
$this->middleware = new TwoFactorMiddleware($this->twoFactorManager, $this->userSession, $this->session, $this->urlGenerator, $this->reflector, $this->request);
}
public function testBeforeControllerNotLoggedIn(): void {

View file

@ -123,7 +123,7 @@ class DispatcherTest extends \Test\TestCase {
$this->request = $this->createMock(Request::class);
$this->reflector = new ControllerMethodReflector();
$this->reflector = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$this->dispatcher = new Dispatcher(
$this->http,

View file

@ -30,7 +30,7 @@ class BruteForceMiddlewareTest extends TestCase {
protected function setUp(): void {
parent::setUp();
$this->reflector = new ControllerMethodReflector();
$this->reflector = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$this->throttler = $this->createMock(IThrottler::class);
$this->request = $this->createMock(IRequest::class);
$this->logger = $this->createMock(LoggerInterface::class);

View file

@ -33,7 +33,7 @@ class CORSMiddlewareTest extends \Test\TestCase {
protected function setUp(): void {
parent::setUp();
$this->reflector = new ControllerMethodReflector();
$this->reflector = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$this->session = $this->createMock(Session::class);
$this->throttler = $this->createMock(IThrottler::class);
$this->logger = $this->createMock(LoggerInterface::class);
@ -79,6 +79,7 @@ class CORSMiddlewareTest extends \Test\TestCase {
$this->createMock(IRequestId::class),
$this->createMock(IConfig::class)
);
$this->reflector->reflect($this->controller, __FUNCTION__);
$middleware = new CORSMiddleware($request, new MiddlewareUtils($this->reflector, $this->logger), $this->session, $this->throttler);
$response = $middleware->afterController($this->controller, __FUNCTION__, new Response());
@ -300,6 +301,7 @@ class CORSMiddlewareTest extends \Test\TestCase {
$this->createMock(IRequestId::class),
$this->createMock(IConfig::class)
);
$this->reflector->reflect($this->controller, __FUNCTION__);
$middleware = new CORSMiddleware($request, new MiddlewareUtils($this->reflector, $this->logger), $this->session, $this->throttler);
$response = $middleware->afterException($this->controller, __FUNCTION__, new SecurityException('A security exception'));
@ -316,6 +318,7 @@ class CORSMiddlewareTest extends \Test\TestCase {
$this->createMock(IRequestId::class),
$this->createMock(IConfig::class)
);
$this->reflector->reflect($this->controller, __FUNCTION__);
$middleware = new CORSMiddleware($request, new MiddlewareUtils($this->reflector, $this->logger), $this->session, $this->throttler);
$response = $middleware->afterException($this->controller, __FUNCTION__, new SecurityException('A security exception', 501));
@ -335,6 +338,7 @@ class CORSMiddlewareTest extends \Test\TestCase {
$this->createMock(IRequestId::class),
$this->createMock(IConfig::class)
);
$this->reflector->reflect($this->controller, __FUNCTION__);
$middleware = new CORSMiddleware($request, new MiddlewareUtils($this->reflector, $this->logger), $this->session, $this->throttler);
$middleware->afterException($this->controller, __FUNCTION__, new \Exception('A regular exception'));
}

View file

@ -45,7 +45,7 @@ class PasswordConfirmationMiddlewareTest extends TestCase {
private Manager $userManager;
protected function setUp(): void {
$this->reflector = new ControllerMethodReflector();
$this->reflector = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$this->session = $this->createMock(ISession::class);
$this->userSession = $this->createMock(IUserSession::class);
$this->user = $this->createMock(IUser::class);

View file

@ -45,7 +45,7 @@ class RateLimitingMiddlewareTest extends TestCase {
$this->request = $this->createMock(IRequest::class);
$this->userSession = $this->createMock(IUserSession::class);
$this->reflector = new ControllerMethodReflector();
$this->reflector = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$this->limiter = $this->createMock(Limiter::class);
$this->session = $this->createMock(ISession::class);
$this->appConfig = $this->createMock(IAppConfig::class);

View file

@ -61,8 +61,9 @@ class SameSiteCookieMiddlewareTest extends TestCase {
$this->request->method('getScriptName')
->willReturn('/index.php');
$this->reflector->method('hasAnnotation')
->with('NoSameSiteCookieRequired')
$this->reflector->expects(self::once())
->method('hasAnnotationOrAttribute')
->with('NoSameSiteCookieRequired', NoSameSiteCookieRequired::class)
->willReturn(true);
$this->middleware->beforeController(new HasAnnotationController('foo', $this->request), 'foo');
@ -73,8 +74,9 @@ class SameSiteCookieMiddlewareTest extends TestCase {
$this->request->method('getScriptName')
->willReturn('/index.php');
$this->reflector->method('hasAnnotation')
->with('NoSameSiteCookieRequired')
$this->reflector->expects(self::once())
->method('hasAnnotationOrAttribute')
->with('NoSameSiteCookieRequired', NoSameSiteCookieRequired::class)
->willReturn(false);
$this->request->method('passesLaxCookieCheck')
@ -90,8 +92,9 @@ class SameSiteCookieMiddlewareTest extends TestCase {
$this->request->method('getScriptName')
->willReturn('/index.php');
$this->reflector->method('hasAnnotation')
->with('NoSameSiteCookieRequired')
$this->reflector->expects(self::once())
->method('hasAnnotationOrAttribute')
->with('NoSameSiteCookieRequired', NoSameSiteCookieRequired::class)
->willReturn(false);
$this->request->method('passesLaxCookieCheck')

View file

@ -72,7 +72,7 @@ class SecurityMiddlewareTest extends \Test\TestCase {
'test',
$this->request
);
$this->reader = new ControllerMethodReflector();
$this->reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$this->logger = $this->createMock(LoggerInterface::class);
$this->navigationManager = $this->createMock(INavigationManager::class);
$this->urlGenerator = $this->createMock(IURLGenerator::class);
@ -433,6 +433,7 @@ class SecurityMiddlewareTest extends \Test\TestCase {
->willReturn(true);
$controller = new $controllerClass('test', $this->request);
$this->reader->reflect($controller, 'foo');
try {
$this->middleware->beforeController($controller, 'foo');

View file

@ -11,6 +11,7 @@ namespace Test\AppFramework\Middleware;
use OC\AppFramework\Middleware\SessionMiddleware;
use OC\AppFramework\Utility\ControllerMethodReflector;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\UseSession;
use OCP\AppFramework\Http\Response;
use OCP\IRequest;
use OCP\ISession;
@ -19,8 +20,8 @@ use Test\AppFramework\Middleware\Mock\UseSessionController;
use Test\TestCase;
class SessionMiddlewareTest extends TestCase {
private ControllerMethodReflector|MockObject $reflector;
private ISession|MockObject $session;
private ControllerMethodReflector&MockObject $reflector;
private ISession&MockObject $session;
private Controller $controller;
private SessionMiddleware $middleware;
@ -39,70 +40,39 @@ class SessionMiddlewareTest extends TestCase {
public function testSessionNotClosedOnBeforeController(): void {
$this->configureSessionMock(0, 1);
$this->reflector->expects(self::once())
->method('hasAnnotation')
->with('UseSession')
->method('hasAnnotationOrAttribute')
->with('UseSession', UseSession::class)
->willReturn(true);
$this->middleware->beforeController($this->controller, 'withAnnotation');
}
public function testSessionNotClosedOnBeforeControllerWithAttribute(): void {
$this->configureSessionMock(0, 1);
$this->reflector->expects(self::once())
->method('hasAnnotation')
->with('UseSession')
->willReturn(false);
$this->middleware->beforeController($this->controller, 'withAttribute');
}
public function testSessionClosedOnAfterController(): void {
$this->configureSessionMock(1);
$this->reflector->expects(self::once())
->method('hasAnnotation')
->with('UseSession')
->method('hasAnnotationOrAttribute')
->with('UseSession', UseSession::class)
->willReturn(true);
$this->middleware->afterController($this->controller, 'withAnnotation', new Response());
}
public function testSessionClosedOnAfterControllerWithAttribute(): void {
$this->configureSessionMock(1);
$this->reflector->expects(self::once())
->method('hasAnnotation')
->with('UseSession')
->willReturn(true);
$this->middleware->afterController($this->controller, 'withAttribute', new Response());
}
public function testSessionReopenedAndClosedOnBeforeController(): void {
$this->configureSessionMock(1, 1);
$this->reflector->expects(self::exactly(2))
->method('hasAnnotation')
->with('UseSession')
->method('hasAnnotationOrAttribute')
->with('UseSession', UseSession::class)
->willReturn(true);
$this->middleware->beforeController($this->controller, 'withAnnotation');
$this->middleware->afterController($this->controller, 'withAnnotation', new Response());
}
public function testSessionReopenedAndClosedOnBeforeControllerWithAttribute(): void {
$this->configureSessionMock(1, 1);
$this->reflector->expects(self::exactly(2))
->method('hasAnnotation')
->with('UseSession')
->willReturn(false);
$this->middleware->beforeController($this->controller, 'withAttribute');
$this->middleware->afterController($this->controller, 'withAttribute', new Response());
}
public function testSessionClosedOnBeforeController(): void {
$this->configureSessionMock(0);
$this->reflector->expects(self::once())
->method('hasAnnotation')
->with('UseSession')
->method('hasAnnotationOrAttribute')
->with('UseSession', UseSession::class)
->willReturn(false);
$this->middleware->beforeController($this->controller, 'without');
@ -111,8 +81,8 @@ class SessionMiddlewareTest extends TestCase {
public function testSessionNotClosedOnAfterController(): void {
$this->configureSessionMock(0);
$this->reflector->expects(self::once())
->method('hasAnnotation')
->with('UseSession')
->method('hasAnnotationOrAttribute')
->with('UseSession', UseSession::class)
->willReturn(false);
$this->middleware->afterController($this->controller, 'without', new Response());

View file

@ -9,6 +9,7 @@
namespace Test\AppFramework\Utility;
use OC\AppFramework\Utility\ControllerMethodReflector;
use Psr\Log\LoggerInterface;
class BaseController {
/**
@ -69,7 +70,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase {
* @Annotation
*/
public function testReadAnnotation(): void {
$reader = new ControllerMethodReflector();
$reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
'\Test\AppFramework\Utility\ControllerMethodReflectorTest',
'testReadAnnotation'
@ -82,7 +83,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase {
* @Annotation(parameter=value)
*/
public function testGetAnnotationParameterSingle(): void {
$reader = new ControllerMethodReflector();
$reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
self::class,
__FUNCTION__
@ -95,7 +96,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase {
* @Annotation(parameter1=value1, parameter2=value2,parameter3=value3)
*/
public function testGetAnnotationParameterMultiple(): void {
$reader = new ControllerMethodReflector();
$reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
self::class,
__FUNCTION__
@ -111,7 +112,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase {
* @param test
*/
public function testReadAnnotationNoLowercase(): void {
$reader = new ControllerMethodReflector();
$reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
'\Test\AppFramework\Utility\ControllerMethodReflectorTest',
'testReadAnnotationNoLowercase'
@ -127,7 +128,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase {
* @param int $test
*/
public function testReadTypeIntAnnotations(): void {
$reader = new ControllerMethodReflector();
$reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
'\Test\AppFramework\Utility\ControllerMethodReflectorTest',
'testReadTypeIntAnnotations'
@ -145,7 +146,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase {
}
public function testReadTypeIntAnnotationsScalarTypes(): void {
$reader = new ControllerMethodReflector();
$reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
'\Test\AppFramework\Utility\ControllerMethodReflectorTest',
'arguments3'
@ -163,7 +164,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase {
* @param double $test something special
*/
public function testReadTypeDoubleAnnotations(): void {
$reader = new ControllerMethodReflector();
$reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
'\Test\AppFramework\Utility\ControllerMethodReflectorTest',
'testReadTypeDoubleAnnotations'
@ -177,7 +178,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase {
* @param string $foo
*/
public function testReadTypeWhitespaceAnnotations(): void {
$reader = new ControllerMethodReflector();
$reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
'\Test\AppFramework\Utility\ControllerMethodReflectorTest',
'testReadTypeWhitespaceAnnotations'
@ -190,7 +191,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase {
public function arguments($arg, $arg2 = 'hi') {
}
public function testReflectParameters(): void {
$reader = new ControllerMethodReflector();
$reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
'\Test\AppFramework\Utility\ControllerMethodReflectorTest',
'arguments'
@ -203,7 +204,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase {
public function arguments2($arg) {
}
public function testReflectParameters2(): void {
$reader = new ControllerMethodReflector();
$reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
'\Test\AppFramework\Utility\ControllerMethodReflectorTest',
'arguments2'
@ -214,7 +215,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase {
public function testInheritance(): void {
$reader = new ControllerMethodReflector();
$reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect('Test\AppFramework\Utility\EndController', 'test');
$this->assertTrue($reader->hasAnnotation('Annotation'));
@ -222,7 +223,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase {
public function testInheritanceOverride(): void {
$reader = new ControllerMethodReflector();
$reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect('Test\AppFramework\Utility\EndController', 'test2');
$this->assertTrue($reader->hasAnnotation('NoAnnotation'));
@ -231,14 +232,14 @@ class ControllerMethodReflectorTest extends \Test\TestCase {
public function testInheritanceOverrideNoDocblock(): void {
$reader = new ControllerMethodReflector();
$reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect('Test\AppFramework\Utility\EndController', 'test3');
$this->assertFalse($reader->hasAnnotation('Annotation'));
}
public function testRangeDetectionPsalm(): void {
$reader = new ControllerMethodReflector();
$reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect('Test\AppFramework\Utility\EndController', 'test4');
$rangeInfo1 = $reader->getRange('rangedOne');
@ -259,7 +260,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase {
}
public function testRangeDetectionNative(): void {
$reader = new ControllerMethodReflector();
$reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect('Test\AppFramework\Utility\EndController', 'test5');
$rangeInfo1 = $reader->getRange('rangedOne');