Compare commits

..

1178 Commits

Author SHA1 Message Date
Timothy Warren 7afdab80ac Update frontend minification config and dependencies
timw4mail/HummingBirdAnimeClient/pipeline/head This commit looks good Details
2024-02-15 15:21:26 -05:00
Timothy Warren 144718866d Merge branch 'develop'
timw4mail/HummingBirdAnimeClient/pipeline/head This commit looks good Details
2024-01-23 13:35:40 -05:00
Timothy Warren 1dd9fdd0c2 Attmept to fix issue with Stringy 2024-01-17 08:32:48 -05:00
Timothy Warren 3794ed20a8 Update CI to use several PHP versions 2023-12-21 13:49:54 -05:00
Timothy Warren ff8c837fd9 Update views and templates to use render helper object 2023-12-21 13:46:15 -05:00
Timothy Warren fe1caffc0f Simplify setup of rendering methods by putting them in a wrapper class 2023-12-21 13:19:59 -05:00
Timothy Warren 8e7b2a04fd Fix broken test 2023-10-27 09:28:06 -04:00
Timothy Warren 0e684736bd Vastly simplify logic for getting a user's anime library. Most basic API functionality seems to be working 2023-10-26 16:00:13 -04:00
Timothy Warren 1ad4427584 Start of migration to amphp/http-client 5.0 2023-10-26 11:10:21 -04:00
Timothy Warren b0a16e7730 Pin latest working version of Aura Router 2023-10-25 07:42:13 -04:00
Timothy Warren 7559f79ef6 Various tweaks 2023-10-02 11:48:34 -04:00
Timothy Warren c8b642be1c Add anilist example config file, and make the interface a bit more helpful 2023-07-13 14:17:51 -04:00
Timothy Warren 91c435cdac Update header comments 2023-07-13 11:08:05 -04:00
Timothy Warren 57249882ab Some minor code style fixes 2023-07-13 11:06:52 -04:00
Timothy Warren c28dfc09b3 Update js/css dependencies 2023-06-28 15:48:33 -04:00
Timothy Warren cd5841c4c8 Merge pull request 'default config and documentation update' (#43) from colwellkr/HummingBirdAnimeClient:develop into develop
Reviewed-on: #43
2023-06-28 15:24:25 -04:00
Timothy Warren c83b30f43a Merge branch 'develop' into develop 2023-06-28 15:23:56 -04:00
Kevin Colwell 011160a3c2 add php extensions required to README.md 2023-06-28 18:37:44 +00:00
Timothy Warren 067d888f4c Fix route issue for manga pages 2023-06-28 14:30:30 -04:00
Kevin Colwell 1b5a5080f2 add default theme to config.toml.example 2023-06-28 18:22:00 +00:00
Timothy Warren 1a97277ec4 Tweak a Stringy method to have a more sensible return type 2023-06-28 14:03:15 -04:00
Timothy Warren e426fdd4a3 Fix a load of code cleanliness and style issues 2023-05-19 16:34:38 -04:00
Timothy Warren 5758de7667 Update tooling and config 2023-05-19 16:34:07 -04:00
Timothy Warren d21d9a86d4 Update frontend dependencies, remove period on update banner 2023-05-19 16:33:14 -04:00
Timothy Warren a435162a2b Update rector config 2023-05-19 11:00:12 -04:00
Timothy Warren 4fef2b2942 Fix some remaining formatting issues 2023-05-19 10:57:59 -04:00
Timothy Warren 77c6419c80 Rector updates for tests 2023-05-19 10:56:23 -04:00
Timothy Warren 97fe3b4b40 PHP 8.1 syntax updates 2023-05-19 10:54:08 -04:00
Timothy Warren 5396091b83 Move new helper functions to a more logical place, fix UserTransformer test 2023-05-19 10:42:25 -04:00
Timothy Warren 655ad119ce Fix broken test 2023-05-18 17:00:00 -04:00
Timothy Warren 351446a2ee Fix formatting 2023-05-18 16:27:31 -04:00
Timothy Warren f2b7f61030 More user page tweaks 2023-05-18 16:25:50 -04:00
Timothy Warren b678a3401e More local fixes, add some more data to user profile page 2023-05-18 15:17:19 -04:00
Timothy Warren 465cd99165 Add specific locale arguments to keep up with the API 2023-05-18 12:55:38 -04:00
Timothy Warren 2e67b49447 More code style updates 2023-05-09 12:52:11 -04:00
Timothy Warren 45449b6907 Code style updates 2023-05-09 12:49:36 -04:00
Timothy Warren 05d4fb1ad7 Style and tool updates 2023-05-09 12:46:52 -04:00
Timothy Warren 81d81f4393 Update aviat/query to fix PHP 8.2 deprecation notice 2023-03-17 16:38:41 -04:00
Timothy Warren 60ddcaa08e Make error handling for ajax list incrementing more robust 2023-03-17 11:09:43 -04:00
Timothy Warren 0e780f26b9 Update Kitsu GraphQL schema 2023-03-16 22:20:17 -04:00
Timothy Warren bedd504b64 Update cache dependency 2023-03-16 22:19:56 -04:00
Timothy Warren 2f657dc20b Add Routing attributes to controllers for a potential future refactoring 2023-03-16 13:04:55 -04:00
Timothy Warren 4f8eefe71e Extract Stringy to fix deprecations 2023-03-16 13:03:48 -04:00
Timothy Warren dd63767ddf Update DB dependency 2023-03-16 13:02:17 -04:00
Timothy Warren e1ff1c6e21 Use MAL and Anlist IDs to do simultaneous updates and syncing. Resolves #39 2022-11-16 10:21:00 -05:00
Timothy Warren f673a84cf6 More work on #39 2022-09-22 12:08:21 -04:00
Timothy Warren 4a2273c93c Fix tests 2022-09-22 11:13:53 -04:00
Timothy Warren 3cb90acb13 Fix incrementing with anilist 2022-09-22 10:21:09 -04:00
Timothy Warren ab38e03af9 Update frontend tooling 2022-09-22 10:20:15 -04:00
Timothy Warren 2139f031f4 Pass anilist ids more directly, see #39 2022-09-21 15:36:38 -04:00
Timothy Warren ec280cd76d Skip another test failing on CI 2022-06-29 11:28:12 -04:00
Timothy Warren 5e7f57eb0a Skip failing tests 2022-06-29 11:25:14 -04:00
Timothy Warren 26cbe4b592 Update broken test 2022-06-29 11:15:47 -04:00
Timothy Warren e8aa2bd42b Bugfix for manga pages without characters 2022-06-28 18:57:50 -04:00
Timothy Warren 501062ac37 Update GraphQL schemas 2022-06-08 20:21:50 -04:00
Timothy Warren 4dc0bb29d2 Show completed message for the last episode/chapter of an anime/manga 2022-03-22 09:53:41 -04:00
Timothy Warren b1c4c8cb5e Move header update script to tools folder 2022-03-04 15:52:18 -05:00
Timothy Warren e4fe5bbfec Simplify file headers 2022-03-04 15:50:35 -05:00
Timothy Warren 4b35d25849 Update header comments 2022-03-04 12:32:17 -05:00
Timothy Warren 3b57d08c0a Tweak formatting settings 2022-03-04 12:31:13 -05:00
Timothy Warren 29e70a8e3f More formatting fixes 2022-03-04 12:25:29 -05:00
Timothy Warren a0d30c002a Reformat test suite files 2022-03-04 12:19:47 -05:00
Timothy Warren 327065498b Reformat misc files 2022-03-03 18:19:02 -05:00
Timothy Warren 047ee4cb37 Set up a proper formatter for more consistent code style 2022-03-03 17:26:09 -05:00
Timothy Warren 9b945ca0a5 Remove more redundant phpdoc properties 2022-03-03 14:20:10 -05:00
Timothy Warren e70b0fdb40 Fix tests 2022-03-03 13:52:06 -05:00
Timothy Warren c8a38d5785 Remove a lot of redundant PHPDoc properties 2022-03-03 13:25:10 -05:00
Timothy Warren 10eb7794e9 Remove setup checks for removed directories 2022-01-17 10:22:46 -05:00
Timothy Warren 0dee5f52fc Remove now unused image caching directories 2022-01-17 10:19:20 -05:00
Timothy Warren 7195258d7e Update broken tests 2022-01-17 10:05:14 -05:00
Timothy Warren 9750d63e55 Use images directly from Kitsu for the rest of the views 2022-01-17 09:59:27 -05:00
Timothy Warren e8a14fedf2 Update user details page to pull images directly from Kitsu 2022-01-17 08:58:59 -05:00
Timothy Warren eb897adbd1 Update more views to use images directly from Kitsu 2022-01-17 08:37:00 -05:00
Timothy Warren 5fb1b87e67 Make all media images come directly from Kitsu API, including on the search pages 2022-01-12 18:23:40 -05:00
Timothy Warren a9b24f0cf7 Update more views to use direct kitsu urls for poster images 2022-01-12 18:00:00 -05:00
Timothy Warren f40ee254c9 Fix more cover image stuff 2022-01-10 17:19:28 -05:00
Timothy Warren 2b047634a0 Use kitsu urls for anime cover images 2022-01-10 17:06:05 -05:00
Timothy Warren 7baa5bfe91 Show images directly for anime detail pages, so cover images are pulled correctly 2022-01-10 16:56:10 -05:00
Timothy Warren 2d6058a6b3 Ensure that list items always have some sort of cover image 2022-01-08 13:04:24 -05:00
Timothy Warren d34c79b4cd Remove unused placeholder images in public directory 2022-01-07 20:27:33 -05:00
Timothy Warren ed558a6484 Use image builder class to simplify createPlaceholderImage 2022-01-07 19:57:07 -05:00
Timothy Warren 854987bd44 Create image builder class to simplify creating placeholder images 2022-01-07 19:53:31 -05:00
Timothy Warren 2977f7385e Merge pull request 'Fix table sorting algorithm' (#41) from colwellkr/HummingBirdAnimeClient:fix-sort into develop
Reviewed-on: #41
2022-01-07 17:04:19 -05:00
Timothy Warren 760cc71768 Merge branch 'develop' into fix-sort 2022-01-07 17:02:19 -05:00
Kevin Colwell 573eac78f1 Removed whitespace from string.replace() call 2022-01-07 18:29:37 +00:00
Timothy Warren 02fa04d19d Code style fixes 2022-01-07 12:33:01 -05:00
Timothy Warren 6e1d190230 Update Anilist GraphQL schema 2022-01-06 12:56:46 -05:00
Timothy Warren 80b2495c11 Make Kitsu auth token error easier to recover from 2022-01-06 12:50:26 -05:00
Kevin Colwell 3d9d8202d9 Updated sorting algorithm 2022-01-02 22:48:20 +00:00
Kevin Colwell 188baa5cc8 Update "TV Rating" to "Age Rating" and add additional classes for sorting. 2022-01-02 21:29:08 +00:00
Kevin Colwell 3dbaf7ef32 Update column headers for better consistency between pages 2022-01-02 21:16:34 +00:00
Timothy Warren 545984bb18 Allow adding items to anime collection that are in the anime list 2021-12-29 17:04:55 -05:00
Timothy Warren f9a5716002 Fix testsuite by disabling tests with outdated data 2021-12-02 17:13:31 -05:00
Timothy Warren 818fcf114d Partially fix broken tests 2021-12-02 17:08:11 -05:00
Timothy Warren 3ca606d6f5 Update and streamline dependencies 2021-12-02 16:28:57 -05:00
Timothy Warren 288e64f357 Remove old CodeIgniter style sniffs, as it is not being used 2021-12-02 16:27:43 -05:00
Timothy Warren 6ed1b81451 Lots of little code fixes, hides notices shown on PHP 8.1 2021-12-02 16:06:34 -05:00
Timothy Warren 823ca8a805 sync Manga before Anime, as it's usually faster 2021-10-18 12:20:03 -04:00
Timothy Warren 7301c4852d Update library creation mutation to remove now redundant userID argument 2021-10-18 12:15:47 -04:00
Timothy Warren 602f0fc9c5 Update frontend dependencies, and update Kitsu graphql schema 2021-10-14 22:09:50 -04:00
Timothy Warren 694e7cc01c Remove redundant updates on finishing a media item 2021-10-08 22:55:54 -04:00
Timothy Warren 7efa34efee Update test snapshot for anime detail page with new info 2021-10-08 19:33:25 -04:00
Timothy Warren 49675ffbee Show full Language names on streaming info for anime detail pages 2021-10-08 19:32:10 -04:00
Timothy Warren b82b7d74fc Add airing date range to anime detail pages 2021-10-08 19:31:40 -04:00
Timothy Warren 5102c7c459 Filter out titles not in English or Japanese from media cards 2021-10-08 18:28:30 -04:00
Timothy Warren 1d022bc8ae Show when a media item is already in the list when searching on the /add pages, resolves #38 2021-10-08 12:16:59 -04:00
Timothy Warren 489ec27602 Refactor media search rendering to be less redundant 2021-10-08 12:15:34 -04:00
Timothy Warren 6e4e065b75 Check user library when searching for new media 2021-10-08 12:06:08 -04:00
Timothy Warren 69db87e305 Attempt to fix Jenkins build, again 2021-10-07 21:51:29 -04:00
Timothy Warren 2dacca5d06 Make some anime detail pages more robust 2021-10-07 21:45:17 -04:00
Timothy Warren 1abac0ac0e Sort libraryEvents so watch history is in correct order 2021-07-30 09:37:06 -04:00
Timothy Warren ba6ed8967c Update Kitsu GraphQL schema 2021-07-30 09:36:25 -04:00
Timothy Warren 3d80f755a1 Merge branch 'develop' 2021-04-23 19:23:08 -04:00
Timothy Warren 7a541b609f Fix build issue with phpstan 2021-04-23 19:22:45 -04:00
Timothy Warren 0f4383563f Merge remote-tracking branch 'origin/develop' 2021-04-23 19:01:21 -04:00
Timothy Warren 7b33d40de4 Update GraphQL reference schemas 2021-04-23 19:00:44 -04:00
Timothy Warren 4c85c22c30 Drastically simplify setup for bundling js files 2021-04-23 18:58:51 -04:00
Timothy Warren 7839cf1515 Even less floating, please 2021-04-21 20:20:39 -04:00
Timothy Warren d2a9aaee54 We don't want our ratings to float... 2021-04-21 20:09:03 -04:00
Timothy Warren ff85cb6153 A few minor tweaks 2021-04-21 19:35:22 -04:00
Timothy Warren 4c396ba9c6 Update filtering of MAL IDs for items to check to update 2021-04-21 19:33:51 -04:00
Timothy Warren d2c397f6b9 Fix null error on updating Anime or Manga 2021-03-01 10:08:36 -05:00
Timothy Warren e679322122 Coverage fix for Ion DI 2021-03-01 10:08:07 -05:00
Timothy Warren e6ae6c9e9c Update Kitsu GraphQL schema 2021-03-01 10:06:12 -05:00
Timothy Warren d387b793ea Misc fixes 2021-02-26 14:42:07 -05:00
Timothy Warren 50bb525f60 Replace Whoops with Tracy 2021-02-23 17:08:36 -05:00
Timothy Warren 8de60b332d Remove redundant docblocks from Type classes 2021-02-23 17:08:16 -05:00
Timothy Warren 51eb460ce9 Test Type classes 2021-02-23 15:38:29 -05:00
Timothy Warren 78a37c736f Attempt to fix the build with the right extension 2021-02-23 13:33:54 -05:00
Timothy Warren 380c455332 Use correct symfony polyfill 2021-02-23 13:15:37 -05:00
Timothy Warren 6c35ade209 Fix broken tests 2021-02-23 13:10:26 -05:00
Timothy Warren 633f30d365 Increase test coverage of Kitsu Transformer classes 2021-02-23 13:00:30 -05:00
Timothy Warren 8c1d882404 Improve test coverage 2021-02-23 12:00:22 -05:00
Timothy Warren 6af73cea55 Better handle update API errors 2021-02-22 15:39:03 -05:00
Timothy Warren d3732d1a54 Update GraphQL schemas 2021-02-22 15:38:29 -05:00
Timothy Warren 3aecaf9161 Better catch api errors on incrementing progress 2021-02-22 15:37:35 -05:00
Timothy Warren b12e94cee4 A few minor fixes 2021-02-18 12:48:59 -05:00
Timothy Warren 3d5d2c05ce Remove RoboFile 2021-02-18 07:37:33 -05:00
Timothy Warren f01cc77f92 Remove some invalid exception docblock tags 2021-02-18 07:22:10 -05:00
Timothy Warren c81271864d Fix Content Security Policy 2021-02-18 07:15:43 -05:00
Timothy Warren 10ea494594 Simplify search template functions 2021-02-18 07:14:07 -05:00
Timothy Warren 836b1d17e6 Use str_contains over strpos 2021-02-17 20:02:51 -05:00
Timothy Warren 5004a9f332 Update js build dependencies 2021-02-17 19:50:15 -05:00
Timothy Warren 40f134d7bc Merge remote-tracking branch 'origin/develop' 2021-02-17 13:07:02 -05:00
Timothy Warren 391708a49c Make PHPStan errors CI failures 2021-02-16 15:07:25 -05:00
Timothy Warren 566c9fbd1e Make PHPStan errors CI failures 2021-02-16 15:05:17 -05:00
Timothy Warren 56bda5ed71 Make PHPStan errors CI failures 2021-02-16 15:01:48 -05:00
Timothy Warren d2fbd3b56a Make PHPStan errors CI failures 2021-02-16 14:58:33 -05:00
Timothy Warren 9f680a75e3 Make PHPStan errors CI failures 2021-02-16 14:57:43 -05:00
Timothy Warren 8fadf9d589 Make PHPStan errors CI failures 2021-02-16 14:56:05 -05:00
Timothy Warren b64d8c6c5b Make PHPStan errors CI failures 2021-02-16 14:53:21 -05:00
Timothy Warren b393c695a5 Resolve remaining PHPStan issues 2021-02-16 14:43:51 -05:00
Timothy Warren 1ab4dedddb Merge remote-tracking branch 'origin/develop' 2021-02-16 12:21:52 -05:00
Timothy Warren 73ee1a41e1 Fix more PHPStan issues 2021-02-12 19:17:39 -05:00
Timothy Warren 44a7d36174 Increase warning level of PHPStan 2021-02-12 17:52:58 -05:00
Timothy Warren 77f314ee55 Fix failing test 2021-02-12 13:14:58 -05:00
Timothy Warren 8d742e62ed Fix a bunch more phpstan errors 2021-02-12 13:09:57 -05:00
Timothy Warren e1fd2bed59 Just go back to CheckStyle 2021-02-12 12:00:44 -05:00
Timothy Warren 61d44146cd Try to report phpStan errors more directly 2021-02-12 11:57:36 -05:00
Timothy Warren b2761541ec Try to report phpStan errors more directly 2021-02-12 11:54:22 -05:00
Timothy Warren 6412f1108b Try to report phpStan errors more directly 2021-02-12 11:48:24 -05:00
Timothy Warren c37f50d06e Try to report phpStan errors more directly 2021-02-12 11:43:25 -05:00
Timothy Warren c900e379c5 Try to report phpStan errors more directly 2021-02-12 11:40:25 -05:00
Timothy Warren 326436c0b5 Try to report phpStan errors more directly 2021-02-12 11:27:20 -05:00
Timothy Warren 66df53bf43 Try to report phpStan errors more directly 2021-02-12 11:24:57 -05:00
Timothy Warren 2cd9f99011 Solve more PHPStan issues 2021-02-12 11:14:45 -05:00
Timothy Warren 35ec3c8bfa Fix code warnings for 'src/AnimeClient/AnimeClient.php' 2021-02-12 10:53:07 -05:00
Timothy Warren 52a0ff275d Attempt to add PHPStan messages to CI 2021-02-12 10:42:51 -05:00
Timothy Warren a26c90ff86 Attempt to add PHPStan messages to CI 2021-02-12 10:40:03 -05:00
Timothy Warren c173a8c196 Attempt to add PHPStan messages to CI 2021-02-12 10:38:16 -05:00
Timothy Warren 73cf8ccd5a Attempt to add PHPStan messages to CI 2021-02-12 10:34:08 -05:00
Timothy Warren 244372ff8c Attempt to add PHPStan messages to CI 2021-02-12 10:19:58 -05:00
Timothy Warren 74ef13713d Attempt to add PHPStan messages to CI 2021-02-12 10:07:55 -05:00
Timothy Warren 057d4bfae7 Attempt to add PHPStan messages to CI 2021-02-12 10:04:13 -05:00
Timothy Warren 68bc4693cb Attempt to add PHPStan messages to CI 2021-02-12 09:59:29 -05:00
Timothy Warren ce3260a2f3 Attempt to add PHPStan messages to CI 2021-02-12 09:51:52 -05:00
Timothy Warren 4c5aa1e3de Attempt to add PHPStan messages to CI 2021-02-12 09:42:54 -05:00
Timothy Warren 3c8b564ab9 Attempt to add PHPStan messages to CI 2021-02-12 09:39:28 -05:00
Timothy Warren 7505907976 Yet more PHPStan fixes 2021-02-11 19:54:22 -05:00
Timothy Warren 05455a518b A few more PHPStan fixes 2021-02-10 17:31:20 -05:00
Timothy Warren c39bc23061 Add a bumch of soundness checks suggested by PHPStan 2021-02-10 17:17:51 -05:00
Timothy Warren 9ba1bd4c90 Code style fixes 2021-02-10 13:59:37 -05:00
Timothy Warren 2f789cc4cf Add tests for title uniqueness check 2021-02-10 10:59:15 -05:00
Timothy Warren a18c0bd7b5 Handle null values better in title uniqueness check 2021-02-08 17:03:04 -05:00
Timothy Warren 2b31cae57b Fix the CI build? 2021-02-07 08:54:20 -05:00
Timothy Warren 48dcaa4bcb Fix the CI build? 2021-02-05 20:21:05 -05:00
Timothy Warren 4342b2e795 Fix the CI build? 2021-02-05 20:16:55 -05:00
Timothy Warren b2361c57c2 Fix the CI build? 2021-02-05 20:05:33 -05:00
Timothy Warren e6fdea28d4 Fix the CI build? 2021-02-05 17:49:19 -05:00
Timothy Warren 15dcdfe39c Update docs and CI 2021-02-05 17:19:11 -05:00
Timothy Warren 0250a50731 Merge remote-tracking branch 'origin/develop' 2021-02-04 12:41:24 -05:00
Timothy Warren f2aca2b76f Fix snapshot test 2021-02-04 12:35:01 -05:00
Timothy Warren 97a7d501d0 Fix tests? 2021-02-04 12:27:52 -05:00
Timothy Warren 8c3b583f92 Update PHP version in header comments 2021-02-04 11:57:01 -05:00
Timothy Warren d6e174a014 Fix tests 2021-02-03 10:27:04 -05:00
Timothy Warren df7a9e311b Merge pull request 'develop' (#37) from develop into master
Reviewed-on: #37
2021-02-03 10:07:11 -05:00
Timothy Warren ebf22643ef Update CI to PHP 8 2021-02-03 09:52:18 -05:00
Timothy Warren 3039f412aa Move to PHP 8 2021-02-03 09:46:36 -05:00
Timothy Warren 37ab6034ba Cleanup some path related things 2021-02-03 09:45:18 -05:00
Timothy Warren d5931ff53b Merge pull request 'Update header year code' (#36) from colwellkr/HummingBirdAnimeClient:develop into develop
Reviewed-on: #36
2021-01-14 12:50:22 -05:00
Kevin Colwell fe1250732c Update header year code 2021-01-13 01:58:28 -05:00
Timothy Warren 144e3f5229 Increase test coverage 2020-12-11 15:37:55 -05:00
Timothy Warren 5f494aa9bd Fix tests for PHP8...? 2020-12-11 14:26:54 -05:00
Timothy Warren 7e0cbe8b83 Make sure to run tests for PHP8 2020-12-11 10:26:24 -05:00
Timothy Warren 31ed9d11ab Fix anime collection error 2020-12-11 10:15:24 -05:00
Timothy Warren 6e3a70f9f6 Update dependencies 2020-12-11 10:14:59 -05:00
Timothy Warren 3c47570cce Bump version in header comments 2020-12-10 17:06:50 -05:00
Timothy Warren b4d9e9f21f A little more test coverage 2020-12-10 17:04:45 -05:00
Timothy Warren 1ea5750a76 Refactor, increase test coverage 2020-12-10 15:59:37 -05:00
Timothy Warren 36b396be71 Update Kitsu GraphQL schema file 2020-12-02 12:43:04 -05:00
Timothy Warren bf4f86a010 Add random anime and random manga pages 2020-12-02 12:42:47 -05:00
Timothy Warren 45b0209d8a Merge pull request 'All in GraphQL' (#34) from develop into master
Reviewed-on: #34
2020-12-01 10:07:48 -05:00
Timothy Warren f37ec8022e Revert status mapping change 2020-10-21 21:23:35 -04:00
Timothy Warren 415778295f Fix broken test 2020-10-21 18:53:32 -04:00
Timothy Warren ad0dcb5750 Remove some more dead code 2020-10-21 18:52:12 -04:00
Timothy Warren e0ad68b9d2 Merge remote-tracking branch 'origin/master' into develop 2020-10-21 18:35:43 -04:00
Timothy Warren 608251452f More cleanup, update changelog 2020-10-21 18:12:22 -04:00
Timothy Warren 8c5547d69d More Kitsu GraphQL API cleanup, resolves #33 2020-10-21 17:59:43 -04:00
Timothy Warren 6c29af4533 Remove test for JsonAPI nonsense 2020-10-21 17:07:50 -04:00
Timothy Warren 898dfebbde Use GraphQL to update thumbnails, refactor GraphQL pagination, merge Anime and Manga traits back into the Kitsu model 2020-10-21 17:06:50 -04:00
Timothy Warren 2d5ae3b1c6 Use GraphQL search endpoints, see #33 2020-10-21 15:45:30 -04:00
Timothy Warren 8256815032 Remove old transformer classes 2020-10-21 15:02:25 -04:00
Timothy Warren fe6f737815 Add missing GraphQL query 2020-10-21 14:56:33 -04:00
Timothy Warren 87d15024bb More GraphQL conversion, test updates, see #33 2020-10-21 14:51:17 -04:00
Timothy Warren 470d25f269 Sync Kitsu and Anilist both via GraphQL, see #33 2020-10-16 16:18:56 -04:00
Timothy Warren 70a33e36c0 Fetch Manga List via GraphQL, see #33 2020-10-16 13:28:35 -04:00
Timothy Warren 94d227b08e Fix Manga List Incrementing, start of GraphQL conversion 2020-10-12 14:06:49 -04:00
Timothy Warren ecb913322f Pull anime lists from GraphQL, see #33 2020-10-09 16:18:45 -04:00
Timothy Warren b001af868f Update dependency versions, add Amp base package as dependency 2020-10-09 16:16:23 -04:00
Timothy Warren 1fbf0283ba Fix updating anime status when certain fields are empty 2020-10-07 15:30:42 -04:00
Timothy Warren 5bcc046a12 Add back search query canceling for anime search 2020-10-07 09:10:11 -04:00
Timothy Warren 9009da4b86 Fix hiding anime on completion 2020-10-05 12:32:12 -04:00
Timothy Warren 47a4be2cf9 Update GraphQL queries to match API changes 2020-09-15 08:08:39 -04:00
Timothy Warren 52aabc2b12 Map more external sites 2020-09-10 15:36:34 -04:00
Timothy Warren 7b1217bafe Fix possible issue with hiding completed anime/manga 2020-09-10 15:35:43 -04:00
Timothy Warren a79ab842ee Remove genres from manga list view 2020-09-09 13:26:31 -04:00
Timothy Warren 810731dfbd Update streaming logs, remove genres from anime list view 2020-09-09 13:25:27 -04:00
Timothy Warren c224c8d977 Only show total length of a series if the number is positive 2020-09-09 10:24:55 -04:00
Timothy Warren ce3e3427dc Update GraphQL schema for Kitsu 2020-09-09 10:24:12 -04:00
Timothy Warren 7211aa0de7 Add limit to all relationships 2020-09-09 10:23:17 -04:00
Timothy Warren 02bd0288f2 Do not check session unless already logged in 2020-08-28 14:27:14 -04:00
Timothy Warren a15496e4a5 Sort voice acting roles by character name 2020-08-27 15:39:23 -04:00
Timothy Warren a14ac3a122 Get Person detail pages via GraphQL, resolves #27 2020-08-27 15:01:00 -04:00
Timothy Warren 1a3f1e9654 More components, resolve #31 2020-08-26 17:26:42 -04:00
Timothy Warren 0c936b3fa7 Misc tweaks 2020-08-26 15:25:31 -04:00
Timothy Warren ccb9c9d331 Extract common methods for Anime and Manga models into a trait 2020-08-26 15:24:49 -04:00
Timothy Warren 738e39ba92 Fix Dispatcher test 2020-08-26 15:23:47 -04:00
Timothy Warren 18e8d47167 Move Kitsu class out of API namespace 2020-08-26 15:22:14 -04:00
Timothy Warren c429ce64d3 Missing pieces of previous commit 2020-08-25 16:06:00 -04:00
Timothy Warren 9003c15929 Abort previous requests when search for anime or manga 2020-08-25 16:02:15 -04:00
Timothy Warren eb56ab4c4f Misc fixes and tweaks 2020-08-25 15:11:08 -04:00
Timothy Warren 29a79577d9 Start of pulling library from GraphQL 2020-08-25 13:22:38 -04:00
Timothy Warren e890f978db Update History to use GraphQL, resolves #29,#30 2020-08-24 19:17:41 -04:00
Timothy Warren e944ddc75c Update profile page to use GraphQL, see #27 2020-08-24 15:20:07 -04:00
Timothy Warren 778cda6efc Some syncing cleanup 2020-08-24 13:10:43 -04:00
Timothy Warren e912c83079 Update some GraphQL queries 2020-08-24 13:09:43 -04:00
Timothy Warren 78b9146249 Get library entry via GraphQL, see #28 2020-08-24 13:07:47 -04:00
Timothy Warren e40a1d028f Fix setup of console commands 2020-08-21 19:26:54 -04:00
Timothy Warren edb022be13 Use components instead of duplicating html everywhere 2020-08-21 19:25:27 -04:00
Timothy Warren b75a99a145 Fix tests 2020-08-21 13:07:00 -04:00
Timothy Warren 7aeb74874b Create component system to help cut down on view duplication, see #31 2020-08-21 12:30:01 -04:00
Timothy Warren 9749c59549 Drastically reduce the amount of junk logging, and remove old logic from Character transformer 2020-08-18 16:59:08 -04:00
Timothy Warren 5da0ba87a7 Use constants for the API names instead of literals 2020-08-17 21:08:53 -04:00
Timothy Warren c749c7c923 Fix sync command 2020-08-17 18:08:58 -04:00
Timothy Warren 9b4c9ad76f Full character page pulled from GraphQL API, see #27 2020-08-17 16:36:55 -04:00
Timothy Warren 681a70fd92 Get character details page from GraphQL, still need to do castings section, see #27 2020-08-17 14:01:55 -04:00
Timothy Warren 67d3b7c1dc Fix manga description page 2020-08-17 11:36:01 -04:00
Timothy Warren 79aee53524 Add streaming links back to anime description pages, see #27 2020-08-17 10:45:17 -04:00
Timothy Warren 56f7d5142d Update Kitsu GraphQL schema reference 2020-08-17 10:25:36 -04:00
Timothy Warren 5f7f4b6bdd Update Kitsu GraphQL Mutations 2020-08-17 10:24:17 -04:00
Timothy Warren 0c3ff2ef11 Improve error logging 2020-08-17 10:23:32 -04:00
Timothy Warren 5997ce8a0f Remove some naming redundancies 2020-08-06 09:39:12 -04:00
Timothy Warren 687831efd5 Add missing change from previous commit 2020-08-05 21:52:36 -04:00
Timothy Warren 5a65c7b645 Add background check for session validity
This checks when the app is made visible -- like the tab is switched to,
if the current session is still valid. If the session is not still
valid, the page is reloaded so that the session expiration is apparent.

Resolves #25
2020-08-05 21:46:14 -04:00
Timothy Warren 9dc6643b78 slugs in person urls, refactor AnilistTrait to match KitsuTrait 2020-08-05 20:57:01 -04:00
Timothy Warren c7beb76404 Create and delete media items via GraphQL, see #28 2020-08-05 13:30:24 -04:00
Timothy Warren c132766486 Move GraphQL queries up a level 2020-08-04 14:25:18 -04:00
Timothy Warren 9a112dc413 Bump version 2020-08-04 09:30:21 -04:00
Timothy Warren 1c3216e26a Get manga updates working correctly with GraphQL, see #28 2020-08-04 09:20:28 -04:00
Timothy Warren 78b195f966 Add some previously missing GraphQL fields 2020-08-03 14:36:14 -04:00
Timothy Warren a35bce8a4b Actually fix anime episode incrementing 2020-07-31 20:00:11 -04:00
Timothy Warren 93faf7d88c Fix json loading overlay for anime updates 2020-07-31 19:32:13 -04:00
Timothy Warren a0e7ebd2a0 Increment chapter/episode counts via GraphQL 2020-07-31 19:03:27 -04:00
Timothy Warren 2b54ab5497 Add GraphQL schema reference for Kitsu 2020-07-31 18:59:16 -04:00
Timothy Warren 7bfdd74f22 Add GraphQL schema reference for Anilist 2020-07-31 18:58:49 -04:00
Timothy Warren 4582e2e917 Refactor/streamline View layer 2020-07-31 16:22:32 -04:00
Timothy Warren b0c75d989f Groundwork for some upcoming API updates 2020-07-30 15:16:24 -04:00
Timothy Warren a3bae9255b Actually fix the character API call, previous commit added authentication to GraphQL calls 2020-07-30 10:02:44 -04:00
Timothy Warren 3ab34a64d0 Fix issue retrieving some characters 2020-07-30 09:58:36 -04:00
Timothy Warren 8110f10c3d Skip broken test 2020-07-29 22:08:54 -04:00
Timothy Warren 7dae2dd6eb Small fixes for anime detail pages 2020-07-29 20:06:59 -04:00
Timothy Warren 7c0ea492e1 Get Manga details from GraphQL, See #27 2020-07-29 17:51:58 -04:00
Timothy Warren 9135598649 Fetch anime details by id for the collection 2020-07-29 16:25:57 -04:00
Timothy Warren 0b0e06af00 Anime detail page cleanup 2020-07-29 15:49:16 -04:00
Timothy Warren 1ae99d2189 get anime staff from GraphQL, see #27 2020-07-29 14:04:03 -04:00
Timothy Warren 7275d81468 Re-add characters to anime details page, see #27 2020-07-29 11:00:54 -04:00
Timothy Warren dbfdd1c239 Run local phpunit from robo 2020-07-29 11:00:06 -04:00
Timothy Warren 9eec7123a3 Use GraphQL request for anime detail pages, see #27 2020-07-28 17:46:18 -04:00
Timothy Warren 710d18a43b Prepare for Kitsu GraphQL 2020-07-28 16:11:13 -04:00
Timothy Warren 6d66ad1ea4 Merge remote-tracking branch 'origin/develop' 2020-05-19 13:19:20 -04:00
Timothy Warren 8d87d2fb2b Remove extra titles from cover/list views 2020-05-18 13:52:27 -04:00
Timothy Warren 61fcffdcbe Make sure reAuthenticate method has optional parameter 2020-05-18 13:47:41 -04:00
Timothy Warren 057216a21c Make sure re-authenticate gets arguments 2020-05-18 13:32:02 -04:00
Timothy Warren abb17844fd Add aria attributes to selected menu items 2020-05-18 12:53:00 -04:00
Timothy Warren 891d8af469 Remove extra titles from list/cover display 2020-05-18 12:52:32 -04:00
Timothy Warren c701999af1 Bug fixes 2020-05-11 09:17:11 -04:00
Timothy Warren af0b392e78 Only the command line should be able to get credentials from the cache 2020-05-08 21:34:36 -04:00
Timothy Warren 2cc85049f3 Refactor KitsuTrait 2020-05-08 19:18:10 -04:00
Timothy Warren 21a98dc48e Remove APCu as a cache option...it doesn't work with CLI authentication 2020-05-08 19:17:11 -04:00
Timothy Warren 3ecccb6ad8 Fix settings page subforms (so all the fields show for the cache) 2020-05-08 19:16:04 -04:00
Timothy Warren e724f885c8 Simplify caching 2020-05-08 19:15:21 -04:00
Timothy Warren 43f07dac6c Set up Event-based handling for a few things 2020-05-06 13:16:40 -04:00
Timothy Warren 7bcff79d6e Fix failing test 2020-05-06 10:12:49 -04:00
Timothy Warren f9f868be9d Show more alternate titles on anime detail pages 2020-05-06 09:08:27 -04:00
Timothy Warren 4a70422b23 Add better re-read messages to manga 2020-05-05 19:12:17 -04:00
Timothy Warren d8167ed075 Comment cleanup of sync command 2020-05-04 17:15:50 -04:00
Timothy Warren b6c0db7636 Refactor list sync to be easier to follow 2020-05-04 17:13:03 -04:00
Timothy Warren ffd7fb8745 Improve rewatched messages 2020-05-04 16:46:27 -04:00
Timothy Warren 75bd011a2c Various code tweaks 2020-05-01 19:38:45 -04:00
Timothy Warren 03638991a3 Fix collection episode length/count, display newlines in notes 2020-05-01 19:33:51 -04:00
Timothy Warren a7e6b3f198 Make authentication more reliable for list syncing 2020-05-01 17:08:20 -04:00
Timothy Warren d5e3dcaff8 Merge remote-tracking branch 'origin/develop' 2020-05-01 11:26:25 -04:00
Timothy Warren 9108fe066a Tweak anime list view a bit 2020-04-30 15:35:32 -04:00
Timothy Warren f810e2573e Collection updates for 'all' tab 2020-04-30 15:33:16 -04:00
Timothy Warren a371a334d0 Collection view tweaks 2020-04-30 15:30:52 -04:00
Timothy Warren ed72eaef84 Merge remote-tracking branch 'origin/develop' 2020-04-28 12:25:35 -04:00
Timothy Warren bcbd76d4a9 Update dependency versions 2020-04-28 12:24:34 -04:00
Timothy Warren 754cf80c0b Type *Type classes a bit more strictly 2020-04-28 12:24:12 -04:00
Timothy Warren ce0935333b Tweak error handling of anime collection db calls 2020-04-28 12:13:35 -04:00
Timothy Warren 050ff98d2c Add AnimeCollection link to MainMenu, similar to lists 2020-04-28 12:04:42 -04:00
Timothy Warren 44d2c0e29d Move unusued graphQL queries 2020-04-28 12:03:14 -04:00
Timothy Warren c14bf3a8af Merge remote-tracking branch 'origin/develop' 2020-04-24 16:55:34 -04:00
Timothy Warren 42ffef32fe Don't show episode/chapter 0 in history 2020-04-24 14:18:35 -04:00
Timothy Warren 1cc5703cd7 Fix some bugs with history view 2020-04-24 14:14:52 -04:00
Timothy Warren 62be0beae6 Fix history and collection bug 2020-04-23 20:03:55 -04:00
Timothy Warren e2e23a290f tweak cleanup migration 2020-04-23 19:40:59 -04:00
Timothy Warren 541b59bb28 Improve anime collection with multiple media selections 2020-04-23 18:57:22 -04:00
Timothy Warren d81fba030c Add migrations for collection improvements 2020-04-23 18:54:54 -04:00
Timothy Warren 209655adc3 Update dependency to published version 2020-04-23 18:53:51 -04:00
Timothy Warren 8be0fceb69 Minor tweaks to css and js 2020-04-23 18:51:12 -04:00
Timothy Warren 8094ff5927 More refactoring of History transformers 2020-04-22 17:53:25 -04:00
Timothy Warren b614505499 Add migration to create a link table between anime_sets and media 2020-04-22 17:52:07 -04:00
Timothy Warren e17846f4a4 Refactor history transformers 2020-04-22 12:38:59 -04:00
Timothy Warren 59f2d21a7f Add menu items for history, add manga reading history 2020-04-22 11:39:44 -04:00
Timothy Warren 0a83184db6 Convert Type constructors to static methods 2020-04-22 07:53:52 -04:00
Timothy Warren e3e32b4408 Fix off-by-one errors 2020-04-21 20:37:42 -04:00
Timothy Warren c424e3a65a Merge remote-tracking branch 'origin/php74' into develop 2020-04-21 20:13:59 -04:00
Timothy Warren 2325c8f4ec Fix aggregation of anime watch history items 2020-04-21 20:10:01 -04:00
Timothy Warren 5a3d9547ae Fix tests 2020-04-21 20:09:37 -04:00
Timothy Warren bc529e57e8 Big Work in progress commit 2020-04-21 19:22:56 -04:00
Timothy Warren f71a1ee1ae Update outdated interface reference 2020-04-17 13:34:36 -04:00
Timothy Warren 797e66e520 Temporarily require develop of Query 2020-04-17 13:19:43 -04:00
Timothy Warren 308a564a2d Merge branch 'php74' of github.com:timw4mail/HummingBirdAnimeClient into php74 2020-04-13 09:20:45 -04:00
Timothy Warren 174877ec81 More types 2020-04-13 09:20:05 -04:00
Timothy Warren 83bb85615a Fix merge conflict 2020-04-13 09:17:50 -04:00
Timothy Warren 570c18a069 Type all the class attributes 2020-04-10 20:01:46 -04:00
Timothy Warren 462e93292b Add more types 2020-04-10 16:35:01 -04:00
Timothy Warren 82cd204469 Remove some old frontend files 2020-04-10 15:43:12 -04:00
Timothy Warren 6d55d4136e Bump version and PHP requirement in headers 2020-04-10 15:39:39 -04:00
Timothy Warren 546789ce40 Update dependencies to latest versions 2020-04-10 15:38:32 -04:00
Timothy Warren 97be2e40f8 Merge branch 'php74' of timw4mail/HummingBirdAnimeClient into develop 2020-04-10 15:27:28 -04:00
Timothy Warren dd708bb1fa Just combine JS files for modern browsers, no minifying 2020-04-10 15:20:47 -04:00
Timothy Warren 93a6dbe7d6 Clean up public folder, move JS tools to frontEndSrc folder 2020-04-10 15:07:08 -04:00
Timothy Warren fae3314b56 Merge remote-tracking branch 'origin/develop' 2020-04-10 10:17:23 -04:00
Timothy Warren dbb61372c6 Fix streaming logo display 2020-04-08 10:08:56 -04:00
Timothy Warren 0b4c2c81c3 Merge remote-tracking branch 'origin/develop' 2020-04-07 22:07:01 -04:00
Timothy Warren 0aee62c174 Fix image snapshot test 2020-04-07 22:04:15 -04:00
Timothy Warren 7fd881c8e9 Lazy load images 2020-04-07 21:53:53 -04:00
Timothy Warren 9158d01fdf Update snapshot tests for form generation 2020-03-17 15:39:33 -04:00
Timothy Warren ae8df3e6d6 Simplify Jenkins build again 2020-03-17 15:15:20 -04:00
Timothy Warren f6e00d4336 Downgrade snapshot library to a version that works with PHP 7.3 2020-03-17 15:05:28 -04:00
Timothy Warren 34b454c175 Attempt to clear dependencies on each step 2020-03-17 11:25:17 -04:00
Timothy Warren 5ce34200c9 Add PHP 7.3 test section back 2020-03-17 11:21:27 -04:00
Timothy Warren 1a6a30ef5d Update test snapshots 2020-03-16 15:47:33 -04:00
Timothy Warren 8faf33c438 Try only PHP 7.4 for tests 2020-03-16 15:25:31 -04:00
Timothy Warren 6e16632988 Revert "Will tests still work with fewer file priviledges?"
This reverts commit 14db3f1ec9.
2020-03-16 15:23:19 -04:00
Timothy Warren 14db3f1ec9 Will tests still work with fewer file priviledges? 2020-03-16 15:19:43 -04:00
Timothy Warren a4fe28f7b5 Fix some style issues 2020-03-16 15:06:55 -04:00
Timothy Warren 7c796b3d7b Cleanup some build/quality check stuff 2020-03-13 09:53:31 -04:00
Timothy Warren 06529d7c92 More test coverage of FormGenerator 2020-03-12 12:47:02 -04:00
Timothy Warren 42948017a4 Test FormGenerator 2020-03-12 12:32:32 -04:00
Timothy Warren 055ec80236 Increase code coverage 2020-03-12 12:04:20 -04:00
Timothy Warren 986ff6de0b Update header comments again 2020-03-12 11:45:11 -04:00
Timothy Warren e6a216704c Remove XML codec 2020-03-12 11:44:19 -04:00
Timothy Warren beaeb13353 Yet another CI code coverage commit 2020-03-12 11:29:00 -04:00
Timothy Warren 0ea35cb421 Yet another CI code coverage commit 2020-03-12 11:20:07 -04:00
Timothy Warren 0feb44a836 Yet another CI code coverage commit 2020-03-12 11:17:27 -04:00
Timothy Warren 9b33a45189 Yet another CI code coverage commit 2020-03-12 11:09:56 -04:00
Timothy Warren e0fa618b4e Yet another CI code coverage commit 2020-03-12 11:08:18 -04:00
Timothy Warren 7672976f47 Yet another CI code coverage commit 2020-03-12 11:04:22 -04:00
Timothy Warren 8036104731 Yet another CI code coverage commit 2020-03-12 10:57:19 -04:00
Timothy Warren 76cb8ca00b Yet another CI code coverage commit 2020-03-12 10:49:32 -04:00
Timothy Warren cc3b999bc5 Yet another CI code coverage commit 2020-03-12 10:44:29 -04:00
Timothy Warren fb327f0c58 Yet another CI code coverage commit 2020-03-12 10:40:39 -04:00
Timothy Warren ee914d048b Yet another CI code coverage commit 2020-03-12 10:36:20 -04:00
Timothy Warren f57466d42c A docker image that exists does help 2020-03-12 10:28:21 -04:00
Timothy Warren 3ce928a67d The correct syntax helps for working CI 2020-03-12 10:26:00 -04:00
Timothy Warren 622b435337 Another attempt to fix CI 2020-03-12 10:24:21 -04:00
Timothy Warren 6acee9ca7a Attempt to do code coverage with less memory to begin with 2020-03-12 10:12:28 -04:00
Timothy Warren 16ecfe3eb5 Does code coverage work with a lower explicit memory limit? 2020-03-12 10:04:05 -04:00
Timothy Warren c0fa4cfed2 Try coverage again without setting memory limit 2020-03-12 10:00:20 -04:00
Timothy Warren 00ef5c3706 Fix test suite 2020-03-12 09:52:45 -04:00
Timothy Warren 618328a4c1 Move AnimeClient tests 2020-03-11 23:18:31 -04:00
Timothy Warren e5ef054f5b Put Ion Namespace back in the codebase directly 2020-03-11 23:04:01 -04:00
Timothy Warren d9e81a7cf1 Increase CI PHP memory limit 2020-03-11 22:27:47 -04:00
Timothy Warren b334a60486 Skip robo lint, as it fails on test snapshots 2020-03-11 22:21:23 -04:00
Timothy Warren 17b01f6d48 Make sure git is installed for CI 2020-03-11 22:18:04 -04:00
Timothy Warren ef7c1da5f2 Move source code to sub folder so we can re-integrate ion 2020-03-11 22:11:00 -04:00
Timothy Warren 6718fc78e9 Remove dependency causing issues on PHP < 7.4 2020-03-11 16:34:33 -04:00
Timothy Warren 5216b60789 Update all the header files again 2020-03-11 16:31:52 -04:00
Timothy Warren 37c3d6ecf0 Move to Amp/HttpClient from Amp/Artax 2020-03-11 16:26:17 -04:00
Timothy Warren eb12f57e7d Attempt to fix Jenkins build, take 2 2020-03-11 15:29:34 -04:00
Timothy Warren a03b9be329 Attempt to fix Jenkins build 2020-03-11 15:24:15 -04:00
Timothy Warren 07de5ff79b Show composer install error for CI, please 2020-03-11 15:16:43 -04:00
Timothy Warren 8aa94f7c14 Update all the header comments 2020-03-11 15:15:05 -04:00
Timothy Warren 8842df76be Bump PHP requirement 2020-03-11 15:14:34 -04:00
Timothy Warren 6047444077 Fix a method of Anilist Model 2020-03-11 15:12:10 -04:00
Timothy Warren 95e8b7920a Remove php7.2 step in CI 2020-03-11 15:05:27 -04:00
Timothy Warren 66b13ef7ba Add code coverage to CI 2020-03-11 15:03:04 -04:00
Timothy Warren b32968588a Minor view updates 2020-01-15 15:23:55 -05:00
Timothy Warren fafd75b791 More error checking 2020-01-15 15:22:38 -05:00
Timothy Warren 70eb4f11b3 Better id mapping error handling for Anilist 2020-01-15 12:35:37 -05:00
Timothy Warren ae70eab9ea Bump copyright year 2020-01-08 15:39:49 -05:00
Timothy Warren 926179a72d More refactoring/cleanup 2019-12-09 16:17:25 -05:00
Timothy Warren 143229bea4 Automatically fix some docblocks 2019-12-09 14:41:04 -05:00
Timothy Warren 3978c4d5cb Update all the docblocks 2019-12-09 14:34:23 -05:00
Timothy Warren 705d48abad Annotate property types for Types classes 2019-12-09 13:40:54 -05:00
Timothy Warren 6044a676a6 Various code style tweaks 2019-12-09 13:13:31 -05:00
Timothy Warren 245e1b4344 Various code cleanup 2019-12-06 15:46:56 -05:00
Timothy Warren ec9edff2f3 Add linting check to CI to help catch version-incompatible code 2019-12-06 10:05:09 -05:00
Timothy Warren 3fa5b7ab88 Downgrade snapshot library so that more PHP versions work for tests 2019-12-06 09:25:04 -05:00
Timothy Warren ceb8159dae Remove composer.lock for each test run to make sure dependencies are correctly installed 2019-12-06 09:19:47 -05:00
Timothy Warren 8b677ab7a7 Update header comments 2019-12-06 09:16:35 -05:00
Timothy Warren b4b5c63d65 Tweak tests for new version of PHPUnit 2019-12-06 09:15:49 -05:00
Timothy Warren 347674f9e5 Update dependencies 2019-12-05 16:59:24 -05:00
Timothy Warren d435a17ec8 Add PHP 7.4 tests 2019-12-05 11:20:06 -05:00
Timothy Warren fde9b05bdf Bump PHP version requirement 2019-12-03 15:17:25 -05:00
Timothy Warren 7d9d2e8990 Merge remote-tracking branch 'origin/develop' 2019-12-02 15:30:04 -05:00
Timothy Warren 995690a341 Update clear thumbnails script to work with lots of files 2019-12-02 15:29:24 -05:00
Timothy Warren 808b704383 Merge remote-tracking branch 'origin/develop' 2019-10-08 20:25:24 -04:00
Timothy Warren cd835055ec Catch errors when mapping MAL ids on sync 2019-10-08 19:59:47 -04:00
Timothy Warren 117427ced0 Misc bugfixes, especially for Anime without a MAL id. 2019-10-07 20:10:27 -04:00
Timothy Warren aebb349543 Update CI stuff 2019-08-16 14:40:15 -04:00
Timothy Warren 37f7616ef4 Merge remote-tracking branch 'origin/develop' 2019-08-16 10:39:50 -04:00
Timothy Warren 28d4ce9e86 Remove php 7.4 version in travis config that doesn't exist yet 2019-08-16 10:35:59 -04:00
Timothy Warren 0e893f06ba Minor code cleanup, add newer php version for travis tests 2019-08-16 10:31:31 -04:00
Timothy Warren 58bb1ab0ba Update base request builder to use the correct user agent 2019-08-10 10:42:02 -04:00
Timothy Warren 46041ccfc6 Add first GraphQL files for Kitsu for future implementation 2019-08-10 10:10:09 -04:00
Timothy Warren 625edf5d0c Improve 404 checks for detail pages 2019-08-10 10:09:07 -04:00
Timothy Warren 4edfd9f62c Update detail pages to use one column for text 2019-08-10 10:07:28 -04:00
Timothy Warren e5baccbf56 Simplify _.show and _.hide useage 2019-07-15 16:05:29 -04:00
Timothy Warren bfd5ff32c1 Merge remote-tracking branch 'origin/develop' 2019-07-15 14:31:17 -04:00
Timothy Warren e1fd639ba9 Fix scroll to top on list item update 2019-07-12 23:12:05 -04:00
Timothy Warren 4e88c27cfb Remove now unused css file 2019-07-12 16:27:39 -04:00
Timothy Warren 0153271a62 Add 'automatic' dark theme, based on browser 'prefers-color-scheme: dark' media query 2019-07-12 15:56:24 -04:00
Timothy Warren 7a529619ed Update js dependencies 2019-07-12 13:33:40 -04:00
Timothy Warren a6020df023 Merge remote-tracking branch 'origin/develop' 2019-07-12 13:28:37 -04:00
Timothy Warren cda711607a Clean up commands a little bit 2019-07-11 19:03:35 -04:00
Timothy Warren c5bb555695 Show fewer sync errors by filtering common data disparity issues 2019-07-11 16:38:21 -04:00
Timothy Warren ea5eb21941 Fix syncing manga to anilist when you have to create a new list item 2019-07-11 15:24:34 -04:00
Timothy Warren 038e61bf37 Make Anilist missing username error more reliable, allow editing anilist username in settings panel 2019-07-11 10:28:09 -04:00
Timothy Warren bce1afa546 Collection "All Tab", and filtering. Resolves #6, #7 2019-07-10 13:32:05 -04:00
Timothy Warren 4502c2f183 No more genre-related database errors, and other collection improvements 2019-07-10 10:20:37 -04:00
Timothy Warren b070282899 Merge remote-tracking branch 'origin/develop' 2019-05-08 16:09:29 -04:00
Timothy Warren aa6965e98f Tweak display of descriptions on detail pages 2019-05-08 16:08:51 -04:00
Timothy Warren b2c8bff967 Merge remote-tracking branch 'origin/develop' 2019-05-08 14:18:49 -04:00
Timothy Warren ea2a368100 Use larger cover images for edit forms 2019-05-08 14:18:18 -04:00
Timothy Warren 523fcbd0d9 Edit form style tweaks 2019-05-08 14:17:57 -04:00
Timothy Warren 003492a964 Merge remote-tracking branch 'origin/develop' 2019-05-08 13:19:32 -04:00
Timothy Warren e98699acbc Fix thumbnail generation command 2019-05-08 13:19:03 -04:00
Timothy Warren eb31096bff Merge branch 'develop' of timw4mail/HummingBirdAnimeClient into master 2019-05-08 12:40:32 -04:00
Timothy Warren d1a0147ae2 Button and Select style tweaks 2019-05-08 11:14:11 -04:00
Timothy Warren 6c81ddbfd4 Add polyfill for older browsers, so Opera 12 works 2019-05-08 08:57:15 -04:00
Timothy Warren 2fdca56501 Update js sourcemaps 2019-05-08 08:56:26 -04:00
Timothy Warren 47d6314178 Use static closures in bootstrap 2019-05-08 08:55:58 -04:00
Timothy Warren e73326fd6c Update css/js dependencies 2019-05-08 08:53:34 -04:00
Timothy Warren 251bbadd96 Style tweaks. Fixes #16. 2019-05-08 08:50:57 -04:00
Timothy Warren 6ee198c742 Fix some edge cases 2019-04-01 16:17:40 -04:00
Timothy Warren dfdc6b7356 Remove XML tests 2019-03-12 09:47:59 -04:00
Timothy Warren 94b15f455c Remove XML codec class 2019-03-12 09:43:17 -04:00
Timothy Warren f6278a1304 Consistent spacing around auth checks 2019-01-29 16:01:31 -05:00
Timothy Warren 04c5b135a7 Add a per-controller-method check for authorization for private routes 2019-01-29 15:12:31 -05:00
Timothy Warren 8a8ea0b470 Cleanup redundant methods in Collection model 2019-01-28 14:31:48 -05:00
Timothy Warren 4e2437f2bc Fix error on attempt to insert a duplicate series 2019-01-22 10:21:58 -05:00
Timothy Warren 27c7f08d7f Hide missing table error on noninitialized collection, see #20 2019-01-08 15:52:53 -05:00
Timothy Warren b6f12ff2f6 Update phinx.yml file for new version of Phinx, see #20 2019-01-07 14:31:17 -05:00
Timothy Warren 317d8fd29b Cleanup database logic a bit 2019-01-07 14:29:15 -05:00
Timothy Warren b66a35843d Small code cleanup 2019-01-07 09:08:00 -05:00
Timothy Warren ac382a96a8 Simplify/clean up some base classes 2018-12-21 15:52:34 -05:00
Timothy Warren 87d0960424 Merge branch 'develop' of timw4mail/HummingBirdAnimeClient into master 2018-12-13 14:51:01 -05:00
Timothy Warren be16ceecb2 Make syncing slightly more robust 2018-12-12 15:31:59 -05:00
Timothy Warren 105b0f52ca Use the same API client instance across the codebase 2018-12-07 10:24:42 -05:00
Timothy Warren 63a50f7ed8 Don't show media tabs with no media on character page, make stats on user page more resiliant 2018-12-07 10:22:16 -05:00
Timothy Warren 4b9f97f49e Remove default API client timeouts, fix time on anime calculation 2018-12-06 16:21:02 -05:00
Timothy Warren 8272cc7240 Remove CSS sourcemaps...because they're pointless 2018-12-06 13:44:31 -05:00
Timothy Warren 538201ef6f Add dark theme with setting toggle 2018-12-06 13:04:54 -05:00
Timothy Warren 5e9780aad7 Update misspelled method, somehow resolves #19 2018-11-29 11:46:06 -05:00
Timothy Warren f3265484da Some API client cleanup 2018-11-29 11:00:50 -05:00
Timothy Warren 4c3f987b85 Fix error in list sync 2018-11-27 15:37:16 -05:00
Timothy Warren 5e3fb46159 Update cache dependency 2018-11-27 14:57:27 -05:00
Timothy Warren 2c73e721d0 Misc code cleanup 2018-11-09 10:38:35 -05:00
Timothy Warren 431f6e7d21 Purge the few inline styles 2018-11-08 14:18:24 -05:00
Timothy Warren c0e16c6d07 Remove data transformation from media detail pages, and into the proper transformers 2018-11-08 12:15:30 -05:00
Timothy Warren 9c0b1e73ef Move data transformation out of controllers, and into transformers 2018-11-08 11:36:42 -05:00
Timothy Warren 05842baccb Fix generic user page route, minor code cleanup 2018-11-07 14:29:21 -05:00
Timothy Warren 7f6b0178a8 Merge remote-tracking branch 'origin/master' into develop 2018-11-05 13:25:42 -05:00
Timothy Warren 8b938add27 Fix collection query 2018-11-05 13:25:18 -05:00
Timothy Warren 8672112bdc Merge branch 'develop' of timw4mail/HummingBirdAnimeClient into master 2018-11-05 13:15:58 -05:00
Timothy Warren 033ea46754 More styling tweaks 2018-11-05 11:22:35 -05:00
Timothy Warren 24f80bc18c Make tables responsive 2018-11-05 11:04:19 -05:00
Timothy Warren 4b75987f21 Fix broken snapshot test 2018-11-05 10:42:51 -05:00
Timothy Warren ca487901c2 Sort streaming links by service 2018-11-05 10:40:29 -05:00
Timothy Warren e195987436 Some visual tweaks 2018-11-05 09:56:38 -05:00
Timothy Warren 350dae0109 Responsive updates for smaller screen sizes 2018-11-05 09:47:05 -05:00
Timothy Warren d514c319c0 Update picture helper, move anilist oauth calls to the settings controller 2018-11-02 12:58:19 -04:00
Timothy Warren 4ace9b6806 Make all the css classes and ids kebob case 2018-11-02 10:48:20 -04:00
Timothy Warren 64478d4507 Update controller test 2018-11-01 22:16:45 -04:00
Timothy Warren f314538972 Various refactoring, better webp image handling 2018-11-01 22:15:20 -04:00
Timothy Warren 155650961b Make Controllers more specialized 2018-11-01 22:12:41 -04:00
Timothy Warren b3366131b8 Lots of visual updates 2018-11-01 22:01:09 -04:00
Timothy Warren 040b7f3fdc More page style tweaks 2018-10-30 13:05:49 -04:00
Timothy Warren ef1e435c6b Add tabs to character page sections 2018-10-30 11:42:32 -04:00
Timothy Warren a9c3a44f37 Fix css for character images on user page 2018-10-30 09:43:54 -04:00
Timothy Warren 3842df13db Small code consistency update 2018-10-29 15:48:54 -04:00
Timothy Warren be2f7708ad Add staff section on Manga detail pages 2018-10-29 15:17:48 -04:00
Timothy Warren 29a4114e8c Fix staff section on Anime detail pages, center unusually sized images instead of stretching them 2018-10-29 14:43:06 -04:00
Timothy Warren 1690d8c1e0 Attempt to fix tests again 2018-10-29 10:07:20 -04:00
Timothy Warren e84cbe1bb2 Update test snapshots 2018-10-29 09:41:50 -04:00
Timothy Warren d0af6fd9e8 Update JsonAPI helper to better handle input data without mangling 2018-10-29 09:39:56 -04:00
Timothy Warren bcc7815ae6 Ugly Progress Commit
* Update Person pages to have series organized by character for Voice
Acting
* Miscellaneous style updates
* Add placeholder images for items missing images
2018-10-26 13:08:45 -04:00
Timothy Warren 5d87bd044c Refactor some silly switches 2018-10-19 10:40:11 -04:00
Timothy Warren e2b4fae83b Fix broken tests 2018-10-19 10:39:38 -04:00
Timothy Warren 019fff5d62 Miscellaneous page improvements, including additional data and sorting 2018-10-19 09:30:27 -04:00
Timothy Warren cf1c495f90 Remove need for www subdomain for streaming service mapping 2018-10-17 14:33:16 -04:00
Timothy Warren cee5a28816 Replace switch statement with array mapping 2018-10-17 14:20:07 -04:00
Timothy Warren 83a6629f03 Fix tests, and category list for Manga detail page 2018-10-16 14:32:52 -04:00
Timothy Warren 5810405f12 Remove a reference to genres from an older version of the Kitsu API 2018-10-16 14:22:47 -04:00
Timothy Warren 7b765c6d0b Account for missing genres in anime collection 2018-10-11 16:40:51 -04:00
Timothy Warren a9acf23a15 Update docs a bit 2018-10-11 13:25:53 -04:00
Timothy Warren b14a827715 Update shell script for Jenkins 2018-10-11 13:06:58 -04:00
Timothy Warren 1cd8386559 Closer to working Jenkins 2018-10-11 12:50:29 -04:00
Timothy Warren 1fa11cd50d Try again, for Jenkins 2018-10-11 12:22:44 -04:00
Timothy Warren 8a7223593d Maybe third time is a charm for Jenkins? 2018-10-11 12:08:57 -04:00
Timothy Warren ccc9ad0c14 Attempt2 with Jenkins 2018-10-11 11:54:27 -04:00
Timothy Warren 509db151e7 Let's do CI with Jenkins 2018-10-11 11:11:24 -04:00
Timothy Warren 0bbc4fe4fb Default to secure (https) urls 2018-10-11 09:53:14 -04:00
Timothy Warren 86c311dddf Add console command to re-generate list thumbnails 2018-10-10 16:04:58 -04:00
Timothy Warren eaf3554611 Attempt to fix ssl detection 2018-10-10 15:58:28 -04:00
Timothy Warren 99aaf0303b Fix broken url generator test 2018-10-10 14:26:44 -04:00
Timothy Warren 6d1df75889 Always set the url protocol for the url generator 2018-10-10 14:21:46 -04:00
Timothy Warren 9c8e396c9a Fix javascript minification 2018-10-10 12:57:11 -04:00
Timothy Warren c9ec11c2df Fix tests 2018-10-09 18:26:42 -04:00
Timothy Warren 587d5fa14e Update config.toml.example file 2018-10-09 18:21:06 -04:00
Timothy Warren 229703a6a6 Update README 2018-10-09 18:15:03 -04:00
Timothy Warren 5b8f0c4a9e Full Anilist settings page OAuth flow, ability to run app without manually editing config files. See #7. Resolves #5 2018-10-09 18:10:20 -04:00
Timothy Warren 41d71dac0c Cleanup styles of settings page, cleanup syncing command a bit 2018-10-09 10:11:42 -04:00
Timothy Warren 6dfa66dbde Fix issue with cache settings 2018-10-08 16:47:40 -04:00
Timothy Warren 324abc0f61 More settings, now with tabs 2018-10-08 16:38:08 -04:00
Timothy Warren 3c0fd79195 Settings control panel saves to admin-override.toml in the app/config directory, resolves #7 2018-10-08 15:45:46 -04:00
Timothy Warren 0d30f57e83 Update gitignore 2018-10-08 15:44:03 -04:00
Timothy Warren 247a9d0e5b More webp images, fix login 2018-10-05 22:36:54 -04:00
Timothy Warren d6800dbc46 Ugly Progress Commit
* Cache and resize images - not just cache them
* Convert to webp on cache
* Show webp images if available
* Settings Form Generation (doesn't yet save)
2018-10-05 21:32:15 -04:00
Timothy Warren ae283cd898 Add command to check Kitsu's MAL id mappings 2018-10-05 14:40:30 -04:00
Timothy Warren a8f898822a Update code to use simpler config 2018-10-05 14:32:05 -04:00
Timothy Warren da936b325e Merge config.toml and route_config.toml 2018-10-05 14:27:07 -04:00
Timothy Warren 8b3ce0f079 Fix some api mapping issues for #5 2018-10-01 13:03:48 -04:00
Timothy Warren c9ed90acb4 Update header comments to version 4.1 2018-10-01 11:35:51 -04:00
Timothy Warren 17a9539e94 More work on #5 2018-10-01 10:50:22 -04:00
Timothy Warren 6f717e6ab7 Fix tests 2018-09-27 16:48:12 -04:00
Timothy Warren 0f31a5e10a Ugly progress commit 2018-09-27 16:45:12 -04:00
Timothy Warren e0376c78d1 Fix tests 2018-09-26 22:43:04 -04:00
Timothy Warren a6c253b969 Lots of Anilist integration, see #5 2018-09-26 22:31:04 -04:00
Timothy Warren 5a607db93e Rebuild scripts and css 2018-09-20 16:12:28 -04:00
Timothy Warren e7dc1e8e53 Anilist CRUD operations for Anime! See #5 2018-09-20 16:08:46 -04:00
Timothy Warren 38a5b78295 Update test snapshots 2018-09-20 11:53:12 -04:00
Timothy Warren 034213fccc Progress with simultaneous updates to Anilist for Anime 2018-09-20 10:41:28 -04:00
Timothy Warren 020f561773 JS style updates 2018-09-19 14:11:35 -04:00
Timothy Warren 2fc26bf4c6 Let's do ES modules for browsers that support them 2018-09-14 11:56:48 -04:00
Timothy Warren 09530efefd Optimize streaming service logos 2018-09-12 14:20:51 -04:00
Timothy Warren 0624c3be67 Check config object shape on page load 2018-08-24 14:37:53 -04:00
Timothy Warren a71fb185bd Add Config 'Type', to keep config settings somewhat in check 2018-08-24 14:36:58 -04:00
Timothy Warren 98ae142757 Cleanup config a bit 2018-08-24 14:23:01 -04:00
Timothy Warren cd150d7fef Fix stupid type error 2018-08-22 13:51:58 -04:00
Timothy Warren 3bca049cd8 Update file header comments 2018-08-22 13:48:27 -04:00
Timothy Warren 95b06a7e7e Eradicate MAL integration 2018-08-22 13:43:04 -04:00
Timothy Warren 81f02ad622 Cleanup javascript into fewer files, add show/description link to search pages 2018-08-22 12:54:06 -04:00
Timothy Warren 64d3c241f6 Update service worker so it only caches images 2018-08-21 17:11:03 -04:00
Timothy Warren 4a91a5cb5d Anime Collection improvements
* Allow editing title and alternate title
* Show list of genres on list view of collection
2018-08-21 17:09:42 -04:00
Timothy Warren 226f0ced83 Getting started with some service workers 2018-08-20 16:24:33 -04:00
Timothy Warren bc2122dd98 Fix test failure 2018-08-20 13:41:25 -04:00
Timothy Warren 2a2ff87b3b Various cleanup, some work on #7 2018-08-20 13:01:16 -04:00
Timothy Warren 7c0d02758b Remove php js minifier script, in favor of commited js files 2018-08-20 12:58:56 -04:00
Timothy Warren e6761807b8 Add basic check for folder permissions for quicker troubleshooting 2018-08-16 12:10:24 -04:00
Timothy Warren bfb5d6323d More progress on #5 2018-08-15 16:19:07 -04:00
Timothy Warren b3a3e19146 Making API requests to Anilist, see #5 2018-08-15 14:05:28 -04:00
Timothy Warren b5f8413ceb More prep for Anilist integration 2018-08-15 08:51:37 -04:00
Timothy Warren b2554378e7 Merge remote-tracking branch 'origin/develop' 2018-08-14 11:37:43 -04:00
Timothy Warren 1fa5cce5ae Remove lines and shading from add forms 2018-08-14 11:36:26 -04:00
Timothy Warren ea31131e0f Adjust layout of edit pages 2018-08-13 15:13:20 -04:00
Timothy Warren 675f8ed9b2 Update test snapshots 2018-08-10 20:11:22 -04:00
Timothy Warren 0dcf25e16c More refactoring work, some groundwork for Anilist integration 2018-08-10 20:10:19 -04:00
Timothy Warren dd46e292c4 Update some styles 2018-08-10 20:09:28 -04:00
Timothy Warren e9888c762e Fix test snapshots 2018-08-10 11:01:30 -04:00
Timothy Warren 49295148d1 Update some types
* Remove empty values from types for serialization, so that empty values
are not sent with API requests
* Allow use of explicit setters for more complex types
2018-08-09 11:34:02 -04:00
Timothy Warren d1421d2eb2 Better error handling for incrementing watched count on Anime list 2018-08-09 11:31:15 -04:00
Timothy Warren 69c2482fc1 Remove references to MAL syncing, resolves #4 2018-08-09 11:16:44 -04:00
Timothy Warren 571bbf7595 More tabs for collections, see issue #2 2018-08-09 11:14:57 -04:00
Timothy Warren e01a96b8fb First go at tabs for collection 2018-08-08 17:04:35 -04:00
Timothy Warren 2c7d866677 Fix PHP 7.1 test 2018-08-08 13:08:10 -04:00
Timothy Warren be2b387391 More refactoring, fix snapshot tests 2018-08-08 13:05:38 -04:00
Timothy Warren 06c55a2094 Fix tests 2018-08-08 11:18:57 -04:00
Timothy Warren 9a7084078f Some minor code cleanliness refactoring 2018-08-08 10:12:45 -04:00
Timothy Warren f71e9dbe4d Merge remote-tracking branch 'origin/master' into develop 2018-06-15 08:47:16 -04:00
Timothy Warren cecca5f9f0 Give a better error message on failing to parse an XML API response 2018-06-15 08:46:28 -04:00
Timothy Warren 79be0ebb34 Use more efficient method of combining large sets of data from Kitsu 2018-04-11 09:26:14 -04:00
Timothy Warren c7a77a2eb5 Merge branch 'master' of timw4mail/HummingBirdAnimeClient into develop 2018-04-05 23:03:43 -04:00
Timothy Warren c0c72e40e4 Add more missing streaming logos 2018-04-05 23:00:58 -04:00
Timothy Warren 01bf7144c2 Merge remote-tracking branch 'origin/develop' 2018-04-05 21:56:02 -04:00
Timothy Warren f5f59b8382 Update wiki and CI links due to move from Gitlab 2018-04-05 21:20:43 -04:00
Timothy Warren 75a5727a2e Add Hidive to streaming service mapping 2018-04-05 08:56:01 -04:00
Timothy Warren 4f0c3f7984 Add Hidive to streaming service mapping 2018-04-05 08:39:49 -04:00
Timothy Warren 83e0310ca7 Merge remote-tracking branch 'origin/develop' 2018-02-02 09:53:22 -05:00
Timothy Warren 9cac51bd82 Miscellaneous style updates 2018-02-02 09:50:58 -05:00
Timothy Warren a434c032a2 Minor refactor of Commands 2018-01-31 15:44:48 -05:00
Timothy Warren ad0154f431 Merge remote-tracking branch 'origin/develop' 2018-01-31 11:36:54 -05:00
Timothy Warren 080b112608 Update test snapshot 2018-01-31 11:00:10 -05:00
Timothy Warren 92ad051f6a Add trailer videos to anime detail pages 2018-01-31 10:55:20 -05:00
Timothy Warren da8f4acb29 Use template literals instead of mustache templates 2018-01-30 16:57:13 -05:00
Timothy Warren 43ab033aec Merge remote-tracking branch 'origin/develop' 2018-01-30 14:28:07 -05:00
Timothy Warren 83f9d14630 Fix issue with anime detail pages 2018-01-30 14:02:28 -05:00
Timothy Warren 634335187e Merge remote-tracking branch 'origin/develop' 2018-01-25 19:31:34 -05:00
Timothy Warren f06ba6e3cd Lots of style fixes and minor logic tweaks 2018-01-18 16:21:45 -05:00
Timothy Warren 675b1ef2f1 Update README for requirements 2018-01-16 15:05:17 -05:00
Timothy Warren a46a85bf71 Remove php 7.0 test 2018-01-16 15:04:25 -05:00
Timothy Warren 3a739e3920 Make character layout more closely match anime/manga pages 2018-01-16 14:58:30 -05:00
Timothy Warren 231babe218 Code style improvements 2018-01-16 14:58:07 -05:00
Timothy Warren 4532bd1865 Remove strict types from Artax client implementation 2018-01-15 14:49:17 -05:00
Timothy Warren 7b9adbf52e Update copyright year 2018-01-15 14:43:15 -05:00
Timothy Warren f607403111 Merge branch 'master' into 'develop'
Correct index of id for kitsu sync

See merge request timw4mail/HummingBirdAnimeClient!22
2018-01-11 09:49:43 -05:00
Timothy Warren 34996f009b Correct index of id for kitsu sync 2018-01-10 16:43:49 -05:00
Timothy Warren 39031ccf3e Simplify syncing script 2018-01-10 16:34:25 -05:00
Timothy Warren 4451544389 Merge remote-tracking branch 'origin/master' into develop 2018-01-10 16:28:37 -05:00
Timothy Warren 5aa750cde7 Fix some documentation generation issues 2018-01-10 16:24:00 -05:00
Timothy Warren 11068029e8 Handle syncing errors more consistently 2018-01-10 16:18:06 -05:00
Timothy Warren e75c52d9dc Fix bug with sync, remove some code duplication 2017-12-13 11:38:21 -05:00
Timothy Warren 09f9aa2069 Merge branch 'master' into 'develop'
Merge branch 'develop' into 'master'

See merge request timw4mail/HummingBirdAnimeClient!21
2017-12-11 13:24:30 -05:00
Timothy Warren bbe2fd0a5d Update Artax, and update other code to work with new version 2017-12-08 22:32:00 -05:00
Timothy Warren 2ad0a24483 Miscellaneous code style changes 2017-12-06 14:40:13 -05:00
Timothy Warren 0c52831ec6 Merge branch 'develop' into 'master'
Update master from develop

See merge request timw4mail/HummingBirdAnimeClient!20
2017-12-06 12:36:23 -05:00
Timothy Warren 55fca3f92f Correct some errors in creating and deleting anime collection items 2017-12-06 12:30:12 -05:00
Timothy Warren 034174418b Update dependencies 2017-12-06 11:48:15 -05:00
Timothy Warren e8f53542e8 Make sure to add git... 2017-12-06 11:20:12 -05:00
Timothy Warren ae52f8737a Don't try to run update, maybe? 2017-12-06 11:16:47 -05:00
Timothy Warren 888dbe7187 Another attempt to fix gitlab ci builds 2017-12-06 11:12:51 -05:00
Timothy Warren 37f1391a07 Try, try, again 2017-12-06 11:10:50 -05:00
Timothy Warren 8b8ece3dad Attempt to fix gitlab ci build 2017-12-06 11:07:23 -05:00
Timothy Warren 015b3d0f34 Attempt to test PHP 7.2 2017-12-06 10:58:26 -05:00
Timothy Warren ee57f72ca6 Merge remote-tracking branch 'origin/master' into develop 2017-12-04 16:07:46 -05:00
Timothy Warren 9497f5c3df Fix MAL sync issue for anime 2017-12-04 16:06:27 -05:00
Timothy Warren 63fe8684c4 Fix js minification url 2017-12-04 15:57:13 -05:00
Timothy Warren a2fbe471e3 Attempt to fix builds 3 2017-10-19 18:38:56 -04:00
Timothy Warren c6f2981d63 Attempt to fix builds 2 2017-10-19 18:34:11 -04:00
Timothy Warren 410ff4fcc1 Attempt to fix builds 2017-10-19 18:31:28 -04:00
Timothy Warren 7e8e9a3141 Merge branch 'master' into develop 2017-10-18 20:00:00 -04:00
Timothy Warren 98c24d4704 Fix about section of user page 2017-10-18 19:59:29 -04:00
Timothy Warren c9533db6a1 Merge branch 'master' into develop 2017-10-18 19:42:38 -04:00
Timothy Warren a4555ca908 Merge branch 'master' of git.timshomepage.net:timw4mail/HummingBirdAnimeClient 2017-10-18 19:42:01 -04:00
Timothy Warren 45e14a7503 Add proper logging to console commands 2017-10-18 19:28:57 -04:00
Timothy Warren 5eaa33ba82 Fix an issue with Kitsu <-> MAL sync 2017-10-18 19:28:22 -04:00
Timothy Warren 38eee85752 Revert former change so that kitsu anime lists are properly pulled for sync 2017-09-15 16:51:47 -04:00
Timothy Warren 2b9adb0395 Adding missing method for manga collection 2017-09-15 15:05:35 -04:00
Timothy Warren 5fb042a773 Better handle empty lists on sync, resolves #29 2017-09-15 15:04:57 -04:00
Timothy Warren 04ec5b2fd6 Tweak handling of empty list sections 2017-09-14 17:33:24 -04:00
Timothy Warren b0ee397994 Fix an issue fetching anime for the add item call 2017-09-14 17:32:40 -04:00
Timothy Warren 200ff1339c Rough start of Manga collection...need to set up proper structure for manga collection items 2017-09-14 16:18:13 -04:00
Timothy Warren a8e2049d08 Refactor a bit to prepare for manga collection 2017-09-14 15:32:53 -04:00
Timothy Warren 07152cc3be Remove PHP 7.2 test that doesn't work 2017-09-12 12:52:56 -04:00
Timothy Warren 89816dc062 Test with php 7.2 2017-09-12 12:38:26 -04:00
Timothy Warren 3c4e34f1ed Fix tests broken by api change fixes 2017-09-12 12:33:57 -04:00
Timothy Warren 372b616101 Update some api calls based on api changes 2017-09-12 12:18:31 -04:00
Timothy Warren d93d22f7df Add overlay during update request on list pages, resolves #31 2017-07-12 16:40:56 -04:00
Timothy Warren 6493f33faf Attempt to re-authenticate when access token expires 2017-06-19 15:31:24 -04:00
Timothy Warren e66a9f885a Some minor refactoring 2017-06-19 13:49:28 -04:00
Timothy Warren fa74e59854 Update htaccess so images can load 2017-04-28 13:20:59 -04:00
Timothy Warren a15a97370b Update readme with another folder that needs to be writable 2017-04-28 13:20:34 -04:00
Timothy Warren 3fd7c84774 Further filter titles, showing only the canonical title if it is really long 2017-04-26 10:09:14 -04:00
Timothy Warren 428a77b93d Merge branch 'develop' into 'master'
Merge develop into master

See merge request !18
2017-04-24 09:28:40 -04:00
Timothy Warren 8e8ee81397 Kitsu <-> MAL manga list item comparison, resolves #18 2017-04-19 16:48:53 -04:00
Timothy Warren cf12dfee76 kitsu <-> mal comparison for anime, see #18 2017-04-19 16:15:39 -04:00
Timothy Warren d2fc955260 Miscellaneous code cleanup 2017-04-17 16:13:36 -04:00
Timothy Warren 4d991629b1 More main menu tweaking 2017-04-17 14:49:33 -04:00
Timothy Warren 6111dfe6f9 Tweak the main menu a bit 2017-04-17 12:45:29 -04:00
Timothy Warren 921d594931 Update dependencies, and set a more locked-down content security policy 2017-04-13 15:08:28 -04:00
Timothy Warren ac13d57634 Use proxy and cached images on user info page 2017-04-13 14:25:39 -04:00
Timothy Warren 42d36ff4bb Update manga transformer tests 2017-04-13 11:54:58 -04:00
Timothy Warren 28da32f2ac Get images from proxy or cache for Manga views, and Add views 2017-04-13 11:44:03 -04:00
Timothy Warren 08aff2ffe8 All anime images now pull from proxy or cache 2017-04-13 11:26:28 -04:00
Timothy Warren 8b43dee20f Css tweaks, and start caching kitsu images 2017-04-13 11:15:16 -04:00
Timothy Warren 0d2cde37a0 Update .gitignore 2017-04-11 13:28:05 -04:00
Timothy Warren 5cca3cf335 Fix changing a list item's status with no score or progress on MAL 2017-04-11 09:28:07 -04:00
Timothy Warren 679560e185 Fix various edge cases 2017-04-10 15:31:35 -04:00
Timothy Warren d157f097d1 Use a more appropriate function for substring filtering 2017-04-07 16:58:08 -04:00
Timothy Warren ec6f9b1189 Tweak handling of alternate titles, to ensure the +1 button is always usable 2017-04-07 16:44:27 -04:00
Timothy Warren 7825e46321 Replace 0 with - 2017-04-07 13:57:14 -04:00
Timothy Warren 6436ca2e9c Update doc generation 2017-04-06 21:27:47 -04:00
Timothy Warren 81a1a927b1 Make sure Cast heading only shows up if there are actual cast entries 2017-04-06 21:27:03 -04:00
Timothy Warren b210954874 Make sure rating parameter sent to Kitsu is greater than 0 2017-04-06 14:53:38 -04:00
Timothy Warren 472be3c4ed Use snapshots library with tests to simplify testcases 2017-04-06 11:59:53 -04:00
Timothy Warren edc6e6227e Simplify css and javascript minification 2017-04-06 11:45:25 -04:00
Timothy Warren 32b3617fed Update postcss 2017-04-06 10:01:09 -04:00
Timothy Warren 45bf1e1136 Add a better API timeout message emoticon 2017-04-05 13:08:16 -04:00
Timothy Warren fb3805b789 Add staff to character pages 2017-04-05 13:02:48 -04:00
Timothy Warren b861db5d1f Catch API timeouts 2017-04-05 13:01:51 -04:00
Timothy Warren e49ed606f5 Merge remote-tracking branch 'origin/develop' 2017-04-03 16:53:25 -04:00
Timothy Warren 8172d1a593 Remove some dead code 2017-04-03 16:53:04 -04:00
Timothy Warren a413d7d9ca Fix collection images, resolves #26 2017-04-03 16:49:40 -04:00
Timothy Warren 8ceec846a5 Fix creating missing Kitsu items 2017-04-03 15:46:16 -04:00
Timothy Warren d2d48905d7 More basic tests, see #16 2017-04-03 14:46:29 -04:00
Timothy Warren 7d7ae73f5e Merge remote-tracking branch 'origin/develop' 2017-03-31 17:02:26 -04:00
Timothy Warren 82c8d36144 small tweak to user page 2017-03-31 17:01:53 -04:00
Timothy Warren c50b1da53b Details and user page updates, resolves #27 2017-03-31 16:36:22 -04:00
Timothy Warren ddd30fc713 Add favorite characters to user page, see #27 2017-03-31 14:15:29 -04:00
Timothy Warren 1e28a1795d Update detail pages 2017-03-31 13:37:53 -04:00
Timothy Warren b2300f4cfb Remove duplicated function 2017-03-30 16:57:58 -04:00
Timothy Warren 92fe6b7146 Update header comments 2017-03-30 16:49:48 -04:00
Timothy Warren fa4ee22100 Allow over-riding the default lists in the user config 2017-03-30 16:47:02 -04:00
Timothy Warren 5ae6864a3f Fix config typo 2017-03-30 16:18:59 -04:00
Timothy Warren fb567e85e9 Simplify routing code a bit 2017-03-30 16:16:40 -04:00
Timothy Warren 2d33663318 Add rereading info to manga list 2017-03-30 14:50:25 -04:00
Timothy Warren 528d3584b8 Make sure rating is only updated if it is numeric 2017-03-29 16:09:22 -04:00
Timothy Warren 69b4d0c88b More tests 2017-03-29 15:14:30 -04:00
Timothy Warren e79021da29 Add and delete manga simulaneously from kitsu and mal 2017-03-29 14:25:03 -04:00
Timothy Warren 79980683d1 Allow manga +1 button to update both kitsu and mal 2017-03-29 14:00:57 -04:00
Timothy Warren ec7e0cc93b Fix tests 2017-03-29 13:42:40 -04:00
Timothy Warren 15b26d8e39 Simultaneously update kitsu and MAL manga list item 2017-03-29 13:29:03 -04:00
Timothy Warren 377e102650 Create missing manga items on kitsu and mal with sync command 2017-03-29 12:32:36 -04:00
Timothy Warren 4a9e0f0293 Update sync lists command to create Kitsu items that are missing compared to MAL 2017-03-28 16:52:27 -04:00
Timothy Warren 0b18c06058 Minor api model refactoring 2017-03-28 14:36:23 -04:00
Timothy Warren 8d289f9eb5 Reorgnize order of Kitsu model methods 2017-03-28 14:34:33 -04:00
Timothy Warren 394c1241fb Update dependencies, use ParallelAPIRequest 2017-03-28 11:01:38 -04:00
Timothy Warren 0c4c0a436c Merge branch 'develop' into 'master'
Develop

See merge request !17
2017-03-28 10:43:51 -04:00
Timothy Warren b8b5beeae1 Code cleanup and fix 'On Hold' title on all section of anime list 2017-03-27 10:09:45 -04:00
Timothy Warren be0baac962 List characters on manga pages 2017-03-24 10:59:07 -04:00
Timothy Warren cf0db8b9fa Update all the page titles 2017-03-24 09:58:27 -04:00
Timothy Warren dd90dd541c Fix title of anime pages 2017-03-24 09:10:30 -04:00
Timothy Warren cdd3878e55 Show custom 404 pages for missing anime and characters 2017-03-24 09:08:39 -04:00
Timothy Warren 51c26e6b30 Remove code coverage ignore annotations 2017-03-24 08:49:39 -04:00
Timothy Warren 0c2cc0e32b Get rid of whoops 2017-03-23 11:21:13 -04:00
Timothy Warren 828b7a2154 Fix 'all' view with missing sections 2017-03-22 16:53:46 -04:00
Timothy Warren be4f54b99d Merge branch 'master' into 'develop'
Master

Closes #24

See merge request !16
2017-03-22 13:48:01 -04:00
Timothy Warren 25e57eb493 Merge branch 'develop' into 'master'
Update favicon with blue version, resolves #24

See merge request !15
2017-03-22 13:17:27 -04:00
Timothy Warren 707a36fe53 Update favicon with blue version, resolves #24 2017-03-22 13:12:29 -04:00
Timothy Warren cd58e083bf Merge branch 'master' of git.timshomepage.net:timw4mail/HummingBirdAnimeClient 2017-03-22 12:49:18 -04:00
Timothy Warren a259ea7b18 Update streaming link handling, and add daisuki and viewster 2017-03-22 12:29:07 -04:00
Timothy Warren 74602f60fa Fix syntax error, prime manga cache too. See #19 2017-03-22 12:28:19 -04:00
Timothy Warren 53b8ce44bf Fix php 7.1 build? 2017-03-22 11:43:20 -04:00
Timothy Warren e99205be54 Add command to prime cache, see #19 2017-03-22 11:41:25 -04:00
Timothy Warren b52d301b2a Fix issue with updating anime item 2017-03-22 11:15:40 -04:00
Timothy Warren 52bd2773c0 Remove unused mappings 2017-03-22 11:14:59 -04:00
Timothy Warren c9768855a5 All anime api calls are now using paginated requests, see #23 2017-03-22 11:13:50 -04:00
Timothy Warren 1a45e57b7c Miscellaneous code cleanup 2017-03-20 19:08:33 -04:00
Timothy Warren cd242596bc Move link to user profile page 2017-03-20 13:16:01 -04:00
Timothy Warren bc6854a8e5 Show characters on anime details page 2017-03-20 13:14:01 -04:00
Timothy Warren 0d4b26e493 Minor model refactoring 2017-03-14 14:28:08 -04:00
Timothy Warren 0e6a1b6591 More work on user profile page 2017-03-10 12:50:48 -05:00
Timothy Warren 84f0a27d86 use readable cache keys 2017-03-10 12:50:29 -05:00
Timothy Warren 8645926006 More work on profile page 2017-03-08 16:21:01 -05:00
Timothy Warren 960537f8e0 Fix tests and start on profile page 2017-03-08 13:46:50 -05:00
Timothy Warren 5d9b7e9e63 Add basic character pages 2017-03-08 12:55:49 -05:00
Timothy Warren 6bf107e1ad Update all the header comments with the correct repository url 2017-03-07 20:53:58 -05:00
Timothy Warren fa7651faf9 Fix issues with sync-lists command, add more docblocks 2017-03-07 20:49:31 -05:00
Timothy Warren 8b2cd7dd1e Fix 'All' section on Manga page 2017-03-07 18:41:51 -05:00
Timothy Warren 5d2dac5b99 Add back 'All' menu item for anime 2017-03-07 17:51:08 -05:00
Timothy Warren df7102d13d Update gitignore, and make sure cache directory for js minifier exists 2017-03-07 17:48:35 -05:00
Timothy Warren 82b596ec3c Make sure to actually add streaming logos to repo 2017-03-07 15:22:45 -05:00
Timothy Warren 497216cffa Make sure mapping is accurately named
\!
2017-03-03 11:51:53 -05:00
Timothy Warren 969ff75078 Update README 2017-03-03 11:33:42 -05:00
Timothy Warren f932a80e58 Minor refactor of bootstrap setup 2017-03-03 11:33:32 -05:00
Timothy Warren ae6b1cb209 Move AnimeWatchingStatus and MangaReadingStatus enums to the same namespace 2017-03-02 11:12:19 -05:00
Timothy Warren d0a236e7ee Remove accidentially created Java file 2017-03-01 22:11:37 -05:00
Timothy Warren ed01b28c0d Rework the rest of the mappings 2017-03-01 22:07:51 -05:00
Timothy Warren 52e1d1822a Update Manga mappings and enums 2017-03-01 21:52:30 -05:00
Timothy Warren 5e9b3db1f2 Add new mapping class for Anime watching statuses 2017-03-01 20:51:40 -05:00
Timothy Warren e0e1b59777 Merge branch 'develop' into 'master'
Develop

See merge request !14
2017-02-28 16:58:53 -05:00
Timothy Warren 443ffaa132 Rename on packagist 2017-02-28 16:47:39 -05:00
Timothy Warren 4b0226838c Attempt to fix travis ci after switch to phpdbg 2017-02-28 14:24:32 -05:00
Timothy Warren 79ce8c7790 Actually install dev dependencies for gitlab ci 2017-02-28 13:52:39 -05:00
Timothy Warren 0fa4a3c963 Try, try, again 2017-02-28 13:44:41 -05:00
Timothy Warren 14967e9ad0 Add phpunit as a dev dependency 2017-02-28 13:39:49 -05:00
Timothy Warren b4573296d8 Properly setup test coverage 2017-02-28 13:21:37 -05:00
Timothy Warren 0127d65dfc Simplify gitlab ci setup 2017-02-28 13:17:06 -05:00
Timothy Warren 14e8fa9f03 More PHPStan fixes 2017-02-22 15:08:29 -05:00
Timothy Warren adc331d60d PHPStan fixes 2017-02-22 14:46:35 -05:00
Timothy Warren 65227e82ac Move some README info to the wiki 2017-02-21 15:56:19 -05:00
Timothy Warren 56ae9ed80e Update method references in Manga controller 2017-02-21 15:37:29 -05:00
Timothy Warren f3d9af311e Update method references in Collection controller 2017-02-21 15:36:34 -05:00
Timothy Warren 136b7dab66 Simplify database config example 2017-02-21 14:56:10 -05:00
Timothy Warren cd7a836db0 Remove old/unused config options from example file 2017-02-21 14:41:59 -05:00
Timothy Warren e87e5cb47c Make sure anime detail pages don't distort images 2017-02-21 12:24:34 -05:00
Timothy Warren 7122085590 Will teh Gitlab build be triggered? 2017-02-20 15:13:16 -05:00
Timothy Warren 9f0484a93b Use new ParallelAPIRequest class 2017-02-20 13:37:08 -05:00
Timothy Warren 93038e61e5 More code style fixes 2017-02-17 11:37:22 -05:00
Timothy Warren 30b43fd27c Lots of style fixes, with more to come 2017-02-17 10:55:17 -05:00
Timothy Warren 6efe1ffbc8 Slightly reorganize model hierarchy 2017-02-17 08:39:27 -05:00
Timothy Warren 8898655a49 Various tweaking 2017-02-17 08:25:19 -05:00
Timothy Warren 07b1422fad Reference svg logos as image files, not raw html 2017-02-16 14:30:39 -05:00
Timothy Warren 0232d18f1f Yet more snake case to camel case 2017-02-16 14:30:06 -05:00
Timothy Warren 0cef44c986 More javascript style fixes 2017-02-16 13:22:26 -05:00
Timothy Warren 6ed755e252 JS style fixes 2017-02-16 11:47:54 -05:00
Timothy Warren 85cd77267b Make sure header comments are actually updated for all code files 2017-02-16 11:09:37 -05:00
Timothy Warren 488a01f8a5 Js snake case to camel case 2017-02-15 16:58:08 -05:00
Timothy Warren ee2760b2b5 Rename test base class 2017-02-15 16:40:18 -05:00
Timothy Warren 84cb1cb520 And more snake case to camel case 2017-02-15 16:30:14 -05:00
Timothy Warren db07976403 Update header comments 2017-02-15 16:13:32 -05:00
Timothy Warren c96a3bbd50 Snake case to camel case 2017-02-15 16:11:52 -05:00
Timothy Warren 8cbfaf3646 More snake case to camel case 2017-02-15 15:56:10 -05:00
Timothy Warren 29c04e62be More code styles fixes 2017-02-15 15:35:41 -05:00
Timothy Warren 1224882092 Javascript style fixes 2017-02-15 14:08:15 -05:00
Timothy Warren df8b64cff9 Snake case to camel case 2017-02-15 14:07:22 -05:00
Timothy Warren ae42fafe84 Update headers 2017-02-15 13:08:17 -05:00
Timothy Warren da9ebe8867 More style fixes 2017-02-15 13:07:36 -05:00
Timothy Warren 0a72e60f68 Fix more code style issues 2017-02-15 11:57:29 -05:00
Timothy Warren 36874cbe55 Properly namespace all the tests 2017-02-15 11:49:38 -05:00
Timothy Warren d94a280437 Snake case to camel case 2017-02-15 11:30:16 -05:00
Timothy Warren 470c39cf79 Remove some unused code 2017-02-15 11:18:55 -05:00
Timothy Warren 941a15c4f4 Add yarn lock file 2017-02-15 11:05:03 -05:00
Timothy Warren 3caad13577 Try, try again 2017-02-15 10:23:07 -05:00
Timothy Warren acbae86a6b Slim build config 2017-02-15 10:12:18 -05:00
Timothy Warren 34d0aaa8e5 Ignore stupid xsl requirement 2017-02-15 10:05:06 -05:00
Timothy Warren 7941303987 Install xsl because of the stupid dev dependency 2017-02-15 09:57:08 -05:00
Timothy Warren da8b34a867 Will xdebug work? 2017-02-15 09:53:46 -05:00
Timothy Warren 9bf362e08e Will xdebug work? 2017-02-15 09:50:13 -05:00
Timothy Warren 6ee319b78c xdebug try again 2017-02-15 09:47:52 -05:00
Timothy Warren 90f1b39db5 Try to use xdebug another way 2017-02-15 09:42:20 -05:00
Timothy Warren 85a6fafd4f Make sure to try to install the correct packages 2017-02-15 09:36:51 -05:00
Timothy Warren 2bdf4be682 Remove unneeded bashism 2017-02-15 09:32:31 -05:00
Timothy Warren 455adf4b11 Maybe this will work better? 2017-02-15 09:30:27 -05:00
Timothy Warren 9e49566641 Maybe stages will help? 2017-02-15 09:26:49 -05:00
Timothy Warren d1f0ab0c73 Attempt to use alpine php image 2017-02-15 09:21:08 -05:00
Timothy Warren 79153ae433 Attempt testing hhvm with a different docker image 2017-02-15 08:55:51 -05:00
Timothy Warren 9c44b5189f Merge branch 'develop' into 'master'
Develop

See merge request !13
2017-02-14 16:39:37 -05:00
Timothy Warren 312125f182 Add hummingbird favicon 2017-02-14 16:23:18 -05:00
Timothy Warren 652eac5be0 Get sync-lists command to create missing entries on MAL 2017-02-14 15:29:13 -05:00
Timothy Warren dba0d47789 Uncomment rewatching stuff 2017-02-13 13:33:01 -05:00
Timothy Warren 4a3be8b4bf Fix mapping from Kitsu to MAL for updating a list item 2017-02-13 12:42:05 -05:00
Timothy Warren 7f5966a147 Attempt to fix hhvm tests 2017-02-10 16:33:42 -05:00
Timothy Warren 8f8f528823 Fix config mapping for BaseCommand 2017-02-10 16:12:02 -05:00
Timothy Warren 1ec7322b18 Split user config from application config 2017-02-10 15:50:07 -05:00
Timothy Warren 8f8c413927 Fix update requests broken by Artax conversion 2017-02-09 20:10:13 -05:00
Timothy Warren 50c543218b Remove 'fix' for issue caused by php.ini setting 2017-02-09 13:45:40 -05:00
Timothy Warren 18af49f1f4 Replace Guzzle with Artax 2017-02-09 13:44:56 -05:00
Timothy Warren 906a1f1efa Another ugly progress commit
- Eradicated Guzzle from main codebase
- All API requests now use Artax
- Refactor code to use function and constant imports
- And more!
2017-02-08 15:48:20 -05:00
Timothy Warren deecb5a912 Start of work to replace Guzzle with Artax 2017-02-08 00:44:57 -05:00
Timothy Warren 02838c5024 Update headers and some whitespace 2017-02-07 13:27:41 -05:00
Timothy Warren bf7f6973a4 Create Request Builder wrapper around Artax 2017-02-07 13:11:42 -05:00
Timothy Warren c0b54e11e1 Update PHPUnit 2017-02-07 09:13:13 -05:00
Timothy Warren 0fe01e14e1 Only translate fields that are passed in 2017-02-07 09:12:44 -05:00
Timothy Warren 2f71a97327 Merge branch 'develop' into 'master'
Develop

See merge request !12
2017-02-06 11:51:58 -05:00
Timothy Warren e73ea09ffd Update test config to allow hhvm failures 2017-02-06 11:35:21 -05:00
Timothy Warren bc0c3774eb Update deprecated test 2017-02-06 11:00:18 -05:00
Timothy Warren b10487ac13 Update changelog 2017-02-06 10:57:38 -05:00
Timothy Warren 64ed6cc0ef Update README 2017-02-06 10:56:27 -05:00
Timothy Warren b6c2aee17a Update dependencies 2017-02-06 10:42:41 -05:00
Timothy Warren 5eea985828 Actually update MAL if enabled 2017-02-04 15:18:34 -05:00
Timothy Warren 1835e34690 Able to create list items on MAL 2017-02-01 09:53:02 -05:00
Timothy Warren 2d0fa51c40 Delete outdated test data 2017-01-31 12:55:28 -05:00
Timothy Warren 108c649a91 Misc updates 2017-01-31 12:52:43 -05:00
Timothy Warren c26a4ca8e8 More test coverage for transformers 2017-01-31 12:51:14 -05:00
Timothy Warren 9d9c1e2cce Add license 2017-01-27 16:34:03 -05:00
Timothy Warren 2cacff6b9b Add coverage button to readme 2017-01-27 15:56:40 -05:00
Timothy Warren 47a43517cb More test coverage, attempt to get Gitlab to see test coverage 2017-01-27 15:41:52 -05:00
Timothy Warren 1b5590bda7 Merge branch 'develop' into 'master'
Develop

See merge request !10
2017-01-27 13:03:53 -05:00
Timothy Warren 91a6d76c4b Attempt to show code coverage 2017-01-27 12:42:57 -05:00
Timothy Warren 03964c446a Ugly progress commit 2017-01-27 12:35:28 -05:00
Timothy Warren 74897faa78 Add back zlib to the docker build 2017-01-27 12:26:32 -05:00
Timothy Warren 2b2ec71edd Add back dependency for xsl in docker build 2017-01-27 12:17:02 -05:00
Timothy Warren a80a860f8d Attempt simpler php setup, with xdebug 2017-01-27 12:09:05 -05:00
Timothy Warren 3d54a0d62c Another attempt at hhvm testing 2017-01-27 11:38:18 -05:00
Timothy Warren aabdf4de30 Attempt to fix hhvm pipeline 2017-01-27 11:21:25 -05:00
Timothy Warren 20c3d69717 Get xml parsing working predictably 2017-01-27 09:43:42 -05:00
Timothy Warren f57c24abe4 Make sure to pass the correct arguments to the cache hash method 2017-01-26 13:06:35 -05:00
Timothy Warren 0ae52a13f3 Refactor KitsuModel, add more docblocks 2017-01-26 13:03:38 -05:00
Timothy Warren ece4f343e2 Fix broken test 2017-01-26 13:02:18 -05:00
Timothy Warren b2fb562de6 Fix display of streaming links in cover and list views 2017-01-25 13:37:39 -05:00
Timothy Warren 19c2d0fddc Merge branch 'develop' into 'master'
Develop

See merge request !9
2017-01-25 12:16:50 -05:00
Timothy Warren b2544fab16 Fix issue with selected list highlighting, fixes #20 2017-01-25 12:13:37 -05:00
Timothy Warren 96cbf78e28 Fix cache clear command 2017-01-19 12:49:18 -05:00
Timothy Warren e30a0b867d Merge branch 'develop' 2017-01-17 12:52:02 -05:00
Timothy Warren 11f9e41254 Update commands 2017-01-17 12:47:02 -05:00
Timothy Warren a45eba3c56 Update cache dependency 2017-01-17 12:46:47 -05:00
Timothy Warren 9bc22baa80 Cache manga list 2017-01-16 14:14:45 -05:00
Timothy Warren 7bad51d867 Fix failing test 2017-01-16 14:05:42 -05:00
Timothy Warren f441b7680a Update views for collection, remove old json import 2017-01-16 14:03:30 -05:00
Timothy Warren 10368fabe4 Fix anime collection 2017-01-16 13:49:51 -05:00
Timothy Warren a42a9bc785 Update README to be more accurate 2017-01-16 12:42:30 -05:00
Timothy Warren 42f152b366 Merge branch 'develop' 2017-01-16 11:27:49 -05:00
Timothy Warren 0ec8d6d6b3 Restore cache clearing functionality 2017-01-16 11:26:19 -05:00
Timothy Warren 1eecff0178 Streaming links, caching, and more MAL integration 2017-01-13 16:53:56 -05:00
Timothy Warren 3e72a66297 Cache API errors at the dispatcher level, so a more appropriate error page can be displayed 2017-01-13 16:52:12 -05:00
Timothy Warren 79c0c6cf90 Update search to bring in My anime list id for future integration 2017-01-13 16:51:31 -05:00
Timothy Warren c1724397d3 Update views to show streaming links 2017-01-13 16:49:46 -05:00
Timothy Warren 9e30783ecb Update transformer tests 2017-01-13 16:48:08 -05:00
Timothy Warren 496eb68078 Really ugly progress commit 2017-01-12 15:41:20 -05:00
Timothy Warren 2fe45a6b57 Update Changelog and Readme 2017-01-12 11:31:49 -05:00
Timothy Warren aca66ae86d Add test data files 2017-01-11 22:27:36 -05:00
Timothy Warren f619c78232 Update config files 2017-01-11 22:26:43 -05:00
Timothy Warren d91432d960 Third time's a charm for updating the header comment? 2017-01-11 19:37:14 -05:00
Timothy Warren 62c06b7731 Start of integration with My Anime List 2017-01-11 19:35:51 -05:00
Timothy Warren e060e1b107 Update header comments, with proper newlines 2017-01-11 10:34:24 -05:00
Timothy Warren 08c40de381 Merge branch 'develop' into 'master'
Replace Hummingbird with Kitsu

See merge request !8
2017-01-11 10:32:10 -05:00
Timothy Warren c76bb4d32a Update header comments 2017-01-11 10:31:17 -05:00
Timothy Warren 93e58874de Merge branch 'master' into 'develop'
Hummingbird to Kitsu

See merge request !7
2017-01-11 10:25:43 -05:00
Timothy Warren 712956d564 Fix unit tests 2017-01-10 21:13:44 -05:00
Timothy Warren 39118d63e5 All basic API functionality:
* Anime List Item:
	* Creation
	* Updating
	* Retreiving
	* Deletion

* Manga List Item:
	* Creation
	* Updating
	* Retreiving
	* Deletion

* Anime detail page
* Manga detail page
2017-01-10 12:35:46 -05:00
Timothy Warren 9f048b739e Fix some javascript issues 2017-01-09 21:38:42 -05:00
Timothy Warren 6e818b7f45 Anime and Manga editing, incrementing, and deletion 2017-01-09 20:36:48 -05:00
Timothy Warren e085754955 Update header comments 2017-01-06 23:34:56 -05:00
Timothy Warren 98bf1e455f Episode incrementing and update work for anime 2017-01-06 21:39:01 -05:00
Timothy Warren 9d84398ee7 Better handling of alternate titles, Airing Status and genres for anime list views 2017-01-05 22:24:45 -05:00
Timothy Warren 09338e9132 Authentication, show edit forms for Anime 2017-01-05 13:41:32 -05:00
Timothy Warren 239b0c055c Update postcss to actually output compatible css 2017-01-04 13:51:04 -05:00
Timothy Warren 444e18c1d9 Update css to fit blocks within poster images 2017-01-04 13:40:46 -05:00
Timothy Warren f1893d9708 Manga lists and detail pages 2017-01-04 13:16:58 -05:00
Timothy Warren 3030b6b908 Start of changes for Manga list 2017-01-03 21:06:49 -05:00
Timothy Warren cdf9ad0105 Remove some old code to better make way for kitsu/MAL api integration 2017-01-03 20:29:43 -05:00
Timothy Warren 05c6f22f67 Another ugly progress commit
Sort of working:
* Get anime list by status
* Get anime description pages
2016-12-22 21:36:23 -05:00
Timothy Warren e74fe9d2f5 Pull stuff from the Kitsu API 2016-12-21 12:46:20 -05:00
Timothy Warren c9f5964d5e Ugly progress commit 2016-12-20 12:58:37 -05:00
Timothy Warren e097b02457 Start of API integration 2016-12-20 12:55:43 -05:00
Timothy Warren f2fcc8ee93 Remove Hummingbird stuff 2016-12-16 21:52:59 -05:00
Timothy Warren 513ba4c70f Fix hhvm tests take 2 2016-11-03 11:39:24 -04:00
Timothy Warren 66e51af8d7 Fix hhvm tests 2016-11-03 11:30:22 -04:00
Timothy Warren ba9c41f495 Update CI tools to exclude old PHP versions 2016-11-01 09:10:11 -04:00
Timothy Warren 07ebb3e988 Update headers and namespaces 2016-10-20 22:32:17 -04:00
Timothy Warren c915ea871d Update EVERYTHING 2016-10-20 22:09:36 -04:00
Timothy Warren 656688a5f3 Make sure to use the version of phpunit I actually install 2016-08-30 12:02:21 -04:00
Timothy Warren 60c9c86580 Attempt to fix travis build 2016-08-30 11:51:35 -04:00
Timothy Warren b0c49ca19c Update Robofile to work properly 2016-08-30 11:45:17 -04:00
Timothy Warren dd2d25d54c Code style fixes to satisfy phpcs 2016-08-30 10:57:41 -04:00
Timothy Warren 230c80459e Update header comments 2016-08-30 10:01:18 -04:00
Timothy Warren f7915ba6f2 Move tests to tests/ directory 2016-08-29 17:09:56 -04:00
Timothy Warren ac971c5248 Move src files to root of src/ 2016-08-29 16:36:13 -04:00
Timothy Warren eaa0e517c1 Build/doc generation updates 2016-08-29 15:50:59 -04:00
Timothy Warren 4e4ac58263 Fix tests broken due to changes in container 2016-08-29 15:36:36 -04:00
Timothy Warren 88e06a0052 Convert Dependency injection bootstrap file to use factory functions, rather than direct instances 2016-08-29 14:51:32 -04:00
Timothy Warren e0e63cf094 Move Ion namespace into composer dependency 2016-08-09 11:08:45 -04:00
Timothy Warren 410d45029f Another attempt at hhvm setup 2016-08-03 18:43:09 -04:00
Timothy Warren 8f3ce089a4 actually use the correct composer command to install phpunit for hhvm 2016-08-03 18:25:28 -04:00
Timothy Warren 7e05a4dcc2 try a different docker container for running hhvm tests 2016-08-03 18:09:55 -04:00
Timothy Warren 7b9b62b200 Attempt hhvm testing on gitlab ci, adjust acceptable failures on travis 2016-08-03 14:30:36 -04:00
Timothy Warren 6bdd33da2a Don't install dev dependencies in test environments 2016-08-03 14:14:38 -04:00
Timothy Warren 3894ba8312 Another attempt to fix gitlab ci build 2016-08-03 14:08:02 -04:00
Timothy Warren 473a046ed8 Attempt to fix gitlab ci build 2016-08-03 13:47:14 -04:00
Timothy Warren 47e67d5d1a Set up mutation testing for unit tests 2016-08-01 14:38:23 -04:00
Timothy Warren e62558d607 Add dev dependencies, augment gitignore 2016-08-01 13:10:00 -04:00
Timothy Warren 6b9770698b Refactor cache to remove dependency on container 2016-08-01 13:02:26 -04:00
Timothy Warren 893584696b Move cache class to IOn namespace, use safer json for serialization in cache drivers 2016-07-28 10:44:13 -04:00
Timothy Warren a108adfa23 Finish moving get_cached_image method to Util class 2016-07-27 14:32:37 -04:00
Timothy Warren f00acbe2d6 Fix travis ci tests 2016-07-27 13:35:30 -04:00
Timothy Warren 563adace2f Refactor out some Interdependency between Ion and AnimeClient namespaces 2016-07-27 13:18:52 -04:00
Timothy Warren cc7046f0ec Update the correct file to change config for gitlab ci 2016-07-25 12:29:42 -04:00
Timothy Warren b415938583 Attempt moving config file in a different way 2016-07-25 12:18:51 -04:00
Timothy Warren 2a41106638 Fix typo in test path 2016-07-25 12:04:56 -04:00
Timothy Warren cb046dbde2 Add redis config file for gitlab ci tests 2016-07-25 11:58:43 -04:00
Timothy Warren 96d3dfdbb4 Update Redis tests to work with gitlab ci 2016-07-22 17:48:13 -04:00
Timothy Warren fa22f7b493 Update Redis cache driver to use PHP-only library, removing the dependence on an extension: 2016-07-22 17:22:00 -04:00
Timothy Warren e2c6c14af8 Remove redundant mbstring extesion from build setup 2016-07-19 10:45:16 -04:00
Timothy Warren ca62a411e1 Attempt 2 to install gd in gitlab ci tests 2016-07-19 10:25:54 -04:00
Timothy Warren 10bb167ff4 Fix failing test by installing gd in gitlab ci test 2016-07-19 10:17:53 -04:00
Timothy Warren ead6f8b487 Set default timezone to prevent stupid test errors 2016-07-18 13:06:37 -04:00
Timothy Warren 672552a1e8 Make tests skip redis integration if the extension is not installed 2016-07-18 12:59:34 -04:00
Timothy Warren f940606f0c Another attempt at getting gitlab ci to run 2016-07-18 12:47:51 -04:00
Timothy Warren b271fd48a6 Attempt tests without redis for now 2016-07-18 10:16:21 -04:00
Timothy Warren 8e00f3a59d Gitlab CI take 3 2016-07-18 10:07:50 -04:00
Timothy Warren ebc8006e04 Make sure docker sh script doesn't have CRLF line endings 2016-07-18 09:58:23 -04:00
Timothy Warren c84e76a869 Gitlab CI take two 2016-07-18 09:55:06 -04:00
Timothy Warren a178ac86c6 First attempt at setting up gitlab ci 2016-07-18 09:47:34 -04:00
Timothy Warren 1e18344990 Merge branch 'develop' 2016-07-15 11:35:31 -04:00
Timothy Warren 6b31e759c9 Minor example file tweaks, add smooth scrolling to browsers that support it 2016-06-07 11:36:02 -04:00
Timothy Warren 1842e1a30b Remove redundant cache loading 2016-04-22 10:52:42 -04:00
Timothy Warren dd20c774ed Shrink api clearing button 2016-04-22 10:47:18 -04:00
Timothy Warren b2990e8457 Add button to clear api cache 2016-04-21 11:14:21 -04:00
Timothy Warren 4e48c8c4fa Update changelog and add additional tests 2016-04-19 14:51:58 -04:00
Timothy Warren 3605ec6d0b Update README for version 3 2016-04-19 13:24:21 -04:00
Timothy Warren 2151d64f25 Small miscellaneous cleanup 2016-04-19 13:23:49 -04:00
Timothy Warren 89080171c9 Add batch image thumbnail creation, see #6, #14 2016-04-19 13:02:50 -04:00
Timothy Warren 733d3f3871 Resolves #10, adds ability to delete from anime collection 2016-04-14 19:10:03 -04:00
Timothy Warren a14d268652 Update sonarqube version 2016-04-14 18:03:34 -04:00
Timothy Warren b5949466e4 Add detail view to anime list 2016-04-14 17:51:00 -04:00
Timothy Warren 1f9afd07f3 Add ability to delete items from manga list. See #10 2016-04-14 17:00:34 -04:00
Timothy Warren 717c296e52 Add ability to delete items from anime list. References #10 2016-04-14 15:16:13 -04:00
Timothy Warren b528b8dc17 Re-add cache to manga controller so cache can be invalidated on update 2016-04-14 11:05:16 -04:00
Timothy Warren 98f709c36e Add tests for Cache Manager class 2016-04-12 14:05:13 -04:00
Timothy Warren 330ac65e18 Add missing update to base API Model 2016-04-12 13:41:50 -04:00
Timothy Warren e26e9f10b6 Update manga model to cache the one api response. 2016-04-12 13:41:03 -04:00
Timothy Warren 7d6c6fe2a0 Add NullDriver for cache layer, for the sake of testing, or config without a cache 2016-04-12 12:05:42 -04:00
Timothy Warren 5d0b879623 Miscellaneous cleanup 2016-04-08 18:05:52 -04:00
Timothy Warren 1a182a62a7 Remove allowed failures for PHP 5.5 & 5.6 2016-04-08 15:21:10 -04:00
Timothy Warren 429c9861e3 One last attempt to get redis to work with travis CI 2016-04-08 15:17:45 -04:00
Timothy Warren 99a5907e1b Another attempt to get redis working 2016-04-08 15:06:16 -04:00
Timothy Warren 1e42d431c8 Update travis config to test redis 2016-04-08 14:56:09 -04:00
Timothy Warren 05a3d0e729 Fix anime collection selection template to match db schema 2016-04-08 14:45:11 -04:00
Timothy Warren 4b4a259f8a Add Redis Cache driver 2016-04-08 14:25:45 -04:00
Timothy Warren 454324aba6 Update first migration to allow empty notes on collection 2016-04-08 13:39:37 -04:00
Timothy Warren 470795f21e Add changelog 2016-04-08 13:22:29 -04:00
Timothy Warren 95abe28322 Remove zepto 2016-04-08 13:22:10 -04:00
Timothy Warren e35373a114 Set up package.json for myth css processing 2016-04-08 11:57:16 -04:00
Timothy Warren ea1d342db5 Remove target=_blank from links 2016-04-08 11:56:17 -04:00
Timothy Warren 83a200871d Add caching to Manga views 2016-04-07 13:11:45 -04:00
Timothy Warren 0f6c998109 Add tests for SQL based api cache 2016-04-07 12:34:57 -04:00
Timothy Warren 440a999c2e Remove json 'cache' files from anime model 2016-04-07 12:32:32 -04:00
Timothy Warren 7711765563 Fix tests 2016-04-06 14:58:19 -04:00
Timothy Warren 7efa180bbf Add some naive cache invalidation to update methods 2016-04-06 12:11:07 -04:00
Timothy Warren 84e4e6ce1b Start of caching implementation 2016-04-05 13:19:35 -04:00
Timothy Warren 972d96c0e0 Fix search methods to work with new Request library 2016-04-05 12:06:07 -04:00
Timothy Warren 3bcb0442ca Add migration for sql cache backend 2016-04-05 12:03:56 -04:00
Timothy Warren 2afbe84afd Start of interface for caching backend 2016-04-01 17:35:53 -04:00
Timothy Warren 06f07978dc Fix broken tests 2016-03-29 11:40:27 -04:00
Timothy Warren 2dde6f8a7d Fix issue with cover not being hidden on last episode 2016-03-29 11:30:51 -04:00
Timothy Warren c8789dc267 Update url generation to use new router 2016-03-07 14:37:49 -05:00
Timothy Warren ed16fd8d45 Fix most of the broken tests 2016-03-03 16:53:17 -05:00
Timothy Warren dd74e85626 Further refactor handling of request variables, routing works again 2016-02-17 11:36:37 -05:00
Timothy Warren ab19e9db08 Get HTML output working again, still refactoring router 2016-02-17 10:29:05 -05:00
Timothy Warren 98f3026a74 Start integration of PSR 7 Request/Response 2016-02-16 16:28:44 -05:00
Timothy Warren 1ba302999d Merge remote-tracking branch 'origin/master' into develop 2016-02-16 12:26:54 -05:00
Timothy Warren 197a1f8326 Update some javascript documentation, and add show/hide methods 2016-02-16 12:07:01 -05:00
Timothy Warren 9cc491a05e Minor style fixes, and fix double message issue 2016-02-10 17:56:46 -05:00
Timothy Warren bcd28acfc5 Minor style fixes, and fix double message issue 2016-02-10 17:50:07 -05:00
Timothy Warren d99f1e7595 Start of migration from php to toml config, see #11 2016-02-10 17:30:45 -05:00
Timothy Warren 1fb95adfbf Merge branch 'develop' into 'master'
Version 2.2

Pull Request tracking changes leading up to version 2.2

See merge request !1
2016-02-10 12:29:39 -05:00
Timothy Warren e8cc479a1e Better front-end tests 2016-02-10 12:25:13 -05:00
Timothy Warren fb29c90691 Update README 2016-02-09 21:42:56 -05:00
Timothy Warren 3027c8a4a8 Update tests relating to issue #9 2016-02-09 21:03:26 -05:00
Timothy Warren 0b6269edd6 Polyfill classList api for browsers lacking support 2016-02-09 20:57:40 -05:00
Timothy Warren 12d05dd71a Fixes issue #9 2016-02-09 20:20:54 -05:00
Timothy Warren ecf3bce14b Partially fix #9 -- API calls fail on 'Plan to Watch' section 2016-02-09 20:12:39 -05:00
Timothy Warren 5563902b69 Combine javascript library files into one base file 2016-02-09 20:07:01 -05:00
Timothy Warren 874ad521a7 Update README with some server setup details, resolves #7 2016-02-09 16:45:22 -05:00
Timothy Warren a9f5e48bb2 Remove last dependencies on zepto 2016-02-08 20:21:41 -05:00
Timothy Warren cbc7555cf2 Remove zepto ajax calls 2016-02-08 13:37:44 -05:00
Timothy Warren e08161aec2 Further improve minifiers, add start of front-end tests 2016-02-08 11:32:39 -05:00
Timothy Warren 7754377ecb Fix #8, make minfiers output correctly 2016-02-08 10:57:44 -05:00
Timothy Warren 0b2a0d4ea9 Add basic htaccess file for apache 2016-02-05 14:14:02 -05:00
Timothy Warren 94f54366a7 Some temporary fixes for tempramental minifiers 2016-02-04 21:57:14 -05:00
Timothy Warren f5dc15659f Make build.xml file more phing friendly 2016-02-03 21:24:10 -05:00
Timothy Warren 1a21a23e73 Rewrite minifiers into cleaner classes. Resolves #5 2016-02-03 14:57:00 -05:00
Timothy Warren 4533ea0b26 Minor spacing fixes 2016-02-02 21:38:38 -05:00
Timothy Warren 540a82fe22 Minor code quality fixes for Scrutinizer 2016-02-02 21:28:32 -05:00
Timothy Warren 467763f8a6 Fix manga editing for sections other than 'Reading' 2016-02-02 14:13:49 -05:00
Timothy Warren 99f2adf491 Add form for manga 2016-02-02 11:34:03 -05:00
Timothy Warren 3fa8e7d8e8 Ugly progress commit 2016-02-01 09:49:18 -05:00
Timothy Warren 9080f45601 Add missing table sorting lib 2016-01-20 20:14:32 -05:00
Timothy Warren 08348fd349 Add proper table sorting and add some security headers 2016-01-20 13:01:41 -05:00
Timothy Warren e109c6a06c Another attempt at code coverage for codeclimate 2016-01-12 12:47:48 -05:00
Timothy Warren 457c2680b6 Code coverage for codeclimate 2016-01-12 12:33:45 -05:00
Timothy Warren a85f0e28c6 Merge pull request #13 from timw4mail/develop
Sync with dev
2016-01-11 15:44:57 -05:00
Timothy Warren b611d02a2c Change logger methods to be inline with interface, fix Manga Model tests 2016-01-11 15:31:53 -05:00
Timothy Warren e51159e7f3 Update whoops to 2.0 2016-01-11 14:57:43 -05:00
Timothy Warren 2391ca14ca Remove errorhandler, and replace with logger 2016-01-11 14:39:53 -05:00
Timothy Warren 212c779552 Update collection to use flash messages and more intelligent redirects 2016-01-11 13:33:56 -05:00
Timothy Warren 0c2243a4f3 Add more test coverage, and update build.xml 2016-01-11 10:42:34 -05:00
Timothy Warren 3981b8471a Further refine Dispatcher 2016-01-08 16:39:18 -05:00
Timothy Warren 276a14a80c Refactor Dispatcher 2016-01-08 15:54:21 -05:00
Timothy Warren b4949eaea2 Fix line endings in view classes 2016-01-08 15:53:50 -05:00
Timothy Warren 993b625042 Actually fix view tests 2016-01-08 11:40:24 -05:00
Timothy Warren 557b27ef77 Fix view tests 2016-01-08 11:19:56 -05:00
Timothy Warren 45b04105f1 Fix http verb for update route, add correct http codes for http errors 2016-01-07 20:48:18 -05:00
Timothy Warren ae4530b5d2 Update codebase to use new Json class 2016-01-07 13:45:43 -05:00
Timothy Warren 00fd23895d Add missing classes 2016-01-06 17:08:44 -05:00
Timothy Warren aa67b941d4 Fix PHP 5.5 build 2016-01-06 17:06:30 -05:00
Timothy Warren b94bf01dee Remove unnamespaced constants, and improve some tests 2016-01-06 15:44:40 -05:00
Timothy Warren ba94f439bb Simplify routing 2016-01-06 11:08:56 -05:00
Timothy Warren e3af767246 Fix testss 2016-01-05 10:05:14 -05:00
Timothy Warren b0f5bdf668 Merge pull request #12 from timw4mail/scrutinizer-patch-2
Scrutinizer Auto-Fixes
2016-01-05 10:02:18 -05:00
Scrutinizer Auto-Fixer 2b5d650ef8 Scrutinizer Auto-Fixes
This commit consists of patches automatically generated for this project on https://scrutinizer-ci.com
2016-01-05 14:55:08 +00:00
Timothy Warren e9e16dd2b1 Update header comments, add start of manga editing functionality 2016-01-04 16:58:33 -05:00
Timothy Warren 6b9be7e4d0 Merge pull request #11 from timw4mail/scrutinizer-patch-1
Scrutinizer Auto-Fixes
2016-01-04 11:16:15 -05:00
Scrutinizer Auto-Fixer 8b528d8659 Scrutinizer Auto-Fixes
This commit consists of patches automatically generated for this project on https://scrutinizer-ci.com
2016-01-04 16:15:25 +00:00
Timothy Warren 9c81836648 Add full edit form to anime list 2016-01-04 10:53:03 -05:00
Timothy Warren c04c85b999 Update composer.json 2015-12-16 10:12:31 -05:00
Timothy Warren 6953cd08e6 Start of delete functionality for anime collection 2015-12-15 15:55:30 -05:00
Timothy Warren c82576e4dd Merge pull request #10 from timw4mail/scrutinizer-patch-1
Scrutinizer Auto-Fixes
2015-12-09 15:13:24 -05:00
Scrutinizer Auto-Fixer b70ff95f03 Scrutinizer Auto-Fixes
This commit consists of patches automatically generated for this project on https://scrutinizer-ci.com
2015-12-09 19:59:54 +00:00
Timothy Warren 30b6afb601 Some more minor code-style fixes 2015-12-09 14:54:11 -05:00
Timothy Warren 6ca086d85b Some code style fixes 2015-12-08 16:39:49 -05:00
Timothy Warren bfb8500386 update travis build file 2015-12-08 14:58:43 -05:00
Timothy Warren 70bfe2bab7 Fix collection functionality 2015-12-08 14:52:59 -05:00
Timothy Warren 7d1c8c383c Update README and composer 2015-11-18 16:03:40 -05:00
Timothy Warren 3b876f2c42 Skip erroring tests on travis 2015-11-18 10:58:12 -05:00
Timothy Warren 56f9fa28aa Fix some minor formating issues 2015-11-18 10:54:06 -05:00
Timothy Warren 2577bad0af Update minor documention issues 2015-11-18 10:48:05 -05:00
Timothy Warren ed1e888c58 Try mocking out get_cached_image method 2015-11-18 10:41:00 -05:00
Timothy Warren 254afc990e More test coverage 2015-11-18 10:31:42 -05:00
Timothy Warren 8d1986d13b Improve some test coverage 2015-11-17 16:45:41 -05:00
Timothy Warren 5d2cad4690 Remove loose functions file 2015-11-16 19:30:04 -05:00
Timothy Warren 49b3f507a6 Fix manga list updating 2015-11-16 15:57:37 -05:00
Timothy Warren 912f1b2ff2 Merge pull request #9 from timw4mail/scrutinizer-patch-1
Scrutinizer Auto-Fixes
2015-11-16 11:40:26 -05:00
Timothy Warren f75016ca69 Update header comments 2015-11-16 11:40:01 -05:00
Scrutinizer Auto-Fixer 4e1bcd962a Scrutinizer Auto-Fixes
This commit consists of patches automatically generated for this project on https://scrutinizer-ci.com
2015-11-16 15:33:30 +00:00
Timothy Warren 69f35d222c Poor style progress update commit 2015-11-13 16:31:01 -05:00
Timothy Warren 898905c21c Update some config and metadata 2015-11-13 11:34:30 -05:00
Timothy Warren f26adc1c28 Update 404 view 2015-11-13 11:33:47 -05:00
Timothy Warren dfe91d0f1c Make updating of anime list work 2015-11-13 11:33:27 -05:00
Timothy Warren 05912cd540 Update js minifier to be more robust, with better error handling 2015-11-13 11:32:12 -05:00
Timothy Warren ab955f5154 Fix various code style nuances 2015-11-11 15:28:51 -05:00
Timothy Warren 8343fa9182 Fix some sonarqube issues 2015-11-11 14:53:09 -05:00
Timothy Warren 406c7c13cb Merge pull request #8 from timw4mail/scrutinizer-patch-1
Scrutinizer Auto-Fixes
2015-11-09 15:55:54 -05:00
Scrutinizer Auto-Fixer cd8185960b Scrutinizer Auto-Fixes
This commit consists of patches automatically generated for this project on https://scrutinizer-ci.com
2015-11-09 20:08:08 +00:00
Timothy Warren 87f5324761 Update config and header for new auth class 2015-11-09 11:50:24 -05:00
Timothy Warren a18f1926d9 Fix ArrayType class 2015-11-09 11:49:51 -05:00
Timothy Warren 17a335275c More quality fixes 2015-11-09 11:10:15 -05:00
Timothy Warren ff13f2ce05 No coverage for scrutinizer 2015-11-05 11:30:51 -05:00
Timothy Warren 4937d4c099 Fix some more code style issues 2015-11-05 11:26:03 -05:00
Timothy Warren 1de8b46657 Some more style fixes 2015-11-05 10:41:46 -05:00
Timothy Warren 6aa51e5915 Some code style fixes 2015-11-04 16:53:22 -05:00
Timothy Warren 8936944743 Some minor refactoring 2015-11-04 16:36:54 -05:00
Timothy Warren 76672d5a60 Merge pull request #7 from timw4mail/scrutinizer-patch-1
Scrutinizer Auto-Fixes
2015-11-04 16:33:18 -05:00
Scrutinizer Auto-Fixer 025bc4ef64 Scrutinizer Auto-Fixes
This commit consists of patches automatically generated for this project on https://scrutinizer-ci.com
2015-11-04 21:31:03 +00:00
Timothy Warren a741526da1 Update metadata and build information files 2015-11-04 16:12:46 -05:00
Timothy Warren 799a3652d4 Fix tests broken by missing fix to Anime Collection Model 2015-10-21 15:46:50 -04:00
Timothy Warren 2f8886c28f More test coverage 2015-10-21 15:43:51 -04:00
Timothy Warren c3643565e3 Fix issue where cache file doesn't exist, add tests for Menu Helper 2015-10-21 11:57:58 -04:00
Timothy Warren 28e03f6fb2 Fix default redirect and tests 2015-10-20 16:41:51 -04:00
Timothy Warren 4ef2d6df57 Fix the rest of the menu urls 2015-10-20 15:59:51 -04:00
Timothy Warren 779f4a00eb Remove another vistigal controller method 2015-10-19 15:19:02 -04:00
Timothy Warren d281c26a1c Remove risky tests, update .gitignore 2015-10-19 15:13:18 -04:00
Timothy Warren 77399e3fa4 Remove some vestigal methods from base controller 2015-10-19 13:58:59 -04:00
Timothy Warren 5f5bf66c75 Fix spacing style 2015-10-19 13:26:50 -04:00
Timothy Warren 385037b669 Fix tests for PHP 5.5 2015-10-19 13:02:10 -04:00
Timothy Warren fee09c50ae More test coverage 2015-10-19 12:50:46 -04:00
Timothy Warren 285a132d35 Scrutinizer fixes 2015-10-16 12:53:55 -04:00
Timothy Warren 0b79ac3596 Better testing for ArrayType and Config classes 2015-10-15 22:00:09 -04:00
Timothy Warren de444857dd Add partial test for config delete 2015-10-15 10:23:00 -04:00
Timothy Warren d231b39fdc Fix origin value in API Model tests 2015-10-15 09:49:38 -04:00
Timothy Warren d5c76a0f01 Fix html view test for PHP < 7 2015-10-15 09:28:10 -04:00
Timothy Warren 485ba46838 More test coverage 2015-10-15 09:25:30 -04:00
Timothy Warren 7f2000f180 Update lots of docblocks 2015-10-14 09:20:52 -04:00
Timothy Warren 34acf00b5e Fix documentation issues 2015-10-12 14:27:20 -04:00
Timothy Warren bc6aed51c8 Remove some dead code 2015-10-12 14:11:00 -04:00
Timothy Warren 011bdda777 Merge pull request #6 from timw4mail/scrutinizer-patch-1
Scrutinizer Auto-Fixes
2015-10-12 11:00:09 -04:00
Scrutinizer Auto-Fixer 80f83e5f53 Scrutinizer Auto-Fixes
This commit consists of patches automatically generated for this project on https://scrutinizer-ci.com
2015-10-10 02:35:39 +00:00
Timothy Warren b687dcf2a8 Rearrange some namespaces and add more docblocks 2015-10-09 22:29:59 -04:00
Timothy Warren bb3e5a643f Merge pull request #5 from timw4mail/scrutinizer-patch-1
Scrutinizer Auto-Fixes
2015-10-09 15:04:55 -04:00
Scrutinizer Auto-Fixer 4dddd3238c Scrutinizer Auto-Fixes
This commit consists of patches automatically generated for this project on https://scrutinizer-ci.com
2015-10-09 18:55:15 +00:00
Timothy Warren a8e3c594e3 Basic Menu generation 2015-10-09 14:34:55 -04:00
Timothy Warren 728850da08 More scrutinizer fixes 2015-10-06 13:38:59 -04:00
Timothy Warren 443802332b Merge pull request #4 from timw4mail/scrutinizer-patch-1
Scrutinizer Auto-Fixes
2015-10-06 13:37:48 -04:00
Scrutinizer Auto-Fixer bf6550d0d9 Scrutinizer Auto-Fixes
This commit consists of patches automatically generated for this project on https://scrutinizer-ci.com
2015-10-06 17:35:42 +00:00
Timothy Warren 37ef0f5621 Fix more scrutinizer issues 2015-10-06 12:15:19 -04:00
Timothy Warren 38cfaa023d Fix failing test 2015-10-06 11:41:21 -04:00
Timothy Warren f3772528c5 Code style improvements 2015-10-06 11:38:20 -04:00
Timothy Warren dbbea163d1 Scrutinizer fixes 2015-10-06 10:44:33 -04:00
Timothy Warren 7269c5c393 Merge pull request #3 from timw4mail/scrutinizer-patch-1
Spacing and docblock fixes
2015-10-06 10:28:33 -04:00
Scrutinizer Auto-Fixer 7e695edd29 Scrutinizer Auto-Fixes
This commit consists of patches automatically generated for this project on https://scrutinizer-ci.com
2015-10-06 14:24:48 +00:00
Timothy Warren 6b322d18da Miscellaneous updates, prep for menu generator 2015-10-05 16:54:25 -04:00
Timothy Warren be96e2c6af Update Router 2015-10-01 16:30:46 -04:00
Timothy Warren 5de88986ed Update some meta files 2015-10-01 16:21:09 -04:00
Timothy Warren b68cbe5a26 fix test 2015-10-01 16:07:40 -04:00
Timothy Warren 2462e09205 Lots of miscellaneous improvements 2015-10-01 16:02:51 -04:00
Timothy Warren acb0a1e8a2 Fix views to match transformed data 2015-10-01 16:01:23 -04:00
Timothy Warren a73e150ee3 Fix broken test 2015-09-28 15:11:45 -04:00
Timothy Warren b8f753a424 Use Anime transformer class 2015-09-28 14:41:45 -04:00
Timothy Warren 23c16fc9c3 Transformers and Enums 2015-09-25 13:41:12 -04:00
Timothy Warren 082b5296b9 Update manga model to use Zipper transformer 2015-09-21 09:48:15 -04:00
Timothy Warren f87dd2636d More tests for Ion 2015-09-18 22:55:40 -04:00
Timothy Warren 60109b3531 Fix failing tests for PHP < 5.6 2015-09-18 13:06:22 -04:00
Timothy Warren e2731db7ea Decouple and generalise 2015-09-17 23:11:18 -04:00
Timothy Warren 156461a0b9 Start of refactoring routing to be more convention based 2015-09-16 12:25:35 -04:00
Timothy Warren 8a68559f0e More namespace refactoring 2015-09-15 13:19:29 -04:00
Timothy Warren 97a5abe665 Namespace refactoring 2015-09-14 19:54:34 -04:00
Timothy Warren d93f5a82a0 fix a few variable changes, remove old code from app folder 2015-09-14 16:14:02 -04:00
Timothy Warren 9d139a7d1c Pass the tests! 2015-09-14 15:49:20 -04:00
Timothy Warren e53f9abf3f Some progress toward better structure through refactoring 2015-09-14 10:54:50 -04:00
Timothy Warren c5f3093a78 Update default config, add phpci config file 2015-07-20 16:13:00 -04:00
Timothy Warren 4622b6efa9 Update readme with new instructions for collection 2015-07-06 14:35:24 -04:00
Timothy Warren 3e39aa0277 Miscellaneous rework, and adding/editing of collection items when logged in 2015-07-02 14:04:04 -04:00
Timothy Warren 3e53ec1526 More dependency injection, and code coverage 2015-06-30 13:03:20 -04:00
Timothy Warren 2abb5f3c3a Merge pull request #1 from timw4mail/scrutinizer-patch-1
Scrutinizer Auto-Fixes
2015-06-29 10:36:28 -04:00
648 changed files with 63393 additions and 41217 deletions

129
.gitignore vendored
View File

@ -1,3 +1,118 @@
# Created by https://www.gitignore.io/api/macos,jetbrains+all
### JetBrains+all ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### JetBrains+all Patch ###
# Ignores the whole .idea folder and all .iml files
# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
.idea/
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
*.iml
modules.xml
.idea/misc.xml
*.ipr
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# End of https://www.gitignore.io/api/macos,jetbrains+all
.codelite
.phing_targets
.sonar/
@ -23,10 +138,20 @@ build/**
app/config/*.toml
!app/config/*.toml.example
phinx.yml
.idea/
Caddyfile
build/humbuglog.txt
public/images/anime/**
public/images/avatars/**
public/images/manga/**
public/images/characters/**
public/images/characters/**
public/images/people/**
public/mal_mappings.json
.phpunit.result.cache
.is-dev
tmp
tools/vendor/
tools/phinx/vendor/
/.php-cs-fixer.php
/.php-cs-fixer.cache

View File

@ -1,21 +0,0 @@
test:7.1:
stage: test
before_script:
- sh build/docker_install.sh > /dev/null
- apk add --no-cache php7-phpdbg
- curl -sS https://getcomposer.org/installer | php
- php composer.phar install --ignore-platform-reqs
image: php:7.1-alpine
script:
- phpdbg -qrr -- ./vendor/bin/phpunit --coverage-text --colors=never
test:7.2:
stage: test
before_script:
- sh build/docker_install.sh > /dev/null
- apk add --no-cache php7-phpdbg
- curl -sS https://getcomposer.org/installer | php
- php composer.phar install --ignore-platform-reqs
image: php:7.2-alpine
script:
- phpdbg -qrr -- ./vendor/bin/phpunit --coverage-text --colors=never

534
.php-cs-fixer.dist.php Normal file
View File

@ -0,0 +1,534 @@
<?php declare(strict_types=1);
use Nexus\CsConfig\Factory;
use PhpCsFixer\{Config, Finder};
$finder = Finder::create()
->in([
__DIR__ . '/src',
__DIR__ . '/tests',
__DIR__ . '/tools',
])
->exclude([
'vendor',
]);
return (new Config())
->setRiskyAllowed(TRUE)
->setFinder($finder)
->setIndent(' ')
->setRules([
'align_multiline_comment' => false,
'array_indentation' => true,
'array_push' => true,
'array_syntax' => ['syntax' => 'short'],
'assign_null_coalescing_to_coalesce_equal' => true,
'backtick_to_shell_exec' => true,
'binary_operator_spaces' => [
'default' => 'single_space',
'operators' => [
'=' => NULL,
'&' => NULL,
]
],
'blank_line_after_namespace' => true,
'blank_line_after_opening_tag' => false,
'blank_line_before_statement' => [
'statements' => [
// 'case',
'continue',
'declare',
'default',
'do',
'exit',
'for',
'foreach',
'goto',
'return',
'switch',
'throw',
'try',
'while',
'yield',
'yield_from',
],
],
// 'braces' => [
// 'allow_single_line_anonymous_class_with_empty_body' => true,
// 'allow_single_line_closure' => true,
// 'position_after_anonymous_constructs' => 'same',
// 'position_after_control_structures' => 'next',
// 'position_after_functions_and_oop_constructs' => 'next',
// ],
'cast_spaces' => ['space' => 'single'],
'class_attributes_separation' => [
'elements' => [
'const' => 'none',
'property' => 'none',
'method' => 'one',
'trait_import' => 'none',
],
],
'class_definition' => [
'multi_line_extends_each_single_line' => true,
'single_item_single_line' => true,
'single_line' => true,
'space_before_parenthesis' => true,
],
'class_reference_name_casing' => true,
'clean_namespace' => true,
'combine_consecutive_issets' => true,
'combine_consecutive_unsets' => true,
'combine_nested_dirname' => true,
'comment_to_phpdoc' => [
'ignored_tags' => [
'todo',
'codeCoverageIgnore',
'codeCoverageIgnoreStart',
'codeCoverageIgnoreEnd',
'phpstan-ignore-line',
'phpstan-ignore-next-line',
],
],
'compact_nullable_typehint' => true,
'concat_space' => ['spacing' => 'one'],
'constant_case' => ['case' => 'upper'],
'control_structure_braces' => true,
'control_structure_continuation_position' => ['position' => 'next_line'],
'curly_braces_position' => [
'allow_single_line_anonymous_functions' => true,
'allow_single_line_empty_anonymous_classes' => true,
'anonymous_functions_opening_brace' => 'same_line',
'classes_opening_brace' => 'next_line_unless_newline_at_signature_end',
'control_structures_opening_brace' => 'next_line_unless_newline_at_signature_end',
'functions_opening_brace' => 'next_line_unless_newline_at_signature_end',
],
'date_time_immutable' => false,
'declare_equal_normalize' => ['space' => 'none'],
'declare_parentheses' => true,
'declare_strict_types' => true,
'dir_constant' => true,
'doctrine_annotation_array_assignment' => false,
'doctrine_annotation_braces' => false,
'doctrine_annotation_indentation' => false,
'doctrine_annotation_spaces' => false,
'echo_tag_syntax' => [
'format' => 'short',
'long_function' => 'echo',
'shorten_simple_statements_only' => false,
],
'elseif' => false,
'empty_loop_body' => ['style' => 'braces'],
'empty_loop_condition' => ['style' => 'while'],
'encoding' => true,
'error_suppression' => [
'mute_deprecation_error' => true,
'noise_remaining_usages' => false,
'noise_remaining_usages_exclude' => [],
],
'escape_implicit_backslashes' => [
'double_quoted' => false,
'heredoc_syntax' => false,
'single_quoted' => false,
],
'explicit_indirect_variable' => false,
'explicit_string_variable' => false,
'final_class' => false,
'final_internal_class' => [
'annotation_exclude' => ['@no-final'],
'annotation_include' => ['@internal'],
'consider_absent_docblock_as_internal_class' => false,
],
'final_public_method_for_abstract_class' => false,
'fopen_flag_order' => true,
'fopen_flags' => ['b_mode' => true],
'full_opening_tag' => true,
'fully_qualified_strict_types' => true,
'function_declaration' => ['closure_function_spacing' => 'one'],
'function_to_constant' => [
'functions' => [
'get_called_class',
'get_class',
'get_class_this',
'php_sapi_name',
'phpversion',
'pi',
],
],
'function_typehint_space' => true,
'general_phpdoc_annotation_remove' => false,
'general_phpdoc_tag_rename' => false,
'get_class_to_class_keyword' => false,
'global_namespace_import' => [
'import_constants' => true,
'import_functions' => true,
'import_classes' => true,
],
'group_import' => true,
'header_comment' => false, // false by default
// 'heredoc_indentation' => ['indentation' => 'start_plus_one'],
'heredoc_to_nowdoc' => true,
'implode_call' => true,
'include' => true,
'increment_style' => ['style' => 'post'],
'indentation_type' => true,
'integer_literal_case' => true,
'is_null' => true,
'lambda_not_used_import' => true,
'line_ending' => true,
'linebreak_after_opening_tag' => false,
'list_syntax' => ['syntax' => 'short'],
'logical_operators' => true,
'lowercase_cast' => true,
'lowercase_keywords' => true,
'lowercase_static_reference' => true,
'magic_constant_casing' => true,
'magic_method_casing' => true,
'mb_str_functions' => false,
'method_argument_space' => [
'after_heredoc' => false,
'keep_multiple_spaces_after_comma' => false,
'on_multiline' => 'ensure_fully_multiline',
],
'method_chaining_indentation' => true,
'modernize_strpos' => false, // requires 8.0+
'modernize_types_casting' => true,
'multiline_comment_opening_closing' => true,
'multiline_whitespace_before_semicolons' => ['strategy' => 'no_multi_line'],
'native_constant_invocation' => false,
'native_function_casing' => true,
'native_function_invocation' => false,
'native_function_type_declaration_casing' => true,
'new_with_braces' => true,
'no_alias_functions' => ['sets' => ['@all']],
'no_alias_language_construct_call' => true,
'no_alternative_syntax' => ['fix_non_monolithic_code' => false],
'no_binary_string' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'no_blank_lines_before_namespace' => false, // conflicts with `single_blank_line_before_namespace`
'no_break_comment' => ['comment_text' => 'no break'],
'no_closing_tag' => true,
'no_empty_comment' => true,
'no_empty_phpdoc' => true,
'no_empty_statement' => true,
'no_extra_blank_lines' => ['tokens' => ['extra']],
'no_homoglyph_names' => true,
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_mixed_echo_print' => ['use' => 'echo'],
'no_multiline_whitespace_around_double_arrow' => true,
'no_null_property_initialization' => true,
'no_short_bool_cast' => true,
'no_singleline_whitespace_before_semicolons' => true,
'no_space_around_double_colon' => true,
'no_spaces_after_function_name' => true,
'no_spaces_around_offset' => ['positions' => ['inside', 'outside']],
'no_spaces_inside_parenthesis' => true,
'no_superfluous_elseif' => true,
'no_superfluous_phpdoc_tags' => [
'allow_mixed' => true,
'allow_unused_params' => true,
'remove_inheritdoc' => false,
],
'no_trailing_comma_in_singleline' => true,
'no_trailing_whitespace' => true,
'no_trailing_whitespace_in_comment' => true,
'no_trailing_whitespace_in_string' => true,
'no_unneeded_control_parentheses' => [
'statements' => [
'break',
'clone',
'continue',
'echo_print',
'return',
'switch_case',
'yield',
],
],
'no_unneeded_curly_braces' => ['namespaces' => true],
'no_unneeded_final_method' => ['private_methods' => true],
'no_unneeded_import_alias' => true,
'no_unreachable_default_argument_value' => true,
'no_unset_cast' => true,
'no_unset_on_property' => false,
'no_unused_imports' => true,
'no_useless_else' => true,
'no_useless_return' => true,
'no_useless_sprintf' => true,
'no_whitespace_before_comma_in_array' => ['after_heredoc' => true],
'no_whitespace_in_blank_line' => true,
'non_printable_character' => ['use_escape_sequences_in_strings' => true],
'normalize_index_brace' => true,
'not_operator_with_space' => true,
'not_operator_with_successor_space' => true,
'nullable_type_declaration_for_default_null_value' => ['use_nullable_type_declaration' => true],
'object_operator_without_whitespace' => true,
'operator_linebreak' => ['only_booleans' => true, 'position' => 'beginning'],
'ordered_class_elements' => [
'order' => [
'use_trait',
'case',
'constant_public',
'constant_protected',
'constant_private',
'property_public',
'property_protected',
'property_private',
'construct',
'destruct',
'magic',
],
'sort_algorithm' => 'none',
],
'ordered_imports' => [
'sort_algorithm' => 'alpha',
'imports_order' => ['class', 'function', 'const'],
],
'ordered_interfaces' => false,
'ordered_traits' => false,
'php_unit_construct' => [
'assertions' => [
'assertSame',
'assertEquals',
'assertNotEquals',
'assertNotSame',
],
],
'php_unit_dedicate_assert' => ['target' => 'newest'],
'php_unit_dedicate_assert_internal_type' => ['target' => 'newest'],
'php_unit_expectation' => ['target' => 'newest'],
'php_unit_fqcn_annotation' => true,
'php_unit_internal_class' => ['types' => ['final']],
'php_unit_method_casing' => ['case' => 'camel_case'],
'php_unit_mock' => ['target' => 'newest'],
'php_unit_mock_short_will_return' => true,
'php_unit_namespaced' => ['target' => 'newest'],
'php_unit_no_expectation_annotation' => [
'target' => 'newest',
'use_class_const' => true,
],
'php_unit_set_up_tear_down_visibility' => true,
'php_unit_size_class' => false,
// 'php_unit_strict' => [
// 'assertions' => [
// 'assertAttributeEquals',
// 'assertAttributeNotEquals',
// 'assertEquals',
// 'assertNotEquals',
// ],
// ],
'php_unit_test_annotation' => ['style' => 'prefix'],
'php_unit_test_case_static_method_calls' => [
'call_type' => 'this',
'methods' => [],
],
'php_unit_test_class_requires_covers' => false,
'phpdoc_add_missing_param_annotation' => ['only_untyped' => true],
'phpdoc_align' => [
'align' => 'left'
],
'phpdoc_annotation_without_dot' => false,
'phpdoc_indent' => true,
'phpdoc_inline_tag_normalizer' => [
'tags' => [
'example',
'id',
'internal',
'inheritdoc',
'inheritdocs',
'link',
'source',
'toc',
'tutorial',
],
],
'phpdoc_line_span' => [
'const' => 'multi',
'method' => 'multi',
'property' => 'multi',
],
'phpdoc_no_access' => true,
'phpdoc_no_empty_return' => false,
'phpdoc_no_package' => false,
'phpdoc_no_useless_inheritdoc' => true,
'phpdoc_order' => true,
'phpdoc_order_by_value' => [
'annotations' => [
'author',
'covers',
'coversNothing',
'dataProvider',
'depends',
'group',
'internal',
'method',
'property',
'property-read',
'property-write',
'requires',
'throws',
'uses',
],
],
'phpdoc_return_self_reference' => [
'replacements' => [
'this' => '$this',
'@this' => '$this',
'$self' => 'self',
'@self' => 'self',
'$static' => 'static',
'@static' => 'static',
],
],
'phpdoc_scalar' => [
'types' => [
'boolean',
'callback',
'double',
'integer',
'real',
'str',
],
],
'phpdoc_separation' => false,
'phpdoc_single_line_var_spacing' => true,
'phpdoc_summary' => false,
'phpdoc_tag_casing' => ['tags' => ['inheritDoc']],
'phpdoc_tag_type' => ['tags' => ['inheritDoc' => 'inline']],
'phpdoc_to_comment' => false,
'phpdoc_to_param_type' => false,
'phpdoc_to_property_type' => false,
'phpdoc_to_return_type' => false,
'phpdoc_trim' => true,
'phpdoc_trim_consecutive_blank_line_separation' => true,
'phpdoc_types' => ['groups' => ['simple', 'alias', 'meta']],
'phpdoc_types_order' => [
'null_adjustment' => 'always_last',
'sort_algorithm' => 'alpha',
],
'phpdoc_var_annotation_correct_order' => true,
'phpdoc_var_without_name' => true,
'pow_to_exponentiation' => true,
'protected_to_private' => true,
'psr_autoloading' => ['dir' => null],
'random_api_migration' => [
'replacements' => [
'getrandmax' => 'mt_getrandmax',
'rand' => 'mt_rand',
'srand' => 'mt_srand',
],
],
'regular_callable_call' => true,
'return_assignment' => true,
'return_type_declaration' => ['space_before' => 'none'],
'self_accessor' => false,
'self_static_accessor' => true,
'semicolon_after_instruction' => false,
'set_type_to_cast' => true,
'short_scalar_cast' => true,
'simple_to_complex_string_variable' => true,
'simplified_if_return' => true,
'simplified_null_return' => false,
'single_blank_line_at_eof' => true,
'single_blank_line_before_namespace' => true,
'single_class_element_per_statement' => ['elements' => ['const', 'property']],
'single_import_per_statement' => false,
'single_line_after_imports' => true,
'single_line_comment_style' => ['comment_types' => ['asterisk', 'hash']],
'single_line_throw' => false,
'single_quote' => ['strings_containing_single_quote_chars' => false],
'single_space_around_construct' => [
'constructs_followed_by_a_single_space' => [
'abstract',
'as',
'attribute',
'break',
'case',
'catch',
'class',
'clone',
'comment',
'const',
'const_import',
'continue',
'do',
'echo',
'else',
'elseif',
'extends',
'final',
'finally',
'for',
'foreach',
'function',
'function_import',
'global',
'goto',
'if',
'implements',
'include',
'include_once',
'instanceof',
'insteadof',
'interface',
'match',
'named_argument',
'new',
'open_tag_with_echo',
'php_doc',
'php_open',
'print',
'private',
'protected',
'public',
'require',
'require_once',
'return',
'static',
'throw',
'trait',
'try',
'use',
'use_lambda',
'use_trait',
'var',
'while',
'yield',
'yield_from',
],
],
'single_trait_insert_per_statement' => true,
'space_after_semicolon' => ['remove_in_empty_for_expressions' => true],
'standardize_increment' => true,
'standardize_not_equals' => true,
'statement_indentation' => true,
'static_lambda' => true,
'strict_comparison' => true,
'strict_param' => true,
'string_length_to_empty' => true,
'string_line_ending' => true,
'switch_case_semicolon_to_colon' => true,
'switch_case_space' => true,
'switch_continue_to_break' => true,
'ternary_operator_spaces' => true,
'ternary_to_elvis_operator' => true,
'ternary_to_null_coalescing' => true,
'trailing_comma_in_multiline' => [
'after_heredoc' => true,
'elements' => ['arrays'],
],
'trim_array_spaces' => true,
'types_spaces' => ['space' => 'none'],
'unary_operator_spaces' => false,
'use_arrow_functions' => true,
'visibility_required' => ['elements' => ['const', 'method', 'property']],
'void_return' => false, // changes method signature
'whitespace_after_comma_in_array' => true,
'yoda_style' => [
'equal' => false,
'identical' => null,
'less_and_greater' => false,
'always_move_variable' => false,
],
]);

View File

@ -4,23 +4,14 @@ install:
- composer install --ignore-platform-reqs
php:
- 7.1
- 7.2
- hhvm
- 8.0
- 8.1
- nightly
script:
- mkdir -p build/logs
- phpdbg -qrr -- vendor/bin/phpunit -c build
- php vendor/bin/phpunit -c build
after_script:
- CODECLIMATE_REPO_TOKEN=2cbddcebcb9256b3402867282e119dbe61de0b31039325356af3c7d72ed6d058 vendor/bin/test-reporter
matrix:
allow_failures:
- php: nightly
- php: hhvm
addons:
code_climate:
repo_token: 2cbddcebcb9256b3402867282e119dbe61de0b31039325356af3c7d72ed6d058
#matrix:
# allow_failures:
# - php: nightly

View File

@ -1,12 +1,46 @@
# Changelog
## Version 5.3
* Update PHP requirement to 8.2
## Version 5.2
* Updated PHP requirement to 8.1
* Updated to support PHP 8.2
* Improve Anilist <-> Kitsu mappings to be more reliable
## Version 5.1
* Added session check, so when coming back to a page, if the session is expired, the page will refresh.
* Updated logging config so that much fewer, much smaller files are generated.
* Updated Kitsu integration to use GraphQL API, reducing a lot of internal complexity.
## Version 5
* Updated PHP requirement to 7.4
* Added anime watching history view
* Added manga reading history view
* Updated anime collection to have more media types
## Version 4.2
* Updated dependencies
* Updated PHP requirement to 7.3
* Added option to automatically set dark mode based on the OS setting
## Version 4.1
* Added optional dark theme
* Removed MAL integration, added Anilist Integration
* Now uses WebP cache images when the browser supports it
* Replaces JS minifier with pre-minified scripts (Removes the need for one caching folder, too)
* Updated console command to sync Kitsu and Anilist data (Kitsu can sync MAL, and MAL's API broke, so MAL sync was removed)
* Added page to update settings without having to edit config files
* Defaulted to secure (HTTPS) urls
* Updated Character pages to show voice actors
* Added People pages, showing which works they contributed to, and in what role
## Version 4
* Updated to use Kitsu API after discontinuation of Hummingbird
* Added streaming links to list entries from the Kitsu API
* Added simple integration with MyAnimeList, so an update can cross-post to both Kitsu and MyAnimeList (anime and manga)
* Added console command to sync Kitsu and MyAnimeList data
* Added character pages
* Added character pages
## Version 3
* Converted user configuration to toml files

65
Jenkinsfile vendored Normal file
View File

@ -0,0 +1,65 @@
pipeline {
agent none
stages {
stage('setup') {
agent any
steps {
sh 'curl -sS https://getcomposer.org/installer | php'
sh 'rm -rf ./vendor'
sh 'rm -f composer.lock'
sh 'php composer.phar install --ignore-platform-reqs'
}
}
stage('PHP 8.1') {
agent {
docker {
image 'php:8.1-cli-alpine'
args '-u root --privileged'
}
}
steps {
sh 'apk add --no-cache git icu-dev'
sh 'docker-php-ext-configure intl && docker-php-ext-install intl'
sh 'php ./vendor/bin/phpunit --colors=never'
}
}
stage('PHP 8.2') {
agent {
docker {
image 'php:8.2-cli-alpine'
args '-u root --privileged'
}
}
steps {
sh 'apk add --no-cache git icu-dev'
sh 'docker-php-ext-configure intl && docker-php-ext-install intl'
sh 'php ./vendor/bin/phpunit --colors=never'
}
}
stage('Latest PHP') {
agent {
docker {
image 'php:cli-alpine'
args '-u root --privileged'
}
}
steps {
sh 'apk add --no-cache git icu-dev'
sh 'docker-php-ext-configure intl && docker-php-ext-install intl'
sh 'php ./vendor/bin/phpunit --colors=never'
}
}
stage('Coverage') {
agent any
steps {
sh 'php composer.phar run-script coverage'
step([
$class: 'CloverPublisher',
cloverReportDir: '',
cloverReportFileName: 'build/logs/clover.xml',
])
junit 'build/logs/junit.xml'
}
}
}
}

View File

@ -1,9 +1,9 @@
# Hummingbird Anime Client
Update your anime/manga list on Kitsu.io and MyAnimeList.net
Update your anime/manga list on Kitsu.io and Anilist
[![Build Status](https://travis-ci.org/timw4mail/HummingBirdAnimeClient.svg?branch=master)](https://travis-ci.org/timw4mail/HummingBirdAnimeClient)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/timw4mail/HummingBirdAnimeClient/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/timw4mail/HummingBirdAnimeClient/?branch=master)
[![Build Status](https://travis-ci.com/timw4mail/HummingBirdAnimeClient.svg?branch=master)](https://travis-ci.com/github/timw4mail/HummingBirdAnimeClient)
[![Build Status](https://jenkins.timshome.page/buildStatus/icon?job=timw4mail/HummingBirdAnimeClient/develop)](https://jenkins.timshome.page/job/timw4mail/job/HummingBirdAnimeClient/job/develop/)
[[Hosted Example](https://list.timshomepage.net)]
@ -31,24 +31,33 @@ Update your anime/manga list on Kitsu.io and MyAnimeList.net
### Requirements
* PHP 7.1+
* PDO SQLite or PDO PostgreSQL (For collection tab)
* GD
* PHP 8.2
* ext-dom (For editing the DOM)
* ext-gd (For caching images)
* ext-intl (For time localization)
* ext-json
* ext-mbstring
* ext-pdo
### Highly Recommended
* Redis or Memcached for caching
* PDO SQLite or PDO PostgreSQL (For collection tab)
### Installation
1. Install via git, then install dependencies via composer: `composer install`
2. Duplicate `app/config/*.toml.example` files as `app/config/*.toml`
2. Duplicate `app/config/config.toml.example` file as `app/config/config.toml`
3. Configure settings in `app/config/config.toml` to your liking
4. Create the following directories if they don't exist, and make sure they are world writable
* app/config
* app/logs
* public/js/cache
* public/images/avatars
* public/images/anime
* public/images/characters
* public/images/manga
5. Make sure the `console` script is executable
6. Additional settings are on the settings page once you log in.
### Server Setup

View File

@ -1,305 +0,0 @@
<?php declare(strict_types=1);
use Robo\Tasks;
if ( ! function_exists('glob_recursive'))
{
// Does not support flag GLOB_BRACE
function glob_recursive($pattern, $flags = 0)
{
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir)
{
$files = array_merge($files, glob_recursive($dir.'/'.basename($pattern), $flags));
}
return $files;
}
}
/**
* This is project's console commands configuration for Robo task runner.
*
* @see http://robo.li/
*/
class RoboFile extends Tasks {
/**
* Directories used by analysis tools
*
* @var array
*/
protected $taskDirs = [
'build/logs',
'build/pdepend',
'build/phpdox',
];
/**
* Directories to remove with the clean task
*
* @var array
*/
protected $cleanDirs = [
'coverage',
'docs',
'phpdoc',
'build/logs',
'build/phpdox',
'build/pdepend'
];
/**
* Do static analysis tasks
*/
public function analyze()
{
$this->prepare();
$this->lint();
$this->phploc(TRUE);
$this->phpcs(TRUE);
$this->dependencyReport();
$this->phpcpdReport();
}
/**
* Run all tests, generate coverage, generate docs, generate code statistics
*/
public function build()
{
$this->analyze();
$this->coverage();
$this->docs();
}
/**
* Cleanup temporary files
*/
public function clean()
{
$cleanFiles = [
'build/humbug.json',
'build/humbug-log.txt',
];
array_map(function ($file) {
@unlink($file);
}, $cleanFiles);
// So the task doesn't complain,
// make any 'missing' dirs to cleanup
array_map(function ($dir) {
if ( ! is_dir($dir))
{
`mkdir -p {$dir}`;
}
}, $this->cleanDirs);
$this->_cleanDir($this->cleanDirs);
$this->_deleteDir($this->cleanDirs);
}
/**
* Run unit tests and generate coverage reports
*/
public function coverage()
{
$this->_run(['phpdbg -qrr -- vendor/bin/phpunit -c build']);
}
/**
* Generate documentation with phpdox
*/
public function docs()
{
$cmd_parts = [
'vendor/bin/phpdox',
];
$this->_run($cmd_parts, ' && ');
}
/**
* Verify that source files are valid
*/
public function lint()
{
$files = $this->getAllSourceFiles();
$chunks = array_chunk($files, 12);
foreach($chunks as $chunk)
{
$this->parallelLint($chunk);
}
}
/**
* Run the phpcs tool
*
* @param bool $report - if true, generates reports instead of direct output
*/
public function phpcs($report = FALSE)
{
$report_cmd_parts = [
'vendor/bin/phpcs',
'--standard=./build/phpcs.xml',
'--report-checkstyle=./build/logs/phpcs.xml',
];
$normal_cmd_parts = [
'vendor/bin/phpcs',
'--standard=./build/phpcs.xml',
];
$cmd_parts = ($report) ? $report_cmd_parts : $normal_cmd_parts;
$this->_run($cmd_parts);
}
/**
* Run the phploc tool
*
* @param bool $report - if true, generates reports instead of direct output
*/
public function phploc($report = FALSE)
{
// Command for generating reports
$report_cmd_parts = [
'vendor/bin/phploc',
'--count-tests',
'--log-csv=build/logs/phploc.csv',
'--log-xml=build/logs/phploc.xml',
'src',
'tests'
];
// Command for generating direct output
$normal_cmd_parts = [
'vendor/bin/phploc',
'--count-tests',
'src',
'tests'
];
$cmd_parts = ($report) ? $report_cmd_parts : $normal_cmd_parts;
$this->_run($cmd_parts);
}
/**
* Create temporary directories
*/
public function prepare()
{
array_map([$this, '_mkdir'], $this->taskDirs);
}
/**
* Lint php files and run unit tests
*/
public function test()
{
$this->lint();
$this->_run(['phpunit']);
}
/**
* Watches for file updates, and automatically runs appropriate actions
*/
public function watch()
{
$this->taskWatch()
->monitor('composer.json', function() {
$this->taskComposerUpdate()->run();
})
->monitor('src', function () {
$this->taskExec('test')->run();
})
->monitor('tests', function () {
$this->taskExec('test')->run();
})
->run();
}
/**
* Create pdepend reports
*/
protected function dependencyReport()
{
$cmd_parts = [
'vendor/bin/pdepend',
'--jdepend-xml=build/logs/jdepend.xml',
'--jdepend-chart=build/pdepend/dependencies.svg',
'--overview-pyramid=build/pdepend/overview-pyramid.svg',
'src'
];
$this->_run($cmd_parts);
}
/**
* Get the total list of source files, including tests
*
* @return array
*/
protected function getAllSourceFiles()
{
$files = array_merge(
glob_recursive('build/*.php'),
glob_recursive('src/*.php'),
glob_recursive('src/**/*.php'),
glob_recursive('tests/*.php'),
glob_recursive('tests/**/*.php'),
glob('*.php')
);
sort($files);
return $files;
}
/**
* Run php's linter in one parallel task for the passed chunk
*
* @param array $chunk
*/
protected function parallelLint(array $chunk)
{
$task = $this->taskParallelExec()
->timeout(5)
->printed(FALSE);
foreach($chunk as $file)
{
$task = $task->process("php -l {$file}");
}
$task->run();
}
/**
* Generate copy paste detector report
*/
protected function phpcpdReport()
{
$cmd_parts = [
'vendor/bin/phpcpd',
'--log-pmd build/logs/pmd-cpd.xml',
'src'
];
$this->_run($cmd_parts);
}
/**
* Shortcut for joining an array of command arguments
* and then running it
*
* @param array $cmd_parts - command arguments
* @param string $join_on - what to join the command arguments with
*/
protected function _run(array $cmd_parts, $join_on = ' ')
{
$this->taskExec(implode($join_on, $cmd_parts))->run();
}
}

View File

@ -2,32 +2,51 @@
/**
* 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\loadToml;
use function Aviat\AnimeClient\loadConfig;
// ----------------------------------------------------------------------------
// Lower level configuration
//
// 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 = loadToml(__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",
// No config defaults
'kitsu_username' => 'timw4mail',
'whose_list' => 'Someone',
'cache' => [
'connection' => [],
'driver' => 'null',
],
'secure_urls' => TRUE,
// Routing defaults
'asset_path' => '/public',
'default_list' => 'anime', //anime|manga
'default_anime_list_path' => 'watching', // watching|plan_to_watch|on_hold|dropped|completed|all
'default_manga_list_path' => 'reading', // reading|plan_to_read|on_hold|dropped|completed|all
'default_view_type' => 'cover_view', // cover_view|list_view
// Template file path
'view_path' => "{$APP_DIR}/views",
@ -38,4 +57,4 @@ return array_merge($tomlConfig, [
// Included config files
'routes' => require 'routes.php',
]);
]);

View File

@ -1,19 +1,21 @@
[anime_list]
route_prefix = "/anime"
route_prefix = ""
[anime_list.items]
watching = '/watching'
plan_to_watch = '/plan_to_watch'
on_hold = '/on_hold'
dropped = '/dropped'
completed = '/completed'
all = '/all'
watch_history = '/history/anime'
watching = '/anime/watching'
plan_to_watch = '/anime/plan_to_watch'
on_hold = '/anime/on_hold'
dropped = '/anime/dropped'
completed = '/anime/completed'
all = '/anime/all'
[manga_list]
route_prefix = "/manga"
route_prefix = ""
[manga_list.items]
reading = '/reading'
plan_to_read = '/plan_to_read'
on_hold = '/on_hold'
dropped = '/dropped'
completed = '/completed'
all = '/all'
reading_history = '/history/manga'
reading = '/manga/reading'
plan_to_read = '/manga/plan_to_read'
on_hold = '/manga/on_hold'
dropped = '/manga/dropped'
completed = '/manga/completed'
all = '/manga/all'

View File

@ -1,69 +0,0 @@
<?php declare(strict_types=1);
/**
* Hummingbird Anime List Client
*
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
*
* PHP version 7
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2017 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 4.0
* @link https://github.com/timw4mail/HummingBirdAnimeClient
*/
// --------------------------------------------------------------------------
return [
/*
|--------------------------------------------------------------------------
| JS Folder
|--------------------------------------------------------------------------
|
| The folder where javascript files exist, in relation to the document root
|
*/
'js_root' => 'js/',
/*
|--------------------------------------------------------------------------
| JS Groups
|--------------------------------------------------------------------------
|
| Config array for javascript files to concatenate and minify
|
*/
'groups' => [
'base' => [
'base/classList.js',
'base/AnimeClient.js',
],
'event' => [
'base/events.js',
],
'table' => [
'base/sort_tables.js',
],
'table_edit' => [
'base/sort_tables.js',
'anime_edit.js',
'manga_edit.js',
],
'edit' => [
'anime_edit.js',
'manga_edit.js',
],
'anime_collection' => [
'anime_search_results.js',
'anime_collection.js',
],
'manga_collection' => [
'manga_search_results.js',
'manga_collection.js',
],
]
];
// End of minify_config.php

View File

@ -1,19 +0,0 @@
################################################################################
# Route config
#
# Default views and paths
################################################################################
# Path to public directory, where images/css/javascript are located,
# appended to the url
asset_path = "/public"
# Which list should be the default?
default_list = "anime" # anime or manga
# Default pages for anime/manga
default_anime_list_path = "watching" # watching|plan_to_watch|on_hold|dropped|completed|all
default_manga_list_path = "reading" # reading|plan_to_read|on_hold|dropped|completed|all
# Default view type (cover_view/list_view)
default_view_type = "cover_view"

View File

@ -2,21 +2,24 @@
/**
* 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
*/
use const Aviat\AnimeClient\{
ALPHA_SLUG_PATTERN,
DEFAULT_CONTROLLER,
DEFAULT_CONTROLLER_METHOD,
DEFAULT_CONTROLLER
SLUG_PATTERN,
NUM_PATTERN,
};
// -------------------------------------------------------------------------
@ -24,25 +27,39 @@ use const Aviat\AnimeClient\{
//
// Maps paths to controllers and methods
// -------------------------------------------------------------------------
return [
$base_routes = [
// ---------------------------------------------------------------------
// AJAX Routes
// ---------------------------------------------------------------------
'cache_purge' => [
'path' => '/cache_purge',
'action' => 'clearCache',
],
'heartbeat' => [
'path' => '/heartbeat',
'action' => 'heartbeat',
],
// ---------------------------------------------------------------------
// Anime List Routes
// ---------------------------------------------------------------------
'anime.add.get' => [
'path' => '/anime/add',
'action' => 'addForm',
'verb' => 'get',
],
'anime.add.post' => [
'path' => '/anime/add',
'action' => 'add',
'verb' => 'post',
],
'anime.random' => [
'path' => '/anime/details/random',
'action' => 'random',
],
'anime.details' => [
'path' => '/anime/details/{id}',
'action' => 'details',
'tokens' => [
'id' => '[a-z0-9\-]+',
'id' => SLUG_PATTERN,
],
],
'anime.delete' => [
@ -60,7 +77,6 @@ return [
'manga.add.get' => [
'path' => '/manga/add',
'action' => 'addForm',
'verb' => 'get',
],
'manga.add.post' => [
'path' => '/manga/add',
@ -72,11 +88,15 @@ return [
'action' => 'delete',
'verb' => 'post',
],
'manga.random' => [
'path' => '/manga/details/random',
'action' => 'random',
],
'manga.details' => [
'path' => '/manga/details/{id}',
'action' => 'details',
'tokens' => [
'id' => '[a-z0-9\-]+',
'id' => SLUG_PATTERN,
],
],
// ---------------------------------------------------------------------
@ -89,13 +109,12 @@ return [
'anime.collection.add.get' => [
'path' => '/anime-collection/add',
'action' => 'form',
'params' => [],
],
'anime.collection.edit.get' => [
'path' => '/anime-collection/edit/{id}',
'action' => 'form',
'tokens' => [
'id' => '[0-9]+',
'id' => NUM_PATTERN,
],
],
'anime.collection.add.post' => [
@ -110,10 +129,9 @@ return [
],
'anime.collection.view' => [
'path' => '/anime-collection/view{/view}',
'action' => 'index',
'params' => [],
'action' => 'view',
'tokens' => [
'view' => '[a-z_]+',
'view' => ALPHA_SLUG_PATTERN,
],
],
'anime.collection.delete' => [
@ -121,6 +139,12 @@ return [
'action' => 'delete',
'verb' => 'post',
],
'anime.collection.redirect' => [
'path' => '/anime-collection',
],
'anime.collection.redirect2' => [
'path' => '/anime-collection/',
],
// ---------------------------------------------------------------------
// Manga Collection Routes
// ---------------------------------------------------------------------
@ -131,13 +155,12 @@ return [
'manga.collection.add.get' => [
'path' => '/manga-collection/add',
'action' => 'form',
'params' => [],
],
'manga.collection.edit.get' => [
'path' => '/manga-collection/edit/{id}',
'action' => 'form',
'tokens' => [
'id' => '[0-9]+',
'id' => NUM_PATTERN,
],
],
'manga.collection.add.post' => [
@ -152,10 +175,8 @@ return [
],
'manga.collection.view' => [
'path' => '/manga-collection/view{/view}',
'action' => 'index',
'params' => [],
'tokens' => [
'view' => '[a-z_]+',
'view' => ALPHA_SLUG_PATTERN,
],
],
'manga.collection.delete' => [
@ -168,17 +189,28 @@ return [
// ---------------------------------------------------------------------
'character' => [
'path' => '/character/{slug}',
'action' => 'index',
'params' => [],
'tokens' => [
'slug' => '[a-z0-9\-]+'
]
'slug' => SLUG_PATTERN,
],
],
'user_info' => [
'person' => [
'path' => '/people/{slug}',
'tokens' => [
'slug' => SLUG_PATTERN,
],
],
'default_user_info' => [
'path' => '/me',
'action' => 'me',
'controller' => 'me',
'verb' => 'get',
'controller' => 'user',
],
'user_info' => [
'path' => '/user/{username}',
'controller' => 'user',
'action' => 'about',
'tokens' => [
'username' => '.*?',
],
],
// ---------------------------------------------------------------------
// Default / Shared routes
@ -186,52 +218,64 @@ return [
'anilist-redirect' => [
'path' => '/anilist-redirect',
'action' => 'anilistRedirect',
'controller' => DEFAULT_CONTROLLER,
'controller' => 'settings',
],
'anilist-oauth' => [
'anilist-callback' => [
'path' => '/anilist-oauth',
'action' => 'anilistCallback',
'controller' => DEFAULT_CONTROLLER,
'controller' => 'settings',
],
'image_proxy' => [
'path' => '/public/images/{type}/{file}',
'action' => 'images',
'controller' => DEFAULT_CONTROLLER,
'verb' => 'get',
'action' => 'cache',
'controller' => 'images',
'tokens' => [
'type' => '[a-z0-9\-]+',
'file' => '[a-z0-9\-]+\.[a-z]{3}'
]
'type' => SLUG_PATTERN,
'file' => '[a-z0-9\-]+\.[a-z]{3,4}',
],
],
'cache_purge' => [
'path' => '/cache_purge',
'action' => 'clearCache',
'controller' => DEFAULT_CONTROLLER,
'verb' => 'get',
'settings' => [
'path' => '/settings',
],
'settings-post' => [
'path' => '/settings/update',
'action' => 'update',
'verb' => 'post',
],
'login' => [
'path' => '/login',
'action' => 'login',
'controller' => DEFAULT_CONTROLLER,
'verb' => 'get',
],
'login.post' => [
'path' => '/login',
'action' => 'loginAction',
'controller' => DEFAULT_CONTROLLER,
'verb' => 'post',
],
'logout' => [
'path' => '/logout',
'action' => 'logout',
'controller' => DEFAULT_CONTROLLER,
],
'history' => [
'controller' => 'history',
'path' => '/history/{type}',
'tokens' => [
'type' => SLUG_PATTERN,
],
],
'increment' => [
'path' => '/{controller}/increment',
'action' => 'increment',
'verb' => 'post',
'tokens' => [
'controller' => ALPHA_SLUG_PATTERN,
],
],
'update' => [
'path' => '/{controller}/update',
'action' => 'update',
'verb' => 'post',
'tokens' => [
'controller' => '[a-z_]+',
'controller' => ALPHA_SLUG_PATTERN,
],
],
'update.post' => [
@ -239,28 +283,41 @@ return [
'action' => 'formUpdate',
'verb' => 'post',
'tokens' => [
'controller' => '[a-z_]+',
'controller' => ALPHA_SLUG_PATTERN,
],
],
'edit' => [
'path' => '/{controller}/edit/{id}/{status}',
'action' => 'edit',
'tokens' => [
'id' => '[0-9a-z_]+',
'status' => '([a-zA-Z\-_]|%20)+',
'id' => SLUG_PATTERN,
'status' => SLUG_PATTERN,
],
],
'list' => [
'path' => '/{controller}/{type}{/view}',
'action' => DEFAULT_CONTROLLER_METHOD,
'path' => '/{controller}/{status}{/view}',
'tokens' => [
'type' => '[a-z_]+',
'view' => '[a-z_]+',
'status' => ALPHA_SLUG_PATTERN,
'view' => ALPHA_SLUG_PATTERN,
],
],
'index_redirect' => [
'path' => '/',
'controller' => DEFAULT_CONTROLLER,
'action' => 'redirectToDefaultRoute',
],
];
];
$defaultMap = [
'action' => DEFAULT_CONTROLLER_METHOD,
'controller' => DEFAULT_CONTROLLER,
'params' => [],
'verb' => 'get',
];
$routes = [];
foreach ($base_routes as $name => $route)
{
$routes[$name] = array_merge($defaultMap, $route);
}
return $routes;

View File

@ -2,15 +2,13 @@
/**
* 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.1
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2018 Timothy J. Warren
* @copyright 2015 - 2023 Timothy J. Warren <tim@timshome.page>
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 4.0
* @version 5.2
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
*/
@ -19,104 +17,131 @@ namespace Aviat\AnimeClient;
use Aura\Html\HelperLocatorFactory;
use Aura\Router\RouterContainer;
use Aura\Session\SessionFactory;
use Aviat\AnimeClient\API\{
Anilist,
Kitsu,
MAL,
Kitsu\KitsuRequestBuilder,
MAL\MALRequestBuilder
};
use Aviat\AnimeClient\Model;
use Aviat\Banker\Pool;
use Aviat\AnimeClient\API\{Anilist, Kitsu};
use Aviat\AnimeClient\{Component, Model};
use Aviat\Banker\Teller;
use Aviat\Ion\Config;
use Aviat\Ion\Di\Container;
use Aviat\Ion\Di\{Container, ContainerInterface};
use Laminas\Diactoros\ServerRequestFactory;
use Monolog\Formatter\JsonFormatter;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;
use Zend\Diactoros\{Response, ServerRequestFactory};
use Psr\SimpleCache\CacheInterface;
use function Aviat\Ion\_dir;
if ( ! defined('HB_APP_DIR'))
{
define('HB_APP_DIR', __DIR__);
define('ROOT_DIR', dirname(HB_APP_DIR));
define('TEMPLATE_DIR', _dir(HB_APP_DIR, 'templates'));
}
// -----------------------------------------------------------------------------
// Setup DI container
// -----------------------------------------------------------------------------
return function (array $configArray = []) {
return static function (array $configArray = []): Container {
$container = new Container();
// -------------------------------------------------------------------------
// Logging
// -------------------------------------------------------------------------
$LOG_DIR = _dir(HB_APP_DIR, 'logs');
$appLogger = new Logger('animeclient');
$appLogger->pushHandler(new RotatingFileHandler(__DIR__ . '/logs/app.log', Logger::NOTICE));
$anilistRequestLogger = new Logger('anilist-request');
$anilistRequestLogger->pushHandler(new RotatingFileHandler(__DIR__ . '/logs/anilist_request.log', Logger::NOTICE));
$kitsuRequestLogger = new Logger('kitsu-request');
$kitsuRequestLogger->pushHandler(new RotatingFileHandler(__DIR__ . '/logs/kitsu_request.log', Logger::NOTICE));
$malRequestLogger = new Logger('mal-request');
$malRequestLogger->pushHandler(new RotatingFileHandler(__DIR__ . '/logs/mal_request.log', Logger::NOTICE));
$appLogger->pushHandler(new RotatingFileHandler(_dir($LOG_DIR, 'app.log'), 2, Logger::WARNING));
$container->setLogger($appLogger);
$container->setLogger($anilistRequestLogger, 'anilist-request');
$container->setLogger($kitsuRequestLogger, 'kitsu-request');
$container->setLogger($malRequestLogger, 'mal-request');
foreach (['anilist-request', 'kitsu-request', 'kitsu-graphql'] as $channel)
{
$logger = new Logger($channel);
$handler = new RotatingFileHandler(_dir($LOG_DIR, "{$channel}.log"), 2, Logger::WARNING);
$handler->setFormatter(new JsonFormatter());
$logger->pushHandler($handler);
$container->setLogger($logger, $channel);
}
// -------------------------------------------------------------------------
// Injected Objects
// -------------------------------------------------------------------------
// Create Config Object
$container->set('config', function() use ($configArray) {
return new Config($configArray);
});
$container->set('config', static fn () => new Config($configArray));
// Create Cache Object
$container->set('cache', function($container) {
$container->set('cache', static function (ContainerInterface $container): CacheInterface {
$logger = $container->getLogger();
$config = $container->get('config')->get('cache');
return new Pool($config, $logger);
return new Teller($config, $logger);
});
// Create Aura Router Object
$container->set('aura-router', function() {
return new RouterContainer;
});
$container->set('aura-router', static fn () => new RouterContainer());
// Create Html helper Object
$container->set('html-helper', function($container) {
$htmlHelper = (new HelperLocatorFactory)->newInstance();
$htmlHelper->set('menu', function() use ($container) {
$menuHelper = new Helper\Menu();
$menuHelper->setContainer($container);
return $menuHelper;
});
// Create Html helpers
$container->set('html-helper', static function (ContainerInterface $container) {
$htmlHelper = (new HelperLocatorFactory())->newInstance();
$helpers = [
'menu' => Helper\Menu::class,
'field' => Helper\Form::class,
'picture' => Helper\Picture::class,
];
foreach ($helpers as $name => $class)
{
$htmlHelper->set($name, static function () use ($class, $container) {
$helper = new $class();
$helper->setContainer($container);
return $helper;
});
}
return $htmlHelper;
});
// Create Request/Response Objects
$container->set('request', function() {
return ServerRequestFactory::fromGlobals(
$_SERVER,
$_GET,
$_POST,
$_COOKIE,
$_FILES
);
});
$container->set('response', function() {
return new Response;
// Create Component helpers
$container->set('component-helper', static function (ContainerInterface $container) {
$helper = (new HelperLocatorFactory())->newInstance();
$components = [
'animeCover' => Component\AnimeCover::class,
'mangaCover' => Component\MangaCover::class,
'character' => Component\Character::class,
'media' => Component\Media::class,
'tabs' => Component\Tabs::class,
'verticalTabs' => Component\VerticalTabs::class,
];
foreach ($components as $name => $componentClass)
{
$helper->set($name, static function () use ($container, $componentClass) {
$helper = new $componentClass();
$helper->setContainer($container);
return $helper;
});
}
return $helper;
});
// Create Request Object
$container->set('request', static fn () => ServerRequestFactory::fromGlobals(
$GLOBALS['_SERVER'],
$_GET,
$_POST,
$_COOKIE,
$_FILES
));
// Create session Object
$container->set('session', function() {
return (new SessionFactory())->newInstance($_COOKIE);
});
// Miscellaneous helper methods
$container->set('util', function($container) {
return new Util($container);
});
$container->set('session', static fn () => (new SessionFactory())->newInstance($_COOKIE));
// Models
$container->set('kitsu-model', function($container) {
$requestBuilder = new KitsuRequestBuilder();
$container->set('kitsu-model', static function (ContainerInterface $container): Kitsu\Model {
$requestBuilder = new Kitsu\RequestBuilder($container);
$requestBuilder->setLogger($container->getLogger('kitsu-request'));
$listItem = new Kitsu\ListItem();
@ -129,54 +154,46 @@ return function (array $configArray = []) {
$cache = $container->get('cache');
$model->setCache($cache);
return $model;
});
$container->set('mal-model', function($container) {
$requestBuilder = new MALRequestBuilder();
$requestBuilder->setLogger($container->getLogger('mal-request'));
$container->set('anilist-model', static function (ContainerInterface $container): Anilist\Model {
$requestBuilder = new Anilist\RequestBuilder($container);
$requestBuilder->setLogger($container->getLogger('anilist-request'));
$listItem = new MAL\ListItem();
$listItem = new Anilist\ListItem();
$listItem->setContainer($container);
$listItem->setRequestBuilder($requestBuilder);
$model = new MAL\Model($listItem);
$model = new Anilist\Model($listItem);
$model->setContainer($container);
$model->setRequestBuilder($requestBuilder);
return $model;
});
$container->set('settings-model', static function ($container) {
$model = new Model\Settings($container->get('config'));
$model->setContainer($container);
return $model;
});
$container->set('api-model', function($container) {
return new Model\API($container);
});
$container->set('anime-model', function($container) {
return new Model\Anime($container);
});
$container->set('manga-model', function($container) {
return new Model\Manga($container);
});
$container->set('anime-collection-model', function($container) {
return new Model\AnimeCollection($container);
});
$container->set('manga-collection-model', function($container) {
return new Model\MangaCollection($container);
});
$container->setSimple('anime-model', Model\Anime::class);
$container->setSimple('manga-model', Model\Manga::class);
$container->setSimple('anime-collection-model', Model\AnimeCollection::class);
// Miscellaneous Classes
$container->set('auth', function($container) {
return new Kitsu\Auth($container);
});
$container->set('url-generator', function($container) {
return new UrlGenerator($container);
});
$container->setSimple('util', Util::class);
$container->setSimple('auth', Kitsu\Auth::class);
$container->setSimple('url-generator', UrlGenerator::class);
$container->setSimple('render-helper', RenderHelper::class);
// -------------------------------------------------------------------------
// Dispatcher
// -------------------------------------------------------------------------
$container->set('dispatcher', function($container) {
return new Dispatcher($container);
});
$container->setSimple('dispatcher', Dispatcher::class);
return $container;
};
// End of bootstrap.php
// End of bootstrap.php

View File

@ -0,0 +1,6 @@
################################################################################
# Anilist API #
################################################################################
client_id = "your_client_id"
client_secret = "your_client_secret"
username = "user123"

View File

@ -2,9 +2,9 @@
# Cache Setup #
################################################################################
# See https://git.timshomepage.net/timw4mail/banker for more information
# See https://git.timshomepage.net/aviat/banker for more information
# Available drivers are apcu, memcache, memcached, redis or null
# Available drivers are memcached, redis or null
# Null cache driver means no caching
driver = "redis"
@ -20,5 +20,3 @@ host = "127.0.0.1"
# Database number
database = 2
[options]

View File

@ -3,13 +3,37 @@
################################################################################
# Username for anime and manga lists
kitsu_username = "timw4mail"
kitsu_username = "johnsmith"
# Whose list is it?
whose_list = "Tim"
whose_list = "Someone"
# do you wish to show the anime collection?
show_anime_collection = true
# path to public directory on the server
asset_dir = "/../../public"
# do you wish to show the manga collection?
show_manga_collection = false
# what theme would you like to use? light, dark, or auto
theme = "auto"
################################################################################
# Default views and paths
################################################################################
# Which list should be the default?
default_list = "anime" # anime or manga
# Default pages for anime/manga
default_anime_list_path = "watching" # watching|plan_to_watch|on_hold|dropped|completed|all
default_manga_list_path = "reading" # reading|plan_to_read|on_hold|dropped|completed|all
################################################################################
# Not on Settings Page
#
# These settings are not available to change on the settings page
################################################################################
# Use HTTPs for URLs
# It is not recommended to change this setting
secure_urls = true

View File

@ -2,11 +2,10 @@
# Database Configuration #
################################################################################
[collection]
type = "sqlite"
host = ""
user = ""
pass = ""
port = ""
database = ""
file = "anime_collection.sqlite"
file = "anime_collection.sqlite3"

View File

@ -1,19 +0,0 @@
################################################################################
# Route config
#
# Default views and paths
################################################################################
# Path to public directory, where images/css/javascript are located,
# appended to the url
asset_path = "/public"
# Which list should be the default?
default_list = "anime" # anime or manga
# Default pages for anime/manga
default_anime_list_path = "watching" # watching|plan_to_watch|on_hold|dropped|completed|all
default_manga_list_path = "reading" # reading|plan_to_read|on_hold|dropped|completed|all
# Default view type (cover_view/list_view)
default_view_type = "cover_view"

0
app/logs/.gitkeep Normal file → Executable file
View File

View File

@ -0,0 +1,100 @@
<article
class="media"
data-kitsu-id="<?= $item['id'] ?>"
data-anilist-id="<?= $item['anilist_id'] ?>"
data-mal-id="<?= $item['mal_id'] ?>"
>
<?php if ($_->isAuthenticated()): ?>
<button title="Increment episode count" class="plus-one" hidden>+1 Episode</button>
<?php endif ?>
<?= $_->h->img($item['anime']['cover_image'], ['width' => 220, 'loading' => 'lazy']) ?>
<div class="name">
<a href="<?= $_->urlFromRoute('anime.details', ['id' => $item['anime']['slug']]) ?>">
<span class="canonical"><?= $item['anime']['title'] ?></span>
<?php foreach ($item['anime']['titles'] as $title): ?>
<br/>
<small><?= $title ?></small>
<?php endforeach ?>
</a>
</div>
<div class="table">
<?php if (isset($item['private']) || isset($item['rewatching'])): ?>
<div class="row">
<?php foreach (['private', 'rewatching'] as $attr): ?>
<?php if ($item[$attr]): ?>
<span class="item-<?= $attr ?>"><?= ucfirst($attr) ?></span>
<?php endif ?>
<?php endforeach ?>
</div>
<?php endif ?>
<?php if ($item['rewatched'] > 0): ?>
<div class="row">
<?php if ($item['rewatched'] == 1): ?>
<div>Rewatched once</div>
<?php elseif ($item['rewatched'] == 2): ?>
<div>Rewatched twice</div>
<?php elseif ($item['rewatched'] == 3): ?>
<div>Rewatched thrice</div>
<?php else: ?>
<div>Rewatched <?= $item['rewatched'] ?> times</div>
<?php endif ?>
</div>
<?php endif ?>
<?php if (count($item['anime']['streaming_links']) > 0): ?>
<div class="row">
<?php foreach ($item['anime']['streaming_links'] as $link): ?>
<div class="cover-streaming-link">
<?php if ($link['meta']['link']): ?>
<a href="<?= $link['link'] ?>"
title="Stream '<?= $item['anime']['title'] ?>' on <?= $link['meta']['name'] ?>">
<?= $_->h->img("/public/images/{$link['meta']['image']}", [
'class' => 'streaming-logo',
'width' => 20,
'height' => 20,
'alt' => "{$link['meta']['name']} logo",
]); ?>
</a>
<?php else: ?>
<?= $_->h->img("/public/images/{$link['meta']['image']}", [
'class' => 'streaming-logo',
'width' => 20,
'height' => 20,
'alt' => "{$link['meta']['name']} logo",
]); ?>
<?php endif ?>
</div>
<?php endforeach ?>
</div>
<?php endif ?>
<?php if ($_->isAuthenticated()): ?>
<div class="row">
<span class="edit">
<a class="bracketed" title="Edit information about this anime" href="<?=
$_->urlFromRoute('edit', [
'controller' => 'anime',
'id' => $item['id'],
'status' => $item['watching_status']
]);
?>">Edit</a>
</span>
</div>
<?php endif ?>
<div class="row">
<div class="user-rating">Rating: <?= $item['user_rating'] ?> / 10</div>
<div class="completion">Episodes:
<span class="completed_number"><?= $item['episodes']['watched'] ?></span> /
<span class="total_number"><?= $item['episodes']['total'] ?></span>
</div>
</div>
<div class="row">
<div class="media_type"><?= $_->escape->html($item['anime']['show_type']) ?></div>
<div class="airing-status"><?= $_->escape->html($item['airing']['status']) ?></div>
<div class="age-rating"><?= $_->escape->html($item['anime']['age_rating']) ?></div>
</div>
</div>
</article>

View File

@ -0,0 +1,6 @@
<article class="<?= $className ?>">
<div class="name">
<a href="<?= $link ?>"><?= $name ?></a>
</div>
<a href="<?= $link ?>"><?= $picture ?></a>
</article>

View File

@ -0,0 +1,68 @@
<article class="media" data-kitsu-id="<?= $item['id'] ?>" data-mal-id="<?= $item['mal_id'] ?>">
<?php if ($_->isAuthenticated()): ?>
<div class="edit-buttons" hidden>
<button class="plus-one-chapter">+1 Chapter</button>
</div>
<?php endif ?>
<?= $_->h->img($item['manga']['image'], ['width' => 220, 'loading' => 'lazy']) ?>
<div class="name">
<a href="<?= $_->urlFromRoute('manga.details', ['id' => $item['manga']['slug']]) ?>">
<?= $_->escape->html($item['manga']['title']) ?>
<?php foreach($item['manga']['titles'] as $title): ?>
<br /><small><?= $title ?></small>
<?php endforeach ?>
</a>
</div>
<div class="table">
<?php if ($_->isAuthenticated()): ?>
<div class="row">
<span class="edit">
<a class="bracketed"
title="Edit information about this manga"
href="<?= $_->urlFromRoute('edit', [
'controller' => 'manga',
'id' => $item['id'],
'status' => $name
]) ?>">
Edit
</a>
</span>
</div>
<?php endif ?>
<div class="row">
<div><?= $item['manga']['type'] ?></div>
<div class="user-rating">Rating: <?= $item['user_rating'] ?> / 10</div>
</div>
<?php if ($item['rereading']): ?>
<div class="row">
<?php foreach(['rereading'] as $attr): ?>
<?php if($item[$attr]): ?>
<span class="item-<?= $attr ?>"><?= ucfirst($attr) ?></span>
<?php endif ?>
<?php endforeach ?>
</div>
<?php endif ?>
<?php if ($item['reread'] > 0): ?>
<div class="row">
<?php if ($item['reread'] == 1): ?>
<div>Reread once</div>
<?php elseif ($item['reread'] == 2): ?>
<div>Reread twice</div>
<?php elseif ($item['reread'] == 3): ?>
<div>Reread thrice</div>
<?php else: ?>
<div>Reread <?= $item['reread'] ?> times</div>
<?php endif ?>
</div>
<?php endif ?>
<div class="row">
<div class="chapter_completion">
Chapters: <span class="chapters_read"><?= $item['chapters']['read'] ?></span> /
<span class="chapter_count"><?= $item['chapters']['total'] ?></span>
</div>
</div>
</div>
</article>

12
app/templates/media.php Normal file
View File

@ -0,0 +1,12 @@
<article class="<?= $className ?>">
<a href="<?= $link ?>"><?= $picture ?></a>
<div class="name">
<a href="<?= $link ?>">
<?= array_shift($titles) ?>
<?php foreach ($titles as $title): ?>
<br />
<small><?= $title ?></small>
<?php endforeach ?>
</a>
</div>
</article>

View File

@ -0,0 +1,5 @@
<section class="<?= $className ?>">
<?php foreach ($data as $tabName => $tabData): ?>
<?= $callback($tabData, $tabName) ?>
<?php endforeach ?>
</section>

32
app/templates/tabs.php Normal file
View File

@ -0,0 +1,32 @@
<div class="tabs">
<?php $i = 0; foreach ($data as $tabName => $tabData): ?>
<?php if ( ! empty($tabData)): ?>
<?php $id = "{$name}-{$i}"; ?>
<input
role='tab'
aria-controls="_<?= $id ?>"
type="radio"
name="<?= $name ?>"
id="<?= $id ?>"
<?= ($i === 0) ? 'checked="checked"' : '' ?>
/>
<label for="<?= $id ?>"><?= ucfirst($tabName) ?></label>
<?php if ($hasSectionWrapper): ?>
<div class="content full-height">
<?php endif ?>
<section
id="_<?= $id ?>"
role="tabpanel"
class="<?= $className ?>"
>
<?= $callback($tabData, $tabName) ?>
</section>
<?php if ($hasSectionWrapper): ?>
</div>
<?php endif ?>
<?php endif ?>
<?php $i++; endforeach ?>
</div>

View File

@ -0,0 +1,25 @@
<div class="vertical-tabs">
<?php $i = 0; ?>
<?php foreach ($data as $tabName => $tabData): ?>
<?php $id = "{$name}-{$i}" ?>
<div class="tab">
<input
type="radio"
role='tab'
aria-controls="_<?= $id ?>"
name="<?= $name ?>"
id="<?= $id ?>"
<?= $i === 0 ? 'checked="checked"' : '' ?>
/>
<label for="<?= $id ?>"><?= $tabName ?></label>
<section
id='_<?= $id ?>'
role="tabpanel"
class="<?= $className ?>"
>
<?= $callback($tabData, $tabName) ?>
</section>
</div>
<?php $i++; ?>
<?php endforeach ?>
</div>

View File

@ -1,4 +1,6 @@
<main>
<h1>404</h1>
<h2><?= $message ?></h2>
<pre>(╯°□°)╯︵ ┻━┻
┬─┬ノ( º _ ºノ)</pre>
</main>

View File

@ -1,7 +1,8 @@
<?php if ($auth->isAuthenticated()): ?>
<?php if ($_->isAuthenticated()): ?>
<main>
<h2>Add Anime to your List</h2>
<form action="<?= $action_url ?>" method="post">
<?php include realpath(__DIR__ . '/../js-warning.php') ?>
<section>
<div class="cssload-loader" hidden="hidden">
<div class="cssload-inner cssload-one"></div>
@ -9,7 +10,7 @@
<div class="cssload-inner cssload-three"></div>
</div>
<label for="search">Search for anime by name:&nbsp;&nbsp;&nbsp;&nbsp;<input type="search" id="search" /></label>
<section id="series_list" class="media-wrap">
<section id="series-list" class="media-wrap">
</section>
</section>
<br />
@ -36,5 +37,4 @@
</table>
</form>
</main>
<script defer="defer" src="<?= $urlGenerator->assetUrl('js.php/g/anime_collection') ?>"></script>
<?php endif ?>

View File

@ -1,96 +1,26 @@
<main class="media-list">
<?php if ($auth->isAuthenticated()): ?>
<a class="bracketed" href="<?= $url->generate('anime.add.get') ?>">Add Item</a>
<?php if ($_->isAuthenticated()): ?>
<a class="bracketed" href="<?= $_->urlFromRoute('anime.add.get') ?>">Add Item</a>
<?php endif ?>
<?php if (empty($sections)): ?>
<h3>There's nothing here!</h3>
<?php else: ?>
<br />
<label>Filter: <input type='text' class='media-filter' /></label>
<br />
<?php foreach ($sections as $name => $items): ?>
<?php if (empty($items)): ?>
<section class="status">
<h2><?= $escape->html($name) ?></h2>
<h2><?= $_->escape->html($name) ?></h2>
<h3>There's nothing here!</h3>
</section>
<?php else: ?>
<section class="status">
<h2><?= $escape->html($name) ?></h2>
<h2><?= $_->escape->html($name) ?></h2>
<section class="media-wrap">
<?php foreach($items as $item): ?>
<?php if ($item['private'] && ! $auth->isAuthenticated()) continue; ?>
<article class="media" data-kitsu-id="<?= $item['id'] ?>" data-mal-id="<?= $item['mal_id'] ?>">
<?php if ($auth->isAuthenticated()): ?>
<button title="Increment episode count" class="plus_one" hidden>+1 Episode</button>
<?php endif ?>
<img src="<?= $urlGenerator->assetUrl("images/anime/{$item['anime']['id']}.jpg") ?>" alt="" />
<div class="name">
<a href="<?= $url->generate('anime.details', ['id' => $item['anime']['slug']]); ?>">
<span class="canonical"><?= $item['anime']['title'] ?></span>
<?php foreach ($item['anime']['titles'] as $title): ?>
<br /><small><?= $title ?></small>
<?php endforeach ?>
</a>
</div>
<div class="table">
<?php if ($item['private'] || $item['rewatching']): ?>
<div class="row">
<?php foreach(['private', 'rewatching'] as $attr): ?>
<?php if($item[$attr]): ?>
<span class="item-<?= $attr ?>"><?= ucfirst($attr) ?></span>
<?php endif ?>
<?php endforeach ?>
</div>
<?php endif ?>
<?php if ($item['rewatched'] > 0): ?>
<div class="row">
<div>Rewatched <?= $item['rewatched'] ?> time(s)</div>
</div>
<?php endif ?>
<?php if (count($item['anime']['streaming_links']) > 0): ?>
<div class="row">
<?php foreach($item['anime']['streaming_links'] as $link): ?>
<div class="cover_streaming_link">
<?php if($link['meta']['link']): ?>
<a href="<?= $link['link']?>" title="Stream '<?= $item['anime']['title'] ?>' on <?= $link['meta']['name'] ?>">
<img class="streaming-logo" width="20" height="20" src="<?= $urlGenerator->assetUrl('images', $link['meta']['image']) ?>" alt="<?= $link['meta']['name'] ?> logo" />
</a>
<?php else: ?>
<img class="streaming-logo" width="20" height="20" src="<?= $urlGenerator->assetUrl('images', $link['meta']['image']) ?>" alt="<?= $link['meta']['name'] ?> logo" />
<?php endif ?>
</div>
<?php endforeach ?>
</div>
<?php endif ?>
<?php if ($auth->isAuthenticated()): ?>
<div class="row">
<span class="edit">
<a class="bracketed" title="Edit information about this anime" href="<?=
$url->generate('edit', [
'controller' => 'anime',
'id' => $item['id'],
'status' => $item['watching_status']
]);
?>">Edit</a>
</span>
</div>
<?php endif ?>
<div class="row">
<div class="user_rating">Rating: <?= $item['user_rating'] ?> / 10</div>
<div class="completion">Episodes:
<span class="completed_number"><?= $item['episodes']['watched'] ?></span> /
<span class="total_number"><?= $item['episodes']['total'] ?></span>
</div>
</div>
<div class="row">
<div class="media_type"><?= $escape->html($item['anime']['show_type']) ?></div>
<div class="airing_status"><?= $escape->html($item['airing']['status']) ?></div>
<div class="age_rating"><?= $escape->html($item['anime']['age_rating']) ?></div>
</div>
</div>
</article>
<?php if ($item['private'] && ! $_->isAuthenticated()) continue; ?>
<?= $_->component->animeCover($item) ?>
<?php endforeach ?>
</section>
</section>
@ -98,6 +28,3 @@
<?php endforeach ?>
<?php endif ?>
</main>
<?php if ($auth->isAuthenticated()): ?>
<script defer="defer" src="<?= $urlGenerator->assetUrl('js.php/g/edit') ?>"></script>
<?php endif ?>

View File

@ -1,108 +1,205 @@
<?php
use function Aviat\AnimeClient\friendlyTime;
?>
<main class="details fixed">
<section class="flex flex-no-wrap">
<div>
<img class="cover" width="402" height="284" src="<?= $urlGenerator->assetUrl("images/anime/{$show_data['id']}.jpg") ?>" alt="" />
<section class="flex">
<aside class="info">
<?= $_->h->img($data['cover_image'], ['width' => '390']) ?>
<br />
<br />
<table class="media_details">
<table class="media-details">
<tr>
<td class="align_right">Airing Status</td>
<td><?= $show_data['status'] ?></td>
<td class="align-right">Airing Status</td>
<td><?= $data['status'] ?></td>
</tr>
<?php if ( ! empty($data['airDate'])): ?>
<tr>
<td>Original Airing</td>
<td><?= $data['airDate'] ?></td>
</tr>
<?php endif ?>
<tr>
<td>Show Type</td>
<td><?= $show_data['show_type'] ?></td>
</tr>
<tr>
<td>Episode Count</td>
<td><?= $show_data['episode_count'] ?? '-' ?></td>
</tr>
<?php if ( ! empty($show_data['episode_length'])): ?>
<tr>
<td>Episode Length</td>
<td><?= $show_data['episode_length'] ?> minutes</td>
<td><?= (strlen($data['show_type']) > 3) ? ucfirst(strtolower($data['show_type'])) : $data['show_type'] ?></td>
</tr>
<?php if ($data['episode_count'] !== 1): ?>
<tr>
<td>Episode Count</td>
<td><?= $data['episode_count'] ?? '-' ?></td>
</tr>
<?php endif ?>
<?php if ( ! empty($show_data['age_rating'])): ?>
<tr>
<td>Age Rating</td>
<td><abbr title="<?= $show_data['age_rating_guide'] ?>"><?= $show_data['age_rating'] ?></abbr></td>
</tr>
<?php if (( ! empty($data['episode_length'])) && $data['episode_count'] !== 1): ?>
<tr>
<td>Episode Length</td>
<td><?= friendlyTime($data['episode_length']) ?></td>
</tr>
<?php endif ?>
<?php if (isset($data['total_length'], $data['episode_count']) && $data['total_length'] > 0): ?>
<tr>
<td>Total Length</td>
<td><?= friendlyTime($data['total_length']) ?></td>
</tr>
<?php endif ?>
<?php if ( ! empty($data['age_rating'])): ?>
<tr>
<td>Age Rating</td>
<td><abbr title="<?= $data['age_rating_guide'] ?>"><?= $data['age_rating'] ?></abbr>
</td>
</tr>
<?php endif ?>
<?php if (count($data['links']) > 0): ?>
<tr>
<td>External Links</td>
<td>
<?php foreach ($data['links'] as $urlName => $externalUrl): ?>
<a rel='external' href="<?= $externalUrl ?>"><?= $urlName ?></a><br />
<?php endforeach ?>
</td>
</tr>
<?php endif ?>
<tr>
<td>Genres</td>
<td>
<?= implode(', ', $show_data['genres']) ?>
<?= implode(', ', $data['genres']) ?>
</td>
</tr>
</table>
</div>
<div>
<h2><a rel="external" href="<?= $show_data['url'] ?>"><?= $show_data['title'] ?></a></h2>
<?php foreach ($show_data['titles'] as $title): ?>
<h3><?= $title ?></h3>
<?php endforeach ?>
<br />
<p><?= nl2br($show_data['synopsis']) ?></p>
<?php if (count($show_data['streaming_links']) > 0): ?>
<hr />
<h4>Streaming on:</h4>
<table class="full_width invisible">
<thead>
</aside>
<article class="text">
<h2 class="toph"><?= $data['title'] ?></h2>
<?php foreach ($data['titles_more'] as $title): ?>
<h3><?= $title ?></h3>
<?php endforeach ?>
<br />
<div class="description">
<p><?= str_replace("\n", '</p><p>', $data['synopsis']) ?></p>
</div>
<?php if (count($data['streaming_links']) > 0): ?>
<hr />
<h4>Streaming on:</h4>
<table class="full-width invisible streaming-links">
<thead>
<tr>
<th class="align_left">Service</th>
<th class="align-left">Service</th>
<th>Subtitles</th>
<th>Dubs</th>
</tr>
</thead>
<tbody>
<?php foreach($show_data['streaming_links'] as $link): ?>
<tr>
<td class="align_left">
<?php if ($link['meta']['link'] !== FALSE): ?>
<a href="<?= $link['link'] ?>" title="Stream '<?= $show_data['title'] ?>' on <?= $link['meta']['name'] ?>">
<img class="streaming-logo" width="50" height="50" src="<?= $urlGenerator->assetUrl('images', $link['meta']['image']) ?>" alt="<?= $link['meta']['name'] ?> logo" />
&nbsp;&nbsp;<?= $link['meta']['name'] ?>
</a>
<?php else: ?>
<img class="streaming-logo" width="50" height="50" src="<?= $urlGenerator->assetUrl('images', $link['meta']['image']) ?>" alt="<?= $link['meta']['name'] ?> logo" />
&nbsp;&nbsp;<?= $link['meta']['name'] ?>
<?php endif ?>
</td>
<td><?= implode(', ', $link['subs']) ?></td>
<td><?= implode(', ', $link['dubs']) ?></td>
</tr>
<?php endforeach ?>
</tbody>
</table>
</thead>
<tbody>
<?php foreach ($data['streaming_links'] as $link): ?>
<tr>
<td class="align-left">
<?php if ($link['meta']['link'] !== FALSE): ?>
<a
href="<?= $link['link'] ?>"
title="Stream '<?= $data['title'] ?>' on <?= $link['meta']['name'] ?>"
>
<?= $_->h->img("/public/images/{$link['meta']['image']}", [
'class' => 'streaming-logo',
'width' => 50,
'height' => 50,
'alt' => "{$link['meta']['name']} logo",
]) ?>
&nbsp;&nbsp;<?= $link['meta']['name'] ?>
</a>
<?php else: ?>
<?= $_->h->img("/public/images/{$link['meta']['image']}", [
'class' => 'streaming-logo',
'width' => 50,
'height' => 50,
'alt' => "{$link['meta']['name']} logo",
]) ?>
&nbsp;&nbsp;<?= $link['meta']['name'] ?>
<?php endif ?>
</td>
<td><?= implode(', ', array_map(fn ($sub) => Locale::getDisplayLanguage($sub, 'en'), $link['subs'])) ?></td>
<td><?= implode(', ', array_map(fn ($dub) => Locale::getDisplayLanguage($dub, 'en'), $link['dubs'])) ?></td>
</tr>
<?php endforeach ?>
</tbody>
</table>
<?php endif ?>
<?php if ( ! empty($show_data['trailer_id'])): ?>
<hr />
<h4>Trailer</h4>
<iframe width="560" height="315" src="https://www.youtube.com/embed/<?= $show_data['trailer_id'] ?>" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
<?php if ( ! empty($data['trailer_id'])): ?>
<div class="responsive-iframe">
<h4>Trailer</h4>
<iframe
width="560"
height="315"
role='img'
src="https://www.youtube.com/embed/<?= $data['trailer_id'] ?>"
allow="autoplay; encrypted-media"
allowfullscreen
tabindex='0'
title="<?= $data['title'] ?> trailer video"
></iframe>
</div>
<?php endif ?>
</div>
</article>
</section>
<?php if (count($characters) > 0): ?>
<hr />
<h2>Characters</h2>
<section class="align_center media-wrap">
<?php foreach($characters as $id => $char): ?>
<?php if ( ! empty($char['image']['original'])): ?>
<article class="character">
<?php $link = $url->generate('character', ['slug' => $char['slug']]) ?>
<div class="name">
<?= $helper->a($link, $char['name']); ?>
</div>
<a href="<?= $link ?>">
<?= $helper->img($urlGenerator->assetUrl("images/characters/{$id}.jpg"), [
'width' => '225'
]) ?>
</a>
</article>
<?php endif ?>
<?php endforeach ?>
</section>
<?php if (count($data['characters']) > 0): ?>
<section>
<h2>Characters</h2>
<?= $_->component->tabs('character-types', $data['characters'], static function ($characterList, $role)
use ($_) {
$rendered = [];
foreach ($characterList as $id => $character):
if (empty($character['image']))
{
continue;
}
$rendered[] = $_->component->character(
$character['name'],
$_->urlFromRoute('character', ['slug' => $character['slug']]),
$_->h->img($character['image']),
(strtolower($role) !== 'main') ? 'small-character' : 'character'
);
endforeach;
return implode('', array_map('mb_trim', $rendered));
}) ?>
</section>
<?php endif ?>
<?php if (count($data['staff']) > 0): ?>
<section>
<h2>Staff</h2>
<?= $_->component->verticalTabs('staff-role', $data['staff'], static function ($staffList)
use ($_) {
$rendered = [];
foreach ($staffList as $id => $person):
if (empty($person['image']))
{
continue;
}
$rendered[] = $_ ->component->character(
$person['name'],
$_->urlFromRoute('person', ['slug' => $person['slug']]),
$_->h->img($person['image']),
'character small-person',
);
endforeach;
return implode('', array_map('mb_trim', $rendered));
}) ?>
</section>
<?php endif ?>
</main>

View File

@ -1,4 +1,4 @@
<?php if ($auth->isAuthenticated()): ?>
<?php if ($_->isAuthenticated()): ?>
<main>
<h2>Edit Anime List Item</h2>
<form action="<?= $action ?>" method="post">
@ -6,9 +6,9 @@
<thead>
<tr>
<th>
<h3><?= $escape->html($item['anime']['title']) ?></h3>
<h3><?= $_->escape->html($item['anime']['title']) ?></h3>
<?php foreach($item['anime']['titles'] as $title): ?>
<h4><?= $escape->html($title) ?></h4>
<h4><?= $_->escape->html($title) ?></h4>
<?php endforeach ?>
</th>
</tr>
@ -16,9 +16,7 @@
<tbody>
<tr>
<td rowspan="9">
<article class="media">
<?= $helper->img($urlGenerator->assetUrl('images/anime', "{$item['anime']['id']}.jpg")) ?>
</article>
<?= $_->h->img($item['anime']['cover_image']) ?>
</td>
</tr>
<tr>
@ -34,7 +32,7 @@
<td>
<select name="watching_status" id="watching_status">
<?php foreach($statuses as $status_key => $status_title): ?>
<option <?php if($item['watching_status'] === $status_key): ?>selected="selected"<?php endif ?>
<option <?php if(strtolower($item['watching_status']) === $status_key): ?>selected="selected"<?php endif ?>
value="<?= $status_key ?>"><?= $status_title ?></option>
<?php endforeach ?>
</select>
@ -72,14 +70,16 @@
<tr>
<td><label for="notes">Notes</label></td>
<td>
<textarea name="notes" id="notes"><?= $escape->html($item['notes']) ?></textarea>
<textarea name="notes" id="notes"><?= $_->escape->html($item['notes']) ?></textarea>
</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>
<input type="hidden" value="<?= $item['id'] ?>" name="id" />
<input type="hidden" value="<?= $item['mal_id'] ?>" name="mal_id" />
<?php if ( ! empty($item['mal_id'])): ?>
<input type="hidden" value="<?= $item['mal_id'] ?? '' ?>" name="mal_id" />
<?php endif ?>
<input type="hidden" value="true" name="edit" />
<button type="submit">Submit</button>
</td>
@ -87,27 +87,26 @@
</tbody>
</table>
</form>
<br />
<br />
<fieldset>
<legend>Danger Zone</legend>
<form class="js-delete" action="<?= $url->generate('anime.delete') ?>" method="post">
<form class="js-delete" action="<?= $_->urlFromRoute('anime.delete') ?>" method="post">
<fieldset>
<legend>Danger Zone</legend>
<table class="form invisible">
<tbody>
<tr>
<td>
<td class="danger">
<strong>Permanently</strong> remove this list item and <strong>all</strong> its data?
</td>
<td>
<input type="hidden" value="<?= $item['id'] ?>" name="id" />
<input type="hidden" value="<?= $item['mal_id'] ?>" name="mal_id" />
<?php if (!empty($item['mal_id'])): ?>
<input type="hidden" value="<?= $item['mal_id'] ?? '' ?>" name="mal_id" />
<?php endif ?>
<button type="submit" class="danger">Delete Entry</button>
</td>
</tr>
</tbody>
</table>
</form>
</fieldset>
</fieldset>
</form>
</main>
<script defer="defer" src="<?= $urlGenerator->assetUrl('js.php/g/edit') ?>"></script>
<?php endif ?>

View File

@ -1,52 +1,57 @@
<?php use function Aviat\AnimeClient\colNotEmpty; ?>
<main class="media-list">
<?php if ($auth->isAuthenticated()): ?>
<a class="bracketed" href="<?= $url->generate('anime.add.get') ?>">Add Item</a>
<?php if ($_->isAuthenticated()): ?>
<a class="bracketed" href="<?= $_->urlFromRoute('anime.add.get') ?>">Add Item</a>
<?php endif ?>
<?php if (empty($sections)): ?>
<h3>There's nothing here!</h3>
<?php else: ?>
<br />
<label>Filter: <input type='text' class='media-filter' /></label>
<br />
<?php foreach ($sections as $name => $items): ?>
<h2><?= $name ?></h2>
<?php if (empty($items)): ?>
<h3>There's nothing here!</h3>
<?php else: ?>
<table>
<?php
$hasNotes = colNotEmpty($items, 'notes');
?>
<table class='media-wrap'>
<thead>
<tr>
<?php if($auth->isAuthenticated()): ?>
<td class="no_border">&nbsp;</td>
<?php if($_->isAuthenticated()): ?>
<td class="no-border">&nbsp;</td>
<?php endif ?>
<th>Title</th>
<th>Airing Status</th>
<th>Score</th>
<th class='numeric'>Score</th>
<th>Type</th>
<th>Progress</th>
<th>Rated</th>
<th colspan="2">Attributes</th>
<th>Notes</th>
<th>Genres</th>
<th class='numeric'>Progress</th>
<th class='rating'>Age Rating</th>
<th>Attributes</th>
<?php if($hasNotes): ?><th>Notes</th><?php endif ?>
</tr>
</thead>
<tbody>
<?php foreach($items as $item): ?>
<?php if ($item['private'] && ! $auth->isAuthenticated()) continue; ?>
<?php if ($item['private'] && ! $_->isAuthenticated()) continue; ?>
<tr id="a-<?= $item['id'] ?>">
<?php if ($auth->isAuthenticated()): ?>
<?php if ($_->isAuthenticated()): ?>
<td>
<a class="bracketed" href="<?= $url->generate('edit', [
<a class="bracketed" href="<?= $_->urlFromRoute('edit', [
'controller' => 'anime',
'id' => $item['id'],
'status' => $item['watching_status']
]) ?>">Edit</a>
</td>
<?php endif ?>
<td class="justify">
<a href="<?= $url->generate('anime.details', ['id' => $item['anime']['slug']]) ?>">
<td class="align-left justify">
<a href="<?= $_->urlFromRoute('anime.details', ['id' => $item['anime']['slug']]) ?>">
<?= $item['anime']['title'] ?>
</a>
<?php foreach ($item['anime']['titles'] as $title): ?>
<br/><?= $title ?>
<?php endforeach ?>
<br />
<?= implode('<br />', $item['anime']['titles']) ?>
</td>
<td><?= $item['airing']['status'] ?></td>
<td><?= $item['user_rating'] ?> / 10 </td>
@ -57,35 +62,46 @@
</td>
<td><?= $item['anime']['age_rating'] ?></td>
<td>
<ul>
<?php if ($item['rewatched'] > 0): ?>
<li>Rewatched <?= $item['rewatched'] ?> time(s)</li>
<?php endif ?>
<?php foreach(['private','rewatching'] as $attr): ?>
<?php if($item[$attr]): ?>
<li><?= ucfirst($attr); ?></li>
<?php endif ?>
<?php endforeach ?>
</ul>
</td>
<td>
<?php foreach($item['anime']['streaming_links'] as $link): ?>
<?php if ($link['meta']['link'] !== FALSE): ?>
<a href="<?= $link['link'] ?>" title="Stream '<?= $item['anime']['title'] ?>' on <?= $link['meta']['name'] ?>">
<img class="streaming-logo" width="50" height="50" src="<?= $urlGenerator->assetUrl('images', $link['meta']['image']) ?>" alt="<?= $link['meta']['name'] ?> logo" />
<?= $_->h->img("/public/images/{$link['meta']['image']}", [
'class' => 'small-streaming-logo',
'width' => 25,
'height' => 25,
'alt' => "{$link['meta']['name']} logo",
]) ?>
</a>
<?php else: ?>
<img class="streaming-logo" width="50" height="50" src="<?= $urlGenerator->assetUrl('images', $link['meta']['image']) ?>" alt="<?= $link['meta']['name'] ?> logo" />
<?= $_->h->img("/public/images/{$link['meta']['image']}", [
'class' => 'small-streaming-logo',
'width' => 25,
'height' => 25,
'alt' => "{$link['meta']['name']} logo",
]) ?>
<?php endif ?>
<?php endforeach ?>
<br />
<ul>
<?php if ($item['rewatched'] > 0): ?>
<?php if ($item['rewatched'] == 1): ?>
<li>Rewatched once</li>
<?php elseif ($item['rewatched'] == 2): ?>
<li>Rewatched twice</li>
<?php elseif ($item['rewatched'] == 3): ?>
<li>Rewatched thrice</li>
<?php else: ?>
<li>Rewatched <?= $item['rewatched'] ?> times</li>
<?php endif ?>
<?php endif ?>
<?php foreach(['private','rewatching'] as $attr): ?>
<?php if($item[$attr]): ?><li><?= ucfirst($attr); ?></li><?php endif ?>
<?php endforeach ?>
</ul>
</td>
<td>
<p><?= $escape->html($item['notes']) ?></p>
</td>
<td class="align_left">
<?php sort($item['anime']->genres) ?>
<?= implode(', ', $item['anime']->genres) ?>
</td>
<?php if ($hasNotes): ?><td><p><?= $_->escape->html($item['notes']) ?></p></td><?php endif ?>
</tr>
<?php endforeach ?>
</tbody>
@ -94,5 +110,4 @@
<?php endforeach ?>
<?php endif ?>
</main>
<?php $group = ($auth->isAuthenticated()) ? 'table_edit' : 'table' ?>
<script defer="defer" src="<?= $urlGenerator->assetUrl("js.php/g/{$group}") ?>"></script>
<script defer="defer" src="<?= $_->assetUrl('js/tables.min.js') ?>"></script>

View File

@ -1,128 +0,0 @@
<?php use Aviat\AnimeClient\API\Kitsu; ?>
<main class="details fixed">
<section class="flex flex-no-wrap">
<div>
<img class="cover" width="284" src="<?= $urlGenerator->assetUrl("images/characters/{$data[0]['id']}.jpg") ?>" alt="" />
</div>
<div>
<h2><?= $data[0]['attributes']['name'] ?></h2>
<p class="description"><?= $data[0]['attributes']['description'] ?></p>
</div>
</section>
<?php if (array_key_exists('anime', $data['included']) || array_key_exists('manga', $data['included'])): ?>
<h3>Media</h3>
<section class="flex flex-no-wrap">
<?php if (array_key_exists('anime', $data['included'])): ?>
<div>
<h4>Anime</h4>
<section class="align_left media-wrap">
<?php foreach($data['included']['anime'] as $id => $anime): ?>
<article class="media">
<?php
$link = $url->generate('anime.details', ['id' => $anime['attributes']['slug']]);
$titles = Kitsu::filterTitles($anime['attributes']);
?>
<a href="<?= $link ?>">
<img src="<?= $urlGenerator->assetUrl("images/anime/{$id}.jpg") ?>" width="220" alt="" />
</a>
<div class="name">
<a href="<?= $link ?>">
<?= array_shift($titles) ?>
<?php foreach ($titles as $title): ?>
<br /><small><?= $title ?></small>
<?php endforeach ?>
</a>
</div>
</article>
<?php endforeach ?>
</section>
</div>
<?php endif ?>
</section>
<section class="flex flex-no-wrap">
<?php if (array_key_exists('manga', $data['included'])): ?>
<div>
<h4>Manga</h4>
<section class="align_left media-wrap">
<?php foreach($data['included']['manga'] as $id => $manga): ?>
<article class="media">
<?php
$link = $url->generate('manga.details', ['id' => $manga['attributes']['slug']]);
$titles = Kitsu::filterTitles($manga['attributes']);
?>
<a href="<?= $link ?>">
<img src="<?= $urlGenerator->assetUrl("images/manga/{$id}.jpg") ?>" width="220" alt="" />
</a>
<div class="name">
<a href="<?= $link ?>">
<?= array_shift($titles) ?>
<?php foreach ($titles as $title): ?>
<br /><small><?= $title ?></small>
<?php endforeach ?>
</a>
</div>
</article>
<?php endforeach ?>
</section>
</div>
<?php endif ?>
</section>
<?php endif ?>
<section>
<?php if ($castCount > 0): ?>
<h3>Castings</h3>
<?php foreach($castings as $role => $entries): ?>
<h4><?= $role ?></h4>
<?php foreach($entries as $language => $casting): ?>
<h5><?= $language ?></h5>
<table class="min-table">
<tr>
<th>Cast Member</th>
<th>Series</th>
</tr>
<?php foreach($casting as $c):?>
<tr>
<td style="width:229px">
<article class="character">
<img src="<?= $c['person']['image'] ?>" alt="" />
<div class="name">
<?= $c['person']['name'] ?>
</div>
</article>
</td>
<td>
<section class="align_left media-wrap">
<?php foreach($c['series'] as $series): ?>
<article class="media">
<?php
$link = $url->generate('anime.details', ['id' => $series['attributes']['slug']]);
$titles = Kitsu::filterTitles($series['attributes']);
?>
<a href="<?= $link ?>">
<img src="<?= $series['attributes']['posterImage']['small'] ?>" width="220" alt="" />
</a>
<div class="name">
<a href="<?= $link ?>">
<?= array_shift($titles) ?>
<?php foreach ($titles as $title): ?>
<br /><small><?= $title ?></small>
<?php endforeach ?>
</a>
</div>
</article>
<?php endforeach ?>
</section>
</td>
</tr>
<?php endforeach; ?>
</table>
<?php endforeach ?>
<?php endforeach ?>
<?php endif ?>
</section>
</main>

View File

@ -0,0 +1,162 @@
<?php
use function Aviat\AnimeClient\getLocalImg;
use Aviat\AnimeClient\Kitsu;
?>
<main class="character-page details fixed">
<section class="flex flex-no-wrap">
<aside>
<?= $_->h->img($data['image']) ?>
</aside>
<div>
<h2 class="toph"><?= $data['name'] ?></h2>
<?php foreach ($data['names'] as $name): ?>
<h3><?= $name ?></h3>
<?php endforeach ?>
<?php if ( ! empty($data['otherNames'])): ?>
<h4>Also Known As:</h4>
<ul>
<?php foreach ($data['otherNames'] as $name): ?>
<li><h5><?= $name ?></h5></li>
<?php endforeach ?>
</ul>
<?php endif ?>
<br />
<hr />
<div class="description">
<p><?= nl2br($data['description']) ?></p>
</div>
</div>
</section>
<?php if ( ! (empty($data['media']['anime']) || empty($data['media']['manga']))): ?>
<h3>Media</h3>
<?= $_->component->tabs('character-media', $data['media'], static function ($media, $mediaType) use ($_) {
$rendered = [];
foreach ($media as $id => $item)
{
$rendered[] = $_->component->media(
array_merge([$item['title']], $item['titles']),
$_->urlFromRoute("{$mediaType}.details", ['id' => $item['slug']]),
$_->h->img(Kitsu::getPosterImage($item), ['width' => 220, 'loading' => 'lazy']),
);
}
return implode('', array_map('mb_trim', $rendered));
}, 'media-wrap content') ?>
<?php endif ?>
<section>
<?php if (count($data['castings']) > 0): ?>
<h3>Castings</h3>
<?php
$vas = $data['castings']['Voice Actor'];
unset($data['castings']['Voice Actor']);
ksort($vas)
?>
<?php foreach ($data['castings'] as $role => $entries): ?>
<h4><?= $role ?></h4>
<?php foreach ($entries as $language => $casting): ?>
<h5><?= $language ?></h5>
<table class="min-table">
<tr>
<th>Cast Member</th>
<th>Series</th>
</tr>
<?php foreach ($casting as $cid => $c): ?>
<tr>
<td>
<article class="character">
<?php
$link = $_->urlFromRoute('person', ['id' => $c['person']['id']]);
?>
<a href="<?= $link ?>">
<?= $_->h->img($c['person']['image']) ?>
<div class="name">
<?= $c['person']['name'] ?>
</div>
</a>
</article>
</td>
<td>
<section class="align-left media-wrap">
<?php foreach ($c['series'] as $series): ?>
<article class="media">
<?php
$link = $_->urlFromRoute('anime.details', ['id' => $series['attributes']['slug']]);
$titles = Kitsu::filterTitles($series['attributes']);
?>
<a href="<?= $link ?>">
<?= $_->h->img(Kitsu::getPosterImage($series['attributes'])) ?>
</a>
<div class="name">
<a href="<?= $link ?>">
<?= array_shift($titles) ?>
<?php foreach ($titles as $title): ?>
<br />
<small><?= $title ?></small>
<?php endforeach ?>
</a>
</div>
</article>
<?php endforeach ?>
</section>
</td>
</tr>
<?php endforeach; ?>
</table>
<?php endforeach ?>
<?php endforeach ?>
<?php if ( ! empty($vas)): ?>
<h4>Voice Actors</h4>
<?= $_->component->tabs('character-vas', $vas, static function ($casting) use ($_) {
$castings = [];
foreach ($casting as $id => $c):
$person = $_->component->character(
$c['person']['name'],
$_->urlFromRoute('person', ['slug' => $c['person']['slug']]),
$_->h->img($c['person']['image']['original']['url']),
);
$medias = array_map(fn ($series) => $_->component->media(
array_merge([$series['title']], $series['titles']),
$_->urlFromRoute('anime.details', ['id' => $series['slug']]),
$_->h->img(Kitsu::getPosterImage($series)),
), $c['series']);
$media = implode('', array_map('mb_trim', $medias));
$castings[] = <<<HTML
<tr>
<td>{$person}</td>
<td width="75%">
<section class="align-left media-wrap-flex">
{$media}
</section>
</td>
</tr>
HTML;
endforeach;
$languages = implode('', array_map('mb_trim', $castings));
return <<<HTML
<table class="borderless max-table">
<thead>
<tr>
<th>Cast Member</th>
<th>Series</th>
</tr>
</thead>
<tbody>{$languages}</tbody>
</table>
HTML;
}, 'content') ?>
<?php endif ?>
<?php endif ?>
</section>
</main>

View File

@ -1,28 +1,25 @@
<?php if ($auth->isAuthenticated()): ?>
<?php if ($_->isAuthenticated()): ?>
<main>
<h2>Add <?= ucfirst($collection_type) ?> to your Collection</h2>
<form action="<?= $action_url ?>" method="post">
<?php include realpath(__DIR__ . '/../js-warning.php') ?>
<section>
<div class="cssload-loader" hidden="hidden">
<div class="cssload-inner cssload-one"></div>
<div class="cssload-inner cssload-two"></div>
<div class="cssload-inner cssload-three"></div>
</div>
<label for="search">Search for <?= $collection_type ?> by name:&nbsp;&nbsp;&nbsp;&nbsp;<input type="search" id="search" name="search" /></label>
<section id="series_list" class="media-wrap">
<label for="search-anime-collection">Search for <?= $collection_type ?> by name:&nbsp;&nbsp;&nbsp;&nbsp;<input type="search" id="search-anime-collection" name="search" /></label>
<section id="series-list" class="media-wrap">
</section>
</section>
<br />
<table class="invisible form">
<tbody>
<tr>
<td><label for="media_id">Media</label></td>
<td>
<select name="media_id" id="media_id">
<?php foreach($media_items as $id => $name): ?>
<option value="<?= $id ?>"><?= $name ?></option>
<?php endforeach ?>
</select>
<td class="align-right"><label for="media_id">Media</label></td>
<td class='align-left'>
<?php include 'media-select-list.php' ?>
</td>
</tr>
<tr>
@ -39,5 +36,4 @@
</table>
</form>
</main>
<script defer="defer" src="<?= $urlGenerator->assetUrl("js.php/g/{$collection_type}_collection") ?>"></script>
<?php endif ?>

View File

@ -1,27 +1,28 @@
<article class="media" id="a-<?= $item['hummingbird_id'] ?>">
<img src="<?= $urlGenerator->assetUrl("images/anime/{$item['hummingbird_id']}.jpg") ?>"
alt="<?= $item['title'] ?> cover image"/>
<?= $_->h->picture("images/anime/{$item['hummingbird_id']}.webp") ?>
<div class="name">
<a href="<?= $url->generate('anime.details', ['id' => $item['slug']]) ?>">
<a href="<?= $_->urlFromRoute('anime.details', ['id' => $item['slug']]) ?>">
<?= $item['title'] ?>
<?= ($item['alternate_title'] != "") ? "<small><br />{$item['alternate_title']}</small>" : ""; ?>
</a>
</div>
<div class="table">
<?php if ($auth->isAuthenticated()): ?>
<?php if ($_->isAuthenticated()): ?>
<div class="row">
<span class="edit">
<a class="bracketed"
href="<?= $url->generate($collection_type . '.collection.edit.get', [
href="<?= $_->urlFromRoute($collection_type . '.collection.edit.get', [
'id' => $item['hummingbird_id']
]) ?>">Edit</a>
</span>
</div>
<?php endif ?>
<div class="row">
<?php if ($item['episode_count'] > 1): ?>
<div class="completion">Episodes: <?= $item['episode_count'] ?></div>
<?php endif ?>
<div class="media_type"><?= $item['show_type'] ?></div>
<div class="age_rating"><?= $item['age_rating'] ?></div>
<div class="age-rating"><?= $item['age_rating'] ?></div>
</div>
</div>
</article>

View File

@ -1,25 +1,26 @@
<?php use function Aviat\AnimeClient\renderTemplate; ?>
<main class="media-list">
<?php if ($auth->isAuthenticated()): ?>
<a class="bracketed" href="<?= $url->generate($collection_type . '.collection.add.get') ?>">Add Item</a>
<?php if ($_->isAuthenticated()): ?>
<a class="bracketed" href="<?= $_->urlFromRoute($collection_type . '.collection.add.get') ?>">Add Item</a>
<?php endif ?>
<?php if (empty($sections)): ?>
<h3>There's nothing here!</h3>
<?php else: ?>
<div class="tabs">
<?php $i = 0; ?>
<?php foreach ($sections as $name => $items): ?>
<input <?= $i === 0 ? 'checked="checked"' : '' ?> type="radio" id="collection-tab-<?= $i ?>" name="collection-tabs" />
<label for="collection-tab-<?= $i ?>"><?= $name ?></label>
<div class="content">
<h2><?= $name ?></h2>
<section class="media-wrap">
<?php foreach ($items as $item): ?>
<?php include __DIR__ . '/cover-item.php'; ?>
<?php endforeach ?>
</section>
</div>
<?php $i++; ?>
<?php endforeach ?>
</div>
<br />
<label>Filter: <input type='text' class='media-filter' /></label>
<br />
<?= $_->component->tabs('collection-tab', $sections, static function ($items) use ($_, $collection_type) {
$rendered = [];
foreach ($items as $item)
{
$rendered[] = renderTemplate(__DIR__ . '/cover-item.php', [
'_' => $_,
'collection_type' => $collection_type,
'item' => $item,
]);
}
return implode('', array_map('mb_trim', $rendered));
}, 'media-wrap', true) ?>
<?php endif ?>
</main>

View File

@ -1,39 +1,36 @@
<?php if ($auth->isAuthenticated()): ?>
<?php use function Aviat\AnimeClient\renderTemplate ?>
<?php if ($_->isAuthenticated()): ?>
<main>
<h2>Edit Anime Collection Item</h2>
<form action="<?= $action_url ?>" method="post">
<table class="invisible form" style="border:0">
<thead>
<tr>
<th>
<h3><?= $escape->html($item['title']) ?></h3>
<?php if($item['alternate_title'] != ""): ?>
<h4><?= $item['alternate_title'] ?></h4>
<?php endif ?>
</th>
</tr>
</thead>
<table class="invisible form">
<tbody>
<tr>
<td rowspan="4" class="align_center">
<article class="media">
<?= $helper->img($urlGenerator->assetUrl("images/anime/{$item['hummingbird_id']}.jpg")); ?>
</article>
<td rowspan="6" class="align-center">
<?= $_->h->picture("images/anime/{$item['hummingbird_id']}-original.webp", "jpg", [], ["width" => "390"]) ?>
</td>
</tr>
<tr>
<td class="align_right"><label for="media_id">Media</label></td>
<td class="align_left">
<select name="media_id" id="media_id">
<?php foreach($media_items as $id => $name): ?>
<option <?= $item['media_id'] == $id ? 'selected="selected"' : '' ?> value="<?= $id ?>"><?= $name ?></option>
<?php endforeach ?>
</select>
<td class="align-right"><label for="title">Title</label></td>
<td class="align-left">
<input type="text" id="title" name="title" value="<?= $item['title'] ?>" />
</td>
</tr>
<tr>
<td class="align-right"><label for="alternate_title">Alternate Title</label></td>
<td class="align-left">
<input type="text" id="alternate_title" name="alternate_title" value="<?= $item['alternate_title'] ?>"/>
</td>
</tr>
<tr>
<td class="align-right"><label for="media_id">Media</label></td>
<td class="align-left">
<?php include 'media-select-list.php' ?>
</td>
</tr>
<tr>
<td><label for="notes">Notes</label></td>
<td><textarea id="notes" name="notes"><?= $escape->html($item['notes']) ?></textarea></td>
<td><textarea id="notes" name="notes"><?= $_->escape->html($item['notes']) ?></textarea></td>
</tr>
<tr>
<td>&nbsp;</td>
@ -47,13 +44,15 @@
</tbody>
</table>
</form>
<fieldset>
<legend>Danger Zone</legend>
<form class="js-delete" action="<?= $url->generate($collection_type . '.collection.delete') ?>" method="post">
<form class="js-delete" action="<?= $_->urlFromRoute($collection_type . '.collection.delete') ?>" method="post">
<fieldset>
<legend>Danger Zone</legend>
<table class="form invisible">
<tbody>
<tr>
<td>&nbsp;</td>
<td class="danger">
<strong>Permanently</strong> remove this list item and <strong>all</strong> its data?
</td>
<td>
<input type="hidden" value="<?= $item['hummingbird_id'] ?>" name="hummingbird_id" />
<button type="submit" class="danger">Delete Entry</button>
@ -61,8 +60,7 @@
</tr>
</tbody>
</table>
</form>
</fieldset>
</fieldset>
</form>
</main>
<script defer="defer" src="<?= $urlGenerator->assetUrl('js.php/g/anime_collection') ?>"></script>
<?php endif ?>

View File

@ -1,19 +1,23 @@
<tr>
<?php if ($auth->isAuthenticated()): ?>
<?php if ($_->isAuthenticated()): ?>
<td>
<a class="bracketed"
href="<?= $url->generate($collection_type . '.collection.edit.get', ['id' => $item['hummingbird_id']]) ?>">Edit</a>
href="<?= $_->urlFromRoute($collection_type . '.collection.edit.get', ['id' => $item['hummingbird_id']]) ?>">Edit</a>
</td>
<?php endif ?>
<td class="align_left">
<a href="<?= $url->generate('anime.details', ['id' => $item['slug']]) ?>">
<td class="align-left">
<a href="<?= $_->urlFromRoute('anime.details', ['id' => $item['slug']]) ?>">
<?= $item['title'] ?>
</a>
<?= (!empty($item['alternate_title'])) ? " <br /><small> " . $item['alternate_title'] . "</small>" : "" ?>
<?= ! empty($item['alternate_title']) ? ' <br /><small> ' . $item['alternate_title'] . '</small>' : '' ?>
</td>
<td><?= $item['episode_count'] ?></td>
<?php if ($hasMedia): ?>
<td><?= implode(', ', $item['media']) ?></td>
<?php endif ?>
<td><?= ($item['episode_count'] > 1) ? $item['episode_count'] : '-' ?></td>
<td><?= $item['episode_length'] ?></td>
<td><?= $item['show_type'] ?></td>
<td><?= $item['age_rating'] ?></td>
<td class="align_left"><?= $item['notes'] ?></td>
<?php if ($hasNotes): ?><td class="align-left"><?= nl2br($item['notes'] ?? '', TRUE) ?></td><?php endif ?>
<td class="align-left"><?= implode(', ', $item['genres']) ?></td>
</tr>

View File

@ -1,42 +1,55 @@
<?php use function Aviat\AnimeClient\{colNotEmpty, renderTemplate}; ?>
<main>
<?php if ($auth->isAuthenticated()): ?>
<a class="bracketed" href="<?= $url->generate($collection_type . '.collection.add.get') ?>">Add Item</a>
<?php if ($_->isAuthenticated()): ?>
<a class="bracketed" href="<?= $_->urlFromRoute($collection_type . '.collection.add.get') ?>">Add Item</a>
<?php endif ?>
<?php if (empty($sections)): ?>
<h3>There's nothing here!</h3>
<?php else: ?>
<?php $i = 0; ?>
<div class="tabs">
<?php foreach ($sections as $name => $items): ?>
<input <?= $i === 0 ? 'checked="checked"' : '' ?> type="radio" id="collection-tab-<?= $i ?>"
name="collection-tabs"/>
<label for="collection-tab-<?= $i ?>"><?= $name ?></label>
<div class="content">
<h2><?= $name ?></h2>
<table>
<thead>
<br />
<label>Filter: <input type='text' class='media-filter' /></label>
<br />
<?= $_->component->tabs('collection-tab', $sections, static function ($items, $section) use ($_, $helper, $collection_type) {
$hasNotes = colNotEmpty($items, 'notes');
$hasMedia = $section === 'All';
$firstTh = ($_->isAuthenticated()) ? '<td>&nbsp;</td>' : '';
$mediaTh = ($hasMedia) ? '<th>Media</th>' : '';
$noteTh = ($hasNotes) ? '<th>Notes</th>' : '';
$rendered = [];
foreach ($items as $item)
{
$rendered[] = renderTemplate(__DIR__ . '/list-item.php', [
'_' => $_,
'collection_type' => $collection_type,
'hasMedia' => $hasMedia,
'hasNotes' => $hasNotes,
'helper' => $helper,
'item' => $item,
]);
}
$rows = implode('', array_map('mb_trim', $rendered));
return <<<HTML
<table class="full-width media-wrap">
<thead>
<tr>
<?php if ($auth->isAuthenticated()): ?>
<td>Actions</td>
<?php endif ?>
{$firstTh}
<th>Title</th>
<th>Episode Count</th>
<th>Episode Length</th>
{$mediaTh}
<th class='numeric'>Episode Count</th>
<th class='numeric'>Episode Length</th>
<th>Show Type</th>
<th>Age Rating</th>
<th>Notes</th>
<th class='rating'>Age Rating</th>
{$noteTh}
<th>Genres</th>
</tr>
</thead>
<tbody>
<?php foreach ($items as $item): ?>
<?php include __DIR__ . '/list-item.php' ?>
<?php endforeach ?>
</tbody>
</table>
</div>
<?php $i++ ?>
<?php endforeach ?>
</div>
</thead>
<tbody>{$rows}</tbody>
</table>
HTML;
}) ?>
<?php endif ?>
</main>
<script defer="defer" src="<?= $urlGenerator->assetUrl('js.php/g/table') ?>"></script>
<script defer="defer" src="<?= $_->assetUrl('js/tables.min.js') ?>"></script>

View File

@ -0,0 +1,11 @@
<select name="media_id[]" id="media_id" multiple size="13">
<?php foreach ($media_items as $group => $items): ?>
<optgroup label='<?= $group ?>'>
<?php foreach ($items as $id => $name): ?>
<option <?= in_array($id, ($item['media_id'] ?? []), FALSE) ? 'selected="selected"' : '' ?> value="<?= $id ?>">
<?= $name ?>
</option>
<?php endforeach ?>
</optgroup>
<?php endforeach ?>
</select>

View File

@ -10,6 +10,7 @@
</div>
</div>
</section>
<script defer="defer" src="<?= $urlGenerator->assetUrl('js.php/g/event') ?>"></script>
<script nomodule="nomodule" src="https://polyfill.io/v3/polyfill.min.js?features=es5%2CObject.assign"></script>
<script async="async" defer="defer" src="<?= $_->assetUrl('js/scripts.min.js') ?>"></script>
</body>
</html>
</html>

View File

@ -6,24 +6,26 @@
<meta http-equiv="cache-control" content="no-store" />
<meta http-equiv="Content-Security-Policy" content="script-src 'self'" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=1" />
<link rel="stylesheet" href="<?= $urlGenerator->assetUrl('css/app.min.css') ?>" />
<link rel="icon" href="<?= $urlGenerator->assetUrl('images/icons/favicon.ico') ?>" />
<link rel="apple-touch-icon" sizes="57x57" href="<?= $urlGenerator->assetUrl('images/icons/apple-icon-57x57.png') ?>">
<link rel="apple-touch-icon" sizes="60x60" href="<?= $urlGenerator->assetUrl('images/icons/apple-icon-60x60.png') ?>">
<link rel="apple-touch-icon" sizes="72x72" href="<?= $urlGenerator->assetUrl('images/icons/apple-icon-72x72.png') ?>">
<link rel="apple-touch-icon" sizes="76x76" href="<?= $urlGenerator->assetUrl('images/icons/apple-icon-76x76.png') ?>">
<link rel="apple-touch-icon" sizes="114x114" href="<?= $urlGenerator->assetUrl('images/icons/apple-icon-114x114.png') ?>">
<link rel="apple-touch-icon" sizes="120x120" href="<?= $urlGenerator->assetUrl('images/icons/apple-icon-120x120.png') ?>">
<link rel="apple-touch-icon" sizes="144x144" href="<?= $urlGenerator->assetUrl('images/icons/apple-icon-144x144.png') ?>">
<link rel="apple-touch-icon" sizes="152x152" href="<?= $urlGenerator->assetUrl('images/icons/apple-icon-152x152.png') ?>">
<link rel="apple-touch-icon" sizes="180x180" href="<?= $urlGenerator->assetUrl('images/icons/apple-icon-180x180.png') ?>">
<link rel="icon" type="image/png" sizes="192x192" href="<?= $urlGenerator->assetUrl('images/icons/android-icon-192x192.png') ?>">
<link rel="icon" type="image/png" sizes="32x32" href="<?= $urlGenerator->assetUrl('images/icons/favicon-32x32.png') ?>">
<link rel="icon" type="image/png" sizes="96x96" href="<?= $urlGenerator->assetUrl('images/icons/favicon-96x96.png') ?>">
<link rel="icon" type="image/png" sizes="16x16" href="<?= $urlGenerator->assetUrl('images/icons/favicon-16x16.png') ?>">
<script defer="defer" src="<?= $urlGenerator->assetUrl('js.php/g/base') ?>"></script>
<link rel="stylesheet" href="<?= $_->assetUrl('css/' . $_->config->get('theme') . '.min.css') ?>" />
<link rel="<?= $_->config->get('theme') === 'dark' ? '' : 'alternate ' ?>stylesheet" title="Dark Theme" href="<?= $_->assetUrl('css/dark.min.css') ?>" />
<link rel="icon" href="<?= $_->assetUrl('images/icons/favicon.ico') ?>" />
<link rel="apple-touch-icon" sizes="57x57" href="<?= $_->assetUrl('images/icons/apple-icon-57x57.png') ?>">
<link rel="apple-touch-icon" sizes="60x60" href="<?= $_->assetUrl('images/icons/apple-icon-60x60.png') ?>">
<link rel="apple-touch-icon" sizes="72x72" href="<?= $_->assetUrl('images/icons/apple-icon-72x72.png') ?>">
<link rel="apple-touch-icon" sizes="76x76" href="<?= $_->assetUrl('images/icons/apple-icon-76x76.png') ?>">
<link rel="apple-touch-icon" sizes="114x114" href="<?= $_->assetUrl('images/icons/apple-icon-114x114.png') ?>">
<link rel="apple-touch-icon" sizes="120x120" href="<?= $_->assetUrl('images/icons/apple-icon-120x120.png') ?>">
<link rel="apple-touch-icon" sizes="144x144" href="<?= $_->assetUrl('images/icons/apple-icon-144x144.png') ?>">
<link rel="apple-touch-icon" sizes="152x152" href="<?= $_->assetUrl('images/icons/apple-icon-152x152.png') ?>">
<link rel="apple-touch-icon" sizes="180x180" href="<?= $_->assetUrl('images/icons/apple-icon-180x180.png') ?>">
<link rel="icon" type="image/png" sizes="192x192" href="<?= $_->assetUrl('images/icons/android-icon-192x192.png') ?>">
<link rel="icon" type="image/png" sizes="32x32" href="<?= $_->assetUrl('images/icons/favicon-32x32.png') ?>">
<link rel="icon" type="image/png" sizes="96x96" href="<?= $_->assetUrl('images/icons/favicon-96x96.png') ?>">
<link rel="icon" type="image/png" sizes="16x16" href="<?= $_->assetUrl('images/icons/favicon-16x16.png') ?>">
</head>
<body class="<?= $escape->attr($url_type) ?> list">
<body class="<?= $_->escape->attr($url_type) ?> list">
<?php include 'setup-check.php' ?>
<header>
<?php
include 'main-menu.php';

47
app/views/history.php Normal file
View File

@ -0,0 +1,47 @@
<main class="details fixed">
<?php if (empty($items)): ?>
<h3>No recent history.</h3>
<?php else: ?>
<section>
<?php foreach ($items as $name => $item): ?>
<article class="flex flex-no-wrap flex-justify-start">
<section class="flex-self-center history-img">
<a href="<?= $item['url'] ?>">
<?= $_->h->img(
$item['coverImg'],
['width' => '110px', 'height' => '156px'],
) ?>
</a>
</section>
<section class="flex-self-center">
<?= $_->h->a($item['url'], $item['title']) ?>
<br />
<br />
<?= $item['action'] ?>
<br />
<small>
<?php if ( ! empty($item['dateRange'])):
[$startDate, $endDate] = array_map(
fn ($date) => $date->format('l, F d'),
$item['dateRange']
);
[$startTime, $endTime] = array_map(
fn ($date) => $date->format('h:i:s A'),
$item['dateRange']
);
?>
<?php if ($startDate === $endDate): ?>
<?= "{$startDate}, {$startTime} &ndash; {$endTime}" ?>
<?php else: ?>
<?= "{$startDate} {$startTime} &ndash; {$endDate} {$endTime}" ?>
<?php endif ?>
<?php else: ?>
<?= $item['updated']->format('l, F d h:i:s A') ?>
<?php endif ?>
</small>
</section>
</article>
<?php endforeach ?>
</section>
<?php endif ?>
</main>

6
app/views/js-warning.php Normal file
View File

@ -0,0 +1,6 @@
<noscript>
<div class="message error">
<span class="icon"></span>
This feature requires Javascript to function :(
</div>
</noscript>

View File

@ -1,7 +1,7 @@
<main>
<h2><?= $config->get('whose_list'); ?>'s Login</h2>
<h2><?= $_->config->get('whose_list'); ?>'s Login</h2>
<?= $message ?>
<form method="post" action="<?= $url->generate('login.post') ?>">
<form method="post" action="<?= $_->urlFromRoute('login.post') ?>">
<table class="form invisible">
<tr>
<td><label for="password">Password: </label></td>

View File

@ -1,80 +1,114 @@
<?php declare(strict_types=1);
/**
* Hummingbird Anime List Client
*
* An API client for Kitsu to manage anime and manga watch lists
*
* PHP version 8.1
*
* @copyright 2015 - 2023 Timothy J. Warren <tim@timshome.page>
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 5.2
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient;
$whose = $config->get('whose_list') . "'s ";
$lastSegment = $urlGenerator->lastSegment();
$whose = $_->config->get('whose_list') . "'s ";
$lastSegment = $_->lastSegment();
$extraSegment = $lastSegment === 'list' ? '/list' : '';
$hasAnime = str_contains($GLOBALS['_SERVER']['REQUEST_URI'], 'anime');
$hasManga = str_contains($GLOBALS['_SERVER']['REQUEST_URI'], 'manga');
?>
<div id="main-nav" class="flex flex-align-end flex-wrap">
<span class="flex-no-wrap grow-1">
<?php if(strpos($route_path, 'collection') === FALSE): ?>
<?= $helper->a(
$urlGenerator->defaultUrl($url_type),
$whose . ucfirst($url_type) . ' List'
<?php if( ! str_contains($route_path, 'collection')): ?>
<?= $_->h->a(
$_->defaultUrl($url_type),
$whose . ucfirst($url_type) . ' List',
['aria-current'=> 'page']
) ?>
<?php if($config->get("show_{$url_type}_collection")): ?>
[<?= $helper->a(
$url->generate("{$url_type}.collection.view") . $extraSegment,
<?php if($_->config->get("show_{$url_type}_collection")): ?>
[<?= $_->h->a(
$_->urlFromRoute("{$url_type}.collection.view") . $extraSegment,
ucfirst($url_type) . ' Collection'
) ?>]
<?php endif ?>
<?php if($config->get("show_{$other_type}_collection")): ?>
[<?= $helper->a(
$url->generate("{$other_type}.collection.view") . $extraSegment,
<?php if($_->config->get("show_{$other_type}_collection")): ?>
[<?= $_->h->a(
$_->urlFromRoute("{$other_type}.collection.view") . $extraSegment,
ucfirst($other_type) . ' Collection'
) ?>]
<?php endif ?>
[<?= $helper->a(
$urlGenerator->defaultUrl($other_type) . $extraSegment,
[<?= $_->h->a(
$_->defaultUrl($other_type) . $extraSegment,
ucfirst($other_type) . ' List'
) ?>]
<?php else: ?>
<?= $whose . ucfirst($url_type) . ' Collection' ?>
<?php if($config->get("show_{$other_type}_collection")): ?>
[<?= $helper->a(
$url->generate("{$other_type}.collection.view") . $extraSegment,
<?= $_->h->a(
$_->urlFromRoute("{$url_type}.collection.view") . $extraSegment,
$whose . ucfirst($url_type) . ' Collection',
['aria-current'=> 'page']
) ?>
<?php if($_->config->get("show_{$other_type}_collection")): ?>
[<?= $_->h->a(
$_->urlFromRoute("{$other_type}.collection.view") . $extraSegment,
ucfirst($other_type) . ' Collection'
) ?>]
<?php endif ?>
[<?= $helper->a($urlGenerator->defaultUrl('anime') . $extraSegment, 'Anime List') ?>]
[<?= $helper->a($urlGenerator->defaultUrl('manga') . $extraSegment, 'Manga List') ?>]
[<?= $_->h->a($_->defaultUrl('anime') . $extraSegment, 'Anime List') ?>]
[<?= $_->h->a($_->defaultUrl('manga') . $extraSegment, 'Manga List') ?>]
<?php endif ?>
</span>
<span class="flex-no-wrap small-font">[<?= $helper->a(
$url->generate('user_info'),
'About '. $config->get('whose_list')
) ?>]</span>
<?php if ($auth->isAuthenticated()): ?>
<span class="flex-no-wrap">&nbsp;</span>
<span class="flex-no-wrap small-font">
<?php if ($_->isAuthenticated() && $_->config->get(['cache', 'driver']) !== 'null'): ?>
<span class="flex-no-wrap small-font">
<button type="button" class="js-clear-cache user-btn">Clear API Cache</button>
</span>
<span class="flex-no-wrap">&nbsp;</span>
<?php endif ?>
<span class="flex-no-wrap small-font">
<?php if ($auth->isAuthenticated()): ?>
<?= $helper->a(
$url->generate('logout'),
'Logout',
['class' => 'bracketed']
) ?>
<?php else: ?>
[<?= $helper->a($url->generate('login'), "{$whose} Login") ?>]
<?php endif ?>
</span>
<span class="flex-no-wrap small-font">[<?= $_->h->a(
$_->urlFromRoute('default_user_info'),
'About '. $_->config->get('whose_list')
) ?>]</span>
<?php if ($_->isAuthenticated()): ?>
<span class="flex-no-wrap small-font">
<?= $_->h->a(
$_->urlFromRoute('settings'),
'Settings',
['class' => 'bracketed']
) ?>
</span>
<span class="flex-no-wrap small-font">
<?= $_->h->a(
$_->urlFromRoute('logout'),
'Logout',
['class' => 'bracketed']
) ?>
</span>
<?php else: ?>
<span class="flex-no-wrap small-font">
[<?= $_->h->a($_->urlFromRoute('login'), "{$whose} Login") ?>]
</span>
<?php endif ?>
</div>
<?php if ($_->isViewPage() && ($hasAnime || $hasManga)): ?>
<nav>
<?php if ($container->get('util')->isViewPage()): ?>
<?= $helper->menu($menu_name) ?>
<?= $_->h->menu($menu_name) ?>
<?php if (stripos($GLOBALS['_SERVER']['REQUEST_URI'], 'history') === FALSE): ?>
<br />
<ul>
<li class="<?= Util::isNotSelected('list', $lastSegment) ?>"><a href="<?= $urlGenerator->url($route_path) ?>">Cover View</a></li>
<li class="<?= Util::isSelected('list', $lastSegment) ?>"><a href="<?= $urlGenerator->url("{$route_path}/list") ?>">List View</a></li>
<?php $currentView = Util::eq('list', $lastSegment) ? 'list' : 'cover' ?>
<li class="<?= Util::isNotSelected('list', $lastSegment) ?>">
<a aria-current="<?= Util::ariaCurrent($currentView === 'cover') ?>"
href="<?= $_->urlFromPath($route_path) ?>">Cover View</a>
</li>
<li class="<?= Util::isSelected('list', $lastSegment) ?>">
<a aria-current="<?= Util::ariaCurrent($currentView === 'list') ?>"
href="<?= $_->urlFromPath("{$route_path}/list") ?>">List View</a>
</li>
</ul>
<?php endif ?>
<?php endif ?>
</nav>
<?php endif ?>

View File

@ -1,7 +1,8 @@
<?php if ($auth->isAuthenticated()): ?>
<?php if ($_->isAuthenticated()): ?>
<main>
<h2>Add Manga to your List</h2>
<form action="<?= $action_url ?>" method="post">
<?php include realpath(__DIR__ . '/../js-warning.php') ?>
<section>
<div class="cssload-loader" hidden="hidden">
<div class="cssload-inner cssload-one"></div>
@ -9,7 +10,7 @@
<div class="cssload-inner cssload-three"></div>
</div>
<label for="search">Search for manga by name:&nbsp;&nbsp;&nbsp;&nbsp;<input type="search" id="search" /></label>
<section id="series_list" class="media-wrap">
<section id="series-list" class="media-wrap">
</section>
</section>
<br />
@ -36,5 +37,4 @@
</table>
</form>
</main>
<script defer="defer" src="<?= $urlGenerator->assetUrl('js.php/g/manga_collection') ?>"></script>
<?php endif ?>

View File

@ -1,86 +1,25 @@
<main class="media-list">
<?php if ($auth->isAuthenticated()): ?>
<a class="bracketed" href="<?= $url->generate('manga.add.get') ?>">Add Item</a>
<?php if ($_->isAuthenticated()): ?>
<a class="bracketed" href="<?= $_->urlFromRoute('manga.add.get') ?>">Add Item</a>
<?php endif ?>
<?php if (empty($sections)): ?>
<h3>There's nothing here!</h3>
<?php else: ?>
<br />
<label>Filter: <input type='text' class='media-filter' /></label>
<br />
<?php foreach ($sections as $name => $items): ?>
<?php if (empty($items)): ?>
<section class="status">
<h2><?= $escape->html($name) ?></h2>
<h2><?= $_->escape->html($name) ?></h2>
<h3>There's nothing here!</h3>
</section>
<?php else: ?>
<section class="status">
<h2><?= $escape->html($name) ?></h2>
<h2><?= $_->escape->html($name) ?></h2>
<section class="media-wrap">
<?php foreach($items as $item): ?>
<article class="media" data-kitsu-id="<?= $item['id'] ?>" data-mal-id="<?= $item['mal_id'] ?>">
<?php if ($auth->isAuthenticated()): ?>
<div class="edit_buttons" hidden>
<button class="plus_one_chapter">+1 Chapter</button>
<?php /* <button class="plus_one_volume">+1 Volume</button> */ ?>
</div>
<?php endif ?>
<img src="<?= $urlGenerator->assetUrl('images/manga', "{$item['manga']['id']}.jpg") ?>" />
<div class="name">
<a href="<?= $url->generate('manga.details', ['id' => $item['manga']['slug']]) ?>">
<?= $escape->html($item['manga']['title']) ?>
<?php foreach($item['manga']['titles'] as $title): ?>
<br /><small><?= $title ?></small>
<?php endforeach ?>
</a>
</div>
<div class="table">
<?php if ($auth->isAuthenticated()): ?>
<div class="row">
<span class="edit">
<a class="bracketed"
title="Edit information about this manga"
href="<?= $url->generate('edit', [
'controller' => 'manga',
'id' => $item['id'],
'status' => $name
]) ?>">
Edit
</a>
</span>
</div>
<?php endif ?>
<div class="row">
<div class="user_rating">Rating: <?= $item['user_rating'] ?> / 10</div>
</div>
<?php if ($item['rereading']): ?>
<div class="row">
<?php foreach(['rereading'] as $attr): ?>
<?php if($item[$attr]): ?>
<span class="item-<?= $attr ?>"><?= ucfirst($attr) ?></span>
<?php endif ?>
<?php endforeach ?>
</div>
<?php endif ?>
<?php if ($item['reread'] > 0): ?>
<div class="row">
<div>Reread <?= $item['reread'] ?> time(s)</div>
</div>
<?php endif ?>
<div class="row">
<div class="chapter_completion">
Chapters: <span class="chapters_read"><?= $item['chapters']['read'] ?></span> /
<span class="chapter_count"><?= $item['chapters']['total'] ?></span>
</div>
<?php /* </div>
<div class="row"> */ ?>
<div class="volume_completion">
Volumes: <span class="volume_count"><?= $item['volumes']['total'] ?></span>
</div>
</div>
</div>
</article>
<?= $component->mangaCover($item, $name) ?>
<?php endforeach ?>
</section>
</section>
@ -88,6 +27,3 @@
<?php endforeach ?>
<?php endif ?>
</main>
<?php if ($auth->isAuthenticated()): ?>
<script defer="defer" src="<?= $urlGenerator->assetUrl('js.php/g/edit') ?>"></script>
<?php endif ?>

View File

@ -1,22 +1,51 @@
<main class="details fixed">
<section class="flex flex-no-wrap">
<div>
<img class="cover" src="<?= $urlGenerator->assetUrl('images/manga', "{$data['id']}.jpg") ?>" alt="<?= $data['title'] ?> cover image" />
<aside class="info">
<?= $_->h->img($data['cover_image'], ['class' => 'cover', 'width' => '350']) ?>
<br />
<br />
<table>
<table class="media-details">
<tr>
<td class="align-right">Publishing Status</td>
<td><?= $data['status'] ?></td>
</tr>
<tr>
<td>Manga Type</td>
<td><?= $data['manga_type'] ?></td>
<td><?= ucfirst(strtolower($data['manga_type'])) ?></td>
</tr>
<?php if ( ! empty($data['volume_count'])): ?>
<tr>
<td>Volume Count</td>
<td><?= $data['volume_count'] ?></td>
</tr>
<?php endif ?>
<?php if ( ! empty($data['chapter_count'])): ?>
<tr>
<td>Chapter Count</td>
<td><?= $data['chapter_count'] ?></td>
</tr>
<?php endif ?>
<?php if ( ! empty($data['age_rating'])): ?>
<tr>
<td>Age Rating</td>
<td><abbr title="<?= $data['age_rating_guide'] ?>"><?= $data['age_rating'] ?></abbr>
</td>
</tr>
<?php endif ?>
<?php if (count($data['links']) > 0): ?>
<tr>
<td>External Links</td>
<td>
<?php foreach ($data['links'] as $urlName => $externalUrl): ?>
<a rel='external' href="<?= $externalUrl ?>"><?= $urlName ?></a><br />
<?php endforeach ?>
</td>
</tr>
<?php endif ?>
<tr>
<td>Genres</td>
<td>
@ -24,36 +53,53 @@
</td>
</tr>
</table>
</div>
<div>
<h2><a rel="external" href="<?= $data['url'] ?>"><?= $data['title'] ?></a></h2>
<?php if( ! empty($data['en_title'])): ?>
<h3><?= $data['en_title'] ?></h3>
<?php endif ?>
<br />
<p><?= nl2br($data['synopsis']) ?></p>
</div>
</aside>
<article class="text">
<h2 class="toph"><?= $data['title'] ?></h2>
<?php foreach ($data['titles_more'] as $title): ?>
<h3><?= $title ?></h3>
<?php endforeach ?>
<br />
<div class="description">
<p><?= str_replace("\n", '</p><p>', $data['synopsis']) ?></p>
</div>
</article>
</section>
<?php if (count($characters) > 0): ?>
<h2>Characters</h2>
<section class="media-wrap">
<?php foreach($characters as $id => $char): ?>
<?php if ( ! empty($char['image']['original'])): ?>
<article class="character">
<?php $link = $url->generate('character', ['slug' => $char['slug']]) ?>
<div class="name">
<?= $helper->a($link, $char['name']); ?>
</div>
<a href="<?= $link ?>">
<?= $helper->img($urlGenerator->assetUrl('images/characters', "{$id}.jpg"), [
'width' => '225'
]) ?>
</a>
</article>
<?php endif ?>
<?php endforeach ?>
</section>
<?php if (count($data['characters']) > 0): ?>
<h2>Characters</h2>
<?= $component->tabs('manga-characters', $data['characters'], static function($list, $role) use ($component, $helper, $_) {
$rendered = [];
foreach ($list as $id => $char)
{
$rendered[] = $component->character(
$char['name'],
$_->urlFromRoute('character', ['slug' => $char['slug']]),
$_->h->img($char['image'], ['loading' => 'lazy']),
($role !== 'main') ? 'small-character' : 'character'
);
}
return implode('', array_map('mb_trim', $rendered));
}) ?>
<?php endif ?>
<?php if (count($data['staff']) > 0): ?>
<h2>Staff</h2>
<?= $component->verticalTabs('manga-staff', $data['staff'],
fn($people) => implode('', array_map(
fn ($person) => $component->character(
$person['name'],
$_->urlFromRoute('person', ['slug' => $person['slug']]),
$_->h->img($person['image']),
),
$people
))
) ?>
<?php endif ?>
</main>

View File

@ -1,4 +1,4 @@
<?php if ($auth->isAuthenticated()): ?>
<?php if ($_->isAuthenticated()): ?>
<main>
<h2>
Edit Manga List Item
@ -8,9 +8,9 @@
<thead>
<tr>
<th>
<h3><?= $escape->html($item['manga']['title']) ?></h3>
<h3><?= $_->escape->html($item['manga']['title']) ?></h3>
<?php foreach ($item['manga']['titles'] as $title): ?>
<h4><?= $escape->html($title) ?></h4>
<h4><?= $_->escape->html($title) ?></h4>
<?php endforeach ?>
</th>
</tr>
@ -18,9 +18,7 @@
<tbody>
<tr>
<td rowspan="9">
<article class="media">
<?= $helper->img($urlGenerator->assetUrl('images/manga', "{$item['manga']['id']}.jpg")); ?>
</article>
<?= $_->h->img($item['manga']['image']) ?>
</td>
</tr>
<tr>
@ -48,13 +46,6 @@
value="<?= $item['chapters']['read'] ?>"/> / <?= $item['chapters']['total'] ?>
</td>
</tr>
<tr>
<td><label for="volumes_read">Volumes Read</label></td>
<td>
<?php /*<input type="number" disabled="disabled" min="0" name="volumes_read" id="volumes_read" value="" /> */ ?>
- / <?= $item['volumes']['total'] ?>
</td>
</tr>
<tr>
<td><label for="rereading_flag">Rereading?</label></td>
<td>
@ -73,7 +64,7 @@
<tr>
<td><label for="notes">Notes</label></td>
<td>
<textarea name="notes" id="notes"><?= $escape->html($item['notes']) ?></textarea>
<textarea name="notes" id="notes"><?= $_->escape->html($item['notes']) ?></textarea>
</td>
</tr>
<tr>
@ -92,11 +83,13 @@
</form>
<fieldset>
<legend>Danger Zone</legend>
<form class="js-delete" action="<?= $url->generate('manga.delete') ?>" method="post">
<form class="js-delete" action="<?= $_->urlFromRoute('manga.delete') ?>" method="post">
<table class="form invisible">
<tbody>
<tr>
<td>&nbsp;</td>
<td class="danger">
<strong>Permanently</strong> remove this list item and <strong>all</strong> its data?
</td>
<td>
<input type="hidden" value="<?= $item['id'] ?>" name="id"/>
<input type="hidden" value="<?= $item['mal_id'] ?>" name="mal_id"/>

View File

@ -1,44 +1,45 @@
<main class="media-list">
<?php if ($auth->isAuthenticated()): ?>
<a class="bracketed" href="<?= $url->generate('manga.add.get') ?>">Add Item</a>
<?php if ($_->isAuthenticated()): ?>
<a class="bracketed" href="<?= $_->urlFromRoute('manga.add.get') ?>">Add Item</a>
<?php endif ?>
<?php if (empty($sections)): ?>
<h3>There's nothing here!</h3>
<?php else: ?>
<br />
<label>Filter: <input type='text' class='media-filter' /></label>
<br />
<?php foreach ($sections as $name => $items): ?>
<h2><?= $name ?></h2>
<?php if (empty($items)): ?>
<h3>There's nothing here!</h3>
<?php else: ?>
<table>
<table class='media-wrap'>
<thead>
<tr>
<?php if ($auth->isAuthenticated()): ?>
<?php if ($_->isAuthenticated()): ?>
<td>&nbsp;</td>
<?php endif ?>
<th>Title</th>
<th>Rating</th>
<th>Completed Chapters</th>
<th># of Volumes</th>
<th class='numeric'>Score</th>
<th class='numeric'>Completed Chapters</th>
<th>Attributes</th>
<th>Type</th>
<th>Genres</th>
</tr>
</thead>
<tbody>
<?php foreach($items as $item): ?>
<tr id="manga-<?= $item['id'] ?>">
<?php if($auth->isAuthenticated()): ?>
<?php if($_->isAuthenticated()): ?>
<td>
<a class="bracketed" href="<?= $url->generate('edit', [
<a class="bracketed" href="<?= $_->urlFromRoute('edit', [
'controller' => 'manga',
'id' => $item['id'],
'status' => $name
]) ?>">Edit</a>
</td>
<?php endif ?>
<td class="align_left">
<a href="<?= $url->generate('manga.details', ['id' => $item['manga']['slug']]) ?>">
<td class="align-left">
<a href="<?= $_->urlFromRoute('manga.details', ['id' => $item['manga']['slug']]) ?>">
<?= $item['manga']['title'] ?>
</a>
<?php foreach($item['manga']['titles'] as $title): ?>
@ -47,11 +48,16 @@
</td>
<td><?= $item['user_rating'] ?> / 10</td>
<td><?= $item['chapters']['read'] ?> / <?= $item['chapters']['total'] ?></td>
<td><?= $item['volumes']['total'] ?></td>
<td>
<ul>
<?php if ($item['reread'] > 0): ?>
<li>Reread <?= $item['reread'] ?> time(s)</li>
<?php if ($item['reread'] == 1): ?>
<li>Reread once</li>
<?php elseif ($item['reread'] == 2): ?>
<li>Reread twice</li>
<?php elseif ($item['reread'] == 3): ?>
<li>Reread thrice</li>
<?php elseif ($item['reread'] > 3): ?>
<li>Reread <?= $item['reread'] ?> times</li>
<?php endif ?>
<?php foreach(['rereading'] as $attr): ?>
<?php if($item[$attr]): ?>
@ -61,9 +67,6 @@
</ul>
</td>
<td><?= $item['manga']['type'] ?></td>
<td class="align_left">
<?= implode(', ', $item['manga']['genres']) ?>
</td>
</tr>
<?php endforeach ?>
</tbody>
@ -72,4 +75,4 @@
<?php endforeach ?>
<?php endif ?>
</main>
<script defer="defer" src="<?= $urlGenerator->assetUrl('js.php/g/table') ?>"></script>
<script defer="defer" src="<?= $_->assetUrl('js/tables.min.js') ?>"></script>

View File

@ -1,137 +0,0 @@
<?php use Aviat\AnimeClient\API\Kitsu; ?>
<main class="user-page details">
<section class="flex flex-no-wrap">
<div>
<center>
<h2>
<a title='View profile on Kisu'
href="https://kitsu.io/users/<?= $attributes['name'] ?>">
<?= $attributes['name'] ?>
</a>
</h2>
<?php
$file = basename(parse_url($attributes['avatar']['original'], \PHP_URL_PATH));
$parts = explode('.', $file);
$ext = end($parts);
?>
<img src="<?= $urlGenerator->assetUrl('images/avatars', "{$data['id']}.{$ext}") ?>" alt="" />
</center>
<br />
<br />
<table class="media_details">
<tr>
<th colspan="2">General</th>
</tr>
<tr>
<td>Location</td>
<td><?= $attributes['location'] ?></td>
</tr>
<tr>
<td>Website</td>
<td><?= $helper->a($attributes['website'], $attributes['website']) ?></td>
</tr>
<?php if (array_key_exists('waifu', $relationships)): ?>
<tr>
<td><?= $escape->html($attributes['waifuOrHusbando']) ?></td>
<td>
<?php
$character = $relationships['waifu']['attributes'];
echo $helper->a(
$url->generate('character', ['slug' => $character['slug']]),
$character['name']
);
?>
</td>
</tr>
<?php endif ?>
<tr>
<th colspan="2">User Stats</th>
</tr>
<tr>
<td># of Posts</td>
<td><?= $attributes['postsCount'] ?></td>
</tr>
<tr>
<td># of Comments</td>
<td><?= $attributes['commentsCount'] ?></td>
</tr>
<tr>
<td># of Media Rated</td>
<td><?= $attributes['ratingsCount'] ?></td>
</tr>
</table>
</div>
<div>
<dl>
<dt>About:</dt>
<dd><?= $escape->html($attributes['about']) ?></dd>
</dl>
<?php if ( ! empty($favorites)): ?>
<?php if ( ! empty($favorites['characters'])): ?>
<h4>Favorite Characters</h4>
<section class="media-wrap">
<?php foreach($favorites['characters'] as $id => $char): ?>
<?php if ( ! empty($char['image']['original'])): ?>
<article class="small_character">
<?php $link = $url->generate('character', ['slug' => $char['slug']]) ?>
<div class="name"><?= $helper->a($link, $char['name']); ?></div>
<a href="<?= $link ?>">
<?= $helper->img($urlGenerator->assetUrl('images/characters', "{$char['id']}.jpg")) ?>
</a>
</article>
<?php endif ?>
<?php endforeach ?>
</section>
<?php endif ?>
<?php if ( ! empty($favorites['anime'])): ?>
<h4>Favorite Anime</h4>
<section class="media-wrap">
<?php foreach($favorites['anime'] as $anime): ?>
<article class="media">
<?php
$link = $url->generate('anime.details', ['id' => $anime['slug']]);
$titles = Kitsu::filterTitles($anime);
?>
<a href="<?= $link ?>">
<img src="<?= $urlGenerator->assetUrl('images/anime', "{$anime['id']}.jpg") ?>" width="220" alt="" />
</a>
<div class="name">
<a href="<?= $link ?>">
<?= array_shift($titles) ?>
<?php foreach ($titles as $title): ?>
<br /><small><?= $title ?></small>
<?php endforeach ?>
</a>
</div>
</article>
<?php endforeach ?>
</section>
<?php endif ?>
<?php if ( ! empty($favorites['manga'])): ?>
<h4>Favorite Manga</h4>
<section class="media-wrap">
<?php foreach($favorites['manga'] as $manga): ?>
<article class="media">
<?php
$link = $url->generate('manga.details', ['id' => $manga['slug']]);
$titles = Kitsu::filterTitles($manga);
?>
<a href="<?= $link ?>">
<img src="<?= $urlGenerator->assetUrl('images/manga', "{$manga['id']}.jpg") ?>" width="220" alt="" />
</a>
<div class="name">
<a href="<?= $link ?>">
<?= array_shift($titles) ?>
<?php foreach ($titles as $title): ?>
<br /><small><?= $title ?></small>
<?php endforeach ?>
</a>
</div>
</article>
<?php endforeach ?>
</section>
<?php endif ?>
<?php endif ?>
</div>
</section>
</main>

View File

@ -1,5 +1,5 @@
<div class="message <?= $escape->attr($message_type) ?>">
<div class="message <?= $_->escape->attr($message_type) ?>">
<span class="icon"></span>
<?= $escape->html($message) ?>
<?= $_->escape->html($message) ?>
<span class="close"></span>
</div>

View File

@ -0,0 +1,104 @@
<main class="details fixed">
<section class="flex flex-no-wrap">
<div>
<?= $_->h->img($data['image'], ['class' => 'cover' ]) ?>
</div>
<div>
<h2 class="toph"><?= $data['name'] ?></h2>
<?php foreach ($data['names'] as $name): ?>
<h3><?= $name ?></h3>
<?php endforeach ?>
<?php if ( ! empty($data['birthday'])): ?>
<h4><?= $data['birthday'] ?></h4>
<?php endif ?>
<br />
<hr />
<div class="description">
<p><?= str_replace("\n", '</p><p>', $data['description']) ?></p>
</div>
</div>
</section>
<?php if ( ! empty($data['staff'])): ?>
<section>
<h3>Castings</h3>
<div class="vertical-tabs">
<?php $i = 0 ?>
<?php foreach ($data['staff'] as $role => $entries): ?>
<div class="tab">
<input
type="radio" name="staff-roles" id="staff-role<?= $i ?>" <?= $i === 0 ? 'checked' : '' ?> />
<label for="staff-role<?= $i ?>"><?= $role ?></label>
<?php foreach ($entries as $type => $casting): ?>
<?php if (isset($entries['manga'], $entries['anime'])): ?>
<h4><?= ucfirst($type) ?></h4>
<?php endif ?>
<section class="content media-wrap flex flex-wrap flex-justify-start">
<?php foreach ($casting as $sid => $series): ?>
<?php $mediaType = in_array($type, ['anime', 'manga'], TRUE) ? $type : 'anime'; ?>
<?= $_->component->media(
$series['titles'],
$_->urlFromRoute("{$mediaType}.details", ['id' => $series['slug']]),
$_->h->img($series['image'], ['width' => 220, 'loading' => 'lazy'])
) ?>
<?php endforeach; ?>
</section>
<?php endforeach ?>
</div>
<?php $i++ ?>
<?php endforeach ?>
</div>
</section>
<?php endif ?>
<?php if ( ! empty($data['characters'])): ?>
<section>
<h3>Voice Acting Roles</h3>
<?= $component->tabs('voice-acting-roles', $data['characters'], static function ($characterList) use ($component, $helper, $_) {
$voiceRoles = [];
foreach ($characterList as $cid => $item):
$character = $component->character(
$item['character']['canonicalName'],
$_->urlFromRoute('character', ['slug' => $item['character']['slug']]),
$_->h->img($item['character']['image'], ['loading' => 'lazy']),
);
$medias = [];
foreach ($item['media'] as $sid => $series)
{
$medias[] = $component->media(
$series['titles'],
$_->urlFromRoute('anime.details', ['id' => $series['slug']]),
$_->h->img($series['image'], ['width' => 220, 'loading' => 'lazy'])
);
}
$media = implode('', array_map('mb_trim', $medias));
$voiceRoles[] = <<<HTML
<tr>
<td>{$character}</td>
<td>
<section class="align-left media-wrap">{$media}</section>
</td>
</tr>
HTML;
endforeach;
$roles = implode('', array_map('mb_trim', $voiceRoles));
return <<<HTML
<table class="borderless max-table">
<thead>
<tr>
<th>Character</th>
<th>Series</th>
</tr>
</thead>
<tbody>{$roles}</tbody>
</table>
HTML;
}) ?>
</section>
<?php endif ?>
</main>

View File

@ -0,0 +1,24 @@
<?php if ( ! $hasRequiredAnilistConfig): ?>
<p class="static-message info">See the <a href="https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient/wiki/anilist">wiki</a> to learn how to set up Anilist integration. </p>
<?php else: ?>
<?php $auth = $anilistModel->checkAuth(); ?>
<?php if (array_key_exists('errors', $auth)): ?>
<p class="static-message error">Anilist API Client is Not Authorized.</p>
<?= $_->h->a(
$_->urlFromRoute('anilist-redirect'),
'Link Anilist Account',
['class' => 'bracketed user-btn']
) ?>
<?php else: ?>
<?php $expires = $_->config->get(['anilist', 'access_token_expires']); ?>
<p class="static-message info">
Linked to Anilist. Your access token will expire around <?= date('F j, Y, g:i a T', $expires) ?>
</p>
<?php require __DIR__ . '/_form.php' ?>
<?= $_->h->a(
$_->urlFromRoute('anilist-redirect'),
'Update Access Token',
['class' => 'bracketed user-btn']
) ?>
<?php endif ?>
<?php endif ?>

View File

@ -0,0 +1,5 @@
<article>
<label for="<?= $fieldName ?>"><?= $field['title'] ?></label><br />
<small><?= $field['description'] ?></small><br />
<?= $_->h->field($fieldName, $field); ?>
</article>

View File

@ -0,0 +1,24 @@
<?php
// Higher scoped variables:
// $fields
// $hiddenFields
// $nestedPrefix
?>
<?php foreach ($fields as $name => $field): ?>
<?php
$fieldName = ($section === 'config' || $nestedPrefix !== 'config')
? "{$nestedPrefix}[{$name}]"
: "{$nestedPrefix}[{$section}][{$name}]";
?>
<?php if ($field['type'] === 'subfield'): ?>
<section>
<h4><?= $field['title'] ?></h4>
<?php include '_subfield.php'; ?>
</section>
<?php elseif ( ! empty($field['display'])): ?>
<?php include '_field.php' ?>
<?php else: ?>
<?php $hiddenFields[] = $_->h->field($fieldName, $field); ?>
<?php endif ?>
<?php endforeach ?>

View File

@ -0,0 +1,20 @@
<?php
// Higher scoped variables:
// $field
// $fields
// $hiddenFields
// $nestedPrefix
?>
<?php foreach ($field['fields'] as $name => $field): ?>
<?php
$fieldName = ($section === 'config' || $nestedPrefix !== 'config')
? "{$nestedPrefix}[{$name}]"
: "{$nestedPrefix}[{$section}][{$name}]";
?>
<?php if ( ! empty($field['display'])): ?>
<?php include '_field.php' ?>
<?php else: ?>
<?php $hiddenFields[] = $_->h->field($fieldName, $field); ?>
<?php endif ?>
<?php endforeach ?>

View File

@ -0,0 +1,46 @@
<?php
if ( ! $_->isAuthenticated())
{
echo '<h1>Not Authorized</h1>';
return;
}
$sectionMapping = [
'anilist' => 'Anilist API Integration',
'config' => 'General Settings',
'cache' => 'Caching',
'database' => 'Collection Database Settings',
];
$hiddenFields = [];
$nestedPrefix = 'config';
?>
<form action="<?= $_->urlFromRoute('settings-post') ?>" method="POST">
<main class='settings form'>
<button type="submit">Save Changes</button>
<div class="tabs">
<?php $i = 0; ?>
<?php foreach ($form as $section => $fields): ?>
<input <?= $i === 0 ? 'checked="checked"' : '' ?> type="radio" id="settings-tab<?= $i ?>"
name="settings-tabs"
/>
<label for="settings-tab<?= $i ?>"><h3><?= $sectionMapping[$section] ?></h3></label>
<section class="content">
<?php
($section === 'anilist')
? require __DIR__ . '/_anilist.php'
: require __DIR__ . '/_form.php'
?>
</section>
<?php $i++; ?>
<?php endforeach ?>
</div>
<br />
<?php foreach ($hiddenFields as $field): ?>
<?= $field->__toString() ?>
<?php endforeach ?>
<button type="submit">Save Changes</button>
</main>
</form>

30
app/views/setup-check.php Normal file
View File

@ -0,0 +1,30 @@
<?php declare(strict_types=1);
use function Aviat\AnimeClient\checkFolderPermissions;
$setupErrors = checkFolderPermissions($_->config);
?>
<?php if ( ! empty($setupErrors)): ?>
<aside class="message error">
<h1>Issues with server setup:</h1>
<?php if (array_key_exists('missing', $setupErrors)): ?>
<h3>The following folders need to be created, and writable.</h3>
<ul>
<?php foreach ($setupErrors['missing'] as $error): ?>
<li><?= $error ?></li>
<?php endforeach ?>
</ul>
<?php endif ?>
<?php if (array_key_exists('writable', $setupErrors)): ?>
<h3>The following folders are not writable by the server.</h3>
<ul>
<?php foreach($setupErrors['writable'] as $error): ?>
<li><?= $error ?></li>
<?php endforeach ?>
</ul>
<?php endif ?>
</aside>
<?php endif ?>

110
app/views/user/details.php Normal file
View File

@ -0,0 +1,110 @@
<?php
use Aviat\AnimeClient\Kitsu;
?>
<main class="user-page details">
<h2 class="toph">
About
<?= $_->h->a(
"https://kitsu.io/users/{$data['slug']}",
$data['name'], [
'title' => 'View profile on Kitsu'
])
?>
</h2>
<section class="flex flex-no-wrap">
<aside class="info">
<table class="media-details invisible">
<tr>
<?php if($data['avatar'] !== null): ?>
<td><?= $_->h->img($data['avatar'], ['alt' => '', 'width' => '225']); ?></td>
<?php endif ?>
<td><?= $_->escape->html($data['about']) ?></td>
</tr>
</table>
<br />
<table class="media-details">
<?php foreach ([
'joinDate' => 'Joined',
'birthday' => 'Birthday',
'gender' => 'Gender',
'location' => 'Location'
] as $key => $label): ?>
<?php if ($data[$key] !== null): ?>
<tr>
<td><?= $label ?></td>
<td><?= $data[$key] ?></td>
</tr>
<?php endif ?>
<?php endforeach; ?>
<?php if ($data['website'] !== null): ?>
<tr>
<td>Website</td>
<td><?= $_->h->a($data['website'], $data['website']) ?></td>
</tr>
<?php endif ?>
<?php if ($data['waifu']['character'] !== null): ?>
<tr>
<td><?= $_->escape->html($data['waifu']['label']) ?></td>
<td>
<?php
$character = $data['waifu']['character'];
echo $_->component->character(
$character['names']['canonical'],
$_->urlFromRoute('character', ['slug' => $character['slug']]),
$_->h->img(Kitsu::getImage($character))
);
?>
</td>
</tr>
<?php endif ?>
</table>
<h3>User Stats</h3><br />
<table class="media-details">
<?php foreach($data['stats'] as $label => $stat): ?>
<tr>
<td><?= $label ?></td>
<td><?= $stat ?></td>
</tr>
<?php endforeach ?>
</table>
</aside>
<article>
<?php if ( ! empty($data['favorites'])): ?>
<h3>Favorites</h3>
<?= $_->component->tabs('user-favorites', $data['favorites'], static function ($items, $type) use ($_) {
if ($type === 'character')
{
uasort($items, fn ($a, $b) => $a['names']['canonical'] <=> $b['names']['canonical']);
}
else
{
uasort($items, fn ($a, $b) => $a['titles']['canonical'] <=> $b['titles']['canonical']);
}
$rendered = array_map(fn ($item) => match ($type) {
'character' => $_->component->character(
$item['names']['canonical'],
$_->urlFromRoute('character', ['slug' => $item['slug']]),
$_->h->img(Kitsu::getImage($item))
),
default => $_->component->media(
array_merge(
[$item['titles']['canonical']],
Kitsu::getFilteredTitles($item['titles']),
),
$_->urlFromRoute("{$type}.details", ['id' => $item['slug']]),
$_->h->img(Kitsu::getPosterImage($item), ['width' => 220]),
),
}, $items);
return implode('', array_map('mb_trim', $rendered));
}, 'content full-width media-wrap') ?>
<?php endif ?>
</article>
</section>
</main>

View File

@ -1,28 +0,0 @@
<documentation title="Closing comments instead of PHP closing tag">
<standard>
<![CDATA[
The PHP closing tag on a PHP document ?> is optional to the PHP parser. However, if used, any whitespace following the closing tag, whether introduced by the developer, user, or an FTP application, can cause unwanted output, PHP errors, or if the latter are suppressed, blank pages. For this reason, all PHP files should OMIT the closing PHP tag, and instead use a comment block to mark the end of file and it's location relative to the application root. This allows you to still identify a file as being complete and not truncated.
]]>
</standard>
<code_comparison>
<code title="Examples of valid closing comments">
<![CDATA[
<?php
echo "Here's my code!";
/* End of file myfile.php */
/* Location: ./system/modules/mymodule/myfile.php */
]]>
</code>
<code title="Examples of invalid closing comments">
<![CDATA[
<?php
echo "Here's my code!";
?>
]]>
</code>
</code_comparison>
</documentation>

View File

@ -1,7 +0,0 @@
<documentation title="Unicode (UTF-8) encoding without BOM">
<standard>
<![CDATA[
Files should be saved with Unicode (UTF-8) encoding. The BOM should not be used. Unlike UTF-16 and UTF-32, there's no byte order to indicate in a UTF-8 encoded file, and the BOM can have a negative side effect in PHP of sending output, preventing the application from being able to set its own headers. Unix line endings should be used (LF).
]]>
</standard>
</documentation>

View File

@ -1,31 +0,0 @@
<documentation title="Constructor Names">
<standard>
<![CDATA[
Class names should always start with an uppercase letter. Multiple words should be separated with an underscore, and not CamelCased. All other class methods should be entirely lowercased and named to clearly indicate their function, preferably including a verb. Try to avoid overly long and verbose names.
]]>
</standard>
<code_comparison>
<code title="Examples of valid constructor name">
<![CDATA[
class Super_class
{
function Super_class()
{
echo 'Some code here !';
}
}
]]>
</code>
<code title="Examples of invalid constructor name">
<![CDATA[
class Super_class
{
function __constructor()
{
echo 'Some code here !';
}
}
]]>
</code>
</code_comparison>
</documentation>

View File

@ -1,21 +0,0 @@
<documentation title="Class names">
<standard>
<![CDATA[
Class names should always start with an uppercase letter. Multiple words should be separated with an underscore, and not CamelCased. All other class methods should be entirely lowercased and named to clearly indicate their function, preferably including a verb. Try to avoid overly long and verbose names.
]]>
</standard>
<code_comparison>
<code title="Examples of valid class names">
<![CDATA[
class Super_class
]]>
</code>
<code title="Examples of invalid class names">
<![CDATA[
class SuperClass // words not separated with underscores and words next to the first one start with an upper case
class superclass // words not separated with underscores
class Super_Class // words next to the first one start with an upper case
]]>
</code>
</code_comparison>
</documentation>

View File

@ -1,21 +0,0 @@
<documentation title="File names">
<standard>
<![CDATA[
To be able to find which class is contained in a file, file names should be case-insensitively equal to class names. Some operating systems and tools are case-insensitive, though other are. So, file names should be in lower case to avoid any trouble.
]]>
</standard>
<code_comparison>
<code title="Examples of valid file names">
<![CDATA[
super_class.php
]]>
</code>
<code title="Examples of invalid file names">
<![CDATA[
superclass.php // words not separated with underscores
SuperClass.php // not in lower case and words not separated with underscores
Super_class.php // not in lower case
]]>
</code>
</code_comparison>
</documentation>

View File

@ -1,27 +0,0 @@
<documentation title="Function and Method Names">
<standard>
<![CDATA[
Class names should always start with an uppercase letter. Multiple words should be separated with an underscore, and not CamelCased. All other class methods should be entirely lowercased and named to clearly indicate their function, preferably including a verb. Try to avoid overly long and verbose names.
Methods and variables that are only accessed internally by your class, such as utility and helper functions that your public methods use for code abstraction, should be prefixed with an underscore.
]]>
</standard>
<code_comparison>
<code title="Examples of valid method names">
<![CDATA[
function get_file_properties() // descriptive, underscore separator, and all lowercase letters
private function _get_file_properties()
]]>
</code>
<code title="Examples of invalid method names">
<![CDATA[
function fileproperties() // not descriptive and needs underscore separator
function fileProperties() // not descriptive and uses CamelCase
function getfileproperties() // Better! But still missing underscore separator
function getFileProperties() // uses CamelCase
function get_the_file_properties_from_the_file() // wordy
private function get_the_file_properties() // not prefixed with an underscor, though private
function _get_the_file_properties() // prefixed with an underscor, though public
]]>
</code>
</code_comparison>
</documentation>

View File

@ -1,31 +0,0 @@
<documentation title="Variable names">
<standard>
<![CDATA[
Namely, variables should contain only lowercase letters, use underscore separators, and be reasonably named to indicate their purpose and contents. Very short, non-word variables should only be used as iterators in for() loops.
Methods and variables that are only accessed internally by your class, such as utility and helper functions that your public methods use for code abstraction, should be prefixed with an underscore.
]]>
</standard>
<code_comparison>
<code title="Examples of valid variable names">
<![CDATA[
for ($j = 0; $j < 10; $j++)
$str
$buffer
$group_id
$last_city
private $_internal_data;
]]>
</code>
<code title="Examples of invalid variable names">
<![CDATA[
$j = 'foo'; // single letter variables should only be used in for() loops
$Str // contains uppercase letters
$bufferedText // uses CamelCasing, and could be shortened without losing semantic meaning
$groupid // multiple words, needs underscore separator
$name_of_last_city_used // too long
private $internal_data; // not prefixed with an underscor, though private
$_public_attribute; // prefixed with an underscor, though public
]]>
</code>
</code_comparison>
</documentation>

View File

@ -1,40 +0,0 @@
<documentation title="Strict comparison operators">
<standard>
<![CDATA[
Some PHP functions return FALSE on failure, but may also have a valid return value of "" or 0, which would evaluate to FALSE in loose comparisons. Be explicit by comparing the variable type when using these return values in conditionals to ensure the return value is indeed what you expect, and not a value that has an equivalent loose-type evaluation.
Use the same stringency in returning and checking your own variables. Use === and !== as necessary.
]]>
</standard>
<code_comparison>
<code title="Valid strict comparison">
<![CDATA[
if (strpos($str, 'foo') === FALSE) {
echo 'Do something.';
}
function build_string($str = "")
{
if ($str === "") {
echo 'Buid string.';
}
}
]]>
</code>
<code title="Invalid loose comparison">
<![CDATA[
// If 'foo' is at the beginning of the string, strpos will return a 0,
// resulting in this conditional evaluating as TRUE
if (strpos($str, 'foo') == FALSE) {
echo 'Do something.';
}
function build_string($str = "")
{
if ($str == "") { // uh-oh! What if FALSE or the integer 0 is passed as an argument?
echo 'Buid string.';
}
}
]]>
</code>
</code_comparison>
</documentation>

View File

@ -1,28 +0,0 @@
<documentation title="Double-quoted strings">
<standard>
<![CDATA[
Always use single quoted strings unless you need variables parsed, and in cases where you do need variables parsed, use braces to prevent greedy token parsing. You may also use double-quoted strings if the string contains single quotes, so you do not have to use escape characters.
]]>
</standard>
<code_comparison>
<code title="Examples of invalid double-quoted strings">
<![CDATA[
"My String" // no variable parsing, so no use for double quotes
"My string $foo" // needs braces
'SELECT foo FROM bar WHERE baz = \'bag\'' // ugly
'\r\n' // it isn't wrong, but it won't be interpreted as a new line feed
]]>
</code>
<code title="Examples of valid double-quoted strings">
<![CDATA[
'My String'
"My string {$foo}" // variables in strings may be enclosed with braces in 2 ways
"My string ${foo}"
"My string {$foo['bar']}" // variables in strings may be an array entry
"My string {$foo->bar}" // variables in strings may be an object attribute
"SELECT foo FROM bar WHERE baz = 'bag'"
"\n" // not specified in Code Igniter coding standard, but it should be allowed
]]>
</code>
</code_comparison>
</documentation>

View File

@ -1,187 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Commenting_InlineCommentSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2011 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* CodeIgniter_Sniffs_Commenting_InlineCommentSniff.
*
* Ensure the use of single line comments within code (i.e //)
* and blank lines between large comment blocks and code.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2011 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\Commenting;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
class InlineCommentSniff implements Sniff
{
/**
* @var int Limit defining long comments.
* Long comments count $longCommentLimit or more lines.
*/
public $longCommentLimit = 5;
/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
return array(
T_COMMENT
);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
// keep testing only if it's about the first comment of the block
$previousCommentPtr = $phpcsFile->findPrevious($tokens[$stackPtr]['code'], $stackPtr - 1);
if ($tokens[$previousCommentPtr]['line'] !== $tokens[$stackPtr]['line'] - 1) {
if (TRUE !== $this->_checkCommentStyle($phpcsFile, $stackPtr)) {
return;
}
$commentLines = $this->_getCommentBlock($phpcsFile, $stackPtr);
if (count($commentLines) >= $this->longCommentLimit) {
$this->_checkBlankLinesAroundLongComment($phpcsFile, $commentLines);
}
}
}//end process()
/**
* Add error to $phpcsFile, if comment pointed by $stackPtr doesn't start
* with '//'.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* that has to be a comment.
*
* @return bool TRUE if the content of the token pointed by $stackPtr starts
* with //, FALSE if an error was added to $phpcsFile.
*/
private function _checkCommentStyle(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
if ($tokens[$stackPtr]['content']{0} === '#') {
$error = 'Perl-style comments are not allowed; use "// Comment" or DocBlock comments instead';
$phpcsFile->addError($error, $stackPtr, 'WrongStyle');
return FALSE;
} else if (substr($tokens[$stackPtr]['content'], 0, 2) === '/*'
|| $tokens[$stackPtr]['content']{0} === '*'
) {
$error = 'Multi lines comments are not allowed; use "// Comment" DocBlock comments instead';
$phpcsFile->addError($error, $stackPtr, 'WrongStyle');
return FALSE;
} else if (substr($tokens[$stackPtr]['content'], 0, 2) !== '//') {
$error = 'Use single line or DocBlock comments within code';
$phpcsFile->addError($error, $stackPtr, 'WrongStyle');
return FALSE;
}
return TRUE;
}//_checkCommentStyle()
/**
* Gather into an array all comment lines to which $stackPtr belongs.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr Pointer to the first comment line.
*
* @return type array Pointers to tokens making up the comment block.
*/
private function _getCommentBlock(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$commentLines = array($stackPtr);
$nextComment = $stackPtr;
$lastLine = $tokens[$stackPtr]['line'];
while (($nextComment = $phpcsFile->findNext($tokens[$stackPtr]['code'], ($nextComment + 1), null, false)) !== false) {
if (($tokens[$nextComment]['line'] - 1) !== $lastLine) {
// Not part of the block.
break;
}
$lastLine = $tokens[$nextComment]['line'];
$commentLines[] = $nextComment;
}
return $commentLines;
}//_getCommentBlock()
/**
* Add errors to $phpcsFile, if $commentLines isn't enclosed with blank lines.
*
* @param File $phpcsFile The current file being scanned.
* @param array $commentLines Lines of the comment block being checked.
*
* @return bool TRUE if $commentLines is enclosed with at least a blank line
* before and after, FALSE otherwise.
*/
private function _checkBlankLinesAroundLongComment(File $phpcsFile, array $commentLines)
{
$hasBlankLinesAround = TRUE;
$tokens = $phpcsFile->getTokens();
// check blank line before the long comment
$firstCommentPtr = reset($commentLines);
$firstPreviousSpacePtr = $firstCommentPtr - 1;
while (T_WHITESPACE === $tokens[$firstPreviousSpacePtr]['code'] && $firstPreviousSpacePtr > 0) {
$firstPreviousSpacePtr--;
}
if ($tokens[$firstPreviousSpacePtr]['line'] >= $tokens[$firstCommentPtr]['line'] - 1) {
$error = "Please add a blank line before comments counting more than {$this->longCommentLimit} lines.";
$phpcsFile->addError($error, $firstCommentPtr, 'LongCommentWithoutSpacing');
$hasBlankLinesAround = FALSE;
}
// check blank line after the long comment
$lastCommentPtr = end($commentLines);
$lastNextSpacePtr = $lastCommentPtr + 1;
while (T_WHITESPACE === $tokens[$lastNextSpacePtr]['code'] && $lastNextSpacePtr < count($tokens)) {
$lastNextSpacePtr++;
}
if ($tokens[$lastNextSpacePtr]['line'] <= $tokens[$lastCommentPtr]['line'] + 1) {
$error = "Please add a blank line after comments counting more than {$this->longCommentLimit} lines.";
$phpcsFile->addError($error, $lastCommentPtr, 'LongCommentWithoutSpacing');
$hasBlankLinesAround = FALSE;
}
return $hasBlankLinesAround;
}//end _checkBlanksAroundLongComment()
}//end class
?>

View File

@ -1,98 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Files_ByteOrderMarkSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* CodeIgniter_Sniffs_Files_ByteOrderMarkSniff.
*
* Ensures that no BOM appears at the beginning of file.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\Files;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
class ByteOrderMarkSniff implements Sniff
{
/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
return array( T_OPEN_TAG );
}//end register()
/**
* List of supported BOM definitions.
*
* Use encoding names as keys and hex BOM representations as values.
*
* @return array
*/
protected function getBomDefinitions()
{
return array(
'UTF-8' => 'efbbbf',
'UTF-16 (BE)' => 'feff',
'UTF-16 (LE)' => 'fffe',
'UTF-32 (BE)' => '0000feff',
'UTF-32 (LE)' => 'fffe0000'
);
}//end getBomDefinitions()
/**
* Process tokens.
*
* Actually, only proceed when we're at index 0, this should be the only case
* that will contain BOM. Then check if BOM definition matches what
* we've found as file's inline HTML. Inline HTML could be longer than just BOM
* so make sure you test as much as needed.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(File $phpcsFile, $stackPtr )
{
// We are only interested if this is the first open tag.
if ($stackPtr !== 0) {
if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) {
return;
}
}
$tokens = $phpcsFile->getTokens();
$fileStartString = $tokens[0]['content'];
foreach ($this->getBomDefinitions() as $bomName => $expectedBomHex) {
$bomByteLength = strlen($expectedBomHex) / 2;
$fileStartHex = bin2hex(substr($fileStartString, 0, $bomByteLength));
if ($fileStartHex === $expectedBomHex) {
$error = "File contains a $bomName byte order mark (BOM).";
$phpcsFile->addError($error, $stackPtr, 123);
break;
}
}
}//end process()
}

View File

@ -1,222 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Files_Utf8EncodingSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* CodeIgniter_Sniffs_Files_Utf8EncodingSniff.
*
* Ensures that PHP files are encoded with Unicode (UTF-8) encoding.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\Files;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
class Utf8EncodingSniff implements Sniff
{
/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
return array(
T_OPEN_TAG
);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(File $phpcsFile, $stackPtr)
{
// We are only interested if this is the first open tag.
if ($stackPtr !== 0) {
if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) {
return;
}
}
$file_path = $phpcsFile->getFilename();
$file_name = basename($file_path);
$file_content = file_get_contents($file_path);
if (false === mb_check_encoding($file_content, 'UTF-8')) {
$error = 'File "' . $file_name . '" should be saved with Unicode (UTF-8) encoding.';
$phpcsFile->addError($error, 0);
}
if ( ! self::_checkUtf8W3c($file_content)) {
$error = 'File "' . $file_name . '" should be saved with Unicode (UTF-8) encoding, but it did not successfully pass the W3C test.';
$phpcsFile->addError($error, 0);
}
if ( ! self::_checkUtf8Rfc3629($file_content)) {
$error = 'File "' . $file_name . '" should be saved with Unicode (UTF-8) encoding, but it did not meet RFC3629 requirements.';
$phpcsFile->addError($error, 0);
}
}//end process()
/**
* Checks that the string $content contains only valid UTF-8 chars
* using W3C's method.
* Returns true if $content contains only UTF-8 chars, false otherwise.
*
* @param string $content String to check.
*
* @return bool true if $content contains only UTF-8 chars, false otherwise.
*
* @see http://w3.org/International/questions/qa-forms-utf-8.html
*/
private static function _checkUtf8W3c($content)
{
$content_chunks=self::mb_chunk_split($content, 4096, '');
foreach($content_chunks as $content_chunk)
{
$preg_result= preg_match(
'%^(?:
[\x09\x0A\x0D\x20-\x7E] # ASCII
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
)*$%xs',
$content_chunk
);
if($preg_result!==1)
{
return false;
}
}
return true;
}//end _checkUtf8W3c()
/**
* Checks that the string $content contains only valid UTF-8 chars
* using the method described in RFC 3629.
* Returns true if $content contains only UTF-8 chars, false otherwise.
*
* @param string $content String to check.
*
* @return bool true if $content contains only UTF-8 chars, false otherwise.
*
* @see http://www.php.net/manual/en/function.mb-detect-encoding.php#85294
*/
private static function _checkUtf8Rfc3629($content)
{
$len = strlen($content);
for ($i = 0; $i < $len; $i++) {
$c = ord($content[$i]);
if ($c > 128) {
if (($c >= 254)) {
return false;
} elseif ($c >= 252) {
$bits=6;
} elseif ($c >= 248) {
$bits=5;
} elseif ($c >= 240) {
$bytes = 4;
} elseif ($c >= 224) {
$bytes = 3;
} elseif ($c >= 192) {
$bytes = 2;
} else {
return false;
} if (($i + $bytes) > $len) {
return false;
} while ($bytes > 1) {
$i++;
$b = ord($content[$i]);
if ($b < 128 || $b > 191) {
return false;
}
$bytes--;
}
}
}
return true;
}//_checkUtf8Rfc3629()
/**
* Splits a string to chunks of given size
* This helps to avoid segmentation fault errors when large text is given
* Returns array of strings after splitting
*
* @param string $str String to split.
* @param int $len number of characters per chunk
*
* @return array string array after splitting
*
* @see http://php.net/manual/en/function.chunk-split.php
*/
private static function mb_chunk_split($str, $len, $glue)
{
if (empty($str)) return false;
$array = self::mbStringToArray ($str);
$n = -1;
$new = Array();
foreach ($array as $char) {
$n++;
if ($n < $len) $new []= $char;
elseif ($n == $len) {
$new []= $glue . $char;
$n = 0;
}
}
return $new;
}//mb_chunk_split
/**
* Supporting function for mb_chunk_split
*
* @param string $str
*
* @return array
*
* @see http://php.net/manual/en/function.chunk-split.php
*/
private static function mbStringToArray ($str)
{
if (empty($str)) return false;
$len = mb_strlen($str);
$array = array();
for ($i = 0; $i < $len; $i++) {
$array[] = mb_substr($str, $i, 1);
}
return $array;
}
}//end class
?>

View File

@ -1,81 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Operators_LogicalOperatorAndSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* CodeIgniter_Sniffs_Operators_LogicalOperatorAndSniff.
*
* Ensures that the logical operator 'AND' is in upper case and suggest the use of its symbolic equivalent.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\Operators;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
class LogicalOperatorAndSniff implements Sniff
{
/**
* Returns an array of tokens this test wants to listen for: symbolic and literal operators and.
*
* @return array
*/
public function register()
{
return array(
T_LOGICAL_AND,
);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$operator_token = $tokens[$stackPtr];
$operator_string = $operator_token['content'];
$operator_code = $operator_token['code'];
if ($operator_string !== strtoupper($operator_string)) {
$error_message = 'Logical operator should be in upper case;'
. ' use "' . strtoupper($operator_string)
. '" instead of "' . $operator_string . '"';
$phpcsFile->addError($error_message, $stackPtr, 'LowercaseLogicalOperator');
}
$warning_message = 'The symbolic form "&&" is preferred over the literal form "AND"';
$phpcsFile->addWarning($warning_message, $stackPtr, 'UseOfLiteralAndOperator');
}//end process()
}//end class
?>

View File

@ -1,81 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Operators_StrictComparisonOperatorSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* CodeIgniter_Sniffs_Operators_StrictComparisonOperatorSniff.
*
* Ensures that only strict comparison operators are used instead of
* equal and not equal operators.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\Operators;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
class StrictComparisonOperatorSniff implements Sniff
{
private static $_replacements = array(
T_IS_EQUAL => '===',
T_IS_NOT_EQUAL => '!==',
);
/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
return array(
T_IS_EQUAL,
T_IS_NOT_EQUAL,
);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$operator_token = $tokens[$stackPtr];
$operator_string = $operator_token['content'];
$operator_code = $operator_token['code'];
$error_message = '"==" and "!=" are prohibited; use "'
. self::$_replacements[$operator_code] . '" instead of "'
. $operator_string . '".';
$phpcsFile->addError($error_message, $stackPtr, 'NonStrictComparisonUsed');
}//end process()
}//end class
?>

View File

@ -1,84 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Operators_UppercaseLogicalOperatorOrSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* CodeIgniter_Sniffs_Operators_UppercaseLogicalOperatorOrSniff.
*
* Ensures that the logical operator 'OR' is in upper cases and its symbolic equivalent.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\Operators;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
class UppercaseLogicalOperatorOrSniff implements Sniff
{
/**
* Returns an array of tokens this test wants to listen for: literal and symbolic operators or.
*
* @return array
*/
public function register()
{
return array(
T_BOOLEAN_OR,
T_LOGICAL_OR,
);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$operator_token = $tokens[$stackPtr];
$operator_string = $operator_token['content'];
$operator_code = $operator_token['code'];
if ($operator_code == T_BOOLEAN_OR) {
$error_message = 'Logical operator "' . $operator_string
. '" is prohibited; use "OR" instead';
$phpcsFile->addError($error_message, $stackPtr, 'UseOf||InsteadOfOR');
}
// it is literal, if it is not symbolic
else if ($operator_string !== strtoupper($operator_string)) {
$error_message = 'Logical operator should be in upper case;'
. ' use "' . strtoupper($operator_string)
. '" instead of "' . $operator_string . '"';
$phpcsFile->addError($error_message, $stackPtr, 'UseOfLowercaseOr');
}
}//end process()
}//end class
?>

View File

@ -1,465 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Strings_DoubleQuoteUsageSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2011 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\Strings;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
use Exception;
/**
* CodeIgniter_Sniffs_Strings_DoubleQuoteUsageSniff.
*
* Ensures that double-quoted strings are used only to parse variables,
* to avoid escape characters before single quotes or for chars that need
* to be interpreted like \r, \n or \t.
* If a double-quoted string contain both single and double quotes
* but no variable, then a warning is raised to encourage the use of
* single-quoted strings.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2011 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class VariableUsageSniff implements Sniff
{
/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
/*
return array(
T_DOUBLE_QUOTED_STRING,
T_CONSTANT_ENCAPSED_STRING,
);
*/
return array();
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$string = $tokens[$stackPtr]['content'];
// makes sure that it is about a double quote string,
// since variables are not parsed out of double quoted string
$openDblQtStr = substr($string, 0, 1);
if (0 === strcmp($openDblQtStr, '"')) {
$this->processDoubleQuotedString($phpcsFile, $stackPtr, $string);
} else if (0 === strcmp($openDblQtStr, "'")) {
$this->processSingleQuotedString($phpcsFile, $stackPtr, $string);
}
}//end process()
/**
* Processes this test, when the token encountered is a double-quoted string.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
* @param string $dblQtString The double-quoted string content,
* i.e. without quotes.
*
* @return void
*/
protected function processDoubleQuotedString (File $phpcsFile, $stackPtr, $dblQtString)
{
$variableFound = FALSE;
$strTokens = token_get_all('<?php '.$dblQtString);
$strPtr = 1; // skip php opening tag added by ourselves
$requireDblQuotes = FALSE;
while ($strPtr < count($strTokens)) {
$strToken = $strTokens[$strPtr];
if (is_array($strToken)) {
if (in_array($strToken[0], array(T_DOLLAR_OPEN_CURLY_BRACES, T_CURLY_OPEN))) {
$strPtr++;
try {
$this->_parseVariable($strTokens, $strPtr);
} catch (Exception $err) {
$error = 'There is no variable, object nor array between curly braces. Please use the escape char for $ or {.';
$phpcsFile->addError($error, $stackPtr, 234);
}
$variableFound = TRUE;
if ('}' !== $strTokens[$strPtr]) {
$error = 'There is no matching closing curly brace.';
$phpcsFile->addError($error, $stackPtr, 345);
}
// don't move forward, since it will be done in the main loop
// $strPtr++;
} else if (T_VARIABLE === $strToken[0]) {
$variableFound = TRUE;
$error = "Variable {$strToken[1]} in double-quoted strings should be enclosed with curly braces. Please consider {{$strToken[1]}}";
$phpcsFile->addError($error, $stackPtr, 456);
}
}
$strPtr++;
}
return $variableFound;
}//end processDoubleQuotedString()
/**
* Processes this test, when the token encountered is a single-quoted string.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
* @param string $sglQtString The single-quoted string content,
* i.e. without quotes.
*
* @return void
*/
protected function processSingleQuotedString (File $phpcsFile, $stackPtr, $sglQtString)
{
$variableFound = FALSE;
$strTokens = token_get_all('<?php '.$sglQtString);
$strPtr = 1; // skip php opening tag added by ourselves
while ($strPtr < count($strTokens)) {
$strToken = $strTokens[$strPtr];
if (is_array($strToken)) {
if (T_VARIABLE === $strToken[0]) {
$error = "Variables like {$strToken[1]} should be in double-quoted strings only.";
$phpcsFile->addError($error, $stackPtr);
}
}
$strPtr++;
}
return $variableFound;
}//end processSingleQuotedString()
/**
* Grammar rule to parse the use of a variable. Please notice that it
* doesn't manage the leading $.
*
* _parseVariable ::= <variable>
* | <variable>_parseObjectAttribute()
* | <variable>_parseArrayIndexes()
*
* @exception Exception raised if $strTokens starting from $strPtr
* doesn't matched the rule.
*
* @param array $strTokens Tokens to parse.
* @param int $strPtr Pointer to the token where parsing starts.
*
* @return array The attribute name associated to index 'var', an array with
* indexes 'obj' and 'attr' or an array with indexes 'arr' and 'idx'.
*/
private function _parseVariable ($strTokens, &$strPtr)
{
if ( ! in_array($strTokens[$strPtr][0], array(T_VARIABLE, T_STRING_VARNAME))) {
throw new Exception ('Expected variable name.');
}
$var = $strTokens[$strPtr][1];
$strPtr++;
$startStrPtr = $strPtr;
try {
$attr = $this->_parseObjectAttribute($strTokens, $strPtr);
return array ('obj' => $var, 'attr' => $attr);
} catch (Exception $err) {
if ($strPtr !== $startStrPtr) {
throw $err;
}
}
try {
$idx = $this->_parseArrayIndexes($strTokens, $strPtr);
return array ('arr' => $var, 'idx' => $idx);
} catch (Exception $err) {
if ($strPtr !== $startStrPtr) {
throw $err;
}
}
return array ('var' => $var);
}//end _parseVariable()
/**
* Grammar rule to parse the use of an object attribute.
*
* _parseObjectAttribute ::= -><attribute>
* | -><attribute>_parseObjectAttribute()
* | -><attribute>_parseArrayIndexes()
*
* @exception Exception raised if $strTokens starting from $strPtr
* doesn't matched the rule.
*
* @param array $strTokens Tokens to parse.
* @param int $strPtr Pointer to the token where parsing starts.
*
* @return mixed The attribute name as a string, an array with indexes
* 'obj' and 'attr' or an array with indexes 'arr' and 'idx'.
*/
private function _parseObjectAttribute ($strTokens, &$strPtr)
{
if (T_OBJECT_OPERATOR !== $strTokens[$strPtr][0]) {
throw new Exception ('Expected ->.');
}
$strPtr++;
if (T_STRING !== $strTokens[$strPtr][0]) {
throw new Exception ('Expected an object attribute.');
}
$attr = $strTokens[$strPtr][1];
$strPtr++;
$startStrPtr = $strPtr;
try {
$sub_attr = $this->_parseObjectAttribute($strTokens, $strPtr);
return array ('obj' => $attr, 'attr' => $sub_attr);
} catch (Exception $err) {
if ($strPtr !== $startStrPtr) {
throw $err;
}
}
try {
$idx = $this->_parseArrayIndexes($strTokens, $strPtr);
return array ('arr' => $attr, 'idx' => $idx);
} catch (Exception $err) {
if ($strPtr !== $startStrPtr) {
throw $err;
}
}
return $attr;
}//end _parseObjectAttribute()
/**
* Grammar rule to parse the use of one or more array indexes.
*
* _parseArrayIndexes ::= _parseArrayIndex()+
*
* @exception Exception raised if $strTokens starting from $strPtr
* doesn't matched the rule.
*
* @param array $strTokens Tokens to parse.
* @param int $strPtr Pointer to the token where parsing starts.
*
* @return array Indexes in the same order as in the string.
*/
private function _parseArrayIndexes ($strTokens, &$strPtr)
{
$indexes = array($this->_parseArrayIndex($strTokens, $strPtr));
try {
while (1) {
$startStrPtr = $strPtr;
$indexes [] = $this->_parseArrayIndex($strTokens, $strPtr);
}
} catch (Exception $err) {
if (0 !== ($strPtr - $startStrPtr)) {
throw $err;
}
return $indexes;
}
}//end _parseArrayIndexes()
/**
* Grammar rule to parse the use of array index.
*
* _parseArrayIndex ::= [<index>]
*
* @exception Exception raised if $strTokens starting from $strPtr
* doesn't matched the rule.
*
* @param array $strTokens Tokens to parse.
* @param int $strPtr Pointer to the token where parsing starts.
*
* @return string Index between the 2 square brackets
*/
private function _parseArrayIndex ($strTokens, &$strPtr)
{
if ('[' !== $strTokens[$strPtr]) {
throw new Exception ('Expected [.');
}
$strPtr++;
if (! in_array($strTokens[$strPtr][0], array(T_CONSTANT_ENCAPSED_STRING, T_LNUMBER))) {
throw new Exception ('Expected an array index.');
}
$index = $strTokens[$strPtr][1];
$strPtr++;
if (']' !== $strTokens[$strPtr]) {
throw new Exception ('Expected ].');
}
$strPtr++;
return $index;
}//end _parseArrayIndex()
}//end class
/**
* CodeIgniter_Sniffs_Strings_VariableUsageSniff.
*
* Ensures that variables parsed in double-quoted strings are enclosed with
* braces to prevent greedy token parsing.
* Single-quoted strings don't parse variables, so there is no risk of greedy
* token parsing.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2011 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class DoubleQuoteUsageSniff extends VariableUsageSniff
{
/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
return array(
T_DOUBLE_QUOTED_STRING,
T_CONSTANT_ENCAPSED_STRING,
);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(File $phpcsFile, $stackPtr)
{
// no variable are in the string from here
$tokens = $phpcsFile->getTokens();
$qtString = $tokens[$stackPtr]['content'];
// makes sure that it is about a double quote string,
// since variables are not parsed out of double quoted string
$open_qt_str = substr($qtString, 0, 1);
// clean the enclosing quotes
$qtString = substr($qtString, 1, strlen($qtString) - 1 - 1);
if (0 === strcmp($open_qt_str, '"')) {
$this->processDoubleQuotedString($phpcsFile, $stackPtr, $qtString);
} else if (0 === strcmp($open_qt_str, "'")) {
$this->processSingleQuotedString($phpcsFile, $stackPtr, $qtString);
}
}//end process()
/**
* Processes this test, when the token encountered is a double-quoted string.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
* @param string $qtString The double-quoted string content,
* i.e. without quotes.
*
* @return void
*/
protected function processDoubleQuotedString (File $phpcsFile, $stackPtr, $qtString)
{
// so there should be at least a single quote or a special char
// if there are the 2 kinds of quote and no special char, then add a warning
$has_variable = parent::processDoubleQuotedString($phpcsFile, $stackPtr, '"'.$qtString.'"');
$has_specific_sequence = $this->_hasSpecificSequence($qtString);
$dbl_qt_at = strpos($qtString, '"');
$smpl_qt_at = strpos($qtString, "'");
if (false === $has_variable && false === $has_specific_sequence
&& false === $smpl_qt_at
) {
$error = 'Single-quoted strings should be used unless it contains variables, special chars like \n or single quotes.';
$phpcsFile->addError($error, $stackPtr, 111);
} else if (false !== $smpl_qt_at && false !== $dbl_qt_at
&& false === $has_variable && false === $has_specific_sequence
) {
$warning = 'It is encouraged to use a single-quoted string, since it doesn\'t contain any variable nor special char though it mixes single and double quotes.';
$phpcsFile->addWarning($warning, $stackPtr, 222);
}
}//end processDoubleQuotedString()
/**
* Processes this test, when the token encountered is a single-quoted string.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
* @param string $qtString The single-quoted string content,
* i.e. without quotes.
*
* @return void
*/
protected function processSingleQuotedString (File $phpcsFile, $stackPtr, $qtString)
{
// if there is single quotes without additional double quotes,
// then user is allowed to use double quote to avoid having to
// escape single quotes. Don't add the warning, if an error was
// already added, because a variable was found in a single-quoted
// string.
$has_variable = parent::processSingleQuotedString($phpcsFile, $stackPtr, "'".$qtString."'");
$dbl_qt_at = strpos($qtString, '"');
$smpl_qt_at = strpos($qtString, "'");
if (false === $has_variable && false !== $smpl_qt_at && false === $dbl_qt_at) {
$warning = 'You may also use double-quoted strings if the string contains single quotes, so you do not have to use escape characters.';
$phpcsFile->addWarning($warning, $stackPtr, 333);
}
}//end processSingleQuotedString()
/**
* Return TRUE, if a sequence of chars that is parsed in a specific way
* in double-quoted strings is found, FALSE otherwise.
*
* @param string $string String in which sequence of special chars will
* be researched.
*
* @return TRUE, if a sequence of chars that is parsed in a specific way
* in double-quoted strings is found, FALSE otherwise.
*
* @link http://www.php.net/manual/en/language.types.string.php#language.types.string.syntax.double
*/
private function _hasSpecificSequence($string)
{
$hasSpecificSequence = FALSE;
$specialMeaningStrs = array('\n', '\r', '\t', '\v', '\f');
foreach ($specialMeaningStrs as $splStr) {
if (FALSE !== strpos($string, $splStr)) {
$hasSpecificSequence = TRUE;
}
}
$specialMeaningPtrns = array('\[0-7]{1,3}', '\x[0-9A-Fa-f]{1,2}');
foreach ($specialMeaningPtrns as $splPtrn) {
if (1 === preg_match("/{$splPtrn}/", $string)) {
$hasSpecificSequence = TRUE;
}
}
return $hasSpecificSequence;
}//end _hasSpecificSequence()
}//end class
?>

View File

@ -1,87 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_WhiteSpace_DisallowSpaceIndentSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@gmail.com>
* @copyright 2011 Thomas ERNEST
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* CodeIgniter_Sniffs_WhiteSpace_DisallowSpaceIndentSniff.
*
* Ensures the use of tabs for indentation.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@gmail.com>
* @copyright 2011 Thomas ERNEST
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\WhiteSpace;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
class DisallowSpaceIndentSniff implements Sniff
{
/**
* A list of tokenizers this sniff supports.
*
* @var array
*/
public $supportedTokenizers = array(
'PHP',
'JS',
'CSS',
);
/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
return array(T_WHITESPACE);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param File $phpcsFile All the tokens found in the document.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
// Make sure this is whitespace used for indentation.
$line = $tokens[$stackPtr]['line'];
if ($stackPtr > 0 && $tokens[($stackPtr - 1)]['line'] === $line) {
return;
}
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, 'SpacesUsedForIndentation');
}
}//end process()
}//end class
?>

View File

@ -1,95 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_WhiteSpace_DisallowWitheSpaceAroundPhpTagsSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* CodeIgniter_Sniffs_WhiteSpace_DisallowWitheSpaceAroundPhpTagsSniff.
*
* Ensures that no whitespace precedes the opening PHP tag
* or follows the closing PHP tag.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\WhiteSpace;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
class DisallowWitheSpaceAroundPhpTagsSniff implements Sniff
{
/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
return array(
T_OPEN_TAG,
T_CLOSE_TAG
);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$php_tag_token = $tokens[$stackPtr];
$php_tag_code = $php_tag_token['code'];
if (T_OPEN_TAG === $php_tag_code) {
// opening php tag should be the first token.
// any whitespace beofre an opening php tag is tokenized
// as T_INLINE_HTML, so no need to check the content of the token.
$isFirst = 0 === $stackPtr;
if ( ! $isFirst) {
$error = 'Any char before the opening PHP tag is prohibited. Please remove newline or indentation before the opening PHP tag.';
$phpcsFile->addError($error, $stackPtr);
}
} else {
// if (T_CLOSE_TAG === $php_tag_code)
// closing php tag should be the last token
// and it must not contain any whitespace.
$php_tag_string = $php_tag_token['content'];
$isLast = count($tokens) - 1 === $stackPtr;
// both of the two closing php tags contains 2 chars exactly.
$containsEndTagOnly = strlen($php_tag_string) > 2;
if ( ! $isLast || ! $containsEndTagOnly ) {
$error = 'Any char after the closing PHP tag is prohibited. Please removes newline or spaces after the closing PHP tag.';
$phpcsFile->addError($error, $stackPtr);
}
}
}//end process()
}//end class
?>

View File

@ -1,82 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_WhiteSpace_ElseOnNewLineSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* CodeIgniter_Sniffs_WhiteSpace_ElseOnNewLineSniff.
*
* Ensures that control structures else and elseif stand on new lines.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\WhiteSpace;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
class ElseOnNewLineSniff implements Sniff
{
/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
return array(
T_ELSE,
T_ELSEIF,
);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$else_token = $tokens[$stackPtr];
$previous_non_blank_token_ptr = $phpcsFile->findPrevious(array(T_WHITESPACE), $stackPtr - 1, null, true);
if (false === $previous_non_blank_token_ptr) {
// else is no preceded with any symbol, but it is not the responsibility of this sniff.
return;
}
$previous_non_blank_token = $tokens[$previous_non_blank_token_ptr];
if ($previous_non_blank_token['line'] === $else_token['line']) {
$error = '"' . $else_token['content'] . '" should be on a new line.';
$phpcsFile->addError($error, $stackPtr, 123423);
}
}//end process()
}//end class
?>

View File

@ -1,75 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_WhiteSpace_LogicalNotSpacingSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* CodeIgniter_Sniffs_WhiteSpace_LogicalNotSpacingSniff.
*
* Ensures that at exactly a space precedes and follows the logical operator !.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\WhiteSpace;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
class LogicalNotSpacingSniff implements Sniff
{
/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
return array(
T_BOOLEAN_NOT,
);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$operator_token = $tokens[$stackPtr];
$previous_token = $tokens[$stackPtr - 1];
$next_token = $tokens[$stackPtr + 1];
if (T_WHITESPACE !== $previous_token['code'] || T_WHITESPACE !== $next_token['code']) {
$error = 'Logical operator ! should always be preceded and followed with a whitespace.';
$phpcsFile->addError($error, $stackPtr, 'badNot');
}
}//end process()
}//end class
?>

View File

@ -1,104 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Files_AbstractClosingCommentSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* CodeIgniter_Sniffs_Files_AbstractClosingCommentSniff.
*
* Defines some methods used by
* CodeIgniter_Sniffs_Files_ClosingFileCommentSniff
* and CodeIgniter_Sniffs_Files_ClosingLocationCommentSniff.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\Files;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
class AbstractClosingCommentSniff implements Sniff
{
/**
* As an abstract class, this sniff is not associated to any token.
*/
public function register()
{
return array();
}
/**
* As an abstract class, this sniff is not dedicated to process a token.
*/
public function process(File $phpcsFile, $stackPtr)
{
$error = __CLASS__.'::'.__METHOD__.' is abstract. Please develop this method in a child class.';
throw new PHP_CodeSniffer_Exception($error);
}
/**
* Returns the comment without its delimiter(s) as well as leading
* and traling whitespaces.
*
* It removes the first #, the two first / (i.e. //) or the first /*
* and last \*\/. If a comment starts with /**, then the last * will remain
* as well as whitespaces between this star and the comment content.
*
* @param string $comment Comment containing either comment delimiter(s) and
* trailing or leading whitspaces to clean.
*
* @return string Comment without comment delimiter(s) and whitespaces.
*/
protected static function _getCommentContent ($comment)
{
if (self::_stringStartsWith($comment, '#')) {
$comment = substr($comment, 1);
} else if (self::_stringStartsWith($comment, '//')) {
$comment = substr($comment, 2);
} else if (self::_stringStartsWith($comment, '/*')) {
$comment = substr($comment, 2, strlen($comment) - 2 - 2);
}
$comment = trim($comment);
return $comment;
}//_getCommentContent()
/**
* Binary safe string comparison between $needle and
* the beginning of $haystack. Returns true if $haystack starts with
* $needle, false otherwise.
*
* @param string $haystack The string to search in.
* @param string $needle The string to search for.
*
* @return bool true if $haystack starts with $needle, false otherwise.
*/
protected static function _stringStartsWith ($haystack, $needle)
{
$startsWith = false;
if (strlen($needle) <= strlen($haystack)) {
$haystackBeginning = substr($haystack, 0, strlen($needle));
if (0 === strcmp($haystackBeginning, $needle)) {
$startsWith = true;
}
}
return $startsWith;
}//_stringStartsWith()
}//end class
?>

View File

@ -1,109 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Files_ClosingFileCommentSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* CodeIgniter_Sniffs_Files_ClosingFileCommentSniff.
*
* Ensures that a comment containing the file name is available at the end of file.
* Only other comments and whitespaces are allowed to follow this specific comment.
*
* It may be all kind of comment like multi-line and inline C-style comments as
* well as PERL-style comments. Any number of white may separate comment delimiters
* from comment content. However, content has to be equal to template
* "End of file <file_name>". Comparison between content and template is
* case-sensitive.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\Files;
use PHP_CodeSniffer\Files\File;
class ClosingFileCommentSniff extends AbstractClosingCommentSniff
{
/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
return array(
T_OPEN_TAG,
);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(File $phpcsFile, $stackPtr)
{
// We are only interested if this is the first open tag.
if ($stackPtr !== 0) {
if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) {
return;
}
}
$fullFilename = $phpcsFile->getFilename();
$filename = basename($fullFilename);
$commentTemplate = "End of file $filename";
$tokens = $phpcsFile->getTokens();
$currentToken = count($tokens) - 1;
$hasClosingFileComment = false;
$isNotAWhitespaceOrAComment = false;
while ($currentToken >= 0
&& ! $isNotAWhitespaceOrAComment
&& ! $hasClosingFileComment
) {
$token = $tokens[$currentToken];
$tokenCode = $token['code'];
if (T_COMMENT === $tokenCode) {
$commentString = self::_getCommentContent($token['content']);
if (0 === strcmp($commentString, $commentTemplate)) {
$hasClosingFileComment = true;
}
} else if (T_WHITESPACE === $tokenCode) {
// Whitespaces are allowed between the closing file comment,
// other comments and end of file
} else {
$isNotAWhitespaceOrAComment = true;
}
$currentToken--;
}
if ( ! $hasClosingFileComment) {
$error = 'No comment block marks the end of file instead of the closing PHP tag. Please add a comment block containing only "' . $commentTemplate . '".';
$phpcsFile->addError($error, $currentToken);
}
}//end process()
}//end class
?>

View File

@ -1,182 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_Files_ClosingLocationCommentSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* CodeIgniter_Sniffs_Files_ClosingLocationCommentSniff.
*
* Ensures that a comment containing the file location exists at the end of file.
* Only other comments and whitespaces are allowed between this comment and
* the end of file.
*
* It may be all kind of comment like multi-line and inline C-style comments as
* well as PERL-style comments. Any number of white may separate comment delimiters
* from comment content. However, content has to be equal to template
* "Location: <file_path_relative_to_application_root>".
* Comparison between content and template is case-sensitive.
*
* There are several ways to configure the application root. In order of priority :
* - Configuration variable ci_application_root.
* - Rule property applicationRoot.
* - Default value '/application/'
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2006 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\Files;
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Util\Common;
class ClosingLocationCommentSniff extends AbstractClosingCommentSniff
{
public $applicationRoot = '/application/';
/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
return array(
T_OPEN_TAG
);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(File $phpcsFile, $stackPtr)
{
// We are only interested if this is the first open tag.
if ($stackPtr !== 0) {
if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) {
return;
}
}
$filePath = $phpcsFile->getFilename();
$tokens = $phpcsFile->getTokens();
// removes the application root from the beginning of the file path
$locationPath = self::_getLocationPath($filePath, $this->_getAppRoot());
// add an error, if application root doesn't exist in current file path
if (false === $locationPath) {
$error = 'Unable to find "' . $this->_getAppRoot() . '" in file path "' . $filePath . '". Please set your project\'s application root.';
$phpcsFile->addError($error, count($tokens) - 1);
return;
}
// generates the expected comment
$commentTemplate = "Location: $locationPath";
$currentToken = count($tokens) - 1;
$hasClosingLocationComment = false;
$isNotAWhitespaceOrAComment = false;
while ($currentToken >= 0
&& ! $isNotAWhitespaceOrAComment
&& ! $hasClosingLocationComment
) {
$token = $tokens[$currentToken];
$tokenCode = $token['code'];
if (T_COMMENT === $tokenCode) {
$commentString = self::_getCommentContent($token['content']);
if (0 === strcmp($commentString, $commentTemplate)) {
$hasClosingLocationComment = true;
}
} else if (T_WHITESPACE === $tokenCode) {
// Whitespaces are allowed between the closing file comment,
//other comments and end of file
} else {
$isNotAWhitespaceOrAComment = true;
}
$currentToken--;
}
if ( ! $hasClosingLocationComment) {
$error = 'No comment block marks the end of file instead of the closing PHP tag. Please add a comment block containing only "' . $commentTemplate . '".';
$phpcsFile->addError($error, $currentToken);
}
}//end process()
/**
* Returns the relative path from $appRoot to $filePath, or false if
* $appRoot cannot be found in $filePath, because $appRoot is not a parent
* of $filePath.
*
* @param string $filePath Full path to the file being proceed.
* @param string $appRoot Partial or full path to the CodeIgniter
* application root of the file being proceed. It must not contain the
* full path to the application root, but at least the name of the
* application root. Parent directory of the application root are allowed
* but not mandatory.
*
* @return string|bool The relative path from $appRoot to $filePath, or
* false if $appRoot cannot be found in $filePath.
*/
private static function _getLocationPath ($filePath, $appRoot)
{
// removes the path to application root
// from the beginning of the file path
$appRootAt = strpos($filePath, $appRoot);
if (false === $appRootAt) {
return false;
}
$localPath = substr($filePath, $appRootAt + strlen($appRoot));
// ensures the location path to be a relative path starting with "./".
if ( ! self::_stringStartsWith($localPath, './')) {
$localPath = './' . $localPath;
} else if ( ! self::_stringStartsWith($localPath, '.')
&& self::_stringStartsWith($localPath, '/')
) {
$localPath = '.' . $localPath;
}
return $localPath;
}//end _getLocationPath()
/**
* Returns the application root that should be used first.
*
* There are several ways to configure the application root.
* In order of priority :
* - Configuration variable ci_application_root.
* - Rule property applicationRoot.
* - Default value '/application/'
*
* @return string Path to your project application root.
*/
private function _getAppRoot()
{
$appRoot = Common::getConfigData('ci_application_root');
if (null === $appRoot) {
$appRoot = $this->applicationRoot;
}
return $appRoot;
}//end _getAppRoot()
}//end class
?>

View File

@ -1,142 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_NamingConventions_ConstructorNameSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@gmail.com>
* @copyright 2011 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\NamingConventions;
use PHP_CodeSniffer\Sniffs\AbstractScopeSniff;
use PHP_CodeSniffer\Files\File;
/**
* CodeIgniter_Sniffs_NamingConventions_ConstructorNameSniff.
*
* Favor PHP 4 constructor syntax, which uses "function ClassName()".
* Avoid PHP 5 constructor syntax, which uses "function __construct()".
*
* @todo Try to avoid overly long and verbose names.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@gmail.com>
* @copyright 2010 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class ConstructorNameSniff extends AbstractScopeSniff
{
public $php5Constructors = '1';
/**
* Constructs the test with the tokens it wishes to listen for.
*
* @return void
*/
public function __construct()
{
parent::__construct(array(T_CLASS, T_INTERFACE), array(T_FUNCTION), true);
}//end __construct()
/**
* Processes this test when one of its tokens is encountered.
*
* @param File $phpcsFile The current file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
* @param int $currScope A pointer to the start of the scope.
*
* @return void
*/
protected function processTokenWithinScope(
File $phpcsFile,
$stackPtr,
$currScope
) {
$methodName = $phpcsFile->getDeclarationName($stackPtr);
$className = $phpcsFile->getDeclarationName($currScope);
$isPhp4Constructor = strcasecmp($methodName, $className) === 0;
$isPhp5Constructor = strcasecmp($methodName, '__construct') === 0;
if ($this->php5Constructors != '0') {
if ($isPhp4Constructor) {
$error = "PHP4 style constructors are not allowed; use \"__construct\" instead";
$phpcsFile->addError($error, $stackPtr);
}
} else {
if ($isPhp5Constructor) {
$error = "PHP5 style constructors are not allowed; use \"$className\" instead";
$phpcsFile->addError($error, $stackPtr);
}
}
if ( ! $isPhp4Constructor && ! $isPhp5Constructor ) {
return;
}
$tokens = $phpcsFile->getTokens();
$parentClassName = $phpcsFile->findExtendedClassName($currScope);
$wrongConstructor = '';
// prepares the error message and wrong constructor
if ($this->php5Constructors != '0') {
$error = 'PHP4 style calls to parent constructors are not allowed.';
$error = "$error Please use \"parent::__construct\" instead.";
if (false !== $parentClassName) {
$wrongConstructor = $parentClassName;
}
// Else $wrongConstructor will be empty
// and the test expression will always be false.
// It doesn't check that no parent method should be called
// when no parent class is defined.
} else {
$error = 'PHP5 style calls to parent constructors are not allowed.';
if (false !== $parentClassName) {
$error = "$error Please use \"parent::$parentClassName\" instead.";
}
$wrongConstructor = '__construct';
}
// looks for the use of a wrong constructor.
$endFunctionIndex = $tokens[$stackPtr]['scope_closer'];
$doubleColonIndex = $phpcsFile->findNext(
array(T_DOUBLE_COLON),
$stackPtr,
$endFunctionIndex
);
while ($doubleColonIndex) {
if ($tokens[($doubleColonIndex + 1)]['code'] === T_STRING
&& $tokens[($doubleColonIndex + 1)]['content'] === $wrongConstructor
) {
$phpcsFile->addError($error, ($doubleColonIndex + 1));
}
$doubleColonIndex = $phpcsFile->findNext(
array(T_DOUBLE_COLON),
$doubleColonIndex + 1,
$endFunctionIndex
);
}
}//end processTokenWithinScope()
protected function processTokenOutsideScope(File $phpcsFile, $stackPtr)
{
// TODO: Implement processTokenOutsideScope() method.
}
}//end class
?>

View File

@ -1,84 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_NamingConventions_ValidClassNameSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baoabz.com>
* @copyright 2010 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* CodeIgniter_Sniffs_NamingConventions_ValidClassNameSniff.
*
* Ensures that class and interface names have their first letter uppercase
* and that words are separated with an underscore, and not CamelCased.
*
* @todo Try to avoid overly long and verbose names in using property rule and
* configuration variable to set limits. Have a look at
* CodeIgniter_Sniffs_NamingConventions_ValidMethodNameSniff.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baoabz.com>
* @copyright 2010 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\NamingConventions;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
class ValidClassNameSniff implements Sniff
{
/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
return array(
T_CLASS,
T_INTERFACE,
);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param File $phpcsFile The current file being processed.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(File $phpcsFile, $stackPtr)
{
// get the class name
$className = trim($phpcsFile->getDeclarationName($stackPtr));
// compute the expected class name
// [^_] means "something different from _", but not "nothing or something different from _"
$lcClassNameChunk = preg_replace('/([^_])([A-Z])/', '${1}_${2}', $className);
$expectedClassName
= strtoupper($className[0]) . strtolower(substr($lcClassNameChunk,1));
// ensures that the current class name
// and the expected class name are identical
if (0 !== strcmp($className, $expectedClassName)) {
$error = 'Class names should always have their first letter uppercase. Multiple words should be separated with an underscore, and not CamelCased. Please consider ' . $expectedClassName . ' instead of ' . $className . '.';
$phpcsFile->addError($error, $stackPtr);
}
}//end process()
}//end class
?>

View File

@ -1,84 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_NamingConventions_ValidFileNameSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2011 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* CodeIgniter_Sniffs_NamingConventions_ValidFileNameSniff.
*
* Tests that the file name matchs the name of the class that it contains in lower case.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baobaz.com>
* @copyright 2011 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\NamingConventions;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
class ValidFileNameSniff implements Sniff
{
/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
return array(
T_CLASS,
T_INTERFACE,
);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token in the
* stack passed in $tokens.
*
* @return void
*/
public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
// computes the expected filename based on the name of the class or interface that it contains.
$decNamePtr = $phpcsFile->findNext(T_STRING, $stackPtr);
$decName = $tokens[$decNamePtr]['content'];
$expectedFileName = strtolower($decName);
// extracts filename without extension from its path.
$fullPath = $phpcsFile->getFilename();
$fileNameAndExt = basename($fullPath);
$fileName = substr($fileNameAndExt, 0, strrpos($fileNameAndExt, '.'));
if ($expectedFileName !== $fileName) {
$errorTemplate = 'Filename "%s" doesn\'t match the name of the %s that it contains "%s" in lower case. "%s" was expected.';
$errorMessage = sprintf(
$errorTemplate,
$fileName,
strtolower($tokens[$stackPtr]['content']), // class or interface
$decName,
$expectedFileName
);
$phpcsFile->addError($errorMessage, 0);
}
}//end process()
}//end class
?>

View File

@ -1,161 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_NamingConventions_ValidMethodNameSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baoabz.com>
* @copyright 2010 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* CodeIgniter_Sniffs_NamingConventions_ValidMethodNameSniff.
*
* Ensures that class methods and functions areentirely lowercased and that
* words are separated with an underscore, and not CamelCased.
* Ensures that private class methods are prefixed with an underscore and that
* all other methods are not prefixed with an underscored.
* Ensures that names longer than 50 chars are prohibited. Likewise names longer
* than 35 chars raise a warning.
*
* @todo Use a rule property or a configuration variable to allow users to set
* their own maximum lengths for function and method names. Have a look at
* CodeIgniter_Sniffs_Files_ClosingLocationCommentSniff and application root.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baoabz.com>
* @copyright 2010 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\NamingConventions;
use PHP_CodeSniffer\Sniffs\AbstactScopeSniff;
use PHP_CodeSniffer\Files\File;
class ValidMethodNameSniff extends AbstractScopeSniff
{
/**
* A list of all PHP magic methods.
*
* @var array
*/
protected static $magicMethods = array(
'construct',
'destruct',
'call',
'callStatic',
'get',
'set',
'isset',
'unset',
'sleep',
'wakeup',
'toString',
'set_state',
'clone',
);
/**
* Defines which token(s) in which scope(s) will be proceed.
*/
public function __construct()
{
parent::__construct(array(T_CLASS, T_INTERFACE), array(T_FUNCTION), true);
}//end __construct()
/**
* Processes the tokens within the scope.
*
* @param File $phpcsFile The file being processed.
* @param int $stackPtr The position where this token was
* found.
* @param int $currScope The position of the current scope.
*
* @return void
*/
protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScope)
{
$methodName = $phpcsFile->getDeclarationName($stackPtr);
if ($methodName === null) {
// Ignore closures.
return;
}
$className = $phpcsFile->getDeclarationName($currScope);
// Is this a magic method i.e. is prefixed with "__".
if (0 === strcmp(substr($methodName, 0, 2), '__')) {
$magicPart = substr($methodName, 2);
if (in_array($magicPart, self::$magicMethods) === false) {
$error = "Method name \"$className::$methodName\" is invalid; only PHP magic methods should be prefixed with a double underscore";
$phpcsFile->addError($error, $stackPtr);
}
return;
}
// PHP4 constructors are allowed to break our rules.
if ($methodName === $className) {
return;
}
// PHP4 destructors are allowed to break our rules.
if ($methodName === '_'.$className) {
return;
}
if (0 !== strcmp($methodName, strtolower($methodName))) {
$uscrdMethodName = preg_replace('/([A-Z])/', '_${1}', $methodName);
$expectedMethodName = strtolower($uscrdMethodName);
$error = "Class methods should be entirely lowercased. Please consider \"$expectedMethodName\" instead of \"$methodName\".";
$phpcsFile->addError($error, $stackPtr);
return;
}
$methodProps = $phpcsFile->getMethodProperties($stackPtr);
$scope = $methodProps['scope'];
$scopeSpecified = $methodProps['scope_specified'];
// If it's a private method, it must have an underscore on the front.
if ($scope === 'private' && $methodName{0} !== '_') {
$error = "Private method name \"$className::$methodName\" must be prefixed with an underscore";
$phpcsFile->addError($error, $stackPtr);
return;
}
// If it's not a private method, it must not have an underscore on the front.
if ($scope !== 'private' && $methodName{0} === '_') {
if (true === $scopeSpecified) {
$error = "Public method name \"$className::$methodName\" must not be prefixed with an underscore";
} else {
$error = ucfirst($scope)." method name \"$className::$methodName\" must not be prefixed with an underscore";
}
$phpcsFile->addError($error, $stackPtr);
return;
}
// If name is too verbose,
// then either an error or a warning is displayed.
$error_limit = 50;
$warning_limit = 35;
if (strlen($methodName) > $error_limit) {
$error = "Overly long and verbose names are prohibited. Please find a name shorter than $error_limit chars.";
$phpcsFile->addError($error, $stackPtr);
return;
} else if (strlen($methodName) > $warning_limit) {
$warning = "Try to avoid overly long and verbose names in finding a name shorter than $warning_limit chars.";
$phpcsFile->addWarning($warning, $stackPtr);
}
}//end processTokenWithinScope()
}//end class
?>

View File

@ -1,562 +0,0 @@
<?php
/**
* CodeIgniter_Sniffs_NamingConventions_ValidVariableNameSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baoabz.com>
* @copyright 2010 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* CodeIgniter_Sniffs_NamingConventions_ValidVariableNameSniff.
*
* Ensures that variable names contain only lowercase letters,
* use underscore separators.
* Ensures that class attribute names are prefixed with an underscore,
* only when they are private.
* Ensure that variable names are longer than 3 chars except those declared
* in for loops.
*
* @todo Try to avoid overly long and verbose names in using property rule and
* configuration variable to set limits. Have a look at
* CodeIgniter_Sniffs_NamingConventions_ValidMethodNameSniff.
* @todo Use a property rule or a configuration variable to allow users to set
* minimum variable name length. Have a look at
* CodeIgniter_Sniffs_Files_ClosingLocationCommentSniff and application root.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Thomas Ernest <thomas.ernest@baoabz.com>
* @copyright 2010 Thomas Ernest
* @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
namespace CodeIgniter\Sniffs\NamingConventions;
use PHP_CodeSniffer\Sniffs\AbstractVariableSniff;
use PHP_CodeSniffer\Files\File;
class ValidVariableNameSniff extends AbstractVariableSniff
{
/**
* Processes class member variables.
*
* @param File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
protected function processMemberVar(File $phpcsFile, $stackPtr)
{
// get variable name and properties
$tokens = $phpcsFile->getTokens();
$varTk = $tokens[$stackPtr];
$varName = substr($varTk['content'], 1);
$varProps = $phpcsFile->getMemberProperties($stackPtr);
// check(s)
if ( ! $this->checkLowerCase($phpcsFile, $stackPtr, $varName) ) {
return;
}
if ( ! $this->checkVisibilityPrefix($phpcsFile, $stackPtr, $varName, $varProps)) {
return;
}
if ( ! $this->checkLength($phpcsFile, $stackPtr, $varName)) {
return;
}
}//end processMemberVar()
/**
* Processes normal variables.
*
* @param File $phpcsFile The file where this token was found.
* @param int $stackPtr The position where the token was found.
*
* @return void
*/
protected function processVariable(File $phpcsFile, $stackPtr)
{
// get variable name
$tokens = $phpcsFile->getTokens();
$varTk = $tokens[$stackPtr];
$varName = substr($varTk['content'], 1);
// skip the current object variable, i.e. $this
if (0 === strcmp($varName, 'this')) {
return;
}
// check(s)
if ( ! $this->checkLowerCase($phpcsFile, $stackPtr, $varName)) {
return;
}
if ( ! $this->checkLength($phpcsFile, $stackPtr, $varName)) {
return;
}
}//end processVariable()
/**
* Processes variables in double quoted strings.
*
* @param File $phpcsFile The file where this token was found.
* @param int $stackPtr The position where the token was found.
*
* @return void
*/
protected function processVariableInString(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$stringTk = $tokens[$stackPtr];
$stringString = $stringTk['content'];
$varAt = self::_getVariablePosition($stringString, 0);
while (false !== $varAt) {
// get variable name
$matches = array();
preg_match('/^\$\{?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}?/', substr($stringString, $varAt), $matches);
$varName = $matches[1];
// check(s)
if ( ! $this->checkLowerCase($phpcsFile, $stackPtr, $varName)) {
return;
}
if ( ! $this->checkLength($phpcsFile, $stackPtr, $varName)) {
return;
}
// prepare checking next variable
$varAt = self::_getVariablePosition($stringString, $varAt + 1);
}
}//end processVariableInString()
/**
* Checks that the variable name is all in lower case, else it add an error
* to $phpcsFile. Returns true if variable name is all in lower case, false
* otherwise.
*
* @param File $phpcsFile The current file being processed.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
* @param string $varName The name of the variable to
* procced without $, { nor }.
*
* @return bool true if variable name is all in lower case, false otherwise.
*/
protected function checkLowerCase(File $phpcsFile, $stackPtr, $varName)
{
$isInLowerCase = true;
if (0 !== strcmp($varName, strtolower($varName))) {
// get the expected variable name
$varNameWithUnderscores = preg_replace('/([A-Z])/', '_${1}', $varName);
$expectedVarName = strtolower(ltrim($varNameWithUnderscores, '_'));
// adapts the error message to the error case
if (strlen($varNameWithUnderscores) > strlen($varName)) {
$error = 'Variables should not use CamelCasing or start with a Capital.';
} else {
$error = 'Variables should be entirely lowercased.';
}
$error = $error . 'Please consider "' . $expectedVarName
. '" instead of "' . $varName . '".';
// adds the error and changes return value
$phpcsFile->addError($error, $stackPtr);
$isInLowerCase = false;
}
return $isInLowerCase;
}//end checkLowerCase()
/**
* Checks that an underscore is used at the beginning of a variable only if
* it is about a private variable. If it isn't a private variable, then it
* must not be prefixed with an underscore. Returns true if $varName is
* properly prefixed according to the variable visibility provided in
* $varProps, false otherwise.
*
* @param File $phpcsFile The current file being processed.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
* @param string $varName The name of the variable to
* procced without $, { nor }.
* @param array $varProps Member variable properties like
* its visibility.
*
* @return bool true if variable name is prefixed with an underscore only
* when it is about a private variable, false otherwise.
*/
protected function checkVisibilityPrefix(File $phpcsFile, $stackPtr, $varName, $varProps)
{
$isVisibilityPrefixRight = true;
$scope = $varProps['scope'];
// If it's a private variable, it must have an underscore on the front.
if ($scope === 'private' && $varName{0} !== '_') {
$error = "Private variable name \"$varName\" must be prefixed with an underscore";
$phpcsFile->addError($error, $stackPtr);
$isVisibilityPrefixRight = false;
} else if ($scope !== 'private' && $varName{0} === '_') {
// If it's not a private variable,
// then it must not start with an underscore.
if (isset ($scopeSpecified) && true === $scopeSpecified) {
$error = "Public variable name \"$varName\" must not be prefixed with an underscore";
} else {
$error = ucfirst($scope) . " variable name \"$varName\" must not be prefixed with an underscore";
}
$phpcsFile->addError($error, $stackPtr);
$isVisibilityPrefixRight = false;
}
return $isVisibilityPrefixRight;
}//end checkVisibilityPrefix()
/**
* Checks that variable name length is not too short. Returns true, if it
* meets minimum length requirement, false otherwise.
*
* A variable name is too short if it is shorter than the minimal
* length and it isn't in the list of allowed short names nor declared in a
* for loop (in which it would be nested).
* The minimal length is defined in the function. It is 3 chars now.
* The list of allowed short names is defined in the function.
* It is case-sensitive. It contains only 'ci' now.
*
* @param File $phpcsFile The current file being processed.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
* @param string $varName The name of the variable to
* procced without $, { nor }.
*
* @return bool false if variable name $varName is shorter than the minimal
* length and it isn't in the list of allowed short names nor declared in a
* for loop (in which it would be nested), otherwise true.
*/
protected function checkLength(File $phpcsFile, $stackPtr, $varName)
{
$minLength = 3;
$allowedShortName = array('ci');
$isLengthRight = true;
// cleans variable name
$varName = ltrim($varName, '_');
if (strlen($varName) <= $minLength) {
// skips adding an error, if it is a specific variable name
if (in_array($varName, $allowedShortName)) {
return $isLengthRight;
}
// skips adding an error, if the variable is in a for loop
if (false !== self::_isInForLoop($phpcsFile, $stackPtr, $varName)) {
return $isLengthRight;
}
// adds the error message finally
$error = 'Very short'
. (
$minLength > 0 ?
' (i.e. less than ' . ($minLength + 1) . ' chars)'
: ''
)
. ', non-word variables like "' . $varName
. '" should only be used as iterators in for() loops.';
$phpcsFile->addError($error, $stackPtr);
$isLengthRight = false;
}
return $isLengthRight;
}//end checkLength()
/**
* Returns the position of closest previous T_FOR, if token associated with
* $stackPtr in $phpcsFile is in a for loop, otherwise false.
*
* @param File $phpcsFile The current file being processed.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
* @param string $varName The name of the variable to
* procced without $, { nor }.
*
* @return int|bool Position of T_FOR if token associated with $stackPtr in
* $phpcsFile is in the head of a for loop, otherwise false.
*/
private static function _isInForLoop(File $phpcsFile, $stackPtr, $varName)
{
$keepLookingFromPtr = $stackPtr;
while (false !== $keepLookingFromPtr) {
// looks if it is in (head or body) of a for loop
$forPtr = self::_isInForLoopHead($phpcsFile, $keepLookingFromPtr);
if (false === $forPtr) {
$forPtr = self::_isInForLoopBody($phpcsFile, $keepLookingFromPtr);
}
// checks if it is declared in here and prepares next step
if (false !== $forPtr) {
if (false !== self::_isDeclaredInForLoop($phpcsFile, $forPtr, $varName)) {
return $forPtr;
}
$keepLookingFromPtr = $forPtr;
} else {
$keepLookingFromPtr = false;
}
}
return false;
}//end _isInForLoop()
/**
* Returns the position of closest previous T_FOR, if token associated with
* $stackPtr in $phpcsFile is in the head of a for loop, otherwise false.
* The head is the code placed between parenthesis next to the key word
* 'for' : for (<loop_head>) {<loop_body>}.
*
* @param File $phpcsFile The current file being processed.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return int|bool Position of T_FOR if token associated with $stackPtr in
* $phpcsFile is in the head of a for loop, otherwise false.
*/
private static function _isInForLoopHead(File $phpcsFile, $stackPtr)
{
$isInForLoop = false;
$tokens = $phpcsFile->getTokens();
$currentTk = $tokens[$stackPtr];
if (array_key_exists('nested_parenthesis', $currentTk)) {
$nestedParenthesis = $currentTk['nested_parenthesis'];
foreach ( $nestedParenthesis as $openParPtr => $closeParPtr) {
$nonWhitspacePtr = $phpcsFile->findPrevious(
array(T_WHITESPACE),
$openParPtr - 1,
null,
true,
null,
true
);
if (false !== $nonWhitspacePtr) {
$isFor = T_FOR === $tokens[$nonWhitspacePtr]['code'];
if ($isFor) {
$isInForLoop = $nonWhitspacePtr;
break;
}
}
}
}
return $isInForLoop;
}//end _isInForLoopHead()
/**
* Returns the position of closest previous T_FOR, if token associated with
* $stackPtr in $phpcsFile is in the body of a for loop, otherwise false.
* The body are the instructions placed after parenthesis of a 'for'
* declaration, enclosed with curly brackets usually.
* 'for' : for (<loop_head>) {<loop_body>}.
*
* @param File $phpcsFile The current file being processed.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return int|bool Position of T_FOR if token associated with $stackPtr in
* $phpcsFile is in the body of a for loop, otherwise false.
*/
private static function _isInForLoopBody(File $phpcsFile, $stackPtr)
{
$isInForLoop = false;
$tokens = $phpcsFile->getTokens();
// get englobing hierarchy
$parentPtrAndCode = $tokens[$stackPtr]['conditions'];
krsort($parentPtrAndCode);
// looks for a for loop having a body not enclosed with curly brackets,
// which involves that its body contains only one instruction.
if (is_array($parentPtrAndCode) && ! empty($parentPtrAndCode)) {
$parentCode = reset($parentPtrAndCode);
$parentPtr = key($parentPtrAndCode);
$openBracketPtr = $tokens[$parentPtr]['scope_opener'];
} else {
$parentCode = 0;
$parentPtr = 0;
$openBracketPtr = 0;
}
$openResearchScopePtr = $stackPtr;
// recursive search, since a for statement may englobe other inline
// control statement or may be near to function calls, etc...
while (false !== $openResearchScopePtr) {
$closeParPtr = $phpcsFile->findPrevious(
array(T_CLOSE_PARENTHESIS),
$openResearchScopePtr,
null,
false,
null,
true
);
// is there a closing parenthesis with a control statement before
// the previous instruction ?
if (false !== $closeParPtr) {
// is there no opening curly bracket specific to
// set of instructions, between the closing parenthesis
// and the current token ?
if ($openBracketPtr < $closeParPtr) {
// starts the search from the token before the closing
// parenthesis, if it isn't a for statement
$openResearchScopePtr = $closeParPtr - 1;
// is this parenthesis associated with a for statement ?
$closeParenthesisTk = $tokens[$closeParPtr];
if (array_key_exists('parenthesis_owner', $closeParenthesisTk)) {
$mayBeForPtr = $closeParenthesisTk['parenthesis_owner'];
$mayBeForTk = $tokens[$mayBeForPtr];
if (T_FOR === $mayBeForTk['code']) {
return $mayBeForPtr;
}
}
} else {
// if it is about a for loop, don't go further
// and detect it after one more loop execution, do it now
if (T_FOR === $parentCode) {
return $parentPtr;
}
// starts the search from the token before the one
// englobing the current statement
$openResearchScopePtr = $parentPtr - 1;
// re-initialize variables about the englobing structure
if (is_array($parentPtrAndCode)) {
$parentCode = next($parentPtrAndCode);
$parentPtr = key($parentPtrAndCode);
$openBracketPtr = $tokens[$parentPtr]['scope_opener'];
}
}
} else {
$openResearchScopePtr = false;
}
}
// looks for a for loop having a body enclosed with curly brackets
foreach ($parentPtrAndCode as $parentPtr => $parentCode) {
if (T_FOR === $parentCode) {
return $parentPtr;
}
}
return false;
}//end _isInForLoopBody()
/**
* Returns true if a variable declared in the head of the for loop pointed
* by $forPtr in file $phpcsFile has the name $varName.
*
* @param File $phpcsFile The current file being processed.
* @param int $forPtr The position of the 'for' token
* in the stack passed in $tokens.
* @param string $varName The name of the variable to
* procced without $, { nor }.
*
* @return int|bool true if a variable declared in the head of the for loop
* pointed by $forPtr in file $phpcsFile has the name $varName.
*/
private static function _isDeclaredInForLoop(File $phpcsFile, $forPtr, $varName)
{
$isDeclaredInFor = false;
$tokens = $phpcsFile->getTokens();
$forVarPtrs = self::_getVarDeclaredInFor($phpcsFile, $forPtr);
foreach ($forVarPtrs as $forVarPtr) {
$forVarTk = $tokens[$forVarPtr];
// get variable name
$matches = array();
preg_match('/^\$\{?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}?/', $forVarTk['content'], $matches);
$forVarName = $matches[1];
if (0 === strcmp($forVarName, $varName)) {
$isDeclaredInFor = $forVarPtr;
break;
}
}
return $isDeclaredInFor;
}//end _isDeclaredInForLoop()
/**
* Returns list of pointers to variables declared in for loop associated to
* $forPtr in file $phpcsFile.
*
* All pointers in the result list are pointing to token with code
* T_VARIABLE. An exception is raised, if $forPtr doesn't point a token with
* code T_FOR.
*
* @param File $phpcsFile The current file being processed.
* @param int $forPtr The position of the current token
* in the stack passed in $tokens.
*
* @return array List of pointers to variables declared in for loop $forPtr.
*/
private static function _getVarDeclaredInFor(File $phpcsFile, $forPtr)
{
$tokens = $phpcsFile->getTokens();
$forTk = $tokens[$forPtr];
if (T_FOR !== $forTk['code']) {
throw new PHP_CodeSniffer_Exception('$forPtr must be of type T_FOR');
}
$openParPtr = $forTk['parenthesis_opener'];
$openParenthesisTk = $tokens[$openParPtr];
$endOfDeclPtr = $phpcsFile->findNext(array(T_SEMICOLON), $openParPtr);
$forVarPtrs = array();
$varPtr = $phpcsFile->findNext(
array(T_VARIABLE),
$openParPtr + 1,
$endOfDeclPtr
);
while (false !== $varPtr) {
$forVarPtrs [] = $varPtr;
$varPtr = $phpcsFile->findNext(
array(T_VARIABLE),
$varPtr + 1,
$endOfDeclPtr
);
}
return $forVarPtrs;
}//end _getVarDeclaredInFor()
/**
* Returns the position of first occurrence of a PHP variable starting with
* $ in $haystack from $offset.
*
* @param string $haystack The string to search in.
* @param int $offset The optional offset parameter allows you to
* specify which character in haystack to start
* searching. The returned position is still
* relative to the beginning of haystack.
*
* @return mixed The position as an integer
* or the boolean false, if no variable is found.
*/
private static function _getVariablePosition($haystack, $offset = 0)
{
$var_starts_at = strpos($haystack, '$', $offset);
$is_a_var = false;
while (false !== $var_starts_at && ! $is_a_var) {
// makes sure that $ is used for a variable and not as a symbol,
// if $ is protected with the escape char, then it is a symbol.
if (0 !== strcmp($haystack[$var_starts_at - 1], '\\')) {
if (0 === strcmp($haystack[$var_starts_at + 1], '{')) {
// there is an opening brace in the right place
// so it looks for the closing brace in the right place
$hsChunk2 = substr($haystack, $var_starts_at + 2);
if (1 === preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\}/', $hsChunk2)) {
$is_a_var = true;
}
} else {
$hsChunk1 = substr($haystack, $var_starts_at + 1);
if (1 === preg_match('/^[a-zA-Z_\x7f-\xff]/', $hsChunk1)) {
// $ is used for a variable and not as a symbol,
// since what follows $ matchs the definition of
// a variable label for PHP.
$is_a_var = true;
}
}
}
// update $var_starts_at for the next variable
// only if no variable was found, since it is returned otherwise.
if ( ! $is_a_var) {
$var_starts_at = strpos($haystack, '$', $var_starts_at + 1);
}
}
if ($is_a_var) {
return $var_starts_at;
} else {
return false;
}
}//end _getVariablePosition()
}//end class
?>

View File

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ruleset name="CodeIgniter">
<description>CodeIgniter coding standard as described at http://codeigniter.com/user_guide/general/styleguide.html.</description>
<rule ref="Generic.Files.LineEndings">
<properties>
<property name="eolChar" value="\n"/>
</properties>
</rule>
<!-- PHP files should OMIT the closing PHP tag -->
<rule ref="Zend.Files.ClosingTag"/>
<!-- Always use full PHP opening tags -->
<rule ref="Generic.PHP.DisallowShortOpenTag"/>
<!-- Constants should always be fully uppercase -->
<rule ref="Generic.NamingConventions.UpperCaseConstantName"/>
<!-- TRUE, FALSE, and NULL keywords should always be fully uppercase -->
<rule ref="Generic.PHP.UpperCaseConstant"/>
<!-- One statement per line -->
<rule ref="Generic.Formatting.DisallowMultipleStatements"/>
<!-- Classes and functions should be commented -->
<rule ref="PEAR.Commenting.ClassComment"/>
<rule ref="PEAR.Commenting.FunctionComment"/>
<rule ref="Squiz.Commenting.FunctionCommentThrowTag"/>
<!-- Use warnings for docblock comments for files and variables, since nothing is cleary explained -->
<rule ref="PEAR.Commenting.FileComment">
<properties>
<property name="error" value="false"/>
</properties>
</rule>
<rule ref="Squiz.Commenting.VariableComment">
<properties>
<property name="error" value="false"/>
</properties>
</rule>
<!-- 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="Generic.Functions.FunctionCallArgumentSpacing"/>
<!-- @todo Please see PHP_CodeSniffer_Standards_CodeIgniter_CodeIgniterCodingStandard for more details about what there is to do -->
</ruleset>

View File

@ -1,12 +0,0 @@
#!/bin/bash
# We need to install dependencies only for Docker
[[ ! -e /.dockerenv ]] && [[ ! -e /.dockerinit ]] && exit 0
set -xe
# Install git (the php image doesn't have it) which is required by composer
echo -e 'http://dl-cdn.alpinelinux.org/alpine/edge/main\nhttp://dl-cdn.alpinelinux.org/alpine/edge/community\nhttp://dl-cdn.alpinelinux.org/alpine/edge/testing' > /etc/apk/repositories
apk add --no-cache \
curl \
git

View File

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

View File

@ -1,32 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
colors="true"
stopOnFailure="false"
bootstrap="../tests/bootstrap.php"
beStrictAboutTestsThatDoNotTestAnything="true"
>
<filter>
<whitelist>
<directory suffix=".php">../src</directory>
</whitelist>
</filter>
<testsuites>
<testsuite name="AnimeClient">
<directory>../tests</directory>
</testsuite>
</testsuites>
<logging>
<log type="coverage-html" target="../coverage"/>
<log type="coverage-clover" target="logs/clover.xml"/>
<log type="coverage-crap4j" target="logs/crap4j.xml"/>
<log type="coverage-xml" target="logs/coverage" />
<log type="junit" target="logs/junit.xml" logIncompleteSkipped="false"/>
</logging>
<php>
<server name="HTTP_USER_AGENT" value="Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:38.0) Gecko/20100101 Firefox/38.0" />
<server name="HTTP_HOST" value="localhost" />
<server name="SERVER_NAME" value="localhost" />
<server name="REQUEST_URI" value="/" />
<server name="REQUEST_METHOD" value="GET" />
</php>
</phpunit>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" colors="true" stopOnFailure="false" bootstrap="../tests/bootstrap.php" beStrictAboutTestsThatDoNotTestAnything="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.1/phpunit.xsd">
<coverage>
<report>
<clover outputFile="logs/clover.xml"/>
<html outputDirectory="../coverage"/>
</report>
</coverage>
<testsuites>
<testsuite name="AnimeClient">
<directory>../tests/AnimeClient</directory>
</testsuite>
<testsuite name="Ion">
<directory>../tests/Ion</directory>
</testsuite>
</testsuites>
<logging>
<junit outputFile="logs/junit.xml"/>
</logging>
<php>
<server name="HTTP_USER_AGENT" value="Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:38.0) Gecko/20100101 Firefox/38.0"/>
<server name="HTTP_HOST" value="localhost"/>
<server name="SERVER_NAME" value="localhost"/>
<server name="REQUEST_URI" value="/"/>
<server name="REQUEST_METHOD" value="GET"/>
</php>
<source>
<include>
<directory suffix=".php">../src</directory>
</include>
</source>
</phpunit>

View File

@ -1,94 +0,0 @@
<?php
declare(strict_types=1);
$file_patterns = [
'app/bootstrap.php',
'migrations/*.php',
'src/**/*.php',
'src/*.php',
'tests/**/*.php',
'tests/*.php',
'index.php',
'Robofile.php'
];
if ( ! function_exists('glob_recursive'))
{
// Does not support flag GLOB_BRACE
function glob_recursive($pattern, $flags = 0)
{
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern) . '/*', GLOB_ONLYDIR | GLOB_NOSORT) as $dir)
{
$files = array_merge($files, glob_recursive($dir . '/' . basename($pattern), $flags));
}
return $files;
}
}
function get_text_to_replace($tokens)
{
$output = '';
// Tokens have the follow structure if arrays:
// [0] => token type constant
// [1] => raw sytax parsed to that token
// [2] => line number
foreach($tokens as $token)
{
// Since we only care about opening docblocks,
// bail out when we get to the namespace token
if (is_array($token) && $token[0] === T_NAMESPACE)
{
break;
}
if (is_array($token))
{
$token = $token[1];
}
$output .= $token;
}
return $output;
}
function get_tokens($source)
{
return token_get_all($source);
}
function replace_files(array $files, $template)
{
print_r($files);
foreach ($files as $file)
{
$source = file_get_contents($file);
if (stripos($source, 'namespace') === FALSE)
{
continue;
}
$tokens = get_tokens($source);
$text_to_replace = get_text_to_replace($tokens);
$header = file_get_contents(__DIR__ . $template);
$new_text = "<?php declare(strict_types=1);\n{$header}";
$new_source = str_replace($text_to_replace, $new_text, $source);
file_put_contents($file, $new_source);
}
}
foreach ($file_patterns as $glob)
{
$files = glob_recursive($glob);
replace_files($files, '/header_comment.txt');
}
echo "Successfully updated headers \n";

View File

@ -2,65 +2,75 @@
"name": "aviat/hummingbird-anime-client",
"description": "A self-hosted anime/manga client for Kitsu.",
"license": "MIT",
"authors": [
{
"name": "Timothy J. Warren",
"email": "tim@timshomepage.net",
"homepage": "https://timshomepage.net",
"role": "Developer"
}
],
"autoload": {
"files": [
"src/constants.php",
"src/AnimeClient.php"
"src/Ion/functions.php",
"src/AnimeClient.php",
"src/AnimeClient/constants.php"
],
"psr-4": {
"Aviat\\AnimeClient\\": "src/"
"Aviat\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Aviat\\AnimeClient\\Tests\\": "tests/",
"CodeIgniter\\": "build/CodeIgniter/"
"Aviat\\AnimeClient\\Tests\\": "tests/AnimeClient",
"Aviat\\Ion\\Tests\\": "tests/Ion"
}
},
"config": {
"lock": false
},
"require": {
"amphp/artax": "^3.0",
"aura/html": "^2.0",
"aura/router": "^3.0",
"aura/session": "^2.0",
"aviat/banker": "^1.0.0",
"aviat/ion": "^2.3.0",
"maximebf/consolekit": "^1.0",
"monolog/monolog": "^1.0",
"psr/http-message": "~1.0",
"psr/log": "~1.0",
"yosymfony/toml": "^1.0",
"zendframework/zend-diactoros": "^1.3"
"amphp/http-client": "^v5.0.0",
"aura/html": "^2.5.0",
"aura/router": "^3.3.0",
"aura/session": "^2.1.0",
"aviat/banker": "^4.1.2",
"aviat/query": "^4.1.0",
"ext-dom": "*",
"ext-gd": "*",
"ext-intl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-pdo": "*",
"laminas/laminas-diactoros": "^3.0.0",
"laminas/laminas-httphandlerrunner": "^2.6.1",
"maximebf/consolekit": "^1.0.3",
"monolog/monolog": "^3.0.0",
"php": ">= 8.2.0",
"psr/http-message": "^1.0.1 || ^2.0.0",
"symfony/polyfill-mbstring": "^1.0.0",
"symfony/polyfill-util": "^1.0.0",
"tracy/tracy": "^2.8.0",
"yosymfony/toml": "^1.0.4"
},
"require-dev": {
"consolidation/robo": "~1.0",
"henrikbjorn/lurker": "^1.1.0",
"pdepend/pdepend": "^2.2",
"phploc/phploc": "^4.0",
"phpmd/phpmd": "^2.4",
"phpstan/phpstan": "^0.9.1",
"phpunit/phpunit": "^6.0",
"phpstan/phpstan": "^1.2.0",
"phpunit/phpunit": "^10.0.0",
"roave/security-advisories": "dev-master",
"robmorgan/phinx": "^0.9.1",
"sebastian/phpcpd": "^3.0",
"spatie/phpunit-snapshot-assertions": "^1.2.0",
"squizlabs/php_codesniffer": "^3.2.2",
"symfony/var-dumper": "^4.0.1",
"theseer/phpdox": "^0.11.0",
"filp/whoops": "^2.1"
"spatie/phpunit-snapshot-assertions": "^5.0.1"
},
"scripts": {
"build": "vendor/bin/robo build",
"build:css": "cd public && npm run build && cd ..",
"clean": "vendor/bin/robo clean",
"coverage": "phpdbg -qrr -- vendor/bin/phpunit -c build",
"phpstan": "phpstan analyse -l 4 -c phpstan.neon src tests ./console index.php",
"watch:css": "cd public && npm run watch",
"test": "vendor/bin/phpunit"
"build:css": "cd public && npm run build:css && cd ..",
"build:js": "cd public && npm run build:js && cd ..",
"coverage": "php -dpcov.enabled=1 -dpcov.directory=. -dpcov.exclude=\"~vendor~\" ./vendor/bin/phpunit -c build",
"phpstan": "phpstan analyse -c phpstan.neon",
"watch:css": "cd public && npm run watch:css",
"watch:js": "cd public && npm run watch:js",
"test": "vendor/bin/phpunit -c build --no-coverage",
"test-update": "vendor/bin/phpunit -c build --no-coverage -d --update-snapshots"
},
"scripts-descriptions": {
"build": "Generate the api docs",
"build:css": "Generate browser css",
"clean": "Remove documentation generation files and folders",
"coverage": "Generate a test coverage report",
"phpstan": "Run PHP Static analysis",
"test": "Run the unit tests"

14
console
View File

@ -7,7 +7,10 @@ require_once __DIR__ . '/vendor/autoload.php';
use Aviat\AnimeClient\Command;
use ConsoleKit\Console;
$_SERVER['HTTP_HOST'] = 'localhost';
$GLOBALS['_SERVER']['HTTP_HOST'] = 'localhost';
const APP_DIR = __DIR__ . '/app';
const TEMPLATE_DIR = APP_DIR . '/templates';
// -----------------------------------------------------------------------------
// Start console script
@ -15,12 +18,15 @@ $_SERVER['HTTP_HOST'] = 'localhost';
try
{
(new Console([
'cache:clear' => Command\CacheClear::class,
'cache:refresh' => Command\CachePrime::class,
'clear:cache' => Command\CacheClear::class,
'clear:thumbnails' => Command\ClearThumbnails::class,
'refresh:cache' => Command\CachePrime::class,
'refresh:thumbnails' => Command\UpdateThumbnails::class,
'lists:sync' => Command\SyncLists::class,
'sync:lists' => Command\SyncLists::class
]))->run();
}
catch (\Exception $e)
catch (Throwable)
{
}

70
frontEndSrc/css.js Normal file
View File

@ -0,0 +1,70 @@
/**
* Script for optimizing css
*/
const fs = require('fs');
const postcss = require('postcss');
const atImport = require('postcss-import');
const cssNext = require('postcss-preset-env');
const cssNano = require('cssnano');
const lightCss = fs.readFileSync('css/light.css', 'utf-8');
const darkCss = fs.readFileSync('css/src/dark-override.css', 'utf-8');
const fullDarkCss = fs.readFileSync('css/dark.css', 'utf-8');
const minOptions = {
autoprefixer: false,
colormin: false,
minifyFontValues: false,
options: {
sourcemap: false
}
};
const processOptions = {
browser: '> 0.5%',
features: {
'custom-properties': true,
},
stage: 0,
};
try {
(async () => {
// Basic theme
const lightMin = await postcss()
.use(atImport())
.use(cssNext(processOptions))
.use(cssNano(minOptions))
.process(lightCss, {
from: 'css/light.css',
to: '/public/css/light.min.css',
}).catch(console.error);
fs.writeFileSync('../public/css/light.min.css', lightMin.css);
// Dark theme
const darkFullMin = await postcss()
.use(atImport())
.use(cssNext(processOptions))
.use(cssNano(minOptions))
.process(fullDarkCss, {
from: 'css/dark.css',
to: '/public/css/dark.min.css',
});
fs.writeFileSync('../public/css/dark.min.css', darkFullMin.css);
// Dark override
const darkMin = await postcss()
.use(atImport())
.use(cssNext(processOptions))
.use(cssNano(minOptions))
.process(darkCss, {
from: 'css/dark-override.css',
to: '/public/css/dark.min.css',
}).catch(console.error);
const autoDarkCss = `${lightMin} @media (prefers-color-scheme: dark) { ${darkMin.css} }`
fs.writeFileSync('../public/css/auto.min.css', autoDarkCss)
})();
} catch (e) {
console.error(e)
}

3
frontEndSrc/css/auto.css Normal file
View File

@ -0,0 +1,3 @@
@media (prefers-color-scheme: dark) {
@import "src/dark-override.css";
}

Some files were not shown because too many files have changed in this diff Show More