Version 5.1 - All the GraphQL #32

Closed
timw4mail wants to merge 1160 commits from develop into master
13 changed files with 213 additions and 37 deletions
Showing only changes of commit 7990b3ad68 - Show all commits

View File

@ -2,16 +2,16 @@
/**
* Hummingbird Anime List Client
*
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
* An API client for Kitsu to manage anime and manga watch lists
*
* PHP version 7
* PHP version 8
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2017 Timothy J. Warren
* @copyright 2015 - 2021 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 4.0
* @link https://github.com/timw4mail/HummingBirdAnimeClient
* @version 5.2
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
*/
use function Aviat\AnimeClient\loadConfig;
@ -21,12 +21,13 @@ use function Aviat\AnimeClient\loadConfig;
//
// You shouldn't generally need to change anything below this line
// ----------------------------------------------------------------------------
$APP_DIR = realpath(__DIR__ . '/../');
$ROOT_DIR = realpath("{$APP_DIR}/../");
$APP_DIR = dirname(__DIR__);
$ROOT_DIR = dirname($APP_DIR);
$tomlConfig = loadConfig(__DIR__);
return array_merge($tomlConfig, [
'root' => $ROOT_DIR,
'asset_dir' => "{$ROOT_DIR}/public",
'base_config_dir' => __DIR__,
'config_dir' => "{$APP_DIR}/config",

View File

@ -2,15 +2,15 @@
/**
* Hummingbird Anime List Client
*
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
* An API client for Kitsu to manage anime and manga watch lists
*
* PHP version 7
* PHP version 8
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2018 Timothy J. Warren
* @copyright 2015 - 2021 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 4.0
* @version 5.2
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
*/

View File

@ -34,11 +34,11 @@ use Psr\SimpleCache\CacheInterface;
use function Aviat\Ion\_dir;
if ( ! defined('APP_DIR'))
if ( ! defined('HB_APP_DIR'))
{
define('APP_DIR', __DIR__);
define('ROOT_DIR', dirname(APP_DIR));
define('TEMPLATE_DIR', _dir(APP_DIR, 'templates'));
define('HB_APP_DIR', __DIR__);
define('ROOT_DIR', dirname(HB_APP_DIR));
define('TEMPLATE_DIR', _dir(HB_APP_DIR, 'templates'));
}
// -----------------------------------------------------------------------------
@ -50,7 +50,7 @@ return static function (array $configArray = []): Container {
// -------------------------------------------------------------------------
// Logging
// -------------------------------------------------------------------------
$LOG_DIR = _dir(APP_DIR, 'logs');
$LOG_DIR = _dir(HB_APP_DIR, 'logs');
$appLogger = new Logger('animeclient');
$appLogger->pushHandler(new RotatingFileHandler(_dir($LOG_DIR, 'app.log'), 2, Logger::WARNING));

View File

@ -2,6 +2,7 @@
declare(strict_types=1);
$file_patterns = [
'app/appConf/*.php',
'app/bootstrap.php',
'migrations/*.php',
'src/**/*.php',
@ -16,7 +17,7 @@ if ( ! function_exists('glob_recursive'))
{
// Does not support flag GLOB_BRACE
function glob_recursive($pattern, $flags = 0)
function glob_recursive(string $pattern, int $flags = 0): array
{
$files = glob($pattern, $flags);
@ -57,17 +58,21 @@ function get_text_to_replace(array $tokens): string
return $output;
}
function get_tokens($source): array
function get_tokens(string $source): array
{
return token_get_all($source);
}
function replace_files(array $files, $template)
function replace_files(array $files, string $template): void
{
print_r($files);
foreach ($files as $file)
{
$source = file_get_contents($file);
if ($source === FALSE)
{
continue;
}
if (stripos($source, 'namespace') === FALSE)
{

View File

@ -4,6 +4,7 @@ parameters:
inferPrivatePropertyTypeFromConstructor: true
level: 8
paths:
- app/appConf
- src
- ./console
- index.php

View File

@ -186,7 +186,7 @@ function checkFolderPermissions(ConfigInterface $config): array
$errors = [];
$publicDir = $config->get('asset_dir');
$APP_DIR = _dir(dirname(__DIR__, 2), '/app');
$APP_DIR = _dir($config->get('root'), 'app');
$pathMap = [
'app/config' => "{$APP_DIR}/config",
@ -211,7 +211,9 @@ function checkFolderPermissions(ConfigInterface $config): array
if ( ! $writable)
{
// @codeCoverageIgnoreStart
$errors['writable'][] = $pretty;
// @codeCoverageIgnoreEnd
}
}
@ -292,6 +294,7 @@ function getLocalImg (string $kitsuUrl, $webp = TRUE): string
/**
* Create a transparent placeholder image
*
* @codeCoverageIgnore
* @param string $path
* @param int|null $width
* @param int|null $height
@ -378,7 +381,6 @@ function colNotEmpty(array $search, string $key): bool
*
* @param CacheInterface $cache
* @return bool
* @throws Throwable
*/
function clearCache(CacheInterface $cache): bool
{
@ -393,9 +395,7 @@ function clearCache(CacheInterface $cache): bool
$userData = array_filter((array)$userData, static fn ($value) => $value !== NULL);
$cleared = $cache->clear();
$saved = ( ! empty($userData))
? $cache->setMultiple($userData)
: TRUE;
$saved = ( ! empty($userData)) ? $cache->setMultiple($userData) : TRUE;
return $cleared && $saved;
}

View File

@ -236,6 +236,9 @@ abstract class AbstractType implements ArrayAccess, Countable {
return TRUE;
}
/**
* @codeCoverageIgnore
*/
final protected function fromObject(mixed $parent = null): float|null|bool|int|array|string
{
$object = $parent ?? $this;

View File

@ -32,6 +32,8 @@ class Config extends AbstractType {
// Settings in config.toml
// ------------------------------------------------------------------------
public string $root; // Path to app root
public ?string $asset_path; // Path to public folder for urls
/**
@ -62,8 +64,6 @@ class Config extends AbstractType {
/**
* Default list view type
* 'cover_view' or 'list_view'
*
* @var string
*/
public ?string $default_view_type;
@ -71,21 +71,13 @@ class Config extends AbstractType {
public bool $secure_urls = TRUE;
/**
* @var string|bool
*/
public string|bool $show_anime_collection = FALSE;
/**
* @var string|bool
*/
public string|bool $show_manga_collection = FALSE;
/**
* CSS theme: light, dark, or auto-switching
* 'auto', 'light', or 'dark'
*
* @var string|null
*/
public ?string $theme = 'auto';

View File

@ -16,9 +16,11 @@
namespace Aviat\AnimeClient\Tests;
use Amp\Http\Client\Response;
use function Aviat\AnimeClient\arrayToToml;
use function Aviat\AnimeClient\checkFolderPermissions;
use function Aviat\AnimeClient\clearCache;
use function Aviat\AnimeClient\colNotEmpty;
use function Aviat\AnimeClient\getLocalImg;
use function Aviat\AnimeClient\getResponse;
use function Aviat\AnimeClient\isSequentialArray;
use function Aviat\AnimeClient\tomlToArray;
@ -89,4 +91,46 @@ class AnimeClientTest extends AnimeClientTestCase
{
$this->assertNotEmpty(getResponse('https://example.com'));
}
public function testCheckFolderPermissions(): void
{
$config = $this->container->get('config');
$actual = checkFolderPermissions($config);
$this->assertTrue(is_array($actual));
}
public function testGetLocalImageEmptyUrl(): void
{
$actual = getLocalImg('');
$this->assertEquals('images/placeholder.webp', $actual);
}
public function testGetLocalImageBadUrl(): void
{
$actual = getLocalImg('//foo.bar');
$this->assertEquals('images/placeholder.webp', $actual);
}
public function testColNotEmpty(): void
{
$hasEmptyCols = [[
'foo' => '',
], [
'foo' => '',
]];
$hasNonEmptyCols = [[
'foo' => 'bar',
], [
'foo' => 'baz',
]];
$this->assertEquals(false, colNotEmpty($hasEmptyCols, 'foo'));
$this->assertEquals(true, colNotEmpty($hasNonEmptyCols, 'foo'));
}
public function testClearCache(): void
{
$this->assertTrue(clearCache($this->container->get('cache')));
}
}

View File

@ -16,6 +16,7 @@
namespace Aviat\AnimeClient\Tests;
use Aviat\Ion\Di\ContainerInterface;
use function Aviat\Ion\_dir;
use Aviat\Ion\Json;
@ -59,6 +60,7 @@ class AnimeClientTestCase extends TestCase {
parent::setUp();
$config_array = [
'root' => self::ROOT_DIR,
'asset_path' => '/assets',
'img_cache_path' => _dir(self::ROOT_DIR, 'public/images'),
'data_cache_path' => _dir(self::TEST_DATA_DIR, 'cache'),
@ -94,7 +96,7 @@ class AnimeClientTestCase extends TestCase {
];
// Set up DI container
$di = require _dir(self::ROOT_DIR, 'app', 'bootstrap.php');
$di = require self::ROOT_DIR . '/app/bootstrap.php';
$container = $di($config_array);
// Use mock session handler

View File

@ -0,0 +1,53 @@
<?php declare(strict_types=1);
/**
* Hummingbird Anime List Client
*
* An API client for Kitsu to manage anime and manga watch lists
*
* PHP version 8
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2021 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 5.2
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient\Tests\Types;
use Aviat\AnimeClient\Types\Config;
use Aviat\AnimeClient\Types\UndefinedPropertyException;
class ConfigTest extends ConfigTestCase {
public function setUp(): void
{
parent::setUp();
$this->testClass = Config::class;
}
public function testSetMethods(): void
{
$type = $this->testClass::from([
'anilist' => [],
'cache' => [],
'database' => [],
]);
$this->assertEquals(3, $type->count());
}
public function testOffsetUnset(): void
{
$type = $this->testClass::from([
'anilist' => [],
]);
$this->assertTrue($type->offsetExists('anilist'));
$type->offsetUnset('anilist');
$this->assertNotTrue($type->offsetExists('anilist'));
}
}

View File

@ -0,0 +1,72 @@
<?php declare(strict_types=1);
/**
* Hummingbird Anime List Client
*
* An API client for Kitsu to manage anime and manga watch lists
*
* PHP version 8
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2021 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 5.2
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient\Tests\Types;
use Aviat\AnimeClient\Tests\AnimeClientTestCase;
use Aviat\AnimeClient\Types\UndefinedPropertyException;
abstract class ConfigTestCase extends AnimeClientTestCase {
public string $testClass;
public function testCheck(): void
{
$result = $this->testClass::check([]);
$this->assertEquals([], $result);
}
public function testSetUndefinedProperty(): void
{
$this->expectException(UndefinedPropertyException::class);
$this->testClass::from([
'foobar' => 'baz',
]);
}
public function testToString(): void
{
$actual = $this->testClass::from([])->__toString();
$this->assertMatchesSnapshot($actual);
}
public function testOffsetExists(): void
{
$actual = $this->testClass::from([
'anilist' => [],
])->offsetExists('anilist');
$this->assertTrue($actual);
}
public function testSetState(): void
{
$normal = $this->testClass::from([]);
$setState = $this->testClass::__set_state([]);
$this->assertEquals($normal, $setState);
}
public function testIsEmpty(): void
{
$type = $this->testClass::from([]);
$this->assertTrue($type->isEmpty());
}
public function testCount(): void
{
$type = $this->testClass::from([]);
$this->assertEquals(0, $type->count());
}
}

View File

@ -0,0 +1,3 @@
Aviat\AnimeClient\Types\Config Object
(
)