diff --git a/.php_cs.dist b/.php_cs.dist index 23a98af..0649143 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -25,11 +25,8 @@ $rules = [ ], 'cast_spaces' => ['space' => "single"], 'concat_space' => ['spacing' => "none"], - 'declare_equal_normalize' => ['space' => "none"], 'function_typehint_space' => true, 'list_syntax' => ['syntax' => "short"], - 'lowercase_cast' => true, - 'lowercase_static_reference' => true, 'magic_constant_casing' => true, 'magic_method_casing' => true, 'modernize_types_casting' => true, @@ -43,8 +40,6 @@ $rules = [ 'no_empty_phpdoc' => true, 'no_empty_statement' => true, 'no_extra_blank_lines' => true, // this could probably use more configuration - 'no_leading_import_slash' => true, - 'no_leading_namespace_whitespace' => true, 'no_mixed_echo_print' => ['use' => "echo"], 'no_short_bool_cast' => true, 'no_trailing_comma_in_singleline_array' => true, @@ -58,13 +53,20 @@ $rules = [ 'pow_to_exponentiation' => true, 'return_type_declaration' => ['space_before' => "none"], 'set_type_to_cast' => true, - 'short_scalar_cast' => true, 'standardize_not_equals' => true, 'trailing_comma_in_multiline_array' => true, 'unary_operator_spaces' => true, 'yoda_style' => false, // PSR standard to apply '@PSR2' => true, + // PSR-12 rules; php-cs-fixer does not yet support PSR-12 natively + 'declare_equal_normalize' => ['space' => "none"], + 'lowercase_cast' => true, + 'lowercase_static_reference' => true, + 'no_leading_import_slash' => true, + 'no_leading_namespace_whitespace' => true, + 'short_scalar_cast' => true, + 'visibility_required' => ['elements' => ["const", "property", "method"]], // house exceptions to PSR rules 'braces' => ['position_after_functions_and_oop_constructs' => "same"], 'function_declaration' => ['closure_function_spacing' => "none"], diff --git a/lib/AbstractException.php b/lib/AbstractException.php index 3162345..706465e 100644 --- a/lib/AbstractException.php +++ b/lib/AbstractException.php @@ -7,7 +7,7 @@ declare(strict_types=1); namespace JKingWeb\Arsse; abstract class AbstractException extends \Exception { - const CODES = [ + public const CODES = [ "Exception.uncoded" => -1, "Exception.unknown" => 10000, "Exception.constantUnknown" => 10001, diff --git a/lib/Arsse.php b/lib/Arsse.php index e6e451c..6694722 100644 --- a/lib/Arsse.php +++ b/lib/Arsse.php @@ -7,7 +7,7 @@ declare(strict_types=1); namespace JKingWeb\Arsse; class Arsse { - const VERSION = "0.8.3"; + public const VERSION = "0.8.3"; /** @var Lang */ public static $lang; diff --git a/lib/CLI.php b/lib/CLI.php index 6d08c29..c9a5967 100644 --- a/lib/CLI.php +++ b/lib/CLI.php @@ -10,7 +10,7 @@ use JKingWeb\Arsse\REST\Fever\User as Fever; use JKingWeb\Arsse\ImportExport\OPML; class CLI { - const USAGE = << "boolean", Value::T_STRING => "string", Value::T_FLOAT => "float", VALUE::T_INT => "integer", Value::T_INTERVAL => "interval", ]; - const EXPECTED_TYPES = [ + protected const EXPECTED_TYPES = [ 'dbTimeoutExec' => "double", 'dbTimeoutLock' => "double", 'dbTimeoutConnect' => "double", diff --git a/lib/Database.php b/lib/Database.php index 8bdd437..677e4be 100644 --- a/lib/Database.php +++ b/lib/Database.php @@ -39,23 +39,23 @@ use JKingWeb\Arsse\Misc\URL; */ class Database { /** The version number of the latest schema the interface is aware of */ - const SCHEMA_VERSION = 6; - /** The size of a set of values beyond which the set will be embedded into the query text */ - const LIMIT_SET_SIZE = 25; - /** The length of a string in an embedded set beyond which a parameter placeholder will be used for the string */ - const LIMIT_SET_STRING_LENGTH = 200; + public const SCHEMA_VERSION = 6; /** Makes tag/label association change operations remove members */ - const ASSOC_REMOVE = 0; + public const ASSOC_REMOVE = 0; /** Makes tag/label association change operations add members */ - const ASSOC_ADD = 1; + public const ASSOC_ADD = 1; /** Makes tag/label association change operations replace members */ - const ASSOC_REPLACE = 2; + public const ASSOC_REPLACE = 2; /** A map of database driver short-names and their associated class names */ - const DRIVER_NAMES = [ + public const DRIVER_NAMES = [ 'sqlite3' => \JKingWeb\Arsse\Db\SQLite3\Driver::class, 'postgresql' => \JKingWeb\Arsse\Db\PostgreSQL\Driver::class, 'mysql' => \JKingWeb\Arsse\Db\MySQL\Driver::class, ]; + /** The size of a set of values beyond which the set will be embedded into the query text */ + protected const LIMIT_SET_SIZE = 25; + /** The length of a string in an embedded set beyond which a parameter placeholder will be used for the string */ + protected const LIMIT_SET_STRING_LENGTH = 200; /** @var Db\Driver */ public $db; diff --git a/lib/Db/AbstractStatement.php b/lib/Db/AbstractStatement.php index 1aa7e20..dab1e03 100644 --- a/lib/Db/AbstractStatement.php +++ b/lib/Db/AbstractStatement.php @@ -12,7 +12,7 @@ use JKingWeb\Arsse\Misc\ValueInfo; abstract class AbstractStatement implements Statement { use SQLState; - const TYPE_NORM_MAP = [ + public const TYPE_NORM_MAP = [ self::T_INTEGER => ValueInfo::M_NULL | ValueInfo::T_INT, self::T_STRING => ValueInfo::M_NULL | ValueInfo::T_STRING, self::T_BOOLEAN => ValueInfo::M_NULL | ValueInfo::T_BOOL, diff --git a/lib/Db/Driver.php b/lib/Db/Driver.php index 44a1e98..1488b1b 100644 --- a/lib/Db/Driver.php +++ b/lib/Db/Driver.php @@ -7,11 +7,11 @@ declare(strict_types=1); namespace JKingWeb\Arsse\Db; interface Driver { - const TR_PEND = 0; - const TR_COMMIT = 1; - const TR_ROLLBACK = 2; - const TR_PEND_COMMIT = -1; - const TR_PEND_ROLLBACK = -2; + public const TR_PEND = 0; + public const TR_COMMIT = 1; + public const TR_ROLLBACK = 2; + public const TR_PEND_COMMIT = -1; + public const TR_PEND_ROLLBACK = -2; /** Creates and returns an instance of the class; this is so that either a native or PDO driver may be returned depending on what is available on the server */ public static function create(): Driver; diff --git a/lib/Db/MySQL/Driver.php b/lib/Db/MySQL/Driver.php index 49ed00d..023a281 100644 --- a/lib/Db/MySQL/Driver.php +++ b/lib/Db/MySQL/Driver.php @@ -12,8 +12,8 @@ use JKingWeb\Arsse\Db\Exception; class Driver extends \JKingWeb\Arsse\Db\AbstractDriver { use ExceptionBuilder; - const SQL_MODE = "ANSI_QUOTES,HIGH_NOT_PRECEDENCE,NO_BACKSLASH_ESCAPES,NO_ENGINE_SUBSTITUTION,PIPES_AS_CONCAT,STRICT_ALL_TABLES"; - const TRANSACTIONAL_LOCKS = false; + protected const SQL_MODE = "ANSI_QUOTES,HIGH_NOT_PRECEDENCE,NO_BACKSLASH_ESCAPES,NO_ENGINE_SUBSTITUTION,PIPES_AS_CONCAT,STRICT_ALL_TABLES"; + protected const TRANSACTIONAL_LOCKS = false; /** @var \mysqli */ protected $db; diff --git a/lib/Db/MySQL/Statement.php b/lib/Db/MySQL/Statement.php index 02b56bd..057225a 100644 --- a/lib/Db/MySQL/Statement.php +++ b/lib/Db/MySQL/Statement.php @@ -9,7 +9,7 @@ namespace JKingWeb\Arsse\Db\MySQL; class Statement extends \JKingWeb\Arsse\Db\AbstractStatement { use ExceptionBuilder; - const BINDINGS = [ + protected const BINDINGS = [ self::T_INTEGER => "i", self::T_FLOAT => "d", self::T_DATETIME => "s", diff --git a/lib/Db/PDOStatement.php b/lib/Db/PDOStatement.php index 132e1e7..4425093 100644 --- a/lib/Db/PDOStatement.php +++ b/lib/Db/PDOStatement.php @@ -9,7 +9,7 @@ namespace JKingWeb\Arsse\Db; abstract class PDOStatement extends AbstractStatement { use PDOError; - const BINDINGS = [ + protected const BINDINGS = [ self::T_INTEGER => \PDO::PARAM_INT, self::T_FLOAT => \PDO::PARAM_STR, self::T_DATETIME => \PDO::PARAM_STR, diff --git a/lib/Db/PostgreSQL/Driver.php b/lib/Db/PostgreSQL/Driver.php index a06b6a5..fccc071 100644 --- a/lib/Db/PostgreSQL/Driver.php +++ b/lib/Db/PostgreSQL/Driver.php @@ -12,7 +12,7 @@ use JKingWeb\Arsse\Db\Exception; class Driver extends \JKingWeb\Arsse\Db\AbstractDriver { use Dispatch; - const TRANSACTIONAL_LOCKS = true; + protected const TRANSACTIONAL_LOCKS = true; protected $db; protected $transStart = 0; diff --git a/lib/Db/PostgreSQL/Statement.php b/lib/Db/PostgreSQL/Statement.php index 058ca2e..8c89053 100644 --- a/lib/Db/PostgreSQL/Statement.php +++ b/lib/Db/PostgreSQL/Statement.php @@ -9,7 +9,7 @@ namespace JKingWeb\Arsse\Db\PostgreSQL; class Statement extends \JKingWeb\Arsse\Db\AbstractStatement { use Dispatch; - const BINDINGS = [ + protected const BINDINGS = [ self::T_INTEGER => "bigint", self::T_FLOAT => "decimal", self::T_DATETIME => "timestamp(0) without time zone", diff --git a/lib/Db/SQLite3/Driver.php b/lib/Db/SQLite3/Driver.php index cb23ac6..bef5ec6 100644 --- a/lib/Db/SQLite3/Driver.php +++ b/lib/Db/SQLite3/Driver.php @@ -12,12 +12,12 @@ use JKingWeb\Arsse\Db\Exception; class Driver extends \JKingWeb\Arsse\Db\AbstractDriver { use ExceptionBuilder; - const TRANSACTIONAL_LOCKS = true; + protected const TRANSACTIONAL_LOCKS = true; - const SQLITE_BUSY = 5; - const SQLITE_SCHEMA = 17; - const SQLITE_CONSTRAINT = 19; - const SQLITE_MISMATCH = 20; + public const SQLITE_BUSY = 5; + public const SQLITE_SCHEMA = 17; + public const SQLITE_CONSTRAINT = 19; + public const SQLITE_MISMATCH = 20; protected $db; diff --git a/lib/Db/SQLite3/Statement.php b/lib/Db/SQLite3/Statement.php index 3374689..c97b1d8 100644 --- a/lib/Db/SQLite3/Statement.php +++ b/lib/Db/SQLite3/Statement.php @@ -9,10 +9,10 @@ namespace JKingWeb\Arsse\Db\SQLite3; class Statement extends \JKingWeb\Arsse\Db\AbstractStatement { use ExceptionBuilder; - const SQLITE_BUSY = 5; - const SQLITE_CONSTRAINT = 19; - const SQLITE_MISMATCH = 20; - const BINDINGS = [ + public const SQLITE_BUSY = 5; + public const SQLITE_CONSTRAINT = 19; + public const SQLITE_MISMATCH = 20; + protected const BINDINGS = [ self::T_INTEGER => \SQLITE3_INTEGER, self::T_FLOAT => \SQLITE3_FLOAT, self::T_DATETIME => \SQLITE3_TEXT, diff --git a/lib/Db/Statement.php b/lib/Db/Statement.php index 0ed8685..44e9cd2 100644 --- a/lib/Db/Statement.php +++ b/lib/Db/Statement.php @@ -7,7 +7,7 @@ declare(strict_types=1); namespace JKingWeb\Arsse\Db; interface Statement { - const TYPES = [ + public const TYPES = [ 'int' => self::T_INTEGER, 'integer' => self::T_INTEGER, 'float' => self::T_FLOAT, @@ -43,13 +43,13 @@ interface Statement { 'strict boolean' => self::T_NOT_NULL + self::T_BOOLEAN, 'strict bit' => self::T_NOT_NULL + self::T_BOOLEAN, ]; - const T_INTEGER = 1; - const T_STRING = 2; - const T_BOOLEAN = 3; - const T_DATETIME = 4; - const T_FLOAT = 5; - const T_BINARY = 6; - const T_NOT_NULL = 100; + public const T_INTEGER = 1; + public const T_STRING = 2; + public const T_BOOLEAN = 3; + public const T_DATETIME = 4; + public const T_FLOAT = 5; + public const T_BINARY = 6; + public const T_NOT_NULL = 100; public function run(...$values): Result; public function runArray(array $values = []): Result; diff --git a/lib/Feed/Exception.php b/lib/Feed/Exception.php index 39936b3..2bf181e 100644 --- a/lib/Feed/Exception.php +++ b/lib/Feed/Exception.php @@ -12,8 +12,8 @@ use GuzzleHttp\Exception\TooManyRedirectsException; use PicoFeed\PicoFeedException; class Exception extends \JKingWeb\Arsse\AbstractException { - const CURL_ERROR_MAP = [1 => "invalidUrl",3 => "invalidUrl",5 => "transmissionError","connectionFailed","connectionFailed","transmissionError","forbidden","unauthorized","transmissionError","transmissionError","transmissionError","transmissionError","connectionFailed","connectionFailed","transmissionError","transmissionError","transmissionError","transmissionError","transmissionError","invalidUrl","transmissionError","transmissionError","transmissionError","transmissionError",28 => "timeout","transmissionError","transmissionError","transmissionError","transmissionError","transmissionError",35 => "invalidCertificate","transmissionError","transmissionError","transmissionError","transmissionError",45 => "transmissionError","unauthorized","maxRedirect",52 => "transmissionError","invalidCertificate","invalidCertificate","transmissionError","transmissionError",58 => "invalidCertificate","invalidCertificate","invalidCertificate","transmissionError","invalidUrl","transmissionError","invalidCertificate","transmissionError","invalidCertificate","forbidden","invalidUrl","forbidden","transmissionError",73 => "transmissionError","transmissionError",77 => "invalidCertificate","invalidUrl",90 => "invalidCertificate","invalidCertificate","transmissionError",94 => "unauthorized","transmissionError","connectionFailed"]; - const HTTP_ERROR_MAP = [401 => "unauthorized",403 => "forbidden",404 => "invalidUrl",408 => "timeout",410 => "invalidUrl",414 => "invalidUrl",451 => "invalidUrl"]; + protected const CURL_ERROR_MAP = [1 => "invalidUrl",3 => "invalidUrl",5 => "transmissionError","connectionFailed","connectionFailed","transmissionError","forbidden","unauthorized","transmissionError","transmissionError","transmissionError","transmissionError","connectionFailed","connectionFailed","transmissionError","transmissionError","transmissionError","transmissionError","transmissionError","invalidUrl","transmissionError","transmissionError","transmissionError","transmissionError",28 => "timeout","transmissionError","transmissionError","transmissionError","transmissionError","transmissionError",35 => "invalidCertificate","transmissionError","transmissionError","transmissionError","transmissionError",45 => "transmissionError","unauthorized","maxRedirect",52 => "transmissionError","invalidCertificate","invalidCertificate","transmissionError","transmissionError",58 => "invalidCertificate","invalidCertificate","invalidCertificate","transmissionError","invalidUrl","transmissionError","invalidCertificate","transmissionError","invalidCertificate","forbidden","invalidUrl","forbidden","transmissionError",73 => "transmissionError","transmissionError",77 => "invalidCertificate","invalidUrl",90 => "invalidCertificate","invalidCertificate","transmissionError",94 => "unauthorized","transmissionError","connectionFailed"]; + protected const HTTP_ERROR_MAP = [401 => "unauthorized",403 => "forbidden",404 => "invalidUrl",408 => "timeout",410 => "invalidUrl",414 => "invalidUrl",451 => "invalidUrl"]; public function __construct($url, \Throwable $e) { if ($e instanceof BadResponseException) { diff --git a/lib/Lang.php b/lib/Lang.php index 920ddda..fa8232b 100644 --- a/lib/Lang.php +++ b/lib/Lang.php @@ -7,8 +7,8 @@ declare(strict_types=1); namespace JKingWeb\Arsse; class Lang { - const DEFAULT = "en"; // fallback locale - const REQUIRED = [ // collection of absolutely required strings to handle pathological errors + public const DEFAULT = "en"; // fallback locale + protected const REQUIRED = [ // collection of absolutely required strings to handle pathological errors 'Exception.JKingWeb/Arsse/Exception.uncoded' => 'The specified exception symbol {0} has no code specified in AbstractException.php', 'Exception.JKingWeb/Arsse/Exception.unknown' => 'An unknown error has occurred', 'Exception.JKingWeb/Arsse/Lang/Exception.defaultFileMissing' => 'Default language file "{0}" missing', diff --git a/lib/Misc/ValueInfo.php b/lib/Misc/ValueInfo.php index 806f6a3..e9af527 100644 --- a/lib/Misc/ValueInfo.php +++ b/lib/Misc/ValueInfo.php @@ -10,33 +10,33 @@ use JKingWeb\Arsse\ExceptionType; class ValueInfo { // universal - const VALID = 1 << 0; - const NULL = 1 << 1; + public const VALID = 1 << 0; + public const NULL = 1 << 1; // integers - const ZERO = 1 << 2; - const NEG = 1 << 3; - const FLOAT = 1 << 4; + public const ZERO = 1 << 2; + public const NEG = 1 << 3; + public const FLOAT = 1 << 4; // strings - const EMPTY = 1 << 2; - const WHITE = 1 << 3; + public const EMPTY = 1 << 2; + public const WHITE = 1 << 3; // normalization types - const T_MIXED = 0; // pass through unchanged - const T_NULL = 1; // convert to null - const T_BOOL = 2; // convert to boolean - const T_INT = 3; // convert to integer - const T_FLOAT = 4; // convert to floating point - const T_DATE = 5; // convert to DateTimeInterface instance - const T_STRING = 6; // convert to string - const T_ARRAY = 7; // convert to array - const T_INTERVAL = 8; // convert to time interval + public const T_MIXED = 0; // pass through unchanged + public const T_NULL = 1; // convert to null + public const T_BOOL = 2; // convert to boolean + public const T_INT = 3; // convert to integer + public const T_FLOAT = 4; // convert to floating point + public const T_DATE = 5; // convert to DateTimeInterface instance + public const T_STRING = 6; // convert to string + public const T_ARRAY = 7; // convert to array + public const T_INTERVAL = 8; // convert to time interval // normalization modes - const M_LOOSE = 0; - const M_NULL = 1 << 28; // pass nulls through regardless of target type - const M_DROP = 1 << 29; // drop the value (return null) if the type doesn't match - const M_STRICT = 1 << 30; // throw an exception if the type doesn't match - const M_ARRAY = 1 << 31; // the value should be a flat array of values of the specified type; indexed and associative are both acceptable + public const M_LOOSE = 0; + public const M_NULL = 1 << 28; // pass nulls through regardless of target type + public const M_DROP = 1 << 29; // drop the value (return null) if the type doesn't match + public const M_STRICT = 1 << 30; // throw an exception if the type doesn't match + public const M_ARRAY = 1 << 31; // the value should be a flat array of values of the specified type; indexed and associative are both acceptable // symbolic date and time formats - const DATE_FORMATS = [ // in out + protected const DATE_FORMATS = [ // in out 'iso8601' => ["!Y-m-d\TH:i:s", "Y-m-d\TH:i:s\Z" ], // NOTE: ISO 8601 dates require special input processing because of varying formats for timezone offsets 'iso8601m' => ["!Y-m-d\TH:i:s.u", "Y-m-d\TH:i:s.u\Z" ], // NOTE: ISO 8601 dates require special input processing because of varying formats for timezone offsets 'microtime' => ["U.u", "0.u00 U" ], // NOTE: the actual input format at the user level matches the output format; pre-processing is required for PHP not to fail diff --git a/lib/REST.php b/lib/REST.php index 317a650..41fdaa1 100644 --- a/lib/REST.php +++ b/lib/REST.php @@ -14,7 +14,7 @@ use Laminas\Diactoros\ServerRequestFactory; use Laminas\Diactoros\Response\EmptyResponse; class REST { - const API_LIST = [ + public const API_LIST = [ 'ncn' => [ // Nextcloud News version enumerator 'match' => '/index.php/apps/news/api', 'strip' => '/index.php/apps/news/api', @@ -55,7 +55,7 @@ class REST { // Proprietary (centralized) entities: // Feedly https://developer.feedly.com/ ]; - const DEFAULT_PORTS = [ + protected const DEFAULT_PORTS = [ 'http' => 80, 'https' => 443, ]; diff --git a/lib/REST/Fever/API.php b/lib/REST/Fever/API.php index ac6bb67..9a5779b 100644 --- a/lib/REST/Fever/API.php +++ b/lib/REST/Fever/API.php @@ -19,15 +19,15 @@ use Laminas\Diactoros\Response\XmlResponse; use Laminas\Diactoros\Response\EmptyResponse; class API extends \JKingWeb\Arsse\REST\AbstractHandler { - const LEVEL = 3; - const GENERIC_ICON_TYPE = "image/png;base64"; - const GENERIC_ICON_DATA = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjHxIGmVAAAADUlEQVQYV2NgYGBgAAAABQABijPjAAAAAABJRU5ErkJggg=="; - const ACCEPTED_TYPE = "application/x-www-form-urlencoded"; + public const LEVEL = 3; + protected const GENERIC_ICON_TYPE = "image/png;base64"; + protected const GENERIC_ICON_DATA = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjHxIGmVAAAADUlEQVQYV2NgYGBgAAAABQABijPjAAAAAABJRU5ErkJggg=="; + protected const ACCEPTED_TYPE = "application/x-www-form-urlencoded"; // GET parameters for which we only check presence: these will be converted to booleans - const PARAM_BOOL = ["groups", "feeds", "items", "favicons", "links", "unread_item_ids", "saved_item_ids"]; + protected const PARAM_BOOL = ["groups", "feeds", "items", "favicons", "links", "unread_item_ids", "saved_item_ids"]; // GET parameters which contain meaningful values - const PARAM_GET = [ + protected const PARAM_GET = [ 'api' => V::T_STRING, // this parameter requires special handling 'page' => V::T_INT, // parameter for hot links 'range' => V::T_INT, // parameter for hot links @@ -45,7 +45,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { 'unread_recently_read' => V::T_BOOL, ]; // POST parameters, all of which contain meaningful values - const PARAM_POST = [ + protected const PARAM_POST = [ 'api_key' => V::T_STRING, 'mark' => V::T_STRING, 'as' => V::T_STRING, diff --git a/lib/REST/NextcloudNews/V1_2.php b/lib/REST/NextcloudNews/V1_2.php index 6e1fb27..c7389df 100644 --- a/lib/REST/NextcloudNews/V1_2.php +++ b/lib/REST/NextcloudNews/V1_2.php @@ -23,9 +23,9 @@ use Laminas\Diactoros\Response\JsonResponse as Response; use Laminas\Diactoros\Response\EmptyResponse; class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { - const REALM = "Nextcloud News API v1-2"; - const VERSION = "11.0.5"; - const ACCEPTED_TYPE = "application/json"; + public const VERSION = "11.0.5"; + protected const REALM = "Nextcloud News API v1-2"; + protected const ACCEPTED_TYPE = "application/json"; protected $dateFormat = "unix"; diff --git a/lib/REST/TinyTinyRSS/API.php b/lib/REST/TinyTinyRSS/API.php index d0df548..2df402a 100644 --- a/lib/REST/TinyTinyRSS/API.php +++ b/lib/REST/TinyTinyRSS/API.php @@ -24,27 +24,27 @@ use Laminas\Diactoros\Response\JsonResponse as Response; use Laminas\Diactoros\Response\EmptyResponse; class API extends \JKingWeb\Arsse\REST\AbstractHandler { - const LEVEL = 14; // emulated API level - const VERSION = "17.4"; // emulated TT-RSS version - const LABEL_OFFSET = 1024; // offset below zero at which labels begin, counting down - const LIMIT_ARTICLES = 200; // maximum number of articles returned by getHeadlines - const LIMIT_EXCERPT = 100; // maximum length of excerpts in getHeadlines, counted in grapheme units + public const LEVEL = 14; // emulated API level + public const VERSION = "17.4"; // emulated TT-RSS version + protected const LABEL_OFFSET = 1024; // offset below zero at which labels begin, counting down + protected const LIMIT_ARTICLES = 200; // maximum number of articles returned by getHeadlines + protected const LIMIT_EXCERPT = 100; // maximum length of excerpts in getHeadlines, counted in grapheme units // special feeds - const FEED_ARCHIVED = 0; - const FEED_STARRED = -1; - const FEED_PUBLISHED = -2; - const FEED_FRESH = -3; - const FEED_ALL = -4; - const FEED_READ = -6; + protected const FEED_ARCHIVED = 0; + protected const FEED_STARRED = -1; + protected const FEED_PUBLISHED = -2; + protected const FEED_FRESH = -3; + protected const FEED_ALL = -4; + protected const FEED_READ = -6; // special categories - const CAT_UNCATEGORIZED = 0; - const CAT_SPECIAL = -1; - const CAT_LABELS = -2; - const CAT_NOT_SPECIAL = -3; - const CAT_ALL = -4; + protected const CAT_UNCATEGORIZED = 0; + protected const CAT_SPECIAL = -1; + protected const CAT_LABELS = -2; + protected const CAT_NOT_SPECIAL = -3; + protected const CAT_ALL = -4; // valid input - const ACCEPTED_TYPES = ["application/json", "text/json"]; - const VALID_INPUT = [ + protected const ACCEPTED_TYPES = ["application/json", "text/json"]; + protected const VALID_INPUT = [ 'op' => ValueInfo::T_STRING, // the function ("operation") to perform 'sid' => ValueInfo::T_STRING, // session ID 'seq' => ValueInfo::T_INT, // request number from client @@ -82,7 +82,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { 'data' => ValueInfo::T_STRING, // note text in `updateArticle` if setting a note ]; // generic error construct - const FATAL_ERR = [ + protected const FATAL_ERR = [ 'seq' => null, 'status' => 1, 'content' => ['error' => "MALFORMED_INPUT"], diff --git a/lib/REST/TinyTinyRSS/Search.php b/lib/REST/TinyTinyRSS/Search.php index 929ef4d..ea3dbe6 100644 --- a/lib/REST/TinyTinyRSS/Search.php +++ b/lib/REST/TinyTinyRSS/Search.php @@ -10,22 +10,22 @@ use JKingWeb\Arsse\Context\Context; use JKingWeb\Arsse\Misc\Date; class Search { - const STATE_BEFORE_TOKEN = 0; - const STATE_BEFORE_TOKEN_QUOTED = 1; - const STATE_IN_DATE = 2; - const STATE_IN_DATE_QUOTED = 3; - const STATE_IN_TOKEN_OR_TAG = 4; - const STATE_IN_TOKEN_OR_TAG_QUOTED = 5; - const STATE_IN_TOKEN = 6; - const STATE_IN_TOKEN_QUOTED = 7; + protected const STATE_BEFORE_TOKEN = 0; + protected const STATE_BEFORE_TOKEN_QUOTED = 1; + protected const STATE_IN_DATE = 2; + protected const STATE_IN_DATE_QUOTED = 3; + protected const STATE_IN_TOKEN_OR_TAG = 4; + protected const STATE_IN_TOKEN_OR_TAG_QUOTED = 5; + protected const STATE_IN_TOKEN = 6; + protected const STATE_IN_TOKEN_QUOTED = 7; - const FIELDS_BOOLEAN = [ + protected const FIELDS_BOOLEAN = [ "unread" => "unread", "star" => "starred", "note" => "annotated", "pub" => "published", // TODO: not implemented ]; - const FIELDS_TEXT = [ + protected const FIELDS_TEXT = [ "title" => "titleTerms", "author" => "authorTerms", "note" => "annotationTerms", @@ -36,7 +36,6 @@ class Search { // normalize the input $search = strtolower(trim(preg_replace("<\s+>", " ", $search))); // set initial state - $tokens = []; $pos = -1; $stop = strlen($search); $state = self::STATE_BEFORE_TOKEN; diff --git a/lib/Service.php b/lib/Service.php index fc77e80..597421f 100644 --- a/lib/Service.php +++ b/lib/Service.php @@ -9,7 +9,7 @@ namespace JKingWeb\Arsse; use JKingWeb\Arsse\Misc\Date; class Service { - const DRIVER_NAMES = [ + public const DRIVER_NAMES = [ 'serial' => \JKingWeb\Arsse\Service\Serial\Driver::class, 'subprocess' => \JKingWeb\Arsse\Service\Subprocess\Driver::class, ]; diff --git a/lib/User.php b/lib/User.php index 15d902c..f529991 100644 --- a/lib/User.php +++ b/lib/User.php @@ -9,7 +9,7 @@ namespace JKingWeb\Arsse; use PasswordGenerator\Generator as PassGen; class User { - const DRIVER_NAMES = [ + public const DRIVER_NAMES = [ 'internal' => \JKingWeb\Arsse\User\Internal\Driver::class, ]; diff --git a/lib/User/Driver.php b/lib/User/Driver.php index b5657ac..8faaec7 100644 --- a/lib/User/Driver.php +++ b/lib/User/Driver.php @@ -7,9 +7,9 @@ declare(strict_types=1); namespace JKingWeb\Arsse\User; interface Driver { - const FUNC_NOT_IMPLEMENTED = 0; - const FUNC_INTERNAL = 1; - const FUNC_EXTERNAL = 2; + public const FUNC_NOT_IMPLEMENTED = 0; + public const FUNC_INTERNAL = 1; + public const FUNC_EXTERNAL = 2; // returns an instance of a class implementing this interface. public function __construct(); diff --git a/tests/cases/Database/SeriesArticle.php b/tests/cases/Database/SeriesArticle.php index d268d2a..2f78e9c 100644 --- a/tests/cases/Database/SeriesArticle.php +++ b/tests/cases/Database/SeriesArticle.php @@ -421,6 +421,7 @@ trait SeriesArticle { } public function provideContextMatches(): iterable { + $setSize = (new \ReflectionClassConstant(Database::class, "LIMIT_SET_SIZE"))->getValue(); return [ 'Blank context' => [new Context, [1,2,3,4,5,6,7,8,19,20]], 'Folder tree' => [(new Context)->folder(1), [5,6,7,8]], @@ -473,7 +474,7 @@ trait SeriesArticle { 'Multiple unstarred articles' => [(new Context)->articles([1,2,3])->starred(false), [2,3]], 'Multiple articles' => [(new Context)->articles([1,20,50]), [1,20]], 'Multiple editions' => [(new Context)->editions([1,1001,50]), [1,20]], - '150 articles' => [(new Context)->articles(range(1, Database::LIMIT_SET_SIZE * 3)), [1,2,3,4,5,6,7,8,19,20]], + '150 articles' => [(new Context)->articles(range(1, $setSize * 3)), [1,2,3,4,5,6,7,8,19,20]], 'Search title or content 1' => [(new Context)->searchTerms(["Article"]), [1,2,3]], 'Search title or content 2' => [(new Context)->searchTerms(["one", "first"]), [1]], 'Search title or content 3' => [(new Context)->searchTerms(["one first"]), []], @@ -816,7 +817,8 @@ trait SeriesArticle { } public function testMarkTooManyMultipleArticles(): void { - $this->assertSame(7, Arsse::$db->articleMark($this->user, ['read' => false,'starred' => true], (new Context)->articles(range(1, Database::LIMIT_SET_SIZE * 3)))); + $setSize = (new \ReflectionClassConstant(Database::class, "LIMIT_SET_SIZE"))->getValue(); + $this->assertSame(7, Arsse::$db->articleMark($this->user, ['read' => false,'starred' => true], (new Context)->articles(range(1, $setSize * 3)))); } public function testMarkAMissingArticle(): void { @@ -971,10 +973,11 @@ trait SeriesArticle { } public function testCountArticles(): void { + $setSize = (new \ReflectionClassConstant(Database::class, "LIMIT_SET_SIZE"))->getValue(); $this->assertSame(2, Arsse::$db->articleCount("john.doe@example.com", (new Context)->starred(true))); $this->assertSame(4, Arsse::$db->articleCount("john.doe@example.com", (new Context)->folder(1))); $this->assertSame(0, Arsse::$db->articleCount("jane.doe@example.com", (new Context)->starred(true))); - $this->assertSame(10, Arsse::$db->articleCount("john.doe@example.com", (new Context)->articles(range(1, Database::LIMIT_SET_SIZE * 3)))); + $this->assertSame(10, Arsse::$db->articleCount("john.doe@example.com", (new Context)->articles(range(1, $setSize * 3)))); } public function testCountArticlesWithoutAuthority(): void { diff --git a/tests/cases/Database/TestDatabase.php b/tests/cases/Database/TestDatabase.php index 581bc23..cfaed76 100644 --- a/tests/cases/Database/TestDatabase.php +++ b/tests/cases/Database/TestDatabase.php @@ -35,10 +35,10 @@ class TestDatabase extends \JKingWeb\Arsse\Test\AbstractTest { } public function provideInClauses(): iterable { - $l = Database::LIMIT_SET_SIZE + 1; + $l = (new \ReflectionClassConstant(Database::class, "LIMIT_SET_SIZE"))->getValue() + 1; $strings = array_fill(0, $l, ""); $ints = range(1, $l); - $longString = str_repeat("0", Database::LIMIT_SET_STRING_LENGTH + 1); + $longString = str_repeat("0", (new \ReflectionClassConstant(Database::class, "LIMIT_SET_STRING_LENGTH"))->getValue() + 1); $params = implode(",", array_fill(0, $l, "?")); $intList = implode(",", $ints); $stringList = implode(",", array_fill(0, $l, "''")); @@ -70,9 +70,10 @@ class TestDatabase extends \JKingWeb\Arsse\Test\AbstractTest { } public function provideSearchClauses(): iterable { - $terms = array_fill(0, Database::LIMIT_SET_SIZE + 1, "a"); - $clause = array_fill(0, Database::LIMIT_SET_SIZE + 1, "test like '%a%' escape '^'"); - $longString = str_repeat("0", Database::LIMIT_SET_STRING_LENGTH + 1); + $setSize = (new \ReflectionClassConstant(Database::class, "LIMIT_SET_SIZE"))->getValue(); + $terms = array_fill(0, $setSize + 1, "a"); + $clause = array_fill(0, $setSize + 1, "test like '%a%' escape '^'"); + $longString = str_repeat("0", (new \ReflectionClassConstant(Database::class, "LIMIT_SET_STRING_LENGTH"))->getValue() + 1); return [ ["test like ? escape '^'", ["%a%"], ["a"], ["test"], true], ["(col1 like ? escape '^' or col2 like ? escape '^')", ["%a%", "%a%"], ["a"], ["col1", "col2"], true], diff --git a/tests/cases/Lang/TestBasic.php b/tests/cases/Lang/TestBasic.php index ff55b53..f94b4f3 100644 --- a/tests/cases/Lang/TestBasic.php +++ b/tests/cases/Lang/TestBasic.php @@ -37,8 +37,9 @@ class TestBasic extends \JKingWeb\Arsse\Test\AbstractTest { * @depends testSetLanguage */ public function testLoadInternalStrings(): void { + $exp = (new \ReflectionClassConstant(TestClass::class, "REQUIRED"))->getValue(); $this->assertEquals("", $this->l->set("", true)); - $this->assertCount(sizeof(TestClass::REQUIRED), $this->l->dump()); + $this->assertCount(sizeof($exp), $this->l->dump()); } /** diff --git a/tests/cases/Misc/TestValueInfo.php b/tests/cases/Misc/TestValueInfo.php index 6a4c6ba..efa1bec 100644 --- a/tests/cases/Misc/TestValueInfo.php +++ b/tests/cases/Misc/TestValueInfo.php @@ -400,9 +400,9 @@ class TestValueInfo extends \JKingWeb\Arsse\Test\AbstractTest { public function testNormalizeComplexValues(): void { // Array-mode tests $tests = [ - [I::T_INT | I::M_DROP, [1, 2, 2.2, 3], [1,2,null,3] ], + [I::T_INT | I::M_DROP, [1, 2, 2.2, 3], [1,2,null,3] ], [I::T_INT, [1, 2, 2.2, 3], [1,2,2,3] ], - [I::T_INT | I::M_DROP, new Result([1, 2, 2.2, 3]), [1,2,null,3] ], + [I::T_INT | I::M_DROP, new Result([1, 2, 2.2, 3]), [1,2,null,3] ], [I::T_INT, new Result([1, 2, 2.2, 3]), [1,2,2,3] ], [I::T_STRING | I::M_STRICT, "Bare string", ["Bare string"]], ]; @@ -411,10 +411,11 @@ class TestValueInfo extends \JKingWeb\Arsse\Test\AbstractTest { $this->assertEquals($exp, I::normalize($value, $type | I::M_ARRAY, "iso8601"), "Failed test #$index"); } // Date-to-string format tests + $dateFormats = (new \ReflectionClassConstant(I::class, "DATE_FORMATS"))->getValue(); $test = new \DateTimeImmutable("now", new \DateTimezone("UTC")); - $exp = $test->format(I::DATE_FORMATS['iso8601'][1]); + $exp = $test->format($dateFormats['iso8601'][1]); $this->assertSame($exp, I::normalize($test, I::T_STRING, null), "Failed test for null output date format"); - foreach (I::DATE_FORMATS as $name => $formats) { + foreach ($dateFormats as $name => $formats) { $exp = $test->format($formats[1]); $this->assertSame($exp, I::normalize($test, I::T_STRING, null, $name), "Failed test for output date format '$name'"); } diff --git a/tests/cases/REST/Fever/TestAPI.php b/tests/cases/REST/Fever/TestAPI.php index f65de41..d89a17f 100644 --- a/tests/cases/REST/Fever/TestAPI.php +++ b/tests/cases/REST/Fever/TestAPI.php @@ -488,8 +488,10 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { } public function testListFeedIcons(): void { + $iconType = (new \ReflectionClassConstant(API::class, "GENERIC_ICON_TYPE"))->getValue(); + $iconData = (new \ReflectionClassConstant(API::class, "GENERIC_ICON_DATA"))->getValue(); $act = $this->h->dispatch($this->req("api&favicons")); - $exp = new JsonResponse(['favicons' => [['id' => 0, 'data' => API::GENERIC_ICON_TYPE.",".API::GENERIC_ICON_DATA]]]); + $exp = new JsonResponse(['favicons' => [['id' => 0, 'data' => $iconType.",".$iconData]]]); $this->assertMessage($exp, $act); } diff --git a/tests/cases/REST/TinyTinyRSS/TestAPI.php b/tests/cases/REST/TinyTinyRSS/TestAPI.php index cfd671a..d5ca279 100644 --- a/tests/cases/REST/TinyTinyRSS/TestAPI.php +++ b/tests/cases/REST/TinyTinyRSS/TestAPI.php @@ -997,6 +997,7 @@ LONG_STRING; ['id' => 3, 'name' => "Hardware"], ['id' => 1, 'name' => "Politics"], ]; + $labelOffset = (new \ReflectionClassConstant(API::class, "LABEL_OFFSET"))->getValue(); // set of various mocks for testing \Phake::when(Arsse::$db)->labelAdd(Arsse::$user->id, $db[0])->thenReturn(2)->thenThrow(new ExceptionInput("constraintViolation")); // error on the second call \Phake::when(Arsse::$db)->labelAdd(Arsse::$user->id, $db[1])->thenReturn(3)->thenThrow(new ExceptionInput("constraintViolation")); // error on the second call @@ -1007,14 +1008,14 @@ LONG_STRING; \Phake::when(Arsse::$db)->labelAdd(Arsse::$user->id, ['name' => ""])->thenThrow(new ExceptionInput("missing")); \Phake::when(Arsse::$db)->labelAdd(Arsse::$user->id, ['name' => " "])->thenThrow(new ExceptionInput("whitespace")); // correctly add two labels - $exp = $this->respGood((-1 * API::LABEL_OFFSET) - 2); + $exp = $this->respGood((-1 * $labelOffset) - 2); $this->assertMessage($exp, $this->req($in[0])); - $exp = $this->respGood((-1 * API::LABEL_OFFSET) - 3); + $exp = $this->respGood((-1 * $labelOffset) - 3); $this->assertMessage($exp, $this->req($in[1])); // attempt to add the two labels again - $exp = $this->respGood((-1 * API::LABEL_OFFSET) - 2); + $exp = $this->respGood((-1 * $labelOffset) - 2); $this->assertMessage($exp, $this->req($in[0])); - $exp = $this->respGood((-1 * API::LABEL_OFFSET) - 3); + $exp = $this->respGood((-1 * $labelOffset) - 3); $this->assertMessage($exp, $this->req($in[1])); \Phake::verify(Arsse::$db)->labelPropertiesGet(Arsse::$user->id, "Software", true); \Phake::verify(Arsse::$db)->labelPropertiesGet(Arsse::$user->id, "Hardware", true);