Version 5.1 - All the GraphQL #32

Closed
timw4mail wants to merge 1160 commits from develop into master
21 changed files with 288 additions and 247 deletions
Showing only changes of commit afbde14116 - Show all commits

View File

@ -1,7 +1,7 @@
language: php
install:
- composer install --no-dev
- composer install
php:
- 5.5
@ -17,7 +17,7 @@ before_script:
script:
- mkdir -p build/logs
- phpunit -c build
services:
- redis

View File

@ -67,11 +67,11 @@ class LogicalOperatorAndSniff implements Sniff
$error_message = 'Logical operator should be in upper case;'
. ' use "' . strtoupper($operator_string)
. '" instead of "' . $operator_string . '"';
$phpcsFile->addError($error_message, $stackPtr);
$phpcsFile->addError($error_message, $stackPtr, 'LowercaseLogicalOperator');
}
$warning_message = 'The symbolic form "&&" is preferred over the literal form "AND"';
$phpcsFile->addWarning($warning_message, $stackPtr);
$phpcsFile->addWarning($warning_message, $stackPtr, 'UseOfLiteralAndOperator');
}//end process()

View File

@ -72,7 +72,7 @@ class StrictComparisonOperatorSniff implements Sniff
$error_message = '"==" and "!=" are prohibited; use "'
. self::$_replacements[$operator_code] . '" instead of "'
. $operator_string . '".';
$phpcsFile->addError($error_message, $stackPtr);
$phpcsFile->addError($error_message, $stackPtr, 'NonStrictComparisonUsed');
}//end process()

View File

@ -77,7 +77,7 @@ class DisallowSpaceIndentSniff implements Sniff
if (strpos($tokens[$stackPtr]['content'], " ") !== false) {
$error = 'Tabs must be used to indent lines; spaces are not allowed for code indentation';
$phpcsFile->addError($error, $stackPtr);
$phpcsFile->addError($error, $stackPtr, 'SpacesUsedForIndentation');
}
}//end process()

View File

@ -8,7 +8,7 @@
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2016 Timothy J. Warren
* @link https://github.com/timw4mail/HummingBirdAnimeClient
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.1
* @license MIT
* @link https://github.com/timw4mail/HummingBirdAnimeClient
*/

View File

@ -25,6 +25,8 @@
<!-- One statement per line -->
<rule ref="Generic.Formatting.DisallowMultipleStatements"/>
<!-- Classes and functions should be commented -->
<rule ref="PEAR.Commenting.ClassComment">
<exclude name="PEAR.Commenting.ClassComment.MissingCategoryTag" />
@ -37,9 +39,10 @@
<!-- Exclude this sniff because it doesn't understand multiple types -->
<exclude name="PEAR.Commenting.FunctionComment.MissingParamComment" />
<exclude name="PEAR.Commenting.FunctionComment.SpacingAfterParamType" />
<exclude name="PEAR.Commenting.FunctionComment.SpacingAfterParamName" />
</rule>
<!-- Use warnings for docblock comments for files and variables, since nothing is cleary explained -->
<!-- Use warnings for docblock comments for files and variables, since nothing is clearly explained -->
<rule ref="PEAR.Commenting.FileComment">
<exclude name="PEAR.Commenting.FileComment.InvalidVersion" />
<exclude name="PEAR.Commenting.FileComment.MissingCategoryTag" />
@ -58,7 +61,9 @@
<!-- Use Allman style indenting. With the exception of Class declarations,
braces are always placed on a line by themselves, and indented at the same level as the control statement that "owns" them. -->
<rule ref="Generic.Functions.OpeningFunctionBraceBsdAllman"/>
<rule ref="PEAR.WhiteSpace.ScopeClosingBrace"/>
<rule ref="PEAR.WhiteSpace.ScopeClosingBrace">
<exclude name="PEAR.WhiteSpace.ScopeClosingBrace.BreakIndent" />
</rule>
<rule ref="Generic.Functions.FunctionCallArgumentSpacing"/>
<!-- Use only short array syntax -->

View File

@ -2,9 +2,9 @@
$animeclient_file_patterns = [
'app/config/*.php',
'app/booststrap.php',
'app/bootstrap.php',
'src/functions.php',
'src/Aviat/AnimeClient/*.php'
'src/*.php'
];
if ( ! function_exists('glob_recursive'))

View File

@ -4,15 +4,17 @@
*
* An API client for Hummingbird to manage anime and manga watch lists
*
* PHP version 5.6
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren
* @copyright Copyright (c) 2015 - 2016
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2016 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.1
* @link https://github.com/timw4mail/HummingBirdAnimeClient
* @license MIT
*/
use Aviat\AnimeClient\AnimeClient;
use Whoops\Handler\PrettyPageHandler;
use Whoops\Handler\JsonResponseHandler;
// Work around the silly timezone error
$timezone = ini_get('date.timezone');

View File

@ -8,10 +8,11 @@
<target>phpdoc</target>
</transformer>
<transformations>
<template name="clean" />
<template name="zend" />
</transformations>
<files>
<directory>src</directory>
<directory>vendor/aviat/ion</directory>
<directory>vendor/aviat/ion/src</directory>
<directory>vendor/container-interop/container-interop/src</directory>
</files>
</phpdoc>

View File

@ -22,14 +22,32 @@ use Aviat\AnimeClient\Util;
*/
class CacheImages extends BaseCommand {
/**
* Manga Model
*
* @var Aviat\AnimeClient\Model\Manga
*/
protected $mangaModel;
/**
* Anime Model
*
* @var Aviat\AnimeClient\Model\Anime
*/
protected $animeModel;
/**
* Miscellaneous helper methods
*
* @var Aviat\AnimeClient\Util
*/
protected $util;
/*
/**
* Convert manga images
*
* @throws \ConsoleKit\ConsoleException
* @return void
*/
protected function getMangaImages()
{
@ -51,6 +69,7 @@ class CacheImages extends BaseCommand {
* Convert anime images
*
* @throws \ConsoleKit\ConsoleException
* @return void
*/
protected function getAnimeImages()
{

View File

@ -19,6 +19,7 @@ use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\View\HttpView;
use Aviat\Ion\View\HtmlView;
use Aviat\Ion\View\JsonView;
use Doctrine\Instantiator\Exception\InvalidArgumentException;
/**
* Controller base, defines output methods
@ -60,7 +61,7 @@ class Controller {
protected $model;
/**
* Url generatation class
* Url generation class
* @var UrlGenerator
*/
protected $urlGenerator;
@ -117,6 +118,8 @@ class Controller {
/**
* Redirect to the default controller/url from an empty path
*
* @return void
*/
public function redirect_to_default()
{
@ -151,7 +154,7 @@ class Controller {
}
$util = $this->container->get('util');
$double_form_page = $server_params['HTTP_REFERER'] == $this->request->getUri();
$double_form_page = $server_params['HTTP_REFERER'] === $this->request->getUri();
// Don't attempt to set the redirect url if
// the page is one of the form type pages,
@ -214,6 +217,7 @@ class Controller {
* @param HtmlView $view
* @param string $template
* @param array $data
* @throws \InvalidArgumentException
* @return string
*/
protected function load_partial($view, $template, array $data = [])
@ -273,7 +277,7 @@ class Controller {
$view = new HtmlView($this->container);
if ($status != "")
if ($status !== "")
{
$message = $this->show_message($view, 'error', $status);
}

View File

@ -42,6 +42,7 @@ class Anime extends BaseController {
/**
* Data cache
* @var Aviat\Ion\Cache\CacheInterface
*/
protected $cache;
@ -103,7 +104,7 @@ class Anime extends BaseController {
'list' => 'list'
];
$data = ($type != 'all')
$data = ($type !== 'all')
? $this->cache->get($this->model, 'get_list', ['status' => $model_map[$type]])
: $this->cache->get($this->model, 'get_all_lists', []);
@ -251,6 +252,8 @@ class Anime extends BaseController {
/**
* Update an anime item
*
* @return void
*/
public function update()
{
@ -261,12 +264,14 @@ class Anime extends BaseController {
/**
* Remove an anime from the list
*
* @return void
*/
public function delete()
{
$response = $this->model->delete($this->request->getParsedBody());
if ($response['body'] == TRUE)
if ((bool)$response['body'] === TRUE)
{
$this->set_flash_message("Successfully deleted anime.", 'success');
$this->cache->purge();

View File

@ -177,11 +177,11 @@ class Manga extends Controller {
*
* @return void
*/
public function search()
{
public function search()
{
$query_data = $this->request->getQueryParams();
$this->outputJSON($this->model->search($query_data['query']));
}
$this->outputJSON($this->model->search($query_data['query']));
}
/**
* Update an anime item via a form submission
@ -200,7 +200,7 @@ class Manga extends Controller {
$result = Json::decode((string)$full_result['body']);
if ($full_result['statusCode'] == 200)
if ((int)$full_result['statusCode'] === 200)
{
$m =& $result['manga'][0];
$title = ( ! empty($m['english_title']))
@ -232,12 +232,14 @@ class Manga extends Controller {
/**
* Remove an manga from the list
*
* @return void
*/
public function delete()
{
$response = $this->model->delete($this->request->getParsedBody());
if ($response['body'] == TRUE)
if ((bool)$response['body'] === TRUE)
{
$this->set_flash_message("Successfully deleted manga.", 'success');
$this->cache->purge();

View File

@ -138,6 +138,7 @@ class Dispatcher extends RoutingBase {
* the current route
*
* @param \Aura\Router\Route $route
* @throws \LogicException
* @return array
*/
protected function process_route($route)

View File

@ -17,13 +17,9 @@ namespace Aviat\AnimeClient\Model;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\ResponseInterface;
use GuzzleHttp\Exception\ClientException;
use Psr\Http\Message\ResponseInterface;
use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\Cache\CacheInterface;
use Aviat\Ion\Model;
use Aviat\AnimeClient\AnimeClient;
@ -166,7 +162,7 @@ class API extends Model {
*/
protected function sort_by_name(&$array, $sort_key)
{
$sort = array();
$sort = [];
foreach ($array as $key => $item)
{

View File

@ -59,7 +59,7 @@ class Anime extends API {
public function update($data)
{
$auth = $this->container->get('auth');
if ( ! $auth->is_authenticated() || ! array_key_exists('id', $data))
if ( ! $auth->is_authenticated() OR ! array_key_exists('id', $data))
{
return FALSE;
}
@ -86,7 +86,7 @@ class Anime extends API {
public function delete($data)
{
$auth = $this->container->get('auth');
if ( ! $auth->is_authenticated() || ! array_key_exists('id', $data))
if ( ! $auth->is_authenticated() OR ! array_key_exists('id', $data))
{
return FALSE;
}
@ -176,7 +176,7 @@ class Anime extends API {
*
* @param string $name
* @return array
* @throws RuntimeException
* @throws \RuntimeException
*/
public function search($name)
{
@ -190,12 +190,12 @@ class Anime extends API {
$response = $this->get('search/anime', $config);
if ($response->getStatusCode() != 200)
if ((int) $response->getStatusCode() !== 200)
{
$logger->warning("Non 200 response for search api call");
$logger->warning($response->getBody());
throw new RuntimeException($response->getEffectiveUrl());
throw new \RuntimeException($response->getEffectiveUrl());
}
return Json::decode($response->getBody(), TRUE);
@ -214,7 +214,7 @@ class Anime extends API {
'allow_redirects' => FALSE
];
if ($status != "all")
if ($status !== "all")
{
$config['query']['status'] = $status;
}
@ -250,11 +250,6 @@ class Anime extends API {
];
$username = $this->config->get('hummingbird_username');
/*$auth = $this->container->get('auth');
if ($auth->is_authenticated())
{
$config['query']['auth_token'] = $auth->get_auth_token();
}*/
$response = $this->get("users/{$username}/library", $config);
return Json::decode($response->getBody(), TRUE);
@ -264,7 +259,7 @@ class Anime extends API {
* Handle transforming of api data
*
* @param string $status
* @param \GuzzleHttp\Message\Response
* @param \GuzzleHttp\Message\Response $response
* @return array
*/
protected function transform($status, $response)

View File

@ -218,7 +218,7 @@ class AnimeCollection extends Collection {
*/
private function json_import()
{
if ( ! file_exists('import.json') || ! $this->valid_database)
if ( ! file_exists('import.json') OR ! $this->valid_database)
{
return;
}

View File

@ -32,7 +32,7 @@ class Collection extends DB {
/**
* Whether the database is valid for querying
* @var bool
* @var boolean
*/
protected $valid_database = FALSE;

View File

@ -144,7 +144,7 @@ class Manga extends API {
*
* @param string $name
* @return array
* @throws RuntimeException
* @throws \RuntimeException
*/
public function search($name)
{
@ -160,7 +160,7 @@ class Manga extends API {
$response = $this->get('search.json', $config);
if ($response->getStatusCode() != 200)
if ((int) $response->getStatusCode() !== 200)
{
$logger->warning("Non 200 response for search api call");
$logger->warning($response->getBody());

View File

@ -24,6 +24,7 @@ class UrlGenerator extends RoutingBase {
/**
* The current HTTP host
* @var string
*/
protected $host;
@ -43,7 +44,7 @@ class UrlGenerator extends RoutingBase {
*
* @return string
*/
public function asset_url(/*...*/)
public function asset_url()
{
$args = func_get_args();
$base_url = rtrim($this->url(""), '/');
@ -106,6 +107,7 @@ class UrlGenerator extends RoutingBase {
* Full default path for the list pages
*
* @param string $type
* @throws \InvalidArgumentException
* @return string
*/
public function default_url($type)

View File

@ -1,195 +1,204 @@
<?php
/**
* Hummingbird Anime Client
*
* An API client for Hummingbird to manage anime and manga watch lists
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren
* @copyright Copyright (c) 2015 - 2016
* @link https://github.com/timw4mail/HummingBirdAnimeClient
* @license MIT
*/
namespace Aviat\AnimeClient;
use abeautifulsite\SimpleImage;
use Aviat\Ion\ConfigInterface;
use Aviat\Ion\Di\ContainerInterface;
/**
* Utility method class
*/
class Util {
use \Aviat\Ion\Di\ContainerAware;
private static $form_pages = [
'edit',
'add',
'update',
'update_form',
'login',
'logout',
'details'
];
/**
* The config manager
* @var ConfigInterface
*/
private $config;
/**
* Set up the Util class
*
* @param ContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
$this->setContainer($container);
$this->config = $container->get('config');
}
/**
* HTML selection helper function
*
* @param string $a - First item to compare
* @param string $b - Second item to compare
* @return string
*/
public static function is_selected($a, $b)
{
return ($a === $b) ? 'selected' : '';
}
/**
* Inverse of selected helper function
*
* @param string $a - First item to compare
* @param string $b - Second item to compare
* @return string
*/
public static function is_not_selected($a, $b)
{
return ($a !== $b) ? 'selected' : '';
}
/**
* Determine whether to show the sub-menu
*
* @return bool
*/
public function is_view_page()
{
$url = $this->container->get('request')
->getUri();
$page_segments = explode("/", $url);
$intersect = array_intersect($page_segments, self::$form_pages);
return empty($intersect);
}
/**
* Determine whether the page is a page with a form, and
* not suitable for redirection
*
* @return boolean
*/
public function is_form_page()
{
return ! $this->is_view_page();
}
/**
* Get the path of the cached version of the image. Create the cached image
* if the file does not already exist
*
* @codeCoverageIgnore
* @param string $api_path - The original image url
* @param string $series_slug - The part of the url with the series name, becomes the image name
* @param string $type - Anime or Manga, controls cache path
* @return string - the frontend path for the cached image
* @throws DomainException
*/
public function get_cached_image($api_path, $series_slug, $type = "anime")
{
$path_parts = explode('?', basename($api_path));
$path = current($path_parts);
$ext_parts = explode('.', $path);
$ext = end($ext_parts);
// Workaround for some broken file extensions
if ($ext == "jjpg")
{
$ext = "jpg";
}
// Failsafe for weird urls
if (strlen($ext) > 3)
{
return $api_path;
}
$img_cache_path = $this->config->get('img_cache_path');
$cached_image = "{$series_slug}.{$ext}";
$cached_path = "{$img_cache_path}/{$type}/{$cached_image}";
// Cache the file if it doesn't already exist
if ( ! file_exists($cached_path))
{
if (function_exists('curl_init'))
{
$ch = curl_init($api_path);
$fp = fopen($cached_path, 'wb');
curl_setopt_array($ch, [
CURLOPT_FILE => $fp,
CURLOPT_HEADER => 0
]);
curl_exec($ch);
curl_close($ch);
fclose($fp);
}
else if (ini_get('allow_url_fopen'))
{
copy($api_path, $cached_path);
}
else
{
throw new \DomainException("Couldn't cache images because they couldn't be downloaded.");
}
// Resize the image
if ($type == 'anime')
{
$resize_width = 220;
$resize_height = 319;
$this->_resize($cached_path, $resize_width, $resize_height);
}
}
return "/public/images/{$type}/{$cached_image}";
}
/**
* Resize an image
*
* @codeCoverageIgnore
* @param string $path
* @param string $width
* @param string $height
*/
private function _resize($path, $width, $height)
{
try
{
$img = new SimpleImage($path);
$img->resize($width, $height)->save();
}
catch (Exception $e)
{
// Catch image errors, since they don't otherwise affect
// functionality
}
}
<?php
/**
* Hummingbird Anime Client
*
* An API client for Hummingbird to manage anime and manga watch lists
*
* PHP version 5.6
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2016 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.1
* @link https://github.com/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient;
use abeautifulsite\SimpleImage;
use Aviat\Ion\ConfigInterface;
use Aviat\Ion\Di\ContainerInterface;
/**
* Utility method class
*/
class Util {
use \Aviat\Ion\Di\ContainerAware;
/**
* Routes that don't require a second navigation level
* @var array
*/
private static $form_pages = [
'edit',
'add',
'update',
'update_form',
'login',
'logout',
'details'
];
/**
* The config manager
* @var ConfigInterface
*/
private $config;
/**
* Set up the Util class
*
* @param ContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
$this->setContainer($container);
$this->config = $container->get('config');
}
/**
* HTML selection helper function
*
* @param string $a - First item to compare
* @param string $b - Second item to compare
* @return string
*/
public static function is_selected($a, $b)
{
return ($a === $b) ? 'selected' : '';
}
/**
* Inverse of selected helper function
*
* @param string $a - First item to compare
* @param string $b - Second item to compare
* @return string
*/
public static function is_not_selected($a, $b)
{
return ($a !== $b) ? 'selected' : '';
}
/**
* Determine whether to show the sub-menu
*
* @return bool
*/
public function is_view_page()
{
$url = $this->container->get('request')
->getUri();
$page_segments = explode("/", $url);
$intersect = array_intersect($page_segments, self::$form_pages);
return empty($intersect);
}
/**
* Determine whether the page is a page with a form, and
* not suitable for redirection
*
* @return boolean
*/
public function is_form_page()
{
return ! $this->is_view_page();
}
/**
* Get the path of the cached version of the image. Create the cached image
* if the file does not already exist
*
* @codeCoverageIgnore
* @param string $api_path - The original image url
* @param string $series_slug - The part of the url with the series name, becomes the image name
* @param string $type - Anime or Manga, controls cache path
* @return string - the frontend path for the cached image
* @throws \DomainException
*/
public function get_cached_image($api_path, $series_slug, $type = "anime")
{
$path_parts = explode('?', basename($api_path));
$path = current($path_parts);
$ext_parts = explode('.', $path);
$ext = end($ext_parts);
// Workaround for some broken file extensions
if ($ext === "jjpg")
{
$ext = "jpg";
}
// Failsafe for weird urls
if (strlen($ext) > 3)
{
return $api_path;
}
$img_cache_path = $this->config->get('img_cache_path');
$cached_image = "{$series_slug}.{$ext}";
$cached_path = "{$img_cache_path}/{$type}/{$cached_image}";
// Cache the file if it doesn't already exist
if ( ! file_exists($cached_path))
{
if (function_exists('curl_init'))
{
$ch = curl_init($api_path);
$fp = fopen($cached_path, 'wb');
curl_setopt_array($ch, [
CURLOPT_FILE => $fp,
CURLOPT_HEADER => 0
]);
curl_exec($ch);
curl_close($ch);
fclose($fp);
}
else if (ini_get('allow_url_fopen'))
{
copy($api_path, $cached_path);
}
else
{
throw new \DomainException("Couldn't cache images because they couldn't be downloaded.");
}
// Resize the image
if ($type === 'anime')
{
$resize_width = 220;
$resize_height = 319;
$this->_resize($cached_path, $resize_width, $resize_height);
}
}
return "/public/images/{$type}/{$cached_image}";
}
/**
* Resize an image
*
* @codeCoverageIgnore
* @param string $path
* @param string $width
* @param string $height
* @return void
*/
private function _resize($path, $width, $height)
{
try
{
$img = new SimpleImage($path);
$img->resize($width, $height)->save();
}
catch (Exception $e)
{
// Catch image errors, since they don't otherwise affect
// functionality
}
}
}