diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index c64354ba9..bbc30f485 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -6,7 +6,26 @@ use Nextcloud\CodingStandard\Config; -$config = new Config(); +class CookbookConfig extends Config { + public function __construct($name = 'default') { + parent::__construct($name); + } + + public function getRules() : array { + $parentRules = parent::getRules(); + $additionalRules = [ + 'phpdoc_add_missing_param_annotation' => true, + 'phpdoc_indent' => true, + 'phpdoc_no_empty_return' => true, + 'phpdoc_scalar' => true, + 'phpdoc_single_line_var_spacing' => true, + 'phpdoc_var_without_name' => true + ]; + return array_merge(['@PSR12' => true], $parentRules, $additionalRules); + } +} + +$config = new CookbookConfig(); $config ->getFinder() ->ignoreVCSIgnored(true) @@ -18,5 +37,7 @@ ->exclude('vendor') ->exclude('.github') ->in(__DIR__); + + return $config; diff --git a/CHANGELOG.md b/CHANGELOG.md index 347e5ad77..75333a6c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,10 @@ [#1033](https://github.com/nextcloud/cookbook/pull/1033) @MarcelRobitaille - Reenable PR checks from foreign forks [#1045](https://github.com/nextcloud/cookbook/pull/1045) @christianlupus +- Prevent access to guzzle client without explicit dependency + [#1011](https://github.com/nextcloud/cookbook/pull/1011) @christianlupus +- Make PHP code styling more strict + [#1011](https://github.com/nextcloud/cookbook/pull/1011) @christianlupus ### Codebase maintenance - Removed codecov.io upload of intermediate merge commits during pull requests [#1028](https://github.com/nextcloud/cookbook/issues/1028) diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 47bfecc1d..21e993408 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -14,7 +14,7 @@ if (Util::getVersion()[0] >= 20) { class Application extends App implements IBootstrap { public const APP_ID = 'cookbook'; - + public function __construct(array $urlParams = []) { parent::__construct(self::APP_ID, $urlParams); } @@ -29,7 +29,7 @@ public function boot(IBootContext $context): void { } else { class Application extends App { public const APP_ID = 'cookbook'; - + public function __construct(array $urlParams = []) { parent::__construct(self::APP_ID, $urlParams); } diff --git a/lib/Controller/ConfigController.php b/lib/Controller/ConfigController.php index 7d57f5bdc..0d773aea7 100644 --- a/lib/Controller/ConfigController.php +++ b/lib/Controller/ConfigController.php @@ -17,12 +17,12 @@ class ConfigController extends Controller { * @var RecipeService */ private $service; - + /** * @var DbCacheService */ private $dbCacheService; - + /** * @var RestParameterParser */ @@ -55,7 +55,7 @@ public function __construct( */ public function list() { $this->dbCacheService->triggerCheck(); - + return new DataResponse([ 'folder' => $this->userFolder->getPath(), 'update_interval' => $this->dbCacheService->getSearchIndexUpdateInterval(), @@ -69,7 +69,7 @@ public function list() { */ public function config() { $data = $this->restParser->getParameters(); - + if (isset($data['folder'])) { $this->userFolder->setPath($data['folder']); $this->dbCacheService->updateCache(); @@ -84,10 +84,10 @@ public function config() { } $this->dbCacheService->triggerCheck(); - + return new DataResponse('OK', Http::STATUS_OK); } - + /** * @NoAdminRequired * @NoCSRFRequired diff --git a/lib/Controller/MainController.php b/lib/Controller/MainController.php index e8f6a2511..37b983c86 100755 --- a/lib/Controller/MainController.php +++ b/lib/Controller/MainController.php @@ -33,7 +33,7 @@ class MainController extends Controller { * @var IURLGenerator */ private $urlGenerator; - + /** * @var RestParameterParser */ @@ -83,13 +83,13 @@ public function index(): TemplateResponse { * will prevent the controller to be called. If this does not happen for some reason, let the exception be * thrown and the user most probably has found a bug. A stack trace might help there. */ - + $this->dbCacheService->triggerCheck(); Util::addScript('cookbook', 'nextcloud-cookbook-main'); return new TemplateResponse($this->appName, 'index'); // templates/index.php } - + /** * @NoAdminRequired * @NoCSRFRequired @@ -113,7 +113,7 @@ public function getApiVersion(): DataResponse { */ public function categories() { $this->dbCacheService->triggerCheck(); - + $categories = $this->service->getAllCategoriesInSearchIndex(); return new DataResponse($categories, 200, ['Content-Type' => 'application/json']); } @@ -124,7 +124,7 @@ public function categories() { */ public function keywords() { $this->dbCacheService->triggerCheck(); - + $keywords = $this->service->getAllKeywordsInSearchIndex(); return new DataResponse($keywords, 200, ['Content-Type' => 'application/json']); } @@ -132,10 +132,11 @@ public function keywords() { /** * @NoAdminRequired * @NoCSRFRequired + * @param mixed $query */ public function search($query) { $this->dbCacheService->triggerCheck(); - + $query = urldecode($query); try { $recipes = $this->service->findRecipesInSearchIndex($query); @@ -167,10 +168,11 @@ public function search($query) { /** * @NoAdminRequired * @NoCSRFRequired + * @param mixed $category */ public function category($category) { $this->dbCacheService->triggerCheck(); - + $category = urldecode($category); try { $recipes = $this->service->getRecipesByCategory($category); @@ -201,6 +203,7 @@ public function category($category) { /** * @NoAdminRequired * @NoCSRFRequired + * @param mixed $category */ public function categoryUpdate($category) { $this->dbCacheService->triggerCheck(); @@ -230,6 +233,7 @@ public function categoryUpdate($category) { /** * @NoAdminRequired * @NoCSRFRequired + * @param mixed $keywords */ public function tags($keywords) { $this->dbCacheService->triggerCheck(); @@ -268,9 +272,9 @@ public function tags($keywords) { */ public function import() { $this->dbCacheService->triggerCheck(); - + $data = $this->restParser->getParameters(); - + if (!isset($data['url'])) { return new DataResponse('Field "url" is required', 400); } @@ -299,7 +303,7 @@ public function import() { */ public function new() { $this->dbCacheService->triggerCheck(); - + try { $recipe_data = $this->restParser->getParameters(); $file = $this->service->addRecipe($recipe_data); @@ -314,10 +318,11 @@ public function new() { /** * @NoAdminRequired * @NoCSRFRequired + * @param mixed $id */ public function update($id) { $this->dbCacheService->triggerCheck(); - + try { $recipe_data = $this->restParser->getParameters(); @@ -325,7 +330,7 @@ public function update($id) { $file = $this->service->addRecipe($recipe_data); $this->dbCacheService->addRecipe($file); - + return new DataResponse($id); } catch (\Exception $e) { return new DataResponse($e->getMessage(), 500); diff --git a/lib/Controller/RecipeController.php b/lib/Controller/RecipeController.php index 6305ec035..0ee29e61d 100755 --- a/lib/Controller/RecipeController.php +++ b/lib/Controller/RecipeController.php @@ -28,12 +28,12 @@ class RecipeController extends Controller { * @var IURLGenerator */ private $urlGenerator; - + /** * @var DbCacheService */ private $dbCacheService; - + /** * @var RestParameterParser */ @@ -75,7 +75,7 @@ public function __construct( */ public function index() { $this->dbCacheService->triggerCheck(); - + if (empty($_GET['keywords'])) { $recipes = $this->service->getAllRecipesInSearchIndex(); } else { @@ -96,7 +96,7 @@ public function index() { */ public function show($id) { $this->dbCacheService->triggerCheck(); - + $json = $this->service->getRecipeById($id); if (null === $json) { @@ -105,7 +105,7 @@ public function show($id) { $json['printImage'] = $this->service->getPrintImage(); $json['imageUrl'] = $this->urlGenerator->linkToRoute('cookbook.recipe.image', ['id' => $json['id'], 'size' => 'full']); - + return new DataResponse($json, Http::STATUS_OK, ['Content-Type' => 'application/json']); } @@ -122,7 +122,7 @@ public function show($id) { */ public function update($id) { $this->dbCacheService->triggerCheck(); - + $recipeData = $this->restParser->getParameters(); try { $file = $this->service->addRecipe($recipeData); @@ -151,12 +151,12 @@ public function update($id) { */ public function create() { $this->dbCacheService->triggerCheck(); - + $recipeData = $this->restParser->getParameters(); try { $file = $this->service->addRecipe($recipeData); $this->dbCacheService->addRecipe($file); - + return new DataResponse($file->getParent()->getId(), Http::STATUS_OK, ['Content-Type' => 'application/json']); } catch (RecipeExistsException $ex) { $json = [ @@ -183,7 +183,7 @@ public function create() { */ public function destroy($id) { $this->dbCacheService->triggerCheck(); - + try { $this->service->deleteRecipe($id); return new DataResponse('Recipe ' . $id . ' deleted successfully', Http::STATUS_OK); @@ -200,7 +200,7 @@ public function destroy($id) { */ public function image($id) { $this->dbCacheService->triggerCheck(); - + $acceptHeader = $this->request->getHeader('Accept'); $acceptedExtensions = $this->acceptHeaderParser->parseHeader($acceptHeader); @@ -220,7 +220,7 @@ public function image($id) { } else { // The client accepts the SVG file. Send it. $file = file_get_contents(dirname(__FILE__) . '/../../img/recipe.svg'); - + return new DataDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => 'image/svg+xml']); } } diff --git a/lib/Db/DbTypesPolyfillHelper.php b/lib/Db/DbTypesPolyfillHelper.php index d57d4e84e..1d294cf89 100644 --- a/lib/Db/DbTypesPolyfillHelper.php +++ b/lib/Db/DbTypesPolyfillHelper.php @@ -13,7 +13,7 @@ class DbTypesPolyfillHelper { * @var String */ private $string; - + public function __construct(Util $util) { switch ($util->getVersion()[0]) { case 18: @@ -22,14 +22,14 @@ public function __construct(Util $util) { $this->int = \Doctrine\DBAL\Types\Type::INTEGER; $this->string = \Doctrine\DBAL\Types\Type::STRING; break; - + default: $this->int = \OCP\DB\Types::INTEGER; $this->string = \OCP\DB\Types::STRING; break; } } - + /** * @return string */ diff --git a/lib/Db/RecipeDb.php b/lib/Db/RecipeDb.php index 6318701ec..ef7fbb7a0 100755 --- a/lib/Db/RecipeDb.php +++ b/lib/Db/RecipeDb.php @@ -10,14 +10,14 @@ class RecipeDb { private const DB_TABLE_RECIPES = 'cookbook_names'; private const DB_TABLE_KEYWORDS = 'cookbook_keywords'; private const DB_TABLE_CATEGORIES = 'cookbook_categories'; - + private $db; - + /** * @var DbTypesPolyfillHelper */ private $types; - + public function __construct(IDBConnection $db, DbTypesPolyfillHelper $polyfillTypes) { $this->db = $db; $this->types = $polyfillTypes; @@ -43,43 +43,43 @@ public function findRecipeById(int $id) { if ($row === false) { throw new DoesNotExistException("Recipe with $id was not found in database."); } - + $ret = []; $ret['name'] = $row['name']; $ret['id'] = $row['recipe_id']; - + return $ret; } - + public function deleteRecipeById(int $id) { $qb = $this->db->getQueryBuilder(); $qb->delete(self::DB_TABLE_RECIPES) ->where('recipe_id = :id'); $qb->setParameter('id', $id, IQueryBuilder::PARAM_INT); - + $qb->execute(); - + $qb = $this->db->getQueryBuilder(); - + $qb->delete(self::DB_TABLE_KEYWORDS) ->where('recipe_id = :id'); $qb->setParameter('id', $id, IQueryBuilder::PARAM_INT); - + $qb->execute(); - + $qb = $this->db->getQueryBuilder(); - + $qb->delete(self::DB_TABLE_CATEGORIES) ->where('recipe_id = :id'); $qb->setParameter('id', $id, IQueryBuilder::PARAM_INT); $qb->execute(); } - + public function findAllRecipes(string $user_id) { $qb = $this->db->getQueryBuilder(); - + $qb->select(['r.recipe_id', 'r.name', 'k.name AS keywords']) ->from(self::DB_TABLE_RECIPES, 'r') ->where('r.user_id = :user') @@ -120,15 +120,15 @@ public function unique(array $result) { $unique_result[$recipe['recipe_id']] = $recipe; } - + return array_values($unique_result); } - + private function sortRecipes(array $recipes): array { usort($recipes, function ($a, $b) { return strcasecmp($a['name'], $b['name']); }); - + return $recipes; } @@ -146,15 +146,15 @@ public function findAllKeywords(string $user_id) { $cursor = $qb->execute(); $result = $cursor->fetchAll(); $cursor->closeCursor(); - + $result = $this->sortRecipes($result); - + $result = array_unique($result, SORT_REGULAR); $result = array_filter($result); - + return $result; } - + public function findAllCategories(string $user_id) { $qb = $this->db->getQueryBuilder(); @@ -170,9 +170,9 @@ public function findAllCategories(string $user_id) { $cursor = $qb->execute(); $result = $cursor->fetchAll(); $cursor->closeCursor(); - + $qb = $this->db->getQueryBuilder(); - + // Get count of recipes without category $qb->select($qb->createFunction('COUNT(1) as cnt')) ->from(self::DB_TABLE_RECIPES, 'r') @@ -189,11 +189,11 @@ public function findAllCategories(string $user_id) { $qb->expr()->eq('r.user_id', $qb->expr()->literal($user_id)), $qb->expr()->isNull('c.name') ); - + $cursor = $qb->execute(); $row = $cursor->fetch(); $cursor->closeCursor(); - + $result[] = [ 'name' => '*', 'recipe_count' => $row['cnt'] @@ -201,10 +201,10 @@ public function findAllCategories(string $user_id) { $result = array_unique($result, SORT_REGULAR); $result = array_filter($result); - + return $result; } - + /** * @throws \OCP\AppFramework\Db\DoesNotExistException if not found * @@ -224,7 +224,7 @@ public function getRecipesByCategory(string $category, string $user_id) { ->andWhere('c.user_id = :user') ->setParameter('category', $category, $this->types->STRING()) ->setParameter('user', $user_id, $this->types->STRING()); - + $qb->join('c', self::DB_TABLE_RECIPES, 'r', 'c.recipe_id = r.recipe_id'); $qb->leftJoin('c', self::DB_TABLE_KEYWORDS, 'k', 'c.recipe_id = k.recipe_id'); @@ -252,7 +252,7 @@ public function getRecipesByCategory(string $category, string $user_id) { $cursor = $qb->execute(); $result = $cursor->fetchAll(); $cursor->closeCursor(); - + // group recipes, convert keywords to comma-separated list $recipesGroupedTags = $this->groupKeywordInResult($result); @@ -290,7 +290,7 @@ public function getRecipesByKeywords(string $keywords, string $user_id) { return $this->unique($recipesGroupedTags); } - + /** * @throws \OCP\AppFramework\Db\DoesNotExistException if not found */ @@ -305,21 +305,21 @@ public function findRecipes(array $keywords, string $user_id) { $qb->select(['r.recipe_id', 'r.name', 'k.name AS keywords']) ->from(self::DB_TABLE_RECIPES, 'r'); - + $qb->leftJoin('r', self::DB_TABLE_KEYWORDS, 'k', 'k.recipe_id = r.recipe_id'); $qb->leftJoin('r', self::DB_TABLE_CATEGORIES, 'c', 'r.recipe_id = c.recipe_id'); - + $paramIdx = 1; $params = []; $types = []; - + foreach ($keywords as $keyword) { $lowerKeyword = strtolower($keyword); - + $qb->orWhere("LOWER(k.name) LIKE :keyword$paramIdx"); $qb->orWhere("LOWER(r.name) LIKE :keyword$paramIdx"); $qb->orWhere("LOWER(c.name) LIKE :keyword$paramIdx"); - + $params["keyword$paramIdx"] = "%$lowerKeyword%"; $types["keyword$paramIdx"] = $this->types->STRING(); $paramIdx++; @@ -342,7 +342,7 @@ public function findRecipes(array $keywords, string $user_id) { return $this->unique($recipesGroupedTags); } - + /** * @param array $results Array of recipes with double entries for different keywords * Group recipes by id and convert keywords to comma-separated list @@ -360,34 +360,34 @@ public function groupKeywordInResult(array $result) { } return $recipesGroupedTags; } - + /** * @param string $user_id * @deprecated */ public function emptySearchIndex(string $user_id) { $qb = $this->db->getQueryBuilder(); - + $qb->delete(self::DB_TABLE_RECIPES) ->where('user_id = :user') ->orWhere('user_id = :empty'); $qb->setParameter('user', $user_id, $this->types->STRING()); $qb->setParameter('empty', 'empty', $this->types->STRING()); - + $qb->execute(); - + $qb->delete(self::DB_TABLE_KEYWORDS) ->where('user_id = :user') ->orWhere('user_id = :empty'); $qb->setParameter('user', $user_id, $this->types->STRING()); $qb->setParameter('empty', 'empty', $this->types->STRING()); - + $qb->delete(self::DB_TABLE_CATEGORIES) ->where('user_id = :user') ->orWhere('user_id = :empty'); $qb->setParameter('user', $user_id, $this->types->STRING()); $qb->setParameter('empty', 'empty', $this->types->STRING()); - + $qb->execute(); } @@ -401,11 +401,11 @@ public function deleteRecipes(array $ids, string $userId) { if (!is_array($ids) || empty($ids)) { return; } - + foreach ($ids as $id) { // Remove category $this->removeCategoryOfRecipe($id, $userId); - + // Remove all keywords $keywords = $this->getKeywordsOfRecipe($id, $userId); $pairs = array_map(function ($kw) use ($id) { @@ -413,11 +413,11 @@ public function deleteRecipes(array $ids, string $userId) { }, $keywords); $this->removeKeywordPairs($pairs, $userId); } - + $qb = $this->db->getQueryBuilder(); - + $qb->delete(self::DB_TABLE_RECIPES); - + foreach ($ids as $id) { $qb->orWhere( $qb->expr()->andX( @@ -425,10 +425,10 @@ public function deleteRecipes(array $ids, string $userId) { $qb->expr()->eq("user_id", $qb->expr()->literal($userId)) )); } - + $qb->execute(); } - + /** * @param array $recipes */ @@ -436,91 +436,91 @@ public function insertRecipes(array $recipes, string $userId) { if (!is_array($recipes) || empty($recipes)) { return; } - + $qb = $this->db->getQueryBuilder(); - + $qb->insert(self::DB_TABLE_RECIPES) ->values([ 'recipe_id' => ':id', 'user_id' => ':userid', 'name' => ':name' ]); - + $qb->setParameter('userid', $userId); - + foreach ($recipes as $recipe) { $qb->setParameter('id', $recipe['id'], $this->types->INT()); $qb->setParameter('name', $recipe['name'], $this->types->STRING()); - + $qb->execute(); } } - + public function updateRecipes(array $recipes, string $userId) { if (!is_array($recipes) || empty($recipes)) { return; } - + $qb = $this->db->getQueryBuilder(); - + foreach ($recipes as $recipe) { $qb->update(self::DB_TABLE_RECIPES) ->where('recipe_id = :id', 'user_id = :uid'); - + $literal = []; $literal['name'] = $qb->expr()->literal($recipe['name'], IQueryBuilder::PARAM_STR); $qb->set('name', $literal['name']); - + $qb->setParameter('id', $recipe['id']); $qb->setParameter('uid', $userId); - + $qb->execute(); } } - + public function getKeywordsOfRecipe(int $recipeId, string $userId) { $qb = $this->db->getQueryBuilder(); - + $qb->select('name') ->from(self::DB_TABLE_KEYWORDS) ->where('recipe_id = :rid', 'user_id = :uid'); - + $qb->setParameter('rid', $recipeId); $qb->setParameter('uid', $userId); - + $cursor = $qb->execute(); $result = $cursor->fetchAll(); $cursor->closeCursor(); - + $ret = array_map(function ($row) { $r = $row['name']; return $r; }, $result); - + return $ret; } - + public function getCategoryOfRecipe(int $recipeId, string $userId) { $qb = $this->db->getQueryBuilder(); - + $qb->select('name') ->from(self::DB_TABLE_CATEGORIES) ->where('recipe_id = :rid', 'user_id = :uid'); - + $qb->setParameter('rid', $recipeId); $qb->setParameter('uid', $userId); - + $cursor = $qb->execute(); $result = $cursor->fetch(); $cursor->closeCursor(); - + if ($result === false) { return null; } else { return $result['name']; } } - + public function updateCategoryOfRecipe(int $recipeId, string $categoryName, string $userId) { $qb = $this->db->getQueryBuilder(); $qb->update(self::DB_TABLE_CATEGORIES) @@ -530,7 +530,7 @@ public function updateCategoryOfRecipe(int $recipeId, string $categoryName, stri $qb->setParameter('user', $userId, $this->types->STRING()); $qb->execute(); } - + public function addCategoryOfRecipe(int $recipeId, string $categoryName, string $userId) { // NOTE: We're using * as a placeholder for no category if (empty($categoryName)) { @@ -540,21 +540,21 @@ public function addCategoryOfRecipe(int $recipeId, string $categoryName, string // { // $json['recipeCategory'] = reset($json['recipeCategory']); // } - + $qb = $this->db->getQueryBuilder(); $qb->insert(self::DB_TABLE_CATEGORIES) ->values(['recipe_id' => ':rid', 'name' => ':name', 'user_id' => ':user']); $qb->setParameter('rid', $recipeId, $this->types->INT()); $qb->setParameter('name', $categoryName, $this->types->STRING()); $qb->setParameter('user', $userId, $this->types->STRING()); - + try { $qb->execute(); } catch (\Exception $e) { // Category didn't meet restrictions, skip it } } - + public function removeCategoryOfRecipe(int $recipeId, string $userId) { $qb = $this->db->getQueryBuilder(); $qb->delete(self::DB_TABLE_CATEGORIES) @@ -563,21 +563,21 @@ public function removeCategoryOfRecipe(int $recipeId, string $userId) { $qb->setParameter('user', $userId, $this->types->STRING()); $qb->execute(); } - + public function addKeywordPairs(array $pairs, string $userId) { if (!is_array($pairs) || empty($pairs)) { return; } - + $qb = $this->db->getQueryBuilder(); $qb->insert(self::DB_TABLE_KEYWORDS) ->values(['recipe_id' => ':rid', 'name' => ':name', 'user_id' => ':user']); $qb->setParameter('user', $userId, $this->types->STRING()); - + foreach ($pairs as $p) { $qb->setParameter('rid', $p['recipeId'], $this->types->INT()); $qb->setParameter('name', $p['name'], $this->types->STRING()); - + try { $qb->execute(); } catch (\Exception $ex) { @@ -585,15 +585,15 @@ public function addKeywordPairs(array $pairs, string $userId) { } } } - + public function removeKeywordPairs(array $pairs, string $userId) { if (!is_array($pairs) || empty($pairs)) { return; } - + $qb = $this->db->getQueryBuilder(); $qb->delete(self::DB_TABLE_KEYWORDS); - + foreach ($pairs as $p) { $qb->orWhere( $qb->expr()->andX( @@ -603,7 +603,7 @@ public function removeKeywordPairs(array $pairs, string $userId) { ) ); } - + $qb->execute(); } } diff --git a/lib/Helper/AcceptHeaderParsingHelper.php b/lib/Helper/AcceptHeaderParsingHelper.php index c21330923..786e86e03 100644 --- a/lib/Helper/AcceptHeaderParsingHelper.php +++ b/lib/Helper/AcceptHeaderParsingHelper.php @@ -9,7 +9,6 @@ * Higher priorities are sorted first in the array. */ class AcceptHeaderParsingHelper { - /** * Parse the content of a header and generate the list of valid file extensions the client will accept. * diff --git a/lib/Helper/HTMLFilter/AbstractHtmlFilter.php b/lib/Helper/HTMLFilter/AbstractHtmlFilter.php index 83cf63e7e..bd8c66dfc 100644 --- a/lib/Helper/HTMLFilter/AbstractHtmlFilter.php +++ b/lib/Helper/HTMLFilter/AbstractHtmlFilter.php @@ -3,7 +3,6 @@ namespace OCA\Cookbook\Helper\HTMLFilter; abstract class AbstractHtmlFilter { - /** * Filter the HTML according to the rules of this class * diff --git a/lib/Helper/HTMLParser/AbstractHtmlParser.php b/lib/Helper/HTMLParser/AbstractHtmlParser.php index 4921c0715..28aed502d 100644 --- a/lib/Helper/HTMLParser/AbstractHtmlParser.php +++ b/lib/Helper/HTMLParser/AbstractHtmlParser.php @@ -6,16 +6,15 @@ use OCP\IL10N; abstract class AbstractHtmlParser { - /** * @var IL10N */ protected $l; - + public function __construct(IL10N $l10n) { $this->l = $l10n; } - + /** * Extract the recipe from the given document. * diff --git a/lib/Helper/HTMLParser/HttpJsonLdParser.php b/lib/Helper/HTMLParser/HttpJsonLdParser.php index 7bc81ce5c..7163265bd 100644 --- a/lib/Helper/HTMLParser/HttpJsonLdParser.php +++ b/lib/Helper/HTMLParser/HttpJsonLdParser.php @@ -11,35 +11,34 @@ * @author Christian Wolf */ class HttpJsonLdParser extends AbstractHtmlParser { - /** * @var JsonService */ private $jsonService; - + public function __construct(IL10N $l10n, JsonService $jsonService) { parent::__construct($l10n); - + $this->jsonService = $jsonService; } - + public function parse(\DOMDocument $document): array { $xpath = new \DOMXPath($document); - + $json_ld_elements = $xpath->query("//*[@type='application/ld+json']"); - + foreach ($json_ld_elements as $json_ld_element) { if (!$json_ld_element || !$json_ld_element->nodeValue) { continue; } - + try { return $this->parseJsonLdElement($json_ld_element); } catch (HtmlParsingException $ex) { // Parsing failed for this element. Let's see if there are more... } } - + throw new HtmlParsingException($this->l->t('Could not find recipe in HTML code.')); } @@ -52,28 +51,28 @@ public function parse(\DOMDocument $document): array { */ private function parseJsonLdElement(\DOMNode $node): array { $string = $node->nodeValue; - + $this->fixRawJson($string); - + $json = json_decode($string, true); - + if ($json === null) { throw new HtmlParsingException($this->l->t('JSON cannot be decoded.')); } - + if ($json === false || $json === true || ! is_array($json)) { throw new HtmlParsingException($this->l->t('No recipe was found.')); } - + // Look through @graph field for recipe $this->mapGraphField($json); - + // Look for an array of recipes $this->mapArray($json); // Ensure the type of the object is never an array $this->checkForArrayType($json); - + if ($this->jsonService->isSchemaObject($json, 'Recipe')) { // We found our recipe return $json; @@ -81,7 +80,7 @@ private function parseJsonLdElement(\DOMNode $node): array { throw new HtmlParsingException($this->l->t('No recipe was found.')); } } - + /** * Fix any JSON issues before trying to decode it * @@ -90,7 +89,7 @@ private function parseJsonLdElement(\DOMNode $node): array { private function fixRawJson(string &$rawJson): void { $rawJson = $this->removeNewlinesInJson($rawJson); } - + /** * Fix newlines in raw JSON string * @@ -102,7 +101,7 @@ private function fixRawJson(string &$rawJson): void { private function removeNewlinesInJson(string $rawJson): string { return preg_replace('/\s+/', ' ', $rawJson); } - + /** * Look for recipes in the JSON graph * @@ -121,13 +120,13 @@ private function removeNewlinesInJson(string $rawJson): string { private function mapGraphField(array &$json) { if (isset($json['@graph']) && is_array($json['@graph'])) { $tmp = $this->searchForRecipeInArray($json['@graph']); - + if ($tmp !== null) { $json = $tmp; } } } - + /** * Look for an array of recipes. * @@ -141,13 +140,13 @@ private function mapGraphField(array &$json) { private function mapArray(array &$json) { if (isset($json[0])) { $tmp = $this->searchForRecipeInArray($json); - + if ($tmp !== null) { $json = $tmp; } } } - + /** * Search for a recipe object in an array * @param array $arr The array to search @@ -162,7 +161,7 @@ private function searchForRecipeInArray(array $arr): ?array { return $item; } } - + // No recipe was found return null; } @@ -173,7 +172,6 @@ private function searchForRecipeInArray(array $arr): ?array { * This checks if the '@type' entry is an array and corrects that. * * @param array $json The JSON object to parse - * @return void */ private function checkForArrayType(array &$json) { if (! $this->jsonService->isSchemaObject($json)) { diff --git a/lib/Helper/HTMLParser/HttpMicrodataParser.php b/lib/Helper/HTMLParser/HttpMicrodataParser.php index f255f9136..abeb374c9 100644 --- a/lib/Helper/HTMLParser/HttpMicrodataParser.php +++ b/lib/Helper/HTMLParser/HttpMicrodataParser.php @@ -17,7 +17,6 @@ * @todo Tools need to be imported */ class HttpMicrodataParser extends AbstractHtmlParser { - /** * @var \DOMXPath */ @@ -100,7 +99,7 @@ private function fixupInstructions(DOMNode $recipeNode): void { /** * Search for images in the microdata of a recipe * @param DOMNode $recipeNode The recipe to search within - * @return boolean true, if a property was found + * @return bool true, if a property was found */ private function parseImage(DOMNode $recipeNode): bool { return $this->searchMultipleProperties( @@ -114,7 +113,7 @@ private function parseImage(DOMNode $recipeNode): bool { /** * Search for ingredients in the microdata of a recipe * @param DOMNode $recipeNode The recipe to search within - * @return boolean true, if a property was found + * @return bool true, if a property was found */ private function parseIngredients(DOMNode $recipeNode): bool { return $this->searchMultipleProperties( @@ -128,7 +127,7 @@ private function parseIngredients(DOMNode $recipeNode): bool { /** * Search for instructions in the microdata of a recipe * @param DOMNode $recipeNode The recipe to search within - * @return boolean true, if a property was found + * @return bool true, if a property was found */ private function parseInstructions(DOMNode $recipeNode): bool { return $this->searchMultipleProperties( @@ -152,7 +151,7 @@ private function parseInstructions(DOMNode $recipeNode): bool { * @param array $properties The properties to look for one-by-one * @param array $attributes The attributes that will contain the data * @param string $dst The name of the property list in the internal structure - * @return boolean true, if the property was found + * @return bool true, if the property was found */ private function searchMultipleProperties( DOMNode $recipeNode, diff --git a/lib/Helper/HtmlToDomParser.php b/lib/Helper/HtmlToDomParser.php index 7cbd49343..06d637291 100644 --- a/lib/Helper/HtmlToDomParser.php +++ b/lib/Helper/HtmlToDomParser.php @@ -17,22 +17,22 @@ class HtmlToDomParser { /** * Indicates the parsing was successfully terminated - * @var integer + * @var int */ public const PARSING_SUCCESS = 0; /** * Indicates the parsing terminated with warnings - * @var integer + * @var int */ public const PARSING_WARNING = 1; /** * Indicates the parsing terminated with an error - * @var integer + * @var int */ public const PARSING_ERROR = 2; /** * Indicates that the parsing terminated with a fatal error - * @var integer + * @var int */ public const PARSING_FATAL_ERROR = 3; @@ -74,10 +74,10 @@ public function __construct(ILogger $logger, IL10N $il10n) { */ public function loadHtmlString(DOMDocument $dom, string $url, string $html): DOMDocument { $libxml_previous_state = libxml_use_internal_errors(true); - + try { $parsedSuccessfully = $dom->loadHTML($html); - + // Error handling $errors = libxml_get_errors(); try { @@ -86,14 +86,14 @@ public function loadHtmlString(DOMDocument $dom, string $url, string $html): DOM throw new ImportException($this->l->t('Parsing of HTML failed.'), null, $ex); } libxml_clear_errors(); - + if (!$parsedSuccessfully) { throw new ImportException($this->l->t('Parsing of HTML failed.')); } } finally { libxml_use_internal_errors($libxml_previous_state); } - + return $dom; } @@ -120,7 +120,7 @@ public function getState(): int { */ private function checkXMLErrors(array $errors, string $url): void { $grouped = $this->groupErrors($errors); - + $this->state = self::PARSING_SUCCESS; $this->logAllErrors($grouped, $url); @@ -163,7 +163,7 @@ private function groupErrors(array $errors): array { return $ret; } - + /** * Log the found error groups to the NC core error logger. * @@ -171,7 +171,6 @@ private function groupErrors(array $errors): array { * * @param array $groupedErrors The grouped errors as defined in groupErrors * @param string $url The URL to import - * @return void * @throws \Exception */ private function logAllErrors(array $groupedErrors, string $url): void { @@ -200,7 +199,7 @@ private function logWarning(int $code, array $group, string $url): void { $this->state = max($this->state, self::PARSING_WARNING); } - + private function logError(int $code, array $group, string $url): void { $msg = $this->l->n('Error %u occurred while parsing %s.', 'Error %u occurred %n times while parsing %s.', $group['count'], [$code, $url]); $this->logger->warning($this->formatError($msg, $group['first'])); diff --git a/lib/Helper/ImageService/ImageFileHelper.php b/lib/Helper/ImageService/ImageFileHelper.php index efed71f4e..4a868cade 100644 --- a/lib/Helper/ImageService/ImageFileHelper.php +++ b/lib/Helper/ImageService/ImageFileHelper.php @@ -39,7 +39,7 @@ public function getImage(Folder $recipeFolder): File { * Check if a recipe folder contains an image * * @param Folder $recipeFolder The folder of the recipe to check - * @return boolean true, if there is an image present + * @return bool true, if there is an image present */ public function hasImage(Folder $recipeFolder): bool { return $recipeFolder->nodeExists(self::NAME_MAIN); @@ -49,7 +49,6 @@ public function hasImage(Folder $recipeFolder): bool { * Drop the image of a recipe * * @param Folder $recipeFolder The folder containing the recipe - * @return void */ public function dropImage(Folder $recipeFolder): void { if ($recipeFolder->nodeExists(self::NAME_MAIN)) { diff --git a/lib/Helper/ImageService/ImageGenerationHelper.php b/lib/Helper/ImageService/ImageGenerationHelper.php index dc75979c5..e8777acbd 100644 --- a/lib/Helper/ImageService/ImageGenerationHelper.php +++ b/lib/Helper/ImageService/ImageGenerationHelper.php @@ -39,7 +39,6 @@ public function __construct( * @param File $fullImage The full-sized image to use as a starting point * @param int $type The requested size of the thumbnail * @param File $dstFile The name of the file to store the thumbnail to - * @return void * @throws NotPermittedException if the IO to read or write the image file was not allowed * @throws LockedException if the image file was locked and thus could not be read or written * @throws GenericFileException if the writing fails for some reason @@ -55,7 +54,7 @@ public function generateThumbnail(File $fullImage, int $type, File $dstFile): vo $fullContent = $fullImage->getContent(); $thumbContent = $this->thumbnailService->getThumbnail($fullContent, $type); - + $dstFile->putContent($thumbContent); $dstFile->touch(); } @@ -69,8 +68,7 @@ public function generateThumbnail(File $fullImage, int $type, File $dstFile): vo * The main image will not be dropped. * * @param Folder $recipeFolder The folder containing the recipe - * @param integer $type The type of the thumbnail to remove - * @return void + * @param int $type The type of the thumbnail to remove * @throws NotPermittedException if the image could not be removed * @throws InvalidPathException */ @@ -78,7 +76,7 @@ public function drop(Folder $recipeFolder, int $type): void { if ($type === ImageSize::PRIMARY_IMAGE) { return; } - + $filename = ImageSize::NAME_MAP[$type]; try { diff --git a/lib/Helper/ImageService/ThumbnailFileHelper.php b/lib/Helper/ImageService/ThumbnailFileHelper.php index 42604547a..2e7fe8412 100644 --- a/lib/Helper/ImageService/ThumbnailFileHelper.php +++ b/lib/Helper/ImageService/ThumbnailFileHelper.php @@ -13,7 +13,6 @@ * This class allows to handle the files of the thumbnails */ class ThumbnailFileHelper { - /** * @var ImageGenerationHelper */ @@ -43,7 +42,7 @@ public function __construct( * Ensure that a thumbnail for a certain size exists and returns it * * @param Folder $recipeFolder The folder of the recipe to check for - * @param integer $type The type of the thumbnail to generate + * @param int $type The type of the thumbnail to generate * @return File The thumbnail file * @throws NoRecipeImageFoundException if the recipe has no primary image to create a thumbnail from * @throws NotPermittedException if the thumbnail generation could not write the thumbnail to the correct location @@ -57,7 +56,7 @@ public function getThumbnail(Folder $recipeFolder, int $type): File { if ($this->fileHelper->hasImage($recipeFolder)) { $full = $this->fileHelper->getImage($recipeFolder); $file = $recipeFolder->newFile($filename); - + $this->generationHelper->generateThumbnail($full, $type, $file); return $file; } else { @@ -74,8 +73,7 @@ public function getThumbnail(Folder $recipeFolder, int $type): File { * Otherwise a new file is generated. * * @param Folder $recipeFolder The folder containing the recipe - * @param integer $type The thumbnail type to generate - * @return void + * @param int $type The thumbnail type to generate * @throws NoRecipeImageFoundException if the recipe has no primary image to create the thumbnails from * @throws NotFoundException If no full-scale image was found. * @throws NotPermittedException if the IO to read or write the image file was not allowed @@ -86,7 +84,7 @@ public function getThumbnail(Folder $recipeFolder, int $type): File { */ private function recreateSingleThumbnail(Folder $recipeFolder, int $type): void { $filename = ImageSize::NAME_MAP[$type]; - + if ($this->fileHelper->hasImage($recipeFolder)) { $full = $this->fileHelper->getImage($recipeFolder); if ($recipeFolder->nodeExists($filename)) { @@ -100,14 +98,13 @@ private function recreateSingleThumbnail(Folder $recipeFolder, int $type): void $this->getThumbnail($recipeFolder, $type); } } - + /** * Recreate all thumbnails in the recipe. * * This will remove them and create new ones. * * @param Folder $recipeFolder The folder containing the files of a recipe. - * @return void * @throws NoRecipeImageFoundException if the recipe has no primary image to create the thumbnails from * @throws NotFoundException If no full-scale image was found. * @throws NotPermittedException if the IO to read or write the image file was not allowed @@ -125,8 +122,7 @@ public function recreateThumbnails(Folder $recipeFolder): void { * Drop a thumbnail in a recipe * * @param Folder $recipeFolder The folder of the recipe - * @param integer $type The thumbnail type to remove - * @return void + * @param int $type The thumbnail type to remove */ private function dropSingleThumbnail(Folder $recipeFolder, int $type): void { $filename = ImageSize::NAME_MAP[$type]; @@ -139,7 +135,6 @@ private function dropSingleThumbnail(Folder $recipeFolder, int $type): void { * Drop all thumbnails from a recipe folder * * @param Folder $recipeFolder The folder to drop the thumbnails from - * @return void */ public function dropThumbnails(Folder $recipeFolder): void { $this->dropSingleThumbnail($recipeFolder, ImageSize::THUMBNAIL); diff --git a/lib/Helper/RestParameterParser.php b/lib/Helper/RestParameterParser.php index ba74c6bca..794ea8a6a 100644 --- a/lib/Helper/RestParameterParser.php +++ b/lib/Helper/RestParameterParser.php @@ -2,23 +2,22 @@ namespace OCA\Cookbook\Helper; -use function GuzzleHttp\json_decode; use OCP\IL10N; class RestParameterParser { private const CHARSET = 'charset'; private const CONTENT_TYPE = 'CONTENT_TYPE'; private const REQUEST_METHOD = 'REQUEST_METHOD'; - + /** * @var IL10N */ private $l; - + public function __construct(IL10N $l10n) { $this->l = $l10n; } - + /** * Fetch the parameters from the input accordingly * @@ -30,13 +29,13 @@ public function __construct(IL10N $l10n) { public function getParameters(): array { if (isset($_SERVER[self::CONTENT_TYPE])) { $parts = explode(';', $_SERVER[self::CONTENT_TYPE], 2); - + switch (trim($parts[0])) { case 'application/json': $enc = $this->getEncoding($_SERVER[self::CONTENT_TYPE]); return $this->parseApplicationJSON($enc); break; - + case 'multipart/form-data': if ($this->isPost()) { return $_POST; @@ -44,7 +43,7 @@ public function getParameters(): array { throw new \Exception($this->l->t('Cannot parse non-POST multipart encoding. This is a bug.')); } break; - + case 'application/x-www-form-urlencoded': if ($this->isPost()) { return $_POST; @@ -58,7 +57,7 @@ public function getParameters(): array { throw new \Exception($this->l->t('Cannot detect type of transmitted data. This is a bug, please report it.')); } } - + /** * Parse data transmitted as application/json * @param $encoding string The encoding to use @@ -66,13 +65,13 @@ public function getParameters(): array { */ private function parseApplicationJSON(string $encoding): array { $rawData = file_get_contents('php://input'); - + if ($encoding !== 'UTF-8') { $rawData = iconv($encoding, 'UTF-8', $rawData); } return json_decode($rawData, true); } - + /** * Parse the URL encoded value transmitted * @@ -88,36 +87,36 @@ private function parseUrlEncoded(string $encoding): array { if ($encoding !== 'UTF-8') { $rawData = iconv($encoding, 'UTF-8', $rawData); } - + $ret = []; foreach (explode('&', $rawData) as $assignment) { $parts = explode('=', $assignment, 2); - + if (count($parts) < 2) { throw new \Exception($this->l->t('Invalid URL-encoded string found. Please report a bug.')); } - + $key = $parts[0]; $value = urldecode($parts[1]); - + if (substr_compare($key, '[]', -2, 2)) { // $key ends in [] // Drop '[]' at the end $key = substr($key, 0, -2); - + if (!array_key_exists($key, $ret)) { $ret[$key] = []; } - + $ret[$key][] = $value; } else { $ret[$key] = $value; } } - + return $ret; } - + /** * Get the encoding from the header * @param string $header The header to parse @@ -125,10 +124,10 @@ private function parseUrlEncoded(string $encoding): array { */ private function getEncoding(string $header): string { $parts = explode(';', $header); - + // Fallback encoding $enc = 'UTF-8'; - + for ($i = 1; $i < count($parts); $i++) { if (substr_compare(trim($parts[$i]), self::CHARSET, 0, strlen(self::CHARSET))) { // parts[$i] begins with charset= @@ -137,10 +136,10 @@ private function getEncoding(string $header): string { break; } } - + return $enc; } - + /** * Check if the request is a POST request * @return bool true, if the request is a POST request. diff --git a/lib/Helper/UserConfigHelper.php b/lib/Helper/UserConfigHelper.php index 0957e6691..980b1b0c7 100644 --- a/lib/Helper/UserConfigHelper.php +++ b/lib/Helper/UserConfigHelper.php @@ -44,7 +44,6 @@ public function __construct( /** * Checks if the user is logged in and the configuration can be obtained at all * - * @return void * @throws UserNotLoggedInException if no user is logged in */ private function ensureUserIsLoggedIn(): void { @@ -70,7 +69,6 @@ private function getRawValue(string $key): string { * * @param string $key The key of the configuration * @param string $value The value of the config entry - * @return void * @throws UserNotLoggedInException if no user is logged in */ private function setRawValue(string $key, string $value): void { @@ -81,7 +79,7 @@ private function setRawValue(string $key, string $value): void { /** * Get the timestamp of the last rescan of the library * - * @return integer The timestamp of the last index rebuild + * @return int The timestamp of the last index rebuild * @throws UserNotLoggedInException if no user is logged in */ public function getLastIndexUpdate(): int { @@ -96,8 +94,7 @@ public function getLastIndexUpdate(): int { /** * Set the timestamp of the last rescan of the library * - * @param integer $value The timestamp of the last index rebuild - * @return void + * @param int $value The timestamp of the last index rebuild * @throws UserNotLoggedInException if no user is logged in */ public function setLastIndexUpdate(int $value): void { @@ -107,7 +104,7 @@ public function setLastIndexUpdate(int $value): void { /** * Get the number of seconds between rescans of the library * - * @return integer The number of seconds to wait before a new rescan is triggered + * @return int The number of seconds to wait before a new rescan is triggered * @throws UserNotLoggedInException if no user is logged in */ public function getUpdateInterval(): int { @@ -122,8 +119,7 @@ public function getUpdateInterval(): int { /** * Set the interval between the rescan events of the complete library * - * @param integer $value The number of seconds to wait at least between rescans - * @return void + * @param int $value The number of seconds to wait at least between rescans * @throws UserNotLoggedInException if no user is logged in */ public function setUpdateInterval(int $value): void { @@ -133,7 +129,7 @@ public function setUpdateInterval(int $value): void { /** * Check if the primary imgae should be printed or not * - * @return boolean true, if the image should be printed + * @return bool true, if the image should be printed * @throws UserNotLoggedInException if no user is logged in */ public function getPrintImage(): bool { @@ -147,8 +143,7 @@ public function getPrintImage(): bool { /** * Set if the image should be printed * - * @param boolean $value true if the image should be printed - * @return void + * @param bool $value true if the image should be printed * @throws UserNotLoggedInException if no user is logged in */ public function setPrintImage(bool $value): void { @@ -191,7 +186,6 @@ public function getFolderName(): string { * Instead use the methods of the UserFolderHelper class * * @param string $value The name of the folder within the user's files - * @return void * @throws UserNotLoggedInException if no user is logged in */ public function setFolderName(string $value): void { diff --git a/lib/Helper/UserFolderHelper.php b/lib/Helper/UserFolderHelper.php index 9fbabe4a5..9977a4da5 100644 --- a/lib/Helper/UserFolderHelper.php +++ b/lib/Helper/UserFolderHelper.php @@ -19,7 +19,6 @@ * The user folder is the path, were all recipes are stored. */ class UserFolderHelper { - /** * @var UserConfigHelper */ @@ -60,12 +59,11 @@ public function __construct( $this->cache = null; } - + /** * Set the current path in the settings relative to the user's root folder * * @param string $path The name of the path to be used for the recipes - * @return void */ public function setPath(string $path) { $this->config->setFolderName($path); @@ -102,7 +100,7 @@ public function getFolder(): Folder { // Correct path to be relative to nc root $path = '/' . $this->userId . '/files/' . $path; $path = str_replace('//', '/', $path); - + $this->cache = $this->getOrCreateFolder($path); } diff --git a/lib/Migration/Version000000Date20190312140601.php b/lib/Migration/Version000000Date20190312140601.php index 421b8baba..0f41b3484 100644 --- a/lib/Migration/Version000000Date20190312140601.php +++ b/lib/Migration/Version000000Date20190312140601.php @@ -8,7 +8,6 @@ use OCP\Migration\IOutput; class Version000000Date20190312140601 extends SimpleMigrationStep { - /** * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` @@ -31,7 +30,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt $table->setPrimaryKey(['recipe_id']); } - + if (!$schema->hasTable('cookbook_keywords')) { $table = $schema->createTable('cookbook_keywords'); $table->addColumn('recipe_id', 'integer', [ @@ -42,7 +41,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt 'length' => 64, ]); } - + return $schema; } } diff --git a/lib/Migration/Version000000Date20190910100911.php b/lib/Migration/Version000000Date20190910100911.php index 6658f1c0e..e169f482f 100644 --- a/lib/Migration/Version000000Date20190910100911.php +++ b/lib/Migration/Version000000Date20190910100911.php @@ -19,7 +19,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt $schema = $schemaClosure(); $recipes_table = $schema->getTable('cookbook_recipes'); - + if (!$recipes_table->hasColumn('user_id')) { $recipes_table->addColumn('user_id', 'string', [ 'notnull' => true, @@ -27,9 +27,9 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt 'default' => 'empty', ]); } - + $keywords_table = $schema->getTable('cookbook_keywords'); - + if (!$keywords_table->hasColumn('user_id')) { $keywords_table->addColumn('user_id', 'string', [ 'notnull' => true, diff --git a/lib/Migration/Version000000Date20200315121603.php b/lib/Migration/Version000000Date20200315121603.php index 652aa7600..0831fa80a 100644 --- a/lib/Migration/Version000000Date20200315121603.php +++ b/lib/Migration/Version000000Date20200315121603.php @@ -8,7 +8,6 @@ use OCP\Migration\IOutput; class Version000000Date20200315121603 extends SimpleMigrationStep { - /** * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` @@ -37,14 +36,14 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt 'length' => 256, ]); } - + if (!$table->hasColumn('user_id')) { $table->addColumn('user_id', 'string', [ 'notnull' => true, 'length' => 64, ]); } - + return $schema; } } diff --git a/lib/Migration/Version000000Date20210427082010.php b/lib/Migration/Version000000Date20210427082010.php index c8b4aebd0..fc7d24e11 100644 --- a/lib/Migration/Version000000Date20210427082010.php +++ b/lib/Migration/Version000000Date20210427082010.php @@ -13,7 +13,6 @@ * Auto-generated migration step: Please modify to your needs! */ class Version000000Date20210427082010 extends SimpleMigrationStep { - /** * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` @@ -25,7 +24,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt * @var ISchemaWrapper $schema */ $schema = $schemaClosure(); - + $categoriesTable = $schema->getTable('cookbook_categories'); if (! $categoriesTable->hasIndex('categories_recipe_idx')) { $categoriesTable->addIndex([ @@ -33,7 +32,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt 'recipe_id', ], 'categories_recipe_idx'); } - + $keywordsTable = $schema->getTable('cookbook_keywords'); if (! $keywordsTable->hasIndex('keywords_recipe_idx')) { $keywordsTable->addIndex([ @@ -41,7 +40,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt 'recipe_id', ], 'keywords_recipe_idx'); } - + return $schema; } } diff --git a/lib/Migration/Version000000Date20210701093123.php b/lib/Migration/Version000000Date20210701093123.php index 382aee400..3f4d58770 100644 --- a/lib/Migration/Version000000Date20210701093123.php +++ b/lib/Migration/Version000000Date20210701093123.php @@ -15,21 +15,20 @@ * Auto-generated migration step: Please modify to your needs! */ class Version000000Date20210701093123 extends SimpleMigrationStep { - /** * @var IDBConnection */ private $db; - + public function __construct(IDBConnection $db) { $this->db = $db; } - + public function preSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) { $this->db->beginTransaction(); try { $qb = $this->db->getQueryBuilder(); - + // Fetch all rows that are non-unique $qb->selectAlias('n.user_id', 'user') ->selectAlias('n.recipe_id', 'recipe') @@ -37,13 +36,13 @@ public function preSchemaChange(IOutput $output, \Closure $schemaClosure, array ->groupBy('n.user_id', 'n.recipe_id') ->having('COUNT(*) > 1'); //echo $qb->getSQL() . "\n"; - + $cursor = $qb->execute(); $result = $cursor->fetchAll(); - + if (sizeof($result) > 0) { // We have to fix the database - + // Drop all redundant rows $qb = $this->db->getQueryBuilder(); $qb->delete('cookbook_names') @@ -51,7 +50,7 @@ public function preSchemaChange(IOutput $output, \Closure $schemaClosure, array 'user_id = :user', 'recipe_id = :recipe' ); - + $qb2 = $this->db->getQueryBuilder(); $qb2->update('preferences') ->set('configvalue', $qb->expr()->literal('1', IQueryBuilder::PARAM_STR)) @@ -62,17 +61,17 @@ public function preSchemaChange(IOutput $output, \Closure $schemaClosure, array ); $qb2->setParameter('app', 'cookbook'); $qb2->setParameter('property', 'last_index_update'); - + foreach ($result as $r) { $qb->setParameter('user', $r['user']); $qb->setParameter('recipe', $r['recipe']); $qb->execute(); - + $qb2->setParameter('user', $r['user']); $qb2->execute(); } } - + // Finish the transaction $this->db->commit(); } catch (\Exception $e) { @@ -81,7 +80,7 @@ public function preSchemaChange(IOutput $output, \Closure $schemaClosure, array throw $e; } } - + /** * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` @@ -93,7 +92,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt * @var ISchemaWrapper $schema */ $schema = $schemaClosure(); - + $namesTable = $schema->getTable('cookbook_names'); if ($namesTable->hasPrimaryKey()) { $namesTable->dropPrimaryKey(); @@ -104,7 +103,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt 'user_id' ], 'names_recipe_idx'); } - + return $schema; } } diff --git a/lib/Search/Provider.php b/lib/Search/Provider.php index 6c9015b5a..f99eb3718 100644 --- a/lib/Search/Provider.php +++ b/lib/Search/Provider.php @@ -18,7 +18,6 @@ // Remove conditional once we end support for NC 19 if (Util::getVersion()[0] >= 20) { class Provider implements IProvider { - /** @var IL10N */ private $l; @@ -59,7 +58,7 @@ public function getOrder(string $route, array $routeParameters): int { public function search(IUser $user, ISearchQuery $query): SearchResult { $recipes = $this->recipeService->findRecipesInSearchIndex($query->getTerm()); $result = array_map( - function (array $recipe) use ($user) : SearchResultEntry { + function (array $recipe) use ($user): SearchResultEntry { $id = $recipe['recipe_id']; $subline = ''; diff --git a/lib/Service/DbCacheService.php b/lib/Service/DbCacheService.php index 2ead509f4..687f99643 100644 --- a/lib/Service/DbCacheService.php +++ b/lib/Service/DbCacheService.php @@ -11,45 +11,45 @@ class DbCacheService { private $userId; // var $root; - + /** * @var RecipeDb */ private $db; - + /** * @var RecipeService */ private $recipeService; - + /** * @var UserConfigHelper */ private $userConfigHelper; - + private $jsonFiles; private $dbReceipeFiles; private $dbKeywords; private $dbCategories; - + private $newRecipes; private $obsoleteRecipes; private $updatedRecipes; - + public function __construct(?string $UserId, RecipeDb $db, RecipeService $recipeService, UserConfigHelper $userConfigHelper) { $this->userId = $UserId; $this->db = $db; $this->recipeService = $recipeService; $this->userConfigHelper = $userConfigHelper; } - + public function updateCache() { $this->jsonFiles = $this->parseJSONFiles(); $this->dbReceipeFiles = $this->fetchDbRecipeInformations(); - + $this->carryOutUpdate(); } - + /** * @param File $recipeFile */ @@ -60,11 +60,11 @@ public function addRecipe(File $recipeFile) { // XXX Put a log message and infor the user of problem. return; } - + $id = $json['id']; - + $this->jsonFiles = [$id => $json]; - + $this->dbReceipeFiles = []; try { $dbEntry = $this->fetchSingleRecipeDbInformations($id); @@ -72,30 +72,30 @@ public function addRecipe(File $recipeFile) { } catch (DoesNotExistException $e) { // No entry was found, keep the array empty } - + $this->carryOutUpdate(); } - + private function carryOutUpdate() { $this->resetFields(); $this->compareReceipeLists(); - + $this->applyDbReceipeChanges(); - + $this->fetchDbAssociatedInformations(); $this->updateCategories(); $this->updateKeywords(); } - + private function resetFields() { $this->newRecipes = []; $this->obsoleteRecipes = []; $this->updatedRecipes = []; } - + private function parseJSONFiles() { $ret = []; - + $jsonFiles = $this->recipeService->getRecipeFiles(); foreach ($jsonFiles as $jsonFile) { try { @@ -104,53 +104,53 @@ private function parseJSONFiles() { continue; } $id = $json['id']; - + $ret[$id] = $json; } - + return $ret; } - + /** * @param File $jsonFile * @throws InvalidJSONFileException * @return array */ - private function parseJSONFile(File $jsonFile) : array { + private function parseJSONFile(File $jsonFile): array { // XXX Export of file reading into library/service? $json = json_decode($jsonFile->getContent(), true); - + if (!$json || !isset($json['name']) || $json['name'] === 'No name') { $id = $jsonFile->getParent()->getId(); - + throw new InvalidJSONFileException("The JSON file in the folder with id $id does not have a valid name."); } - + $id = (int) $jsonFile->getParent()->getId(); $json['id'] = $id; - + return $json; } - + private function fetchDbRecipeInformations() { $dbResult = $this->db->findAllRecipes($this->userId); - + $ret = []; - + foreach ($dbResult as $row) { // XXX Create an Entity from DB row better in DB file $id = $row['recipe_id']; - + $obj = []; $obj['name'] = $row['name']; $obj['id'] = $id; - + $ret[$id] = $obj; } - + return $ret; } - + /** * * @param int $id @@ -160,32 +160,32 @@ private function fetchDbRecipeInformations() { private function fetchSingleRecipeDbInformations(int $id) { return $this->db->findRecipeById($id); } - + private function fetchDbAssociatedInformations() { $recipeIds = array_keys($this->jsonFiles); - + $this->dbKeywords = []; $this->dbCategories = []; - + foreach ($recipeIds as $rid) { // XXX Enhancement by selecting all keywords/categories and associating in RAM into data structure $this->dbKeywords[$rid] = $this->db->getKeywordsOfRecipe($rid, $this->userId); $category = $this->db->getCategoryOfRecipe($rid, $this->userId); - + $this->dbCategories[$rid] = $category; } } - + private function compareReceipeLists() { foreach (array_keys($this->jsonFiles) as $id) { if (array_key_exists($id, $this->dbReceipeFiles)) { // The file was at least in the database - + if (! $this->isDbEntryUpToDate($id)) { // An update is needed $this->updatedRecipes[] = $id; } - + // Remove from array for later removal of old recipes unset($this->dbReceipeFiles[$id]); } else { @@ -193,27 +193,27 @@ private function compareReceipeLists() { $this->newRecipes[] = $id; } } - + // Any remining recipe in dbFiles is to be removed $this->obsoleteRecipes = array_keys($this->dbReceipeFiles); } - + // private function - + private function isDbEntryUpToDate($id) { $dbEntry = $this->dbReceipeFiles[$id]; $fileEntry = $this->jsonFiles[$id]; - + if ($dbEntry['name'] !== $fileEntry['name']) { return false; } - + return true; } - + private function applyDbReceipeChanges() { $this->db->deleteRecipes($this->obsoleteRecipes, $this->userId); - + $newRecipes = array_map( function ($id) { return $this->jsonFiles[$id]; @@ -221,7 +221,7 @@ function ($id) { $this->newRecipes ); $this->db->insertRecipes($newRecipes, $this->userId); - + $updatedRecipes = array_map( function ($id) { return $this->jsonFiles[$id]; @@ -230,14 +230,14 @@ function ($id) { ); $this->db->updateRecipes($updatedRecipes, $this->userId); } - + private function updateCategories() { foreach ($this->jsonFiles as $rid => $json) { if ($this->hasJSONCategory($json)) { // There is a category in the JSON file present. - + $category = trim($this->getJSONCategory($json)); - + if (isset($this->dbCategories[$rid])) { // There is a category present. Update needed? if ($this->dbCategories[$rid] !== trim($category)) { @@ -254,10 +254,10 @@ private function updateCategories() { } } } - + /** * @param array $json - * @return boolean + * @return bool */ private function hasJSONCategory(array $json): bool { return ! is_null($this->getJSONCategory($json)); @@ -290,11 +290,11 @@ private function getJSONCategory(array $json): ?string { } return $category; } - + private function updateKeywords() { $newPairs = []; $obsoletePairs = []; - + foreach ($this->jsonFiles as $rid => $json) { $textKeywords = $json['keywords'] ?? ''; if (is_array($textKeywords)) { @@ -308,16 +308,16 @@ private function updateKeywords() { $keywords = array_filter($keywords, function ($v) { return ! empty($v); }); - + $dbKeywords = $this->dbKeywords[$rid]; - + $onlyInDb = array_filter($dbKeywords, function ($v) use ($keywords) { return empty(array_keys($keywords, $v)); }); $onlyInJSON = array_filter($keywords, function ($v) use ($dbKeywords) { return empty(array_keys($dbKeywords, $v)); }); - + $newPairs = array_merge($newPairs, array_map(function ($keyword) use ($rid) { return [ 'recipeId' => $rid, @@ -331,50 +331,50 @@ private function updateKeywords() { ]; }, $onlyInDb)); } - + $this->db->addKeywordPairs($newPairs, $this->userId); $this->db->removeKeywordPairs($obsoletePairs, $this->userId); } - + /** * Gets the last time the search index was updated */ public function getSearchIndexLastUpdateTime() { return $this->userConfigHelper->getLastIndexUpdate(); } - + /** * @return int */ public function getSearchIndexUpdateInterval(): int { $interval = $this->userConfigHelper->getUpdateInterval(); - + if ($interval < 1) { $interval = 5; } - + return $interval; } - + public function triggerCheck() { // TODO Locking // XXX Catch Exceptions $this->checkSearchIndexUpdate(); } - + /** * Checks if a search index update is needed and performs it */ private function checkSearchIndexUpdate() { $last_index_update = $this->getSearchIndexLastUpdateTime(); $interval = $this->getSearchIndexUpdateInterval(); - + if ($last_index_update < 1 || time() > $last_index_update + ($interval * 60)) { $this->updateCache(); - + // Cache the last index update $this->userConfigHelper->setLastIndexUpdate(time()); - + // TODO Make triggers more general, need refactoring of *all* Services $this->recipeService->updateSearchIndex(); } diff --git a/lib/Service/HtmlDownloadService.php b/lib/Service/HtmlDownloadService.php index 1e5ac0a10..fea956970 100644 --- a/lib/Service/HtmlDownloadService.php +++ b/lib/Service/HtmlDownloadService.php @@ -11,32 +11,31 @@ use OCP\ILogger; class HtmlDownloadService { - /** * @var array */ private $htmlFilters; - + /** * @var ILogger */ private $logger; - + /** * @var IL10N */ private $l; - + /** * @var HtmlToDomParser */ private $htmlParser; - + /** * @var DOMDocument */ private $dom; - + public function __construct(HtmlEntityDecodeFilter $htmlEntityDecodeFilter, ILogger $logger, IL10N $l10n, HtmlToDomParser $htmlParser) { $this->htmlFilters = [ $htmlEntityDecodeFilter ]; @@ -44,7 +43,7 @@ public function __construct(HtmlEntityDecodeFilter $htmlEntityDecodeFilter, $this->l = $l10n; $this->htmlParser = $htmlParser; } - + /** * Download a recipe URL and extract the JSON from it * @@ -57,18 +56,18 @@ public function __construct(HtmlEntityDecodeFilter $htmlEntityDecodeFilter, */ public function downloadRecipe(string $url): int { $html = $this->fetchHtmlPage($url); - + // Filter the HTML code /** @var AbstractHtmlFilter $filter */ foreach ($this->htmlFilters as $filter) { $filter->apply($html); } - + $dom = new DOMDocument(); $this->dom = $this->htmlParser->loadHtmlString($dom, $url, $html); return $this->htmlParser->getState(); } - + /** * Get the HTML docuemnt after it has been downloaded and parsed with downloadRecipe() * @return ?DOMDocument The loaded HTML document or null if document could not be loaded successfully @@ -85,26 +84,26 @@ public function getDom(): ?DOMDocument { */ private function fetchHtmlPage(string $url): string { $host = parse_url($url); - + if (!$host) { throw new ImportException($this->l->t('Could not parse URL')); } - + $opts = [ "http" => [ "method" => "GET", "header" => "User-Agent: Nextcloud Cookbook App" ] ]; - + $context = stream_context_create($opts); - + $html = file_get_contents($url, false, $context); - + if ($html === false) { throw new ImportException($this->l->t('Could not parse HTML code for site {url}', $url)); } - + return $html; } } diff --git a/lib/Service/ImageService.php b/lib/Service/ImageService.php index a41c0db83..6efd6ea7d 100644 --- a/lib/Service/ImageService.php +++ b/lib/Service/ImageService.php @@ -18,7 +18,6 @@ * @todo Rework the exeption passing */ class ImageService { - /** * @var ThumbnailFileHelper */ @@ -65,7 +64,7 @@ public function getImageAsFile(Folder $recipeFolder): File { * Check if a recipe folder contains an image * * @param Folder $recipeFolder The folder of the recipe to check - * @return boolean true, if there is an image present + * @return bool true, if there is an image present */ public function hasImage(Folder $recipeFolder): bool { return $this->fileHelper->hasImage($recipeFolder); @@ -77,7 +76,6 @@ public function hasImage(Folder $recipeFolder): bool { * This will delete the primary image and all thumbnails * * @param Folder $recipeFolder The folder containing the recipe - * @return void */ public function dropImage(Folder $recipeFolder): void { $this->fileHelper->dropImage($recipeFolder); @@ -88,7 +86,7 @@ public function dropImage(Folder $recipeFolder): void { * Obtain a thumbnail from a recipe * * @param Folder $recipeFolder The folder containing the recipe - * @param integer $type The type of the thumbnail to obtain + * @param int $type The type of the thumbnail to obtain * @see OCA\Cookbook\Helper\ImageService\ImageSize for a list of possible image sizes * @return string The image data * @throws NoRecipeImageFoundException if the recipe has no primary image to create a thumbnail from @@ -104,7 +102,7 @@ public function getThumbnail(Folder $recipeFolder, int $type): string { * Obtain a thumbnail of a recipe's primary image as a file for further processing * * @param Folder $recipeFolder The folder containing the recipe - * @param integer $type The type of the thumbnail to obtain + * @param int $type The type of the thumbnail to obtain * @see OCA\Cookbook\Helper\ImageService\ImageSize for a list of possible image sizes * @return File The file of the thumbnail * @throws NoRecipeImageFoundException if the recipe has no primary image to create a thumbnail from @@ -121,7 +119,6 @@ public function getThumbnailAsFile(Folder $recipeFolder, int $type): File { * * @param Folder $recipeFolder The recipe folder to store the image to * @param string $data The image data - * @return void * @throws NotFoundException * @throws GenericFileException * @throws LockedException diff --git a/lib/Service/JsonService.php b/lib/Service/JsonService.php index fb7db78ff..ad60a2cff 100644 --- a/lib/Service/JsonService.php +++ b/lib/Service/JsonService.php @@ -9,7 +9,6 @@ * */ class JsonService { - /** * Check if an object is a JSON representation of a schema.org object * @@ -19,33 +18,33 @@ class JsonService { * @param string $type The type to check for. If null or '' no type chek is performed * @return bool true, if $obj is an object and optionally satisfies the type check */ - public function isSchemaObject($obj, string $type = null) : bool { + public function isSchemaObject($obj, string $type = null): bool { if (! is_array($obj)) { // Objects must bve encoded as arrays in JSON return false; } - + if (!isset($obj['@context']) || ! preg_match('@^https?://schema\.org/?$@', $obj['@context'])) { // We have no correct context property return false; } - + if (!isset($obj['@type'])) { // Objects must have a property @type return false; } - + // We have an object - + if ($type === null || $type === '') { // No typecheck was requested. So return true return true; } - + // Check if type matches return (strcmp($obj['@type'], $type) === 0); } - + /** * Check if $obj is a schema.org object and contains a named property. * @@ -53,11 +52,11 @@ public function isSchemaObject($obj, string $type = null) : bool { * @param string $property The name of the property to check for * @return bool true, if $obj is a object and has the property given */ - public function hasProperty($obj, string $property) : bool { + public function hasProperty($obj, string $property): bool { if (!$this->isSchemaObject($obj)) { return false; } - + return array_key_exists($property, $obj); } } diff --git a/lib/Service/RecipeExtractionService.php b/lib/Service/RecipeExtractionService.php index a38b963d7..c99e053ae 100644 --- a/lib/Service/RecipeExtractionService.php +++ b/lib/Service/RecipeExtractionService.php @@ -9,23 +9,22 @@ use OCP\IL10N; class RecipeExtractionService { - /** * @var array */ private $parsers; - + /** * @var IL10N */ private $l; - + public function __construct(HttpJsonLdParser $jsonParser, HttpMicrodataParser $microdataParser, IL10N $l10n) { $this->parsers = [$jsonParser, $microdataParser]; $this->l = $l10n; } - + /** * Parse a DOM document using all registered parsers * @@ -42,7 +41,7 @@ public function parse(\DOMDocument $document): array { // Silently ignore failure as there might be other parsers better suited } } - + throw new HtmlParsingException($this->l->t('No parser found for the given import.')); } } diff --git a/lib/Service/RecipeService.php b/lib/Service/RecipeService.php index 6c808705c..769659476 100755 --- a/lib/Service/RecipeService.php +++ b/lib/Service/RecipeService.php @@ -32,16 +32,16 @@ class RecipeService { private $db; private $il10n; /** - * @var UserFolderHelper $userFolder + * @var UserFolderHelper */ private $userFolder; private $logger; - + /** * @var HtmlDownloadService */ private $htmlDownloadService; - + /** * @var RecipeExtractionService */ @@ -97,7 +97,7 @@ public function getRecipeById(int $id) { return $this->parseRecipeFile($file); } - + /** * Get a recipe's modification time by its folder id. * @@ -158,7 +158,7 @@ public function checkRecipe(array $json): array { if (!$json) { throw new Exception('Recipe array was null'); } - + if (empty($json['name'])) { throw new Exception('Field "name" is required'); } @@ -195,7 +195,7 @@ public function checkRecipe(array $json): array { if (empty($img)) { continue; } - + $image_matches = []; preg_match_all('!\d+!', $img, $image_matches); @@ -244,7 +244,7 @@ public function checkRecipe(array $json): array { $json['image'] .= '?' . $image_url['query']; } } - + // Make sure that "recipeCategory" is a string if (isset($json['recipeCategory'])) { @@ -259,10 +259,10 @@ public function checkRecipe(array $json): array { $json['recipeCategory'] = $this->cleanUpString($json['recipeCategory'], false, true); - + // Make sure that "recipeYield" is an integer which is at least 1 if (isset($json['recipeYield']) && $json['recipeYield']) { - + // Check if "recipeYield is an array if (is_array($json['recipeYield'])) { if (count($json['recipeYield']) === 1) { @@ -272,7 +272,7 @@ public function checkRecipe(array $json): array { $json['recipeYield'] = join(' ', $json['recipeYield']); } } - + $regex_matches = []; preg_match('/(\d*)/', $json['recipeYield'], $regex_matches); if (count($regex_matches) >= 1) { @@ -453,7 +453,7 @@ public function checkRecipe(array $json): array { if (isset($duration_matches[1][0]) && !empty($duration_matches[1][0])) { $duration_hours = intval($duration_matches[1][0]); } - + if (isset($duration_matches[2][0]) && !empty($duration_matches[2][0])) { $duration_minutes = intval($duration_matches[2][0]); } @@ -474,12 +474,13 @@ public function checkRecipe(array $json): array { } else { $json['nutrition'] = []; } - + return $json; } /** * @param string $html + * @param mixed $url * * @return array * @deprecated @@ -507,7 +508,7 @@ private function parseRecipeHtml($url, $html) { } finally { libxml_use_internal_errors($libxml_previous_state); } - + $xpath = new \DOMXPath($document); $json_ld_elements = $xpath->query("//*[@type='application/ld+json']"); @@ -555,7 +556,7 @@ private function parseRecipeHtml($url, $html) { // Parse HTML if JSON couldn't be found $json = []; - + $recipes = $xpath->query("//*[@itemtype='http://schema.org/Recipe']"); if (!isset($recipes[0])) { @@ -580,7 +581,7 @@ private function parseRecipeHtml($url, $html) { case 'images': case 'thumbnail': $prop = 'image'; - + if (!isset($json[$prop]) || !is_array($json[$prop])) { $json[$prop] = []; } @@ -599,7 +600,7 @@ private function parseRecipeHtml($url, $html) { case 'recipeIngredient': case 'ingredients': $prop = 'recipeIngredient'; - + if (!isset($json[$prop]) || !is_array($json[$prop])) { $json[$prop] = []; } @@ -612,7 +613,7 @@ private function parseRecipeHtml($url, $html) { } else { array_push($json[$prop], $prop_element->nodeValue); } - + break; case 'recipeInstructions': @@ -620,7 +621,7 @@ private function parseRecipeHtml($url, $html) { case 'steps': case 'guide': $prop = 'recipeInstructions'; - + if (!isset($json[$prop]) || !is_array($json[$prop])) { $json[$prop] = []; } @@ -656,7 +657,7 @@ private function parseRecipeHtml($url, $html) { // Make one final desparate attempt at getting the instructions if (!isset($json['recipeInstructions']) || !$json['recipeInstructions'] || sizeof($json['recipeInstructions']) < 1) { $json['recipeInstructions'] = []; - + $step_elements = $recipes[0]->getElementsByTagName('p'); foreach ($step_elements as $step_element) { @@ -667,23 +668,23 @@ private function parseRecipeHtml($url, $html) { array_push($json['recipeInstructions'], $step_element->nodeValue); } } - + return $this->checkRecipe($json); } private function display_libxml_errors($url, $errors) { $error_counter = []; $by_error_code = []; - + foreach ($errors as $error) { $count = array_key_exists($error->code, $error_counter) ? $error_counter[$error->code] : 0; $error_counter[$error->code] = $count + 1; $by_error_code[$error->code] = $error; } - + foreach ($error_counter as $code => $count) { $error = $by_error_code[$code]; - + switch ($error->level) { case LIBXML_ERR_WARNING: $error_message = "libxml: Warning $error->code "; @@ -700,7 +701,7 @@ private function display_libxml_errors($url, $errors) { $error_message .= "occurred " . $count . " times while parsing " . $url . ". Last time in line $error->line" . " and column $error->column: " . $error->message; - + $this->logger->warning($error_message); } } @@ -753,7 +754,7 @@ public function addRecipe($json) { if ($user_folder->nodeExists($json['name'])) { throw new RecipeExistsException($this->il10n->t('Another recipe with that name already exists')); } - + $recipe_folder->move($new_path); } @@ -831,15 +832,15 @@ public function addRecipe($json) { */ public function downloadRecipe(string $url): File { $this->htmlDownloadService->downloadRecipe($url); - + try { $json = $this->recipeExtractionService->parse($this->htmlDownloadService->getDom()); } catch (HtmlParsingException $ex) { throw new ImportException($ex->getMessage(), null, $ex); } - + $json = $this->checkRecipe($json); - + if (!$json) { $this->logger->error('Importing parsers resulted in null recipe.' . 'This is most probably a bug. Please report.'); @@ -885,29 +886,29 @@ public function updateSearchIndex() { throw $ex; } } - + private function migrateFolderStructure() { // Remove old cache folder if needed $legacy_cache_path = '/cookbook/cache'; - + if ($this->root->nodeExists($legacy_cache_path)) { $this->root->get($legacy_cache_path)->delete(); } - + // Restructure files if needed $user_folder = $this->userFolder->getFolder(); - + foreach ($user_folder->getDirectoryListing() as $node) { // Move JSON files from the user directory into its own folder if ($this->isRecipeFile($node)) { $recipe_name = str_replace('.json', '', $node->getName()); - + $node->move($node->getPath() . '_tmp'); - + $recipe_folder = $user_folder->newFolder($recipe_name); - + $node->move($recipe_folder->getPath() . '/recipe.json'); - + // Rename folders with .json extensions (this was likely caused by a migration bug) } elseif ($node instanceof Folder && strpos($node->getName(), '.json')) { $node->move(str_replace('.json', '', $node->getPath())); @@ -923,7 +924,7 @@ private function migrateFolderStructure() { public function getAllKeywordsInSearchIndex() { return $this->db->findAllKeywords($this->user_id); } - + /** * Gets all categories from the index * @@ -1136,6 +1137,8 @@ private function isRecipeFile($file) { /** * @param string $str + * @param mixed $preserve_newlines + * @param mixed $remove_slashes * * @return string */ @@ -1157,7 +1160,7 @@ private function cleanUpString($str, $preserve_newlines = false, $remove_slashes if ($remove_slashes) { $str = str_replace('/', '_', $str); } - + $str = html_entity_decode($str); // Remove duplicated spaces diff --git a/lib/Service/ThumbnailService.php b/lib/Service/ThumbnailService.php index 552ea4c0f..11a1ac318 100644 --- a/lib/Service/ThumbnailService.php +++ b/lib/Service/ThumbnailService.php @@ -14,7 +14,6 @@ * You need to store the images if they should be preserved. */ class ThumbnailService { - /** * @var IL10N */ @@ -39,7 +38,7 @@ protected function getNewImage(): Image { * Create a thumbnail for a requested thumbnail size * * @param string $data The image data to be rescaled - * @param integer $type The requested type, see the ImageSize class + * @param int $type The requested type, see the ImageSize class * @return string The image data of the generated thumbnail * @throws InvalidThumbnailTypeException if the requested type is either unknown or useless. */ @@ -60,7 +59,7 @@ public function getThumbnail(string $data, int $type): string { * Create a new thumbnail of a given size * * @param string $data The image data - * @param integer $size The maximal width or height of the destination image + * @param int $size The maximal width or height of the destination image * @return string The resized and minimized image */ protected function createThumbnail(string $data, int $size): string { diff --git a/tests/Migration/AppTest.php b/tests/Migration/AppTest.php index 2e9b5c1e9..c987ee067 100755 --- a/tests/Migration/AppTest.php +++ b/tests/Migration/AppTest.php @@ -16,7 +16,7 @@ class AppTest extends TestCase { public function setUp(): void { resetEnvironmentToBackup(); - + parent::setUp(); $app = new App('cookbook'); $this->container = $app->getContainer(); diff --git a/tests/Migration/Setup/Migrations/AbstractMigrationTestCase.php b/tests/Migration/Setup/Migrations/AbstractMigrationTestCase.php index 0e811d01a..0bf042165 100644 --- a/tests/Migration/Setup/Migrations/AbstractMigrationTestCase.php +++ b/tests/Migration/Setup/Migrations/AbstractMigrationTestCase.php @@ -20,40 +20,40 @@ abstract class AbstractMigrationTestCase extends TestCase { * @var IAppContainer */ protected $container; - + /** * @var IDBConnection */ protected $db; - + /** * @var MigrationService */ protected $migrationService; - + /** * @var SchemaWrapper */ protected $schema; - + protected $connection; - + abstract protected function getPreviousMigrationName(): ?string; - + private const TMP_MIGRATIONS = '/tmp/old-migrations'; - + public function setUp(): void { parent::setUp(); - + resetEnvironmentToBackup('plain'); - + $this->hideMigrations(); $this->enableApp(); $this->restoreMigrations(); - + $app = new App('cookbook'); $this->container = $app->getContainer(); - + /** * @var IDBConnection $db */ @@ -64,20 +64,20 @@ public function setUp(): void { */ $this->schema = $this->container->query(SchemaWrapper::class); $this->assertIsObject($this->schema); - + if (Util::getVersion()[0] >= 21) { $this->connection = \OC::$server->query(Connection::class); } else { $this->connection = $this->db; } - + if ($_ENV['INPUT_DB'] === 'sqlite') { $this->resetSQLite(); } - + $this->migrationService = new MigrationService('cookbook', $this->connection); $this->assertIsObject($this->migrationService); - + // Reinstall app partially (just before the migration) $migrationBefore = $this->getPreviousMigrationName(); if (! empty($migrationBefore)) { @@ -86,54 +86,54 @@ public function setUp(): void { $this->renewSchema(); } } - + protected function tearDown(): void { unset($this->container); unset($this->db); unset($this->migrationService); unset($this->connection); } - + protected function renewSchema(): void { $this->schema = new SchemaWrapper($this->connection); } - + private function enableApp() { runOCCCommand(['app:enable', 'cookbook']); } - + private function hideMigrations() { if (! file_exists(self::TMP_MIGRATIONS)) { mkdir(self::TMP_MIGRATIONS); } - + exec('mv lib/Migration/* ' . self::TMP_MIGRATIONS); } - + private function restoreMigrations() { exec('mv ' . self::TMP_MIGRATIONS . '/* lib/Migration'); } - + private function resetSQLite(): void { $allTables = $this->schema->getTables(); $tables = array_filter($allTables, function (Table $t) { return str_starts_with($t->getName(), 'oc_cookbook'); }); - + /** * @var Table $t */ foreach ($tables as $t) { $this->schema->dropTable(preg_replace('/^oc_/', '', $t->getName())); } - + $qb = $this->db->getQueryBuilder(); $qb->delete('migrations')->where('app = :app'); $qb->setParameter('app', 'cookbook'); $qb->execute(); - + $this->schema->performDropTableCalls(); - + $this->renewSchema(); } } diff --git a/tests/Migration/Setup/Migrations/Version000000Date20190312140601Test.php b/tests/Migration/Setup/Migrations/Version000000Date20190312140601Test.php index 13101fabc..ca8d033c3 100644 --- a/tests/Migration/Setup/Migrations/Version000000Date20190312140601Test.php +++ b/tests/Migration/Setup/Migrations/Version000000Date20190312140601Test.php @@ -5,32 +5,31 @@ include_once __DIR__ . '/AbstractMigrationTestCase.php'; class Version000000Date20190312140601Test extends AbstractMigrationTestCase { - /** * @runInSeparateProcess * @covers \OCA\Cookbook\Migration\Version000000Date20190312140601 */ public function testCreatedTables() { - + // Run the migration under test $this->migrationService->migrate('000000Date20190312140601'); $this->renewSchema(); - + $this->postTestAsserts('cookbook_recipes'); $this->postTestAsserts('cookbook_keywords'); } - + private function postTestAsserts(string $tableName): void { $this->assertTrue($this->schema->hasTable($tableName)); - + $table = $this->schema->getTable($tableName); $this->assertTrue($table->hasColumn('recipe_id')); $this->assertTrue($table->hasColumn('name')); - + $this->assertTrue($table->getColumn('recipe_id')->getNotnull()); $this->assertTrue($table->getColumn('name')->getNotnull()); } - + protected function getPreviousMigrationName(): ?string { return null; } diff --git a/tests/Migration/Setup/Migrations/Version000000Date20190910100911Test.php b/tests/Migration/Setup/Migrations/Version000000Date20190910100911Test.php index de76e929b..174eb5c91 100644 --- a/tests/Migration/Setup/Migrations/Version000000Date20190910100911Test.php +++ b/tests/Migration/Setup/Migrations/Version000000Date20190910100911Test.php @@ -5,7 +5,6 @@ include_once __DIR__ . '/AbstractMigrationTestCase.php'; class Version000000Date20190910100911Test extends AbstractMigrationTestCase { - /** * @runInSeparateProcess * @covers \OCA\Cookbook\Migration\Version000000Date20190910100911 @@ -13,21 +12,21 @@ class Version000000Date20190910100911Test extends AbstractMigrationTestCase { public function testAddedUserIdToTables() { $this->preTestAsserts('cookbook_recipes'); $this->preTestAsserts('cookbook_keywords'); - + // Run the migration under test $this->migrationService->migrate('000000Date20190910100911'); $this->renewSchema(); - + $this->postTestAsserts('cookbook_recipes'); $this->postTestAsserts('cookbook_keywords'); } - + private function preTestAsserts(string $tableName): void { $this->assertTrue($this->schema->hasTable($tableName)); $table = $this->schema->getTable($tableName); $this->assertFalse($table->hasColumn('user_id')); } - + private function postTestAsserts(string $tableName): void { $this->assertTrue($this->schema->hasTable($tableName)); $table = $this->schema->getTable($tableName); @@ -35,7 +34,7 @@ private function postTestAsserts(string $tableName): void { $column = $table->getColumn('user_id'); $this->assertTrue($column->getNotnull()); } - + protected function getPreviousMigrationName(): string { return '000000Date20190312140601'; } diff --git a/tests/Migration/Setup/Migrations/Version000000Date20190910223344Test.php b/tests/Migration/Setup/Migrations/Version000000Date20190910223344Test.php index 1c45671b8..3eb8573f3 100644 --- a/tests/Migration/Setup/Migrations/Version000000Date20190910223344Test.php +++ b/tests/Migration/Setup/Migrations/Version000000Date20190910223344Test.php @@ -5,7 +5,6 @@ include_once __DIR__ . '/AbstractMigrationTestCase.php'; class Version000000Date20190910223344Test extends AbstractMigrationTestCase { - /** * @runInSeparateProcess * @covers \OCA\Cookbook\Migration\Version000000Date20190910223344 @@ -13,25 +12,25 @@ class Version000000Date20190910223344Test extends AbstractMigrationTestCase { public function testDropPrimaryKeyFromTables() { $this->assertTrue($this->schema->hasTable('cookbook_recipes')); $this->assertFalse($this->schema->hasTable('cookbook_names')); - + // Run the migration under test $this->migrationService->migrate('000000Date20190910223344'); $this->renewSchema(); - + $this->assertFalse($this->schema->hasTable('cookbook_recipes')); $this->assertTrue($this->schema->hasTable('cookbook_names')); - + $table = $this->schema->getTable('cookbook_names'); - + $this->assertTrue($table->hasColumn('recipe_id')); $this->assertTrue($table->hasColumn('name')); $this->assertTrue($table->hasColumn('user_id')); - + $this->assertTrue($table->getColumn('recipe_id')->getNotnull()); $this->assertTrue($table->getColumn('name') ->getNotnull()); $this->assertTrue($table->getColumn('user_id') ->getNotnull()); } - + protected function getPreviousMigrationName(): string { return '000000Date20190910100911'; } diff --git a/tests/Migration/Setup/Migrations/Version000000Date20200315121603Test.php b/tests/Migration/Setup/Migrations/Version000000Date20200315121603Test.php index 04e376c6a..ec29ea136 100644 --- a/tests/Migration/Setup/Migrations/Version000000Date20200315121603Test.php +++ b/tests/Migration/Setup/Migrations/Version000000Date20200315121603Test.php @@ -5,31 +5,30 @@ include_once __DIR__ . '/AbstractMigrationTestCase.php'; class Version000000Date20200315121603Test extends AbstractMigrationTestCase { - /** * @runInSeparateProcess * @covers \OCA\Cookbook\Migration\Version000000Date20200315121603 */ public function testAddCategoriesTable() { $this->assertFalse($this->schema->hasTable('cookbook_categories')); - + // Run the migration under test $this->migrationService->migrate('000000Date20210427082010'); $this->renewSchema(); - + $this->assertTrue($this->schema->hasTable('cookbook_categories')); - + $table = $this->schema->getTable('cookbook_categories'); - + $this->assertTrue($table->hasColumn('recipe_id')); $this->assertTrue($table->hasColumn('name')); $this->assertTrue($table->hasColumn('user_id')); - + $this->assertTrue($table->getColumn('recipe_id')->getNotnull()); $this->assertTrue($table->getColumn('name') ->getNotnull()); $this->assertTrue($table->getColumn('user_id') ->getNotnull()); } - + protected function getPreviousMigrationName(): string { return '000000Date20190910223344'; } diff --git a/tests/Migration/Setup/Migrations/Version000000Date20210427082010Test.php b/tests/Migration/Setup/Migrations/Version000000Date20210427082010Test.php index 7b5ea8e3b..d36f72376 100644 --- a/tests/Migration/Setup/Migrations/Version000000Date20210427082010Test.php +++ b/tests/Migration/Setup/Migrations/Version000000Date20210427082010Test.php @@ -5,7 +5,6 @@ include_once __DIR__ . '/AbstractMigrationTestCase.php'; class Version000000Date20210427082010Test extends AbstractMigrationTestCase { - /** * @runInSeparateProcess * @covers \OCA\Cookbook\Migration\Version000000Date20210427082010 @@ -14,21 +13,21 @@ public function testAddIndexToTables() { $categoriesTable = $this->schema->getTable('cookbook_categories'); $this->assertFalse($categoriesTable->hasIndex('categories_recipe_idx')); $this->assertEquals([], $categoriesTable->getIndexes()); - + $keywordsTable = $this->schema->getTable('cookbook_keywords'); $this->assertFalse($keywordsTable->hasIndex('keywords_recipe_idx')); $this->assertEquals([], $keywordsTable->getIndexes()); - + // Run the migration under test $this->migrationService->migrate('000000Date20210427082010'); $this->renewSchema(); - + $categoriesTable = $this->schema->getTable('cookbook_categories'); $keywordsTable = $this->schema->getTable('cookbook_keywords'); $this->assertTrue($categoriesTable->hasIndex('categories_recipe_idx')); $this->assertTrue($keywordsTable->hasIndex('keywords_recipe_idx')); } - + protected function getPreviousMigrationName(): string { return '000000Date20200315121603'; } diff --git a/tests/Migration/Setup/Migrations/Version000000Date20210701093123Test.php b/tests/Migration/Setup/Migrations/Version000000Date20210701093123Test.php index f06b0376b..82a5a46f0 100644 --- a/tests/Migration/Setup/Migrations/Version000000Date20210701093123Test.php +++ b/tests/Migration/Setup/Migrations/Version000000Date20210701093123Test.php @@ -7,11 +7,12 @@ include_once __DIR__ . '/AbstractMigrationTestCase.php'; class Version000000Date20210701093123Test extends AbstractMigrationTestCase { - /** * @dataProvider dataProvider * @runInSeparateProcess * @covers \OCA\Cookbook\Migration\Version000000Date20210701093123 + * @param mixed $data + * @param mixed $updatedUsers */ public function testRedundantEntriesInDB($data, $updatedUsers) { // Add recipe dummy data from data provider @@ -26,13 +27,13 @@ public function testRedundantEntriesInDB($data, $updatedUsers) { foreach ($data as $d) { $qb->setParameter('user', $d[0]); $qb->setParameter('recipe', $d[1]); - + $this->assertEquals(1, $qb->execute()); } - + // Initialize configuration values to track reindex timestamps $current = time(); - + $qb = $this->db->getQueryBuilder(); $qb->insert('preferences') ->values([ @@ -41,11 +42,11 @@ public function testRedundantEntriesInDB($data, $updatedUsers) { 'configkey' => ':property', 'configvalue' => ':value', ]); - + $qb->setParameter('value', $current, IQueryBuilder::PARAM_STR); $qb->setParameter('appid', 'cookbook'); $qb->setParameter('property', 'last_index_update'); - + $users = array_unique(array_map(function ($x) { return $x[0]; }, $data)); @@ -53,10 +54,10 @@ public function testRedundantEntriesInDB($data, $updatedUsers) { $qb->setParameter('user', $u); $this->assertEquals(1, $qb->execute()); } - + // Run the migration under test $this->migrationService->migrate('000000Date20210701093123'); - + // Get the (updated) reindex timestamps $qb = $this->db->getQueryBuilder(); $qb->select('userid', 'configvalue') @@ -67,10 +68,10 @@ public function testRedundantEntriesInDB($data, $updatedUsers) { ); $qb->setParameter('appid', 'cookbook'); $qb->setParameter('property', 'last_index_update'); - + $cursor = $qb->execute(); $result = $cursor->fetchAll(); - + // Filter those entries from the configuration that were marked as to be reindexed $result = array_filter($result, function ($x) use ($current) { return $x['configvalue'] < $current; @@ -79,14 +80,14 @@ public function testRedundantEntriesInDB($data, $updatedUsers) { $changedUsers = array_map(function ($x) { return $x['userid']; }, $result); - + // Sort the arrays to allow comparision of them sort($changedUsers); sort($updatedUsers); - + $this->assertEquals($updatedUsers, $changedUsers); } - + public function dataProvider() { return [ 'caseA' => [ @@ -128,7 +129,7 @@ public function dataProvider() { ], ]; } - + protected function getPreviousMigrationName(): string { return '000000Date20210427082010'; } diff --git a/tests/Unit/Controller/ConfigControllerTest.php b/tests/Unit/Controller/ConfigControllerTest.php index 68ac7851f..992c7d795 100644 --- a/tests/Unit/Controller/ConfigControllerTest.php +++ b/tests/Unit/Controller/ConfigControllerTest.php @@ -20,7 +20,6 @@ * @covers :: */ class ConfigControllerTest extends TestCase { - /** * @var ConfigController|MockObject */ @@ -119,6 +118,10 @@ public function testList(): void { /** * @dataProvider dataProviderConfig * @covers ::config + * @param mixed $data + * @param mixed $folderPath + * @param mixed $interval + * @param mixed $printImage */ public function testConfig($data, $folderPath, $interval, $printImage): void { $this->restParser->method('getParameters')->willReturn($data); diff --git a/tests/Unit/Controller/MainControllerTest.php b/tests/Unit/Controller/MainControllerTest.php index b0a8bc25e..54d210b86 100644 --- a/tests/Unit/Controller/MainControllerTest.php +++ b/tests/Unit/Controller/MainControllerTest.php @@ -24,7 +24,6 @@ * @covers \OCA\Cookbook\Exception\UserFolderNotWritableException */ class MainControllerTest extends TestCase { - /** * @var MockObject|RecipeService */ @@ -110,7 +109,7 @@ public function testGetAPIVersion(): void { public function testGetCategories(): void { $this->ensureCacheCheckTriggered(); - + $cat = ['Foo', 'Bar', 'Baz']; $this->recipeService->expects($this->once())->method('getAllCategoriesInSearchIndex')->willReturn($cat); @@ -121,7 +120,7 @@ public function testGetCategories(): void { public function testGetKeywords(): void { $this->ensureCacheCheckTriggered(); - + $kw = ['Foo', 'Bar', 'Baz']; $this->recipeService->expects($this->once())->method('getAllKeywordsInSearchIndex')->willReturn($kw); @@ -132,6 +131,8 @@ public function testGetKeywords(): void { /** * @dataProvider dataProviderNew + * @param mixed $data + * @param mixed $id */ public function testNew($data, $id): void { $this->ensureCacheCheckTriggered(); @@ -163,6 +164,8 @@ public function dataProviderNew() { /** * @dataProvider dataProviderNew + * @param mixed $data + * @param mixed $id */ public function testNewFailed($data, $id): void { $this->ensureCacheCheckTriggered(); @@ -183,6 +186,8 @@ public function testNewFailed($data, $id): void { /** * @dataProvider dataProviderUpdate + * @param mixed $data + * @param mixed $id */ public function testUpdate($data, $id): void { $this->ensureCacheCheckTriggered(); @@ -214,6 +219,8 @@ public function dataProviderUpdate() { /** * @dataProvider dataProviderUpdate + * @param mixed $data + * @param mixed $id */ public function testUpdateFailed($data, $id): void { $this->ensureCacheCheckTriggered(); @@ -316,12 +323,14 @@ public function testImportOther(): void { /** * @dataProvider dataProviderCategory + * @param mixed $cat + * @param mixed $recipes */ public function testCategory($cat, $recipes): void { $this->ensureCacheCheckTriggered(); $this->recipeService->method('getRecipesByCategory')->with($cat)->willReturn($recipes); - + $expected = $this->getExpectedRecipes($recipes); /** @@ -387,7 +396,7 @@ public function testCategoryFailed(): void { $cat = 'My category'; $errorMsg = 'The error is found.'; $this->recipeService->method('getRecipesByCategory')->with($cat)->willThrowException(new Exception($errorMsg)); - + /** * @var DataResponse $ret */ @@ -396,15 +405,17 @@ public function testCategoryFailed(): void { $this->assertEquals(500, $ret->getStatus()); $this->assertEquals($errorMsg, $ret->getData()); } - + /** * @dataProvider dataProviderTags + * @param mixed $keywords + * @param mixed $recipes */ public function testTags($keywords, $recipes): void { $this->ensureCacheCheckTriggered(); $this->recipeService->method('getRecipesByKeywords')->with($keywords)->willReturn($recipes); - + $expected = $this->getExpectedRecipes($recipes); /** @@ -450,14 +461,14 @@ public function dataProviderTags(): array { ], ]; } - + public function testTagsFailed(): void { $this->ensureCacheCheckTriggered(); $keywords = 'Tag 1,Tag B'; $errorMsg = 'The error is found.'; $this->recipeService->method('getRecipesByKeywords')->with($keywords)->willThrowException(new Exception($errorMsg)); - + /** * @var DataResponse $ret */ @@ -470,6 +481,8 @@ public function testTagsFailed(): void { /** * @dataProvider dpSearch * @todo no implementation in controller + * @param mixed $query + * @param mixed $recipes */ public function testSearch($query, $recipes): void { $this->ensureCacheCheckTriggered(); @@ -504,7 +517,7 @@ public function dpSearch() { ], ]; } - + public function testSearchFailed(): void { $this->ensureCacheCheckTriggered(); @@ -523,6 +536,7 @@ public function testSearchFailed(): void { /** * @dataProvider dataProviderCategoryUpdateNoName + * @param mixed $requestParams */ public function testCategoryUpdateNoName($requestParams): void { $this->ensureCacheCheckTriggered(); @@ -546,6 +560,9 @@ public function dataProviderCategoryUpdateNoName() { /** * @dataProvider dpCategoryUpdate * @todo No business logic in controller + * @param mixed $cat + * @param mixed $oldCat + * @param mixed $recipes */ public function testCategoryUpdate($cat, $oldCat, $recipes): void { $this->ensureCacheCheckTriggered(); diff --git a/tests/Unit/Controller/RecipeControllerTest.php b/tests/Unit/Controller/RecipeControllerTest.php index 182cd8900..74b53d2e8 100644 --- a/tests/Unit/Controller/RecipeControllerTest.php +++ b/tests/Unit/Controller/RecipeControllerTest.php @@ -237,7 +237,7 @@ public function testShowFailure(): void { $id = 123; $this->recipeService->method('getRecipeById')->with($id)->willReturn(null); - + /** * @var DataResponse $ret */ @@ -278,6 +278,8 @@ public function testDestroyFailed(): void { * @dataProvider dataProviderImage * @todo Assert on image data/file name * @todo Avoid business code in controller + * @param mixed $setSize + * @param mixed $size */ public function testImage($setSize, $size): void { $this->ensureCacheCheckTriggered(); @@ -327,6 +329,8 @@ public function dpImageNotFound() { /** * @dataProvider dpImageNotFound + * @param mixed $accept + * @param mixed $expectedStatus */ public function testImageNotFound($accept, $expectedStatus) { $id = 123; @@ -348,6 +352,9 @@ public function testImageNotFound($accept, $expectedStatus) { /** * @dataProvider dataProviderIndex * @todo no work on controller + * @param mixed $recipes + * @param mixed $setKeywords + * @param mixed $keywords */ public function testIndex($recipes, $setKeywords, $keywords): void { $this->ensureCacheCheckTriggered(); diff --git a/tests/Unit/Helper/AcceptHeaderParsingHelperTest.php b/tests/Unit/Helper/AcceptHeaderParsingHelperTest.php index 98aac11a7..519d298d3 100644 --- a/tests/Unit/Helper/AcceptHeaderParsingHelperTest.php +++ b/tests/Unit/Helper/AcceptHeaderParsingHelperTest.php @@ -6,7 +6,6 @@ use PHPUnit\Framework\TestCase; class AcceptHeaderParsingHelperTest extends TestCase { - /** * @var AcceptHeaderParsingHelper */ @@ -42,6 +41,8 @@ public function dataProvider() { /** * @dataProvider dataProvider + * @param mixed $header + * @param mixed $expected */ public function testParseHeader($header, $expected) { $this->assertEquals($expected, $this->dut->parseHeader($header)); diff --git a/tests/Unit/Helper/HTMLFilter/HtmlEntityDecodeFilterTest.php b/tests/Unit/Helper/HTMLFilter/HtmlEntityDecodeFilterTest.php index 9b863e5e4..98128c3ad 100644 --- a/tests/Unit/Helper/HTMLFilter/HtmlEntityDecodeFilterTest.php +++ b/tests/Unit/Helper/HTMLFilter/HtmlEntityDecodeFilterTest.php @@ -9,9 +9,9 @@ * @covers \OCA\Cookbook\Helper\HTMLFilter\HtmlEntityDecodeFilter */ class HtmlEntityDecodeFilterTest extends TestCase { - /** * @dataProvider dataProvider + * @param mixed $testString */ public function testDecoder($testString): void { $sut = new HtmlEntityDecodeFilter(); @@ -28,6 +28,8 @@ public function dataProvider() { /** * @dataProvider dataProviderExplicit + * @param mixed $encoded + * @param mixed $expected */ public function testDecoderExplicit($encoded, $expected): void { $sut = new HtmlEntityDecodeFilter(); diff --git a/tests/Unit/Helper/HTMLParser/HttpJsonLdParserTest.php b/tests/Unit/Helper/HTMLParser/HttpJsonLdParserTest.php index f47a4eb7c..bd0fe3d47 100644 --- a/tests/Unit/Helper/HTMLParser/HttpJsonLdParserTest.php +++ b/tests/Unit/Helper/HTMLParser/HttpJsonLdParserTest.php @@ -29,7 +29,7 @@ public function dataProvider(): array { 'caseI' => ['caseI.html', true, 'caseI.json'], ]; } - + /** * @covers ::__construct * @covers \OCA\Cookbook\Helper\HTMLParser\AbstractHtmlParser::__construct @@ -43,18 +43,21 @@ public function testConstructor(): void { * @var IL10N $l */ $l = $this->createStub(IL10N::class); - + $parser = new HttpJsonLdParser($l, $jsonService); - + $lProperty = new \ReflectionProperty(HttpJsonLdParser::class, 'l'); $lProperty->setAccessible(true); $lSaved = $lProperty->getValue($parser); $this->assertSame($l, $lSaved); } - + /** * @dataProvider dataProvider * @covers ::parse + * @param mixed $file + * @param mixed $valid + * @param mixed $jsonFile */ public function testHTMLFile($file, $valid, $jsonFile): void { $jsonService = new JsonService(); @@ -62,20 +65,20 @@ public function testHTMLFile($file, $valid, $jsonFile): void { * @var IL10N $l */ $l = $this->createStub(IL10N::class); - + $parser = new HttpJsonLdParser($l, $jsonService); - + $content = file_get_contents(__DIR__ . "/res_JsonLd/$file"); - + $document = new \DOMDocument(); $document->loadHTML($content); - + try { $res = $parser->parse($document); - + $jsonDest = file_get_contents(__DIR__ . "/res_JsonLd/$jsonFile"); $expected = json_decode($jsonDest, true); - + $this->assertTrue($valid); $this->assertEquals($expected, $res); } catch (HtmlParsingException $ex) { diff --git a/tests/Unit/Helper/HTMLParser/HttpMicrodataParserTest.php b/tests/Unit/Helper/HTMLParser/HttpMicrodataParserTest.php index d0e04b5f8..b7e1353f9 100644 --- a/tests/Unit/Helper/HTMLParser/HttpMicrodataParserTest.php +++ b/tests/Unit/Helper/HTMLParser/HttpMicrodataParserTest.php @@ -16,22 +16,21 @@ * */ class HttpMicrodataParserTest extends TestCase { - /** * @covers ::__construct * @covers \OCA\Cookbook\Helper\HTMLParser\AbstractHtmlParser */ public function testConstructor(): void { $l = $this->createStub(IL10N::class); - + $parser = new HttpMicrodataParser($l); - + $lProperty = new \ReflectionProperty(HttpMicrodataParser::class, 'l'); $lProperty->setAccessible(true); $lSaved = $lProperty->getValue($parser); $this->assertSame($l, $lSaved); } - + public function dataProvider(): array { return [ 'caseA' => ['caseA.html',true,'caseA.json'], @@ -41,109 +40,116 @@ public function dataProvider(): array { 'caseE' => ['caseE.html',true,'caseE.json'], ]; } - + /** * @dataProvider dataProvider * @covers ::parse + * @param mixed $filename + * @param mixed $valid + * @param mixed $jsonFile */ public function testHTMLFile($filename, $valid, $jsonFile): void { $l = $this->createStub(IL10N::class); - + $parser = new HttpMicrodataParser($l); - + $content = file_get_contents(__DIR__ . "/res_Microdata/$filename"); - + $document = new \DOMDocument(); $document->loadHTML($content); - + try { $res = $parser->parse($document); - + $jsonDest = file_get_contents(__DIR__ . "/res_Microdata/$jsonFile"); $expected = json_decode($jsonDest, true); - + $this->assertTrue($valid); $this->assertEquals($expected, $res); } catch (HtmlParsingException $ex) { $this->assertFalse($valid); } } - + public function imageAttributes() { return [['image'], ['images'], ['thumbnail']]; } - + /** * @dataProvider imageAttributes + * @param mixed $attribute */ public function testImageVariantsAsAttribute($attribute): void { $l = $this->createStub(IL10N::class); $parser = new HttpMicrodataParser($l); $content = file_get_contents(__DIR__ . "/res_Microdata/caseImageAttribute.html"); $content = str_replace('%IMAGE_NAME%', $attribute, $content); - + $this->finishTest($parser, $content, 'caseImage.json'); } - + /** * @dataProvider imageAttributes + * @param mixed $attribute */ public function testImageVariantsAsContent($attribute): void { $l = $this->createStub(IL10N::class); $parser = new HttpMicrodataParser($l); $content = file_get_contents(__DIR__ . "/res_Microdata/caseImageContent.html"); $content = str_replace('%IMAGE_NAME%', $attribute, $content); - + $this->finishTest($parser, $content, 'caseImage.json'); } - + public function ingredientVariantAttributes() { yield ['recipeIngredient']; yield ['ingredients']; } - + /** * @dataProvider ingredientVariantAttributes * @param string $attrtibute + * @param mixed $attribute */ public function testIngredientVariants($attribute): void { $l = $this->createStub(IL10N::class); $parser = new HttpMicrodataParser($l); $content = file_get_contents(__DIR__ . "/res_Microdata/caseIngredient.html"); $content = str_replace('%INGREDIENT_NAME%', $attribute, $content); - + $this->finishTest($parser, $content, 'caseIngredient.json'); } - + public function instructionVariantAttributes() { yield ['recipeInstructions']; yield ['instructions']; yield ['steps']; yield ['guide']; } - + /** * @dataProvider instructionVariantAttributes + * @param mixed $attribute */ public function testInstructionVariants($attribute): void { $l = $this->createStub(IL10N::class); $parser = new HttpMicrodataParser($l); $content = file_get_contents(__DIR__ . "/res_Microdata/caseInstruction.html"); $content = str_replace('%INSTRUCTION_NAME%', $attribute, $content); - + $this->finishTest($parser, $content, 'caseInstruction.json'); } - + private function finishTest($parser, $content, $jsonFile): void { $document = new \DOMDocument(); $document->loadHTML($content); - + try { $res = $parser->parse($document); - + $jsonDest = file_get_contents(__DIR__ . "/res_Microdata/$jsonFile"); $expected = json_decode($jsonDest, true); - + $this->assertEquals($expected, $res); } catch (HtmlParsingException $ex) { $this->assertFalse(true); diff --git a/tests/Unit/Helper/HtmlToDomParserTest.php b/tests/Unit/Helper/HtmlToDomParserTest.php index 33fe58a76..48def0472 100644 --- a/tests/Unit/Helper/HtmlToDomParserTest.php +++ b/tests/Unit/Helper/HtmlToDomParserTest.php @@ -46,7 +46,6 @@ public function clearErrors(): void { * @covers :: */ class HtmlToDomParserTest extends TestCase { - /** * @var ILogger|MockObject */ @@ -84,7 +83,7 @@ public function setUp(): void { $this->sut = new HtmlToDomParser($this->logger, $this->l); } - + /** * @covers ::__construct */ @@ -102,6 +101,11 @@ public function testConstructor(): void { * @covers ::loadHtmlString * @covers ::getState * @dataProvider dataProviderParsing + * @param mixed $successDomParsing + * @param mixed $stateAtEnd + * @param mixed $errors + * @param mixed $numErrors + * @param mixed $expectsError */ public function testParsing($successDomParsing, $stateAtEnd, $errors, $numErrors, $expectsError) { /** @@ -116,18 +120,18 @@ public function testParsing($successDomParsing, $stateAtEnd, $errors, $numErrors ->method('useInternalErrors') ->withConsecutive([true], [false]) ->willReturnOnConsecutiveCalls(false, true); - - + + $this->xmlMock->expects($this->once()) ->method('getErrors') ->willReturn($errors); - + if ($expectsError) { $this->expectException(Exception::class); } else { $this->xmlMock->expects($this->once()) ->method('clearErrors'); - + $this->logger->expects($this->exactly($numErrors[2])) ->method('info'); $this->logger->expects($this->exactly($numErrors[1])) @@ -138,7 +142,7 @@ public function testParsing($successDomParsing, $stateAtEnd, $errors, $numErrors $url = 'http://example.com/recipe'; $html = 'Foo Bar Baz'; - + $this->assertEquals(4, $this->sut->getState()); try { @@ -271,7 +275,7 @@ public function testLogging(): void { $this->getXMLError(6, LIBXML_ERR_WARNING, '/file', 1, 2, 'The message'), $this->getXMLError(6, LIBXML_ERR_WARNING, '/file', 1, 2, 'The message'), ]); - + $url = 'http://example.com/recipe'; $this->l->method('n')->willReturnArgument(1); @@ -288,7 +292,7 @@ public function testLogging(): void { ->method('error'); $html = 'Foo Bar Baz'; - + $this->assertEquals(4, $this->sut->getState()); $this->sut->loadHtmlString($dom, $url, $html); @@ -304,6 +308,10 @@ public function dpSingleLogging() { /** * @dataProvider dpSingleLogging + * @param mixed $errorLevel + * @param mixed $logWarn + * @param mixed $logErr + * @param mixed $logCrit */ public function testSingleLogging($errorLevel, $logWarn, $logErr, $logCrit) { /** @@ -315,7 +323,7 @@ public function testSingleLogging($errorLevel, $logWarn, $logErr, $logCrit) { $this->xmlMock->method('getErrors')->willReturn([ $this->getXMLError(2, $errorLevel, '/file', 1, 2, 'The message'), ]); - + $url = 'http://example.com/recipe'; $this->l->method('n')->willReturnArgument(0); @@ -352,13 +360,17 @@ public function testSingleLogging($errorLevel, $logWarn, $logErr, $logCrit) { } $html = 'Foo Bar Baz'; - + $this->sut->loadHtmlString($dom, $url, $html); $this->assertEquals($errorLevel, $this->sut->getState()); } /** * @dataProvider dpSingleLogging + * @param mixed $errorLevel + * @param mixed $logWarn + * @param mixed $logErr + * @param mixed $logCrit */ public function testMultipleLogging($errorLevel, $logWarn, $logErr, $logCrit) { /** @@ -371,7 +383,7 @@ public function testMultipleLogging($errorLevel, $logWarn, $logErr, $logCrit) { $this->getXMLError(2, $errorLevel, '/file', 1, 2, 'The message'), $this->getXMLError(2, $errorLevel, '/file', 10, 20, 'The new message'), ]); - + $url = 'http://example.com/recipe'; $this->l->method('n')->willReturnArgument(1); @@ -408,7 +420,7 @@ public function testMultipleLogging($errorLevel, $logWarn, $logErr, $logCrit) { } $html = 'Foo Bar Baz'; - + $this->sut->loadHtmlString($dom, $url, $html); $this->assertEquals($errorLevel, $this->sut->getState()); } diff --git a/tests/Unit/Helper/ImageService/ImageFileHelperTest.php b/tests/Unit/Helper/ImageService/ImageFileHelperTest.php index a5d517121..ecdae658a 100644 --- a/tests/Unit/Helper/ImageService/ImageFileHelperTest.php +++ b/tests/Unit/Helper/ImageService/ImageFileHelperTest.php @@ -17,7 +17,6 @@ * @covers OCA\Cookbook\Exception\RecipeImageExistsException */ class ImageFileHelperTest extends TestCase { - /** * @var ImageFileHelper */ @@ -47,6 +46,7 @@ public function dpExisting() { /** * @dataProvider dpExisting + * @param mixed $present */ public function testHasImage($present) { $this->folder->method('nodeExists')->with('full.jpg')->willReturn($present); @@ -62,6 +62,7 @@ public function testGetImage() { /** * @dataProvider dpExisting + * @param mixed $existing */ public function testDropImage($existing) { /** @@ -69,7 +70,7 @@ public function testDropImage($existing) { */ $file = $this->createMock(File::class); $this->folder->method('nodeExists')->with('full.jpg')->willReturn($existing); - + if ($existing) { $this->folder->method('get')->with('full.jpg')->willReturn($file); $file->expects($this->once())->method('delete'); @@ -83,6 +84,7 @@ public function testDropImage($existing) { /** * @dataProvider dpExisting + * @param mixed $existing */ public function testCreateImage($existing) { $this->folder->method('nodeExists')->with('full.jpg')->willReturn($existing); diff --git a/tests/Unit/Helper/ImageService/ImageGenerationHelperTest.php b/tests/Unit/Helper/ImageService/ImageGenerationHelperTest.php index 607c8a89e..20e87a706 100644 --- a/tests/Unit/Helper/ImageService/ImageGenerationHelperTest.php +++ b/tests/Unit/Helper/ImageService/ImageGenerationHelperTest.php @@ -16,7 +16,6 @@ * @covers OCA\Cookbook\Helper\ImageService\ImageGenerationHelper */ class ImageGenerationHelperTest extends TestCase { - /** * @var ThumbnailService|MockObject */ @@ -40,6 +39,7 @@ public function dpThumbnails() { /** * @dataProvider dpThumbnails + * @param mixed $type */ public function testThumbnailGeneration($type) { /** @@ -96,6 +96,8 @@ public function dpDropExisting() { /** * @dataProvider dpDropExisting + * @param mixed $type + * @param mixed $filename */ public function testDropThumbnailExisting($type, $filename) { /** @@ -117,6 +119,8 @@ public function testDropThumbnailExisting($type, $filename) { /** * @dataProvider dpDropExisting + * @param mixed $type + * @param mixed $filename */ public function testDropThumbnailNonExisting($type, $filename) { /** diff --git a/tests/Unit/Helper/ImageService/ThumbnailFileHelperTest.php b/tests/Unit/Helper/ImageService/ThumbnailFileHelperTest.php index e774b93b8..92dc1c7ca 100644 --- a/tests/Unit/Helper/ImageService/ThumbnailFileHelperTest.php +++ b/tests/Unit/Helper/ImageService/ThumbnailFileHelperTest.php @@ -20,7 +20,6 @@ * @covers OCA\Cookbook\Exception\NoRecipeImageFoundException */ class ThumbnailFileHelperTest extends TestCase { - /** * @var ThumbnailFileHelper */ @@ -66,6 +65,8 @@ public function dpFilename() { /** * @dataProvider dpFilename + * @param mixed $type + * @param mixed $filename */ public function testGetThumbnailWithExistingThumbnail($type, $filename) { /** @@ -82,6 +83,8 @@ public function testGetThumbnailWithExistingThumbnail($type, $filename) { /** * @dataProvider dpFilename + * @param mixed $type + * @param mixed $filename */ public function testGetThumbnailWithNonExistingThumbnail($type, $filename) { /** @@ -93,7 +96,7 @@ public function testGetThumbnailWithNonExistingThumbnail($type, $filename) { $file = $this->createStub(File::class); $f->method('newFile')->with($filename)->willReturn($file); - + $this->fileHelper->method('hasImage')->willReturn(true); $full = $this->createStub(File::class); $this->fileHelper->method('getImage')->willReturn($full); @@ -106,6 +109,8 @@ public function testGetThumbnailWithNonExistingThumbnail($type, $filename) { /** * @dataProvider dpFilename + * @param mixed $type + * @param mixed $filename */ public function testGetThumbnailWithNonExistingMainImage($type, $filename) { /** @@ -136,6 +141,8 @@ public function dpDrop() { /** * @dataProvider dpDrop + * @param mixed $thumbExists + * @param mixed $miniExists */ public function testDropThumbnails($thumbExists, $miniExists) { /** @@ -171,6 +178,8 @@ public function testDropThumbnails($thumbExists, $miniExists) { /** * @dataProvider dpDrop + * @param mixed $thumbExists + * @param mixed $miniExists */ public function testRecreateThumbnails($thumbExists, $miniExists) { /** @@ -197,7 +206,7 @@ public function testRecreateThumbnails($thumbExists, $miniExists) { ['thumb16.jpg', $mini], ]; $f->method('get')->willReturnMap($fileMap); - + $cnt = 0; if (! $thumbExists) { $cnt ++; diff --git a/tests/Unit/Helper/UserConfigHelperTest.php b/tests/Unit/Helper/UserConfigHelperTest.php index 0d799704c..60563d394 100644 --- a/tests/Unit/Helper/UserConfigHelperTest.php +++ b/tests/Unit/Helper/UserConfigHelperTest.php @@ -24,7 +24,7 @@ class UserConfigHelperTest extends TestCase { * @var string */ private $userId; - + /** * @var MockObject|IConfig */ @@ -39,7 +39,7 @@ protected function setUp(): void { $this->userId = 'myuserid'; $this->config = $this->createMock(IConfig::class); - + $this->l = $this->createStub(IL10N::class); $this->l->method('t')->willReturnArgument(0); @@ -53,10 +53,10 @@ public function testLastIndexUpdate() { $this->config->expects($this->exactly(2))->method('getUserValue') ->with($this->userId, 'cookbook', 'last_index_update') ->willReturnOnConsecutiveCalls(strval($originalValue), strval($saveValue)); - + $this->config->expects($this->once())->method('setUserValue') ->with($this->userId, 'cookbook', 'last_index_update', strval($saveValue)); - + $this->assertEquals($originalValue, $this->dut->getLastIndexUpdate()); $this->dut->setLastIndexUpdate($saveValue); $this->assertEquals($saveValue, $this->dut->getLastIndexUpdate()); @@ -66,7 +66,7 @@ public function testLastIndexUpdateUnset() { $this->config->expects($this->once())->method('getUserValue') ->with($this->userId, 'cookbook', 'last_index_update') ->willReturn(''); - + $this->assertEquals(0, $this->dut->getLastIndexUpdate()); } @@ -77,10 +77,10 @@ public function testUpdateInterval() { $this->config->expects($this->exactly(2))->method('getUserValue') ->with($this->userId, 'cookbook', 'update_interval') ->willReturnOnConsecutiveCalls(strval($originalValue), strval($saveValue)); - + $this->config->expects($this->once())->method('setUserValue') ->with($this->userId, 'cookbook', 'update_interval', strval($saveValue)); - + $this->assertEquals($originalValue, $this->dut->getUpdateInterval()); $this->dut->setUpdateInterval($saveValue); $this->assertEquals($saveValue, $this->dut->getUpdateInterval()); @@ -90,21 +90,21 @@ public function testUpdateIntervalUnset() { $this->config->expects($this->once())->method('getUserValue') ->with($this->userId, 'cookbook', 'update_interval') ->willReturn(''); - + $this->assertEquals(5, $this->dut->getUpdateInterval()); } - + public function testPrintImage() { $this->config->expects($this->exactly(3))->method('getUserValue') ->with($this->userId, 'cookbook', 'print_image') ->willReturnOnConsecutiveCalls('0', '1', '0'); - + $this->config->expects($this->exactly(2))->method('setUserValue') ->withConsecutive( [$this->userId, 'cookbook', 'print_image', '1'], [$this->userId, 'cookbook', 'print_image', '0'] ); - + $this->assertFalse($this->dut->getPrintImage()); $this->dut->setPrintImage(true); $this->assertTrue($this->dut->getPrintImage()); @@ -116,7 +116,7 @@ public function testPrintImageUnset() { $this->config->expects($this->once())->method('getUserValue') ->with($this->userId, 'cookbook', 'print_image') ->willReturn(''); - + $this->assertTrue($this->dut->getPrintImage()); } @@ -127,10 +127,10 @@ public function testFolderName() { $this->config->expects($this->exactly(2))->method('getUserValue') ->with($this->userId, 'cookbook', 'folder') ->willReturnOnConsecutiveCalls($originalValue, $saveValue); - + $this->config->expects($this->once())->method('setUserValue') ->with($this->userId, 'cookbook', 'folder', $saveValue); - + $this->assertEquals($originalValue, $this->dut->getFolderName()); $this->dut->setFolderName($saveValue); $this->assertEquals($saveValue, $this->dut->getFolderName()); @@ -140,10 +140,10 @@ public function testFolderNameUnset() { $this->config->expects($this->once())->method('getUserValue') ->with($this->userId, 'cookbook', 'folder') ->willReturn(''); - + $this->config->expects($this->once())->method('setUserValue') ->with($this->userId, 'cookbook', 'folder', '/Recipes'); - + $this->assertEquals('/Recipes', $this->dut->getFolderName()); } @@ -152,7 +152,7 @@ public function testNoUser() { $this->config->expects($this->never())->method('getUserValue'); $this->config->expects($this->never())->method('setUserValue'); - + $this->expectException(UserNotLoggedInException::class); $this->dut->getFolderName(); } diff --git a/tests/Unit/Helper/UserFolderHelperTest.php b/tests/Unit/Helper/UserFolderHelperTest.php index dda28cb75..da12682d9 100644 --- a/tests/Unit/Helper/UserFolderHelperTest.php +++ b/tests/Unit/Helper/UserFolderHelperTest.php @@ -24,7 +24,6 @@ * @covers \OCA\Cookbook\Exception\UserFolderNotWritableException */ class UserFolderHelperTest extends TestCase { - /** * @var UserConfigHelper|MockObject */ @@ -50,11 +49,11 @@ class UserFolderHelperTest extends TestCase { protected function setUp(): void { parent::setup(); - + $this->userId = 'test_user-id'; - + $this->root = $this->createMock(IRootFolder::class); - + $l = $this->createMock(IL10N::class); /** * @var MockObject|IL10N $l @@ -106,6 +105,7 @@ public function dpExisting() { /** * @dataProvider dpExisting + * @param mixed $existing */ public function testUncachedPath($existing) { /** @@ -135,7 +135,7 @@ public function testUncachedPath($existing) { public function testNoWritingPermissionGetFolder() { $path = '/Recipes'; $fullPath = "/{$this->userId}/files/Recipes"; - + $ex = new NotFoundException(); $this->root->method('get')->with($fullPath)->willThrowException($ex); $ex1 = new NotPermittedException(); @@ -154,7 +154,7 @@ public function testWrongTypeGetFolder() { $nodeStub = $this->createStub(Folder::class); $path = '/Recipes'; $fullPath = "/{$this->userId}/files/Recipes"; - + $ex = new NotFoundException(); $this->root->method('get')->with($fullPath)->willReturn($nodeStub); @@ -173,7 +173,7 @@ public function testReadOnlyGetFolder() { $nodeStub = $this->createStub(Folder::class); $path = '/Recipes'; $fullPath = "/{$this->userId}/files/Recipes"; - + $ex = new NotFoundException(); $this->root->method('get')->with($fullPath)->willReturn($nodeStub); diff --git a/tests/Unit/Service/HtmlDownloadServiceTest.php b/tests/Unit/Service/HtmlDownloadServiceTest.php index 5f5c8997b..54d4a6852 100644 --- a/tests/Unit/Service/HtmlDownloadServiceTest.php +++ b/tests/Unit/Service/HtmlDownloadServiceTest.php @@ -33,7 +33,6 @@ public function getIt($url, $internal, $context) { * @covers :: */ class HtmlDownloadServiceTest extends TestCase { - /** * @var HtmlEntityDecodeFilter|MockObject */ @@ -61,7 +60,7 @@ class HtmlDownloadServiceTest extends TestCase { public static $instance; /** - * @var boolean + * @var bool */ private $runRealFunction; @@ -133,6 +132,11 @@ public function triggerGetContent($path, $useInternalPath, $context) { * @covers ::downloadRecipe * @covers ::getDom * @covers \OCA\Cookbook\Exception\ImportException + * @param mixed $url + * @param mixed $urlValid + * @param mixed $fetchedValue + * @param mixed $parserState + * @param mixed $fetchValid */ public function testFakeDownload($url, $urlValid, $fetchedValue, $parserState, $fetchValid): void { $this->runRealFunction = false; @@ -197,6 +201,7 @@ public function dataProviderFakeDownload() { /** * @dataProvider dataProviderRealDownload * @covers ::downloadRecipe + * @param mixed $data */ public function testRealDownload($data) { $url = 'http://www/test.html'; diff --git a/tests/Unit/Service/ImageServiceTest.php b/tests/Unit/Service/ImageServiceTest.php index 3615bec01..c5d78c8e5 100644 --- a/tests/Unit/Service/ImageServiceTest.php +++ b/tests/Unit/Service/ImageServiceTest.php @@ -16,7 +16,6 @@ * @covers \OCA\Cookbook\Service\ImageService */ class ImageServiceTest extends TestCase { - /** * @var MockObject|ImageFileHelper */ @@ -70,6 +69,7 @@ public function dpThumbnailSizes() { /** * @dataProvider dpThumbnailSizes + * @param mixed $type */ public function testGetThumbnailAsFile($type) { $recipeFolder = $this->createStub(Folder::class); @@ -80,6 +80,7 @@ public function testGetThumbnailAsFile($type) { /** * @dataProvider dpThumbnailSizes + * @param mixed $type */ public function testGetThumbnail($type) { $recipeFolder = $this->createStub(Folder::class); @@ -100,6 +101,7 @@ public function dpHasImage() { /** * @dataProvider dpHasImage + * @param mixed $present */ public function testHasImage($present) { $recipeFolder = $this->createStub(Folder::class); diff --git a/tests/Unit/Service/JsonServiceTest.php b/tests/Unit/Service/JsonServiceTest.php index 89fa6d301..497b63e24 100644 --- a/tests/Unit/Service/JsonServiceTest.php +++ b/tests/Unit/Service/JsonServiceTest.php @@ -6,7 +6,6 @@ use OCA\Cookbook\Service\JsonService; class JsonServiceTest extends TestCase { - /** * @var JsonService */ @@ -33,7 +32,7 @@ public function testIsSchemaObject() { ]; $result = $this->service->isSchemaObject($testData); self::assertFalse($result, 'The object must have a context'); - + // Context must be in schema.org domain $testData = [ "@context" => "https://schema.com/", @@ -46,7 +45,7 @@ public function testIsSchemaObject() { ]; $result = $this->service->isSchemaObject($testData); self::assertFalse($result, 'The object must be in the correct context'); - + // Objects must have a property @type $testData = [ "@context" => "https://schema.org/", @@ -58,7 +57,7 @@ public function testIsSchemaObject() { ]; $result = $this->service->isSchemaObject($testData); self::assertFalse($result, 'The object must have the property @type'); - + // No typecheck will be requested $testData = [ "@context" => "https://schema.org/", @@ -105,7 +104,7 @@ public function testHasProperty() { self::assertTrue($result, 'Property name was not found.'); $result = $this->service->hasProperty($testData, 'Bar'); self::assertFalse($result, 'Property Bar was falsely found.'); - + $result = $this->service->hasProperty(['foo' => 'bar'], 'foo'); self::assertFalse($result, 'Property of a non-object must not be returned.'); } diff --git a/tests/Unit/Service/RecipeExtractionServiceTest.php b/tests/Unit/Service/RecipeExtractionServiceTest.php index 4159a1e9d..193c473ce 100644 --- a/tests/Unit/Service/RecipeExtractionServiceTest.php +++ b/tests/Unit/Service/RecipeExtractionServiceTest.php @@ -10,12 +10,11 @@ use OCA\Cookbook\Service\RecipeExtractionService; class RecipeExtractionServiceTest extends TestCase { - /** * @var IL10N */ private $l; - + protected function setUp(): void { $this->l = $this->createStub(IL10N::class); } @@ -29,7 +28,7 @@ protected function setUp(): void { public function testParsingDelegation($jsonSuccess, $microdataSuccess, $exceptionExpected): void { $jsonParser = $this->createMock(HttpJsonLdParser::class); $microdataParser = $this->createMock(HttpMicrodataParser::class); - + $document = $this->createStub(\DOMDocument::class); $expectedObject = [new \stdClass()]; @@ -38,14 +37,14 @@ public function testParsingDelegation($jsonSuccess, $microdataSuccess, $exceptio ->method('parse') ->with($document) ->willReturn($expectedObject); - + $microdataParser->expects($this->never())->method('parse'); } else { $jsonParser->expects($this->once()) ->method('parse') ->with($document) ->willThrowException(new HtmlParsingException()); - + if ($microdataSuccess) { $microdataParser->expects($this->once()) ->method('parse') @@ -58,18 +57,18 @@ public function testParsingDelegation($jsonSuccess, $microdataSuccess, $exceptio ->willThrowException(new HtmlParsingException()); } } - + $sut = new RecipeExtractionService($jsonParser, $microdataParser, $this->l); - + try { $ret = $sut->parse($document); - + $this->assertEquals($expectedObject, $ret); } catch (HtmlParsingException $ex) { $this->assertTrue($exceptionExpected); } } - + public function dataProvider() { return [ [true, false, false], diff --git a/tests/Unit/Service/ThumbnailServiceTest.php b/tests/Unit/Service/ThumbnailServiceTest.php index 4dfc8d5d4..dfb17e68c 100644 --- a/tests/Unit/Service/ThumbnailServiceTest.php +++ b/tests/Unit/Service/ThumbnailServiceTest.php @@ -17,7 +17,6 @@ * @covers OCA\Cookbook\Exception\InvalidThumbnailTypeException */ class ThumbnailServiceTest extends TestCase { - /** * @var ThumbnailService|MockObject */ @@ -61,6 +60,8 @@ public function dpTypes() { /** * @dataProvider dpTypes + * @param mixed $type + * @param mixed $size */ public function testgetThumbnail($type, $size) { /** @@ -99,6 +100,7 @@ public function dpInvalidTypes() { /** * @dataProvider dpInvalidTypes + * @param mixed $type */ public function testGetThumbnailInvalidType($type) { $this->expectException(InvalidThumbnailTypeException::class); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 1d5b63131..f49cc8026 100755 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -25,9 +25,9 @@ function runOCCCommand(array $args, bool $forceprint = false) { $params = join(' ', array_map(function ($x) { return escapeshellarg($x); }, $args)); - + $cmd = "./.github/actions/run-tests/run-occ.sh $params 2>&1"; - + exec($cmd, $output, $ret); if ($ret !== 0 || $forceprint) { echo "\nStandard output:\n";