Browse Source

fix: Throw `NotFoundExceptionInterface` to fulfill PSR container interface if class not found

Signed-off-by: Ferdinand Thiessen <rpm@fthiessen.de>
Ferdinand Thiessen 1 year ago
parent
commit
ba8a50c059

+ 41 - 0
lib/private/AppFramework/Utility/QueryNotFoundException.php

@@ -0,0 +1,41 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023, Ferdinand Thiessen <rpm@fthiessen.de>
+ *
+ * @author Ferdinand Thiessen <rpm@fthiessen.de>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\AppFramework\Utility;
+
+use OCP\AppFramework\QueryException;
+use Psr\Container\NotFoundExceptionInterface;
+
+/**
+ * Private implementation of the `Psr\Container\NotFoundExceptionInterface`
+ *
+ * QueryNotFoundException is a simple wrapper over the `QueryException`
+ * to fulfill the PSR Container interface.
+ *
+ * You should not catch this class directly but the `NotFoundExceptionInterface`.
+ */
+class QueryNotFoundException extends QueryException implements NotFoundExceptionInterface {
+}

+ 3 - 2
lib/private/AppFramework/Utility/SimpleContainer.php

@@ -127,7 +127,8 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer {
 					' Class can not be instantiated');
 			}
 		} catch (ReflectionException $e) {
-			throw new QueryException($baseMsg . ' ' . $e->getMessage());
+			// Class does not exist
+			throw new QueryNotFoundException($baseMsg . ' ' . $e->getMessage());
 		}
 	}
 
@@ -145,7 +146,7 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer {
 			return $object;
 		}
 
-		throw new QueryException('Could not resolve ' . $name . '!');
+		throw new QueryNotFoundException('Could not resolve ' . $name . '!');
 	}
 
 	/**

+ 1 - 1
lib/public/AppFramework/QueryException.php

@@ -32,7 +32,7 @@ use Psr\Container\ContainerExceptionInterface;
 /**
  * Class QueryException
  *
- * The class extends `NotFoundExceptionInterface` since 20.0.0
+ * The class extends `ContainerExceptionInterface` since 20.0.0
  *
  * @since 8.1.0
  * @deprecated 20.0.0 catch \Psr\Container\ContainerExceptionInterface

+ 2 - 0
lib/public/IContainer.php

@@ -33,6 +33,7 @@ use Closure;
 use OCP\AppFramework\QueryException;
 use Psr\Container\ContainerExceptionInterface;
 use Psr\Container\ContainerInterface;
+use Psr\Container\NotFoundExceptionInterface;
 
 /**
  * Class IContainer
@@ -70,6 +71,7 @@ interface IContainer extends ContainerInterface {
 	 * @return mixed
 	 * @psalm-return ($name is class-string ? T : mixed)
 	 * @throws ContainerExceptionInterface if the query could not be resolved
+	 * @throws NotFoundExceptionInterface if the name could not be found within the container
 	 * @throws QueryException if the query could not be resolved
 	 * @since 6.0.0
 	 * @deprecated 20.0.0 use \Psr\Container\ContainerInterface::get

+ 24 - 3
tests/lib/AppFramework/Utility/SimpleContainerTest.php

@@ -26,6 +26,7 @@ declare(strict_types=1);
 namespace Test\AppFramework\Utility;
 
 use OC\AppFramework\Utility\SimpleContainer;
+use Psr\Container\NotFoundExceptionInterface;
 
 interface TestInterface {
 }
@@ -76,11 +77,31 @@ class SimpleContainerTest extends \Test\TestCase {
 	}
 
 
-
+	/**
+	 * Test querying a class that is not registered without autoload enabled
+	 */
 	public function testNothingRegistered() {
-		$this->expectException(\OCP\AppFramework\QueryException::class);
+		try {
+			$this->container->query('something really hard', false);
+			$this->fail('Expected `QueryException` exception was not thrown');
+		} catch (\Throwable $exception) {
+			$this->assertInstanceOf(\OCP\AppFramework\QueryException::class, $exception);
+			$this->assertInstanceOf(NotFoundExceptionInterface::class, $exception);
+		}
+	}
+
 
-		$this->container->query('something really hard');
+	/**
+	 * Test querying a class that is not registered with autoload enabled
+	 */
+	public function testNothingRegistered_autoload() {
+		try {
+			$this->container->query('something really hard');
+			$this->fail('Expected `QueryException` exception was not thrown');
+		} catch (\Throwable $exception) {
+			$this->assertInstanceOf(\OCP\AppFramework\QueryException::class, $exception);
+			$this->assertInstanceOf(NotFoundExceptionInterface::class, $exception);
+		}
 	}