diff --git a/.docs/README.md b/.docs/README.md new file mode 100644 index 0000000..4ff6334 --- /dev/null +++ b/.docs/README.md @@ -0,0 +1,204 @@ +# Tlapnet Chart + +Graphs and charts based on [C3.js](http://c3js.org/) + +## Content + +- [Assets](#Assets) +- [Graphs](#graphs) + - [Chart](#chart) + - [CategoryChart](#categorychart) + - [DateChart](#datechart) + - [DonutChart](#donutchart) + - [PieChart](#piechart) +- [Series](#series) + - [Stacking series](#stacking-series) + - [Types](#types) + +## Assets + +Graphs are rendered through [C3.js](http://c3js.org/). + +```html + + + + + +``` + +## Graphs + +### Chart + +- x (number), y (number) + +```php +use Tlapnet\Chart\Chart; +use Tlapnet\Chart\Serie\Serie; +use Tlapnet\Chart\Segment\Segment; + +$chart = new Chart(); + +$serie = new Serie(Serie::LINE, 'Serie 1', 'red'); +$serie->addSegment(new Segment(5, 10)); +$serie->addSegment(new Segment(6, 4)); +$serie->addSegment(new Segment(2, 8)); +$chart->addSerie($serie); + +$serie = new Serie(Serie::LINE, 'Serie 2'); +$serie->addSegment(new Segment(2, 8)); +$serie->addSegment(new Segment(4, 6)); +$serie->addSegment(new Segment(8, 5)); +$serie->addSegment(new Segment(7, 7)); +$chart->addSerie($serie); + +echo $chart; +``` + +![Chart](./assets/Chart.png?raw=true) + +### CategoryChart + +- x (unique key, string|int), y (number) + +```php +use Tlapnet\Chart\Category; +use Tlapnet\Chart\CategoryChart; +use Tlapnet\Chart\Serie\CategorySerie; +use Tlapnet\Chart\Segment\CategorySegment; + +$chart = new CategoryChart([ + new Category(1, 'January'), + new Category(2, 'February'), + new Category(3, 'March'), +]); +$chart->setValueSuffix(' $'); + +$serie = new CategorySerie(CategorySerie::BAR, 'Company 1', 'red'); +$serie->addSegment(new CategorySegment(1, 0)); +$serie->addSegment(new CategorySegment(2, 4000)); +$serie->addSegment(new CategorySegment(3, 1000)); +$chart->addSerie($serie, 'group1'); + +$serie = new CategorySerie(CategorySerie::BAR, 'Company 2', 'green'); +$serie->addSegment(new CategorySegment(1, 3000)); +// Segments could be omitted (default value is 0) +$serie->addSegment(new CategorySegment(3, 500)); +$chart->addSerie($serie, 'group1'); + +$serie = new CategorySerie(CategorySerie::LINE, 'Summary'); +$serie->addSegment(new CategorySegment(1, 3000)); +$serie->addSegment(new CategorySegment(3, 1500)); +$serie->addSegment(new CategorySegment(2, 4000)); +$chart->addSerie($serie); + +echo $chart; +``` + +![CategoryChart](./assets/CategoryChart.png?raw=true) + +### DateChart + +- x (date), y (number) + +```php +use Tlapnet\Chart\DateChart; +use Tlapnet\Chart\Serie\DateSerie; +use Tlapnet\Chart\Segment\DateSegment; +use DateTimeImmutable; + +$chart = new DateChart(); +$chart->setValueSuffix(' $'); +//$chart->enableTimePrecision(); // Enable time accurate to seconds + +$serie = new DateSerie(DateSerie::LINE, 'Revenues', 'green'); +$serie->addSegment(new DateSegment(new DateTimeImmutable('2012-01-01'), 10)); +$serie->addSegment(new DateSegment(new DateTimeImmutable('2012-02-01'), 4)); +$serie->addSegment(new DateSegment(new DateTimeImmutable('2012-03-01'), 8)); +$chart->addSerie($serie); + +$serie = new DateSerie(DateSerie::LINE, 'Costs', 'red'); +$serie->addSegment(new DateSegment(new DateTimeImmutable('2012-01-01'), 2)); +$serie->addSegment(new DateSegment(new DateTimeImmutable('2012-02-01'), 9)); +$serie->addSegment(new DateSegment(new DateTimeImmutable('2012-03-01'), 5)); +$chart->addSerie($serie); + +$serie = new DateSerie(DateSerie::AREA_LINE, 'Balance', 'blue'); +$serie->addSegment(new DateSegment(new DateTimeImmutable('2012-01-01'), 8)); +$serie->addSegment(new DateSegment(new DateTimeImmutable('2012-02-01'), -5)); +$serie->addSegment(new DateSegment(new DateTimeImmutable('2012-03-01'), 3)); +$chart->addSerie($serie); + +echo $chart; +``` + +![DateChart](./assets/DateChart.png?raw=true) + +### DonutChart + +```php +use Tlapnet\Chart\DonutChart; +use Tlapnet\Chart\Segment\DonutSegment; + +$chart = new DonutChart(); +$chart->setTitle(15); +$chart->setValueSuffix(' pcs'); +$chart->enableRatioLabel(); // Show percents instead of absolute values +$chart->addSegment(new DonutSegment('Item 1', 5)); +$chart->addSegment(new DonutSegment('Item 2', 8)); +$chart->addSegment(new DonutSegment('Item 3', 2)); + +echo $chart; +``` + +![DonutChart](./assets/DonutChart.png?raw=true) + +### PieChart + +```php +use Tlapnet\Chart\PieChart; +use Tlapnet\Chart\Segment\PieSegment; + +$chart = new PieChart(); +$chart->enableRatioLabel(); // Show percents instead of absolute values +$chart->setValueSuffix(' pcs'); +$chart->addSegment(new PieSegment('Item 1', 5)); +$chart->addSegment(new PieSegment('Item 2', 8)); +$chart->addSegment(new PieSegment('Item 3', 2)); + +echo $chart; +``` + +![PieChart](./assets/PieChart.png?raw=true) + +## Series + +Graphs Chart, CategoryChart and DateChart each have their series (Serie, CategorySerie, DateSerie). + +### Stacking series + +```php +$chart->addSerie($barSerie1, 'group1'); +$chart->addSerie($barSerie2, 'group1'); +$chart->addSerie($barSerie3, 'group1'); +$chart->addSerie($barSerie4, 'group1'); +``` + +```php +// Group name could be any value valid for array key +// Null (default value) mean no group +$chart->addSerie($splineSerie1, 1); +$chart->addSerie($splineSerie2, 1); +``` + +### Types + +- *Serie::BAR +- *Serie::LINE +- *Serie::SPLINE +- *Serie::STEP +- *Serie::AREA_LINE +- *Serie::AREA_SPLINE +- *Serie::AREA_STEP + diff --git a/.docs/assets/CategoryChart.png b/.docs/assets/CategoryChart.png new file mode 100644 index 0000000..66e9a4b Binary files /dev/null and b/.docs/assets/CategoryChart.png differ diff --git a/.docs/assets/Chart.png b/.docs/assets/Chart.png new file mode 100644 index 0000000..54bc15a Binary files /dev/null and b/.docs/assets/Chart.png differ diff --git a/.docs/assets/DateChart.png b/.docs/assets/DateChart.png new file mode 100644 index 0000000..607fd1c Binary files /dev/null and b/.docs/assets/DateChart.png differ diff --git a/.docs/assets/DonutChart.png b/.docs/assets/DonutChart.png new file mode 100644 index 0000000..aa63a38 Binary files /dev/null and b/.docs/assets/DonutChart.png differ diff --git a/.docs/assets/PieChart.png b/.docs/assets/PieChart.png new file mode 100644 index 0000000..ae1c384 Binary files /dev/null and b/.docs/assets/PieChart.png differ diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c46f966 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +# EditorConfig is awesome: http://EditorConfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = tab +indent_size = tab +tab_width = 4 + +[*.md,*.yml] +indent_style = space +indent_size = 4 + +[{composer.json,package.json,.travis.yml}] +indent_style = space +indent_size = 2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e9c635f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +# Not archived +.docs export-ignore +tests export-ignore +.editorconfig export-ignore +.gitattributes export-ignore +.gitignore export-ignore +.travis.yml export-ignore +LICENSE export-ignore +phpstan.neon export-ignore +README.md export-ignore +ruleset.xml export-ignore diff --git a/.gitignore b/.gitignore index 07d60bd..b1b6f4d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,10 @@ -.DS_Store -/.idea/ +# IDE +/.idea -/vendor/ +# Composer +/vendor /composer.lock -phpunit.xml - -!.gitkeep +# Tests +/temp +/coverage.xml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..c3b50a9 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,53 @@ +language: php +php: + - 7.1 + - 7.2 + +install: + # Composer + - travis_retry composer install --no-progress --prefer-dist + +script: + # PhpUnit + - composer run-script phpunit + +jobs: + include: + - env: title="Lowest Dependencies 7.2" + php: 7.2 + install: + - travis_retry composer update --no-progress --prefer-dist --prefer-lowest + script: + - composer run-script phpunit + + - stage: Quality Assurance + php: 7.2 + script: + - composer run-script qa + + - stage: Test Coverage + php: 7.2 + script: + - composer run-script coverage + after_script: + - wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.1.0/php-coveralls.phar + - php php-coveralls.phar --verbose --config tests/.coveralls.yml + + - stage: Phpstan + php: 7.2 + script: + - composer run-script phpstan-install + - composer run-script phpstan + + allow_failures: + - stage: Test Coverage + +after_failure: + # Print *.actual content + - for i in $(find tests -name \*.actual); do echo "--- $i"; cat $i; echo; echo; done + +sudo: false + +cache: + directories: + - $HOME/.composer/cache diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a612ad9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/README.md b/README.md index a48e6f6..c62c6d7 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,63 @@ -# Chart +# Tlapnet Chart -Documentation is situated in global Tlapnet documentation +Graphs and charts based on [C3.js](http://c3js.org/) + +----- + +[![Build Status](https://img.shields.io/travis/tlapnet/chart.svg?style=flat-square)](https://travis-ci.org/tlapnet/chart) +[![Code coverage](https://img.shields.io/coveralls/tlapnet/chart.svg?style=flat-square)](https://coveralls.io/r/tlapnet/chart) +[![Licence](https://img.shields.io/packagist/l/tlapnet/chart.svg?style=flat-square)](https://packagist.org/packages/tlapnet/chart) + +[![Downloads this Month](https://img.shields.io/packagist/dm/tlapnet/chart.svg?style=flat-square)](https://packagist.org/packages/tlapnet/chart) +[![Downloads total](https://img.shields.io/packagist/dt/tlapnet/chart.svg?style=flat-square)](https://packagist.org/packages/tlapnet/chart) +[![Latest stable](https://img.shields.io/packagist/v/tlapnet/chart.svg?style=flat-square)](https://packagist.org/packages/tlapnet/chart) + +## Install + +``` +$ compose require tlapnet/chart +``` + +## Versions + +| State | Version | Branch | PHP | +|-------------|-----------|----------|----------| +| dev | `^2.1.0` | `master` | `>= 7.1` | +| stable | `^2.0.0` | `master` | `>= 7.1` | +| stable | `^1.0.0` | `master` | `>= 5.4` | + +## Overview + +- [Assets](.docs/README.md#assets) +- [Graphs](.docs/README.md#graphs) + - [Chart](.docs/README.md#chart) + - [CategoryChart](.docs/README.md#categorychart) + - [DateChart](.docs/README.md#datechart) + - [DonutChart](.docs/README.md#donutchart) + - [PieChart](.docs/README.md#piechart) +- [Series](.docs/README.md#series) + - [Stacking series](.docs/README.md#stacking-series) + - [Types](.docs/README.md#types) + +## Maintainers + + + + + + + + +
+ + + +
+ Milan Felix Šulc +
+ + + +
+ Marek Bartoš +
diff --git a/composer.json b/composer.json index 06e9b2e..237678f 100644 --- a/composer.json +++ b/composer.json @@ -1,34 +1,57 @@ { - "name": "tlapnet/chart", - "authors": [ - { - "name": "Tlapnet", - "email": "webmaster@tlapnet.cz" - } + "name": "tlapnet/chart", + "description": "Graphs and charts based on C3.js", + "type": "library", + "license": "MPL-2.0", + "homepage": "https://github.com/tlapnet/chart", + "authors": [ + { + "name": "Luděk Benedík" + } + ], + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "ninjify/qa": "^0.8.0", + "phpunit/phpunit": "^7.3.5" + }, + "minimum-stability": "dev", + "prefer-stable": true, + "autoload": { + "psr-4": { + "Tlapnet\\Chart\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Tlapnet\\Chart\\Tests\\": "tests/" + } + }, + "scripts": { + "qa": [ + "linter src tests", + "codesniffer src tests" ], - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "4.2.*" - }, - "autoload": { - "psr-4": { - "Tlapnet\\Chart\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "Tlapnet\\Chart\\Tests\\": "tests/" - } - }, - "minimum-stability": "dev", - "prefer-stable": true, - "license": "proprietary", - "repositories": [ - { - "type": "composer", - "url": "https://packagist.ispalliance.cz/" - } + "phpunit": [ + "phpunit tests --colors=always" + ], + "coverage": [ + "phpunit tests --colors=always -c tests/coverage.xml" + ], + "phpstan-install": [ + "mkdir -p temp/phpstan", + "composer require -d temp/phpstan phpstan/phpstan:0.10.3", + "composer require -d temp/phpstan phpstan/phpstan-deprecation-rules:0.10.2", + "composer require -d temp/phpstan phpstan/phpstan-strict-rules:0.10.1" + ], + "phpstan": [ + "temp/phpstan/vendor/bin/phpstan analyse -l max -c phpstan.neon src" ] -} \ No newline at end of file + }, + "extra": { + "branch-alias": { + "dev-dev": "2.1.x-dev" + } + } +} diff --git a/netterobots.txt b/netterobots.txt deleted file mode 100644 index d392021..0000000 --- a/netterobots.txt +++ /dev/null @@ -1,2 +0,0 @@ -Disallow: /tests -Disallow: /tests_output diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..8ccc328 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,11 @@ +includes: + - temp/phpstan/vendor/phpstan/phpstan-deprecation-rules/rules.neon + - temp/phpstan/vendor/phpstan/phpstan-strict-rules/rules.neon + +parameters: + ignoreErrors: + # Cannot happen + - '#^Parameter \#1 \$unixtimestamp of method DateTimeImmutable\:\:setTimestamp\(\) expects int, int\|string given\.$#' + # Extract has a reason here + - '#^Parameter \#1 \$var_array of function extract is passed by reference, so it expects variables only\.$#' + - '#^Parameter \#1 \$path of function dirname expects string, string\|false given\.$#' diff --git a/phpunit.xml.dist b/phpunit.xml.dist deleted file mode 100644 index dd1fd3a..0000000 --- a/phpunit.xml.dist +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - ./tests/ - - - - - - ./src - - ./src/Resources - - - - diff --git a/ruleset.xml b/ruleset.xml new file mode 100644 index 0000000..a3d4d14 --- /dev/null +++ b/ruleset.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + /tests/tmp + diff --git a/src/AbstractChart.php b/src/AbstractChart.php index 86c570f..88011ac 100644 --- a/src/AbstractChart.php +++ b/src/AbstractChart.php @@ -1,17 +1,15 @@ -valueSuffix = (string) $suffix; + $this->valueSuffix = $suffix; } - - /** - * @return string - */ - public function __toString() + public function __toString(): string { return $this->render(); } - - /** - * @return string - */ - public function render() + public function render(): string { extract($this->getTemplateParameters()); ob_start(); require $this->getTemplateFile(); - return ob_get_clean(); + return (string) ob_get_clean(); } - /** - * @return array + * @return mixed[] */ - protected function getTemplateParameters() + protected function getTemplateParameters(): array { return [ - 'c3Adapter' => new C3Adapter(), - 'chartId' => 'tlapnet-chart-' . self::$rendersCount++, - 'width' => $this->width, - 'height' => $this->height, + 'c3Adapter' => new C3Adapter(), + 'chartId' => 'tlapnet-chart-' . self::$rendersCount++, + 'width' => $this->width, + 'height' => $this->height, 'valueSuffix' => $this->valueSuffix, ]; } - - /** - * @return string - */ - private function getTemplateFile() + private function getTemplateFile(): string { - $classRefl = new ReflectionClass($this); - $classDir = dirname($classRefl->getFileName()); - $classShort = $classRefl->getShortName(); + $classReflection = new ReflectionClass($this); + $classDir = dirname($classReflection->getFileName()); + $classShort = $classReflection->getShortName(); - $file = "$classDir/templates/c3/$classShort.html.php"; + $file = sprintf('%s/templates/c3/%s.phtml', $classDir, $classShort); if (!file_exists($file)) { - throw new \LogicException(sprintf('Template file for "%s" not found.', $classShort)); + throw new LogicException(sprintf('Template file for "%s" not found.', $classShort)); } return $file; } + } diff --git a/src/Category.php b/src/Category.php index f3eca0d..8a1324d 100644 --- a/src/Category.php +++ b/src/Category.php @@ -1,45 +1,30 @@ -key = (string) $key; - $this->title = (string) $title; + $this->key = $key; + $this->title = $title; } - - /** - * @return string - */ - public function getKey() + public function getKey(): string { return $this->key; } - - /** - * @return string - */ - public function getTitle() + public function getTitle(): string { return $this->title; } + } diff --git a/src/CategoryChart.php b/src/CategoryChart.php index a6a664d..700a130 100644 --- a/src/CategoryChart.php +++ b/src/CategoryChart.php @@ -1,4 +1,4 @@ - group */ + /** @var mixed[] serie_index => group */ private $groups = []; - /** * @param Category[] $categories */ - function __construct(array $categories) + public function __construct(array $categories) { - $this->categories = $categories; + $this->categories = $categories; $this->categoryKeys = []; foreach ($this->categories as $category) { @@ -40,34 +36,27 @@ function __construct(array $categories) $this->assertCategoryKeyUniqueness(); } - - /** - * @throws LogicException When category keys are not unique - */ - private function assertCategoryKeyUniqueness() + private function assertCategoryKeyUniqueness(): void { $uniqueKeys = array_unique($this->categoryKeys); if (count($this->categoryKeys) !== count($uniqueKeys)) { - throw new LogicException("Category keys have to be unigue."); + throw new LogicException('Category keys have to be unique.'); } } - /** - * @param CategorySerie $serie * @param mixed $group Valid PHP array key. If NULL then serie is ungrouped */ - public function addSerie(CategorySerie $serie, $group = null) + public function addSerie(CategorySerie $serie, $group = null): void { $categorizedSegments = $this->getCategorizedSegments($serie); - $normalizedSerie = new CategorySerie($serie->getType(), $serie->getTitle(), $serie->getColor()); + $normalizedSerie = new CategorySerie($serie->getType(), $serie->getTitle(), $serie->getColor()); foreach ($this->categoryKeys as $key) { if (isset($categorizedSegments[$key])) { $normalizedSerie->addSegment($categorizedSegments[$key]); - } - else { + } else { $normalizedSerie->addSegment(new CategorySegment($key, 0)); } } @@ -76,20 +65,20 @@ public function addSerie(CategorySerie $serie, $group = null) $this->groups[] = $group; } - /** - * @param CategorySerie $serie - * @return array key => CategorySegment + * @return CategorySegment[] * @throws LogicException When any serie segment has undefined category */ - private function getCategorizedSegments(CategorySerie $serie) + private function getCategorizedSegments(CategorySerie $serie): array { $categorizedSegments = []; foreach ($serie->getSegments() as $segment) { - if (!in_array($segment->getKey(), $this->categoryKeys)) { + if (!in_array($segment->getKey(), $this->categoryKeys, true)) { throw new LogicException(sprintf( - 'Serie "%s" has segment with undefined category key "%s".', $serie->getTitle(), $segment->getKey() + 'Serie "%s" has segment with undefined category key "%s".', + $serie->getTitle(), + $segment->getKey() )); } @@ -99,17 +88,17 @@ private function getCategorizedSegments(CategorySerie $serie) return $categorizedSegments; } - /** * {@inheritdoc} */ - protected function getTemplateParameters() + protected function getTemplateParameters(): array { - $params = parent::getTemplateParameters(); + $params = parent::getTemplateParameters(); $params['categories'] = $this->categories; - $params['series'] = $this->series; - $params['groups'] = $this->groups; + $params['series'] = $this->series; + $params['groups'] = $this->groups; return $params; } + } diff --git a/src/Chart.php b/src/Chart.php index 4d5dfb4..f0e897d 100644 --- a/src/Chart.php +++ b/src/Chart.php @@ -1,42 +1,37 @@ - group */ + /** @var mixed[] serie_index => group */ private $groups = []; - /** - * @param Serie $serie * @param mixed $group Valid PHP array key. If NULL then serie is ungrouped */ - public function addSerie(Serie $serie, $group = null) + public function addSerie(Serie $serie, $group = null): void { $this->series[] = $serie; $this->groups[] = $group; } - /** * {@inheritdoc} */ - protected function getTemplateParameters() + protected function getTemplateParameters(): array { - $params = parent::getTemplateParameters(); + $params = parent::getTemplateParameters(); $params['series'] = $this->series; $params['groups'] = $this->groups; return $params; } + } diff --git a/src/DateChart.php b/src/DateChart.php index 62b6402..44c61a9 100644 --- a/src/DateChart.php +++ b/src/DateChart.php @@ -1,66 +1,53 @@ - group */ + /** @var mixed[] serie_index => group */ private $groups = []; /** @var bool */ private $useTimePrecision = false; - /** - * @param DateSerie $serie * @param mixed $group Valid PHP array key. If NULL then serie is ungrouped */ - public function addSerie(DateSerie $serie, $group = null) + public function addSerie(DateSerie $serie, $group = null): void { $this->series[] = $serie; $this->groups[] = $group; } - - /** - */ - public function enableTimePrecision() + public function enableTimePrecision(): void { $this->useTimePrecision = true; } - /** * {@inheritdoc} */ - protected function getTemplateParameters() + protected function getTemplateParameters(): array { - $params = parent::getTemplateParameters(); - $params['series'] = $this->series; - $params['groups'] = $this->groups; + $params = parent::getTemplateParameters(); + $params['series'] = $this->series; + $params['groups'] = $this->groups; + $params['minTime'] = $this->getMinTime(); + $params['maxTime'] = $this->getMaxTime(); $params['useTimePrecision'] = $this->useTimePrecision; - $params['minTime'] = $this->getMinTime(); - $params['maxTime'] = $this->getMaxTime(); return $params; } - - /** - * @return int - */ - private function getMinTime() + private function getMinTime(): int { - $min = array(); + $min = []; foreach ($this->series as $serie) { $min[] = $serie->getMinTime(); @@ -69,13 +56,9 @@ private function getMinTime() return min($min); } - - /** - * @return int - */ - private function getMaxTime() + private function getMaxTime(): int { - $max = array(); + $max = []; foreach ($this->series as $serie) { $max[] = $serie->getMaxTime(); @@ -83,4 +66,5 @@ private function getMaxTime() return max($max); } + } diff --git a/src/DonutChart.php b/src/DonutChart.php index 44035c6..cbf1341 100644 --- a/src/DonutChart.php +++ b/src/DonutChart.php @@ -1,15 +1,12 @@ -segments[] = $segment; } - - /** - * @param string $title - */ - public function setTitle($title) + public function setTitle(string $title): void { - $this->title = (string) $title; + $this->title = $title; } - - /** - */ - public function enableRatioLabel() + public function enableRatioLabel(): void { $this->enableRatioLabel = true; } - /** * {@inheritdoc} */ - protected function getTemplateParameters() + protected function getTemplateParameters(): array { - $params = parent::getTemplateParameters(); - $params['segments'] = $this->segments; - $params['title'] = $this->title; + $params = parent::getTemplateParameters(); + $params['title'] = $this->title; + $params['segments'] = $this->segments; $params['enableRatioLabel'] = $this->enableRatioLabel; return $params; } + } diff --git a/src/PieChart.php b/src/PieChart.php index 50e329a..9b72042 100644 --- a/src/PieChart.php +++ b/src/PieChart.php @@ -1,48 +1,38 @@ -segments[] = $segment; } - - /** - */ - public function enableRatioLabel() + public function enableRatioLabel(): void { $this->enableRatioLabel = true; } - /** * {@inheritdoc} */ - protected function getTemplateParameters() + protected function getTemplateParameters(): array { - $params = parent::getTemplateParameters(); - $params['segments'] = $this->segments; + $params = parent::getTemplateParameters(); + $params['segments'] = $this->segments; $params['enableRatioLabel'] = $this->enableRatioLabel; return $params; } + } diff --git a/src/Segment/CategorySegment.php b/src/Segment/CategorySegment.php index 53e083e..2120a54 100644 --- a/src/Segment/CategorySegment.php +++ b/src/Segment/CategorySegment.php @@ -1,45 +1,30 @@ -key = (string) $key; - $this->value = (float) $value; + $this->key = $key; + $this->value = $value; } - - /** - * @return string - */ - public function getKey() + public function getKey(): string { return $this->key; } - - /** - * @return float - */ - public function getValue() + public function getValue(): float { return $this->value; } + } diff --git a/src/Segment/DateSegment.php b/src/Segment/DateSegment.php index 5d00cca..a48d7ac 100644 --- a/src/Segment/DateSegment.php +++ b/src/Segment/DateSegment.php @@ -1,57 +1,44 @@ -date = $date; - } - elseif (is_numeric($date)) { - $this->date = new DateTime(); + } elseif (is_numeric($date)) { + $this->date = new DateTimeImmutable(); $this->date->setTimestamp($date); - } - else { - $this->date = new DateTime($date); + } else { + $this->date = new DateTimeImmutable($date); } - $this->value = (float) $value; + $this->value = $value; } - - /** - * @return DateTime - */ - public function getDate() + public function getDate(): DateTimeInterface { return $this->date; } - - /** - * @return float - */ - public function getValue() + public function getValue(): float { return $this->value; } + } diff --git a/src/Segment/DonutSegment.php b/src/Segment/DonutSegment.php index 7e0a776..04669a1 100644 --- a/src/Segment/DonutSegment.php +++ b/src/Segment/DonutSegment.php @@ -1,11 +1,8 @@ -title = (string) $title; - $this->value = (float) $value; + $this->title = $title; + $this->value = $value; } - - /** - * @return string - */ - public function getTitle() + public function getTitle(): string { return $this->title; } - - /** - * @return float - */ - public function getValue() + public function getValue(): float { return $this->value; } + } diff --git a/src/Segment/Segment.php b/src/Segment/Segment.php index 3a20a27..e5f6266 100644 --- a/src/Segment/Segment.php +++ b/src/Segment/Segment.php @@ -1,47 +1,32 @@ -x = (float) $x; - $this->y = (float) $y; + $this->x = $x; + $this->y = $y; } - /** - * @return float - */ - public function getX() + public function getX(): float { return $this->x; } - /** - * @return float - */ - public function getY() + public function getY(): float { return $this->y; } + } diff --git a/src/Serie/AbstractSerie.php b/src/Serie/AbstractSerie.php index c4e1b26..9e485bd 100644 --- a/src/Serie/AbstractSerie.php +++ b/src/Serie/AbstractSerie.php @@ -1,88 +1,82 @@ -assertType($type); - $this->type = (string) $type; - $this->title = (string) $title; - $this->color = $color === null ? null : (string) $color; + $this->type = $type; + $this->title = $title; + $this->color = $color; } - /** - * @param string $type * @throws InvalidArgumentException When type is undefined */ - private function assertType($type) + private function assertType(string $type): void { - static $allowedTypes = [self::AREA_LINE, self::AREA_SPLINE, self::AREA_STEP, self::BAR, self::LINE, self::SPLINE, self::STEP]; - - if (!in_array($type, $allowedTypes)) { + if (!in_array($type, self::TYPES, true)) { throw new InvalidArgumentException(sprintf('Undefined type "%s".', $type)); } } - - /** - * @return string - */ - public function getType() + public function getType(): string { return $this->type; } - - /** - * @return string - */ - public function getTitle() + public function getTitle(): string { return $this->title; } - - /** - * @return string|null - */ - public function getColor() + public function getColor(): ?string { return $this->color; } + } diff --git a/src/Serie/CategorySerie.php b/src/Serie/CategorySerie.php index 34b32c1..7112493 100644 --- a/src/Serie/CategorySerie.php +++ b/src/Serie/CategorySerie.php @@ -1,43 +1,38 @@ -getKey(), $this->usedCategoryKeys)) { + if (in_array($segment->getKey(), $this->usedCategoryKeys, true)) { throw new LogicException(sprintf('Category key "%s" has another segment.', $segment->getKey())); } - $this->segments[] = $segment; + $this->segments[] = $segment; $this->usedCategoryKeys[] = $segment->getKey(); } - /** * @return CategorySegment[] */ - public function getSegments() + public function getSegments(): array { return $this->segments; } + } diff --git a/src/Serie/DateSerie.php b/src/Serie/DateSerie.php index 6615720..50b3f43 100644 --- a/src/Serie/DateSerie.php +++ b/src/Serie/DateSerie.php @@ -1,15 +1,12 @@ -getDate()->getTimestamp(); @@ -33,30 +26,28 @@ public function addSegment(DateSegment $segment) $this->segments[] = $segment; } - /** * @return DateSegment[] */ - public function getSegments() + public function getSegments(): array { return $this->segments; } - /** * @return int Timestamp */ - public function getMinTime() + public function getMinTime(): int { return $this->minTime; } - /** * @return int Timestamp */ - public function getMaxTime() + public function getMaxTime(): int { return $this->maxTime; } + } diff --git a/src/Serie/Serie.php b/src/Serie/Serie.php index 43e61c4..dc1ca11 100644 --- a/src/Serie/Serie.php +++ b/src/Serie/Serie.php @@ -1,33 +1,26 @@ -segments[] = $segment; } - /** * @return Segment[] */ - public function getSegments() + public function getSegments(): array { return $this->segments; } + } diff --git a/src/Util/C3Adapter.php b/src/Util/C3Adapter.php index 0d2c89c..32d4efd 100644 --- a/src/Util/C3Adapter.php +++ b/src/Util/C3Adapter.php @@ -1,20 +1,13 @@ - 'area', @@ -26,4 +19,5 @@ public function getSerieType($libraryType) return str_replace('_', '-', $libraryType); } + } diff --git a/src/templates/c3/CategoryChart.html.php b/src/templates/c3/CategoryChart.phtml similarity index 100% rename from src/templates/c3/CategoryChart.html.php rename to src/templates/c3/CategoryChart.phtml diff --git a/src/templates/c3/Chart.html.php b/src/templates/c3/Chart.html.phtml similarity index 100% rename from src/templates/c3/Chart.html.php rename to src/templates/c3/Chart.html.phtml diff --git a/src/templates/c3/DateChart.html.php b/src/templates/c3/DateChart.phtml similarity index 100% rename from src/templates/c3/DateChart.html.php rename to src/templates/c3/DateChart.phtml diff --git a/src/templates/c3/DonutChart.html.php b/src/templates/c3/DonutChart.phtml similarity index 100% rename from src/templates/c3/DonutChart.html.php rename to src/templates/c3/DonutChart.phtml diff --git a/src/templates/c3/PieChart.html.php b/src/templates/c3/PieChart.phtml similarity index 100% rename from src/templates/c3/PieChart.html.php rename to src/templates/c3/PieChart.phtml diff --git a/tests/.coveralls.yml b/tests/.coveralls.yml new file mode 100644 index 0000000..82764a3 --- /dev/null +++ b/tests/.coveralls.yml @@ -0,0 +1,4 @@ +# for php-coveralls +service_name: travis-ci +coverage_clover: coverage.xml +json_path: coverage.json diff --git a/tests/coverage.xml b/tests/coverage.xml new file mode 100644 index 0000000..180ebfa --- /dev/null +++ b/tests/coverage.xml @@ -0,0 +1,11 @@ + + + + + ./../src + + + + + +