Merge pull request #13 from Pen-y-Fan/php72

Configured for PHP 7.2+
This commit is contained in:
Emily Bache
2020-05-19 08:57:45 +02:00
committed by GitHub
17 changed files with 3837 additions and 378 deletions
+2
View File
@@ -1 +1,3 @@
vendor/ vendor/
/.phpunit.result.cache
/.idea
+131 -5
View File
@@ -1,9 +1,135 @@
Theatrical Players Refactoring Kata - PHP version # Theatrical Players Refactoring Kata - PHP version
========================================================
See the [top level readme](https://github.com/emilybache/Theatrical-Players-Refactoring-Kata) for general information about this exercise. See the [top level readme](../../Theatrical-Players-Refactoring-Kata/README.md) for general information
about this exercise. Download the PDF of the first chapter of
['Refactoring' by Martin Fowler, 2nd Edition](https://www.thoughtworks.com/books/refactoring2) which contains a worked
example of this exercise, in javascript.
This project uses [PHPUnit](https://github.com/sebastianbergmann/phpunit) and [approvaltests](https://github.com/approvals/ApprovalTests.php). ## Installation
Run ```composer install``` then ```./vendor/bin/phpunit``` to run the tests The project uses:
- [PHP 7.2+](https://www.php.net/downloads.php)
- [Composer](https://getcomposer.org)
Recommended:
- [Git](https://git-scm.com/downloads)
Clone the repository
```sh
git clone git@github.com:emilybache/Theatrical-Players-Refactoring-Kata.git
```
or
```shell script
git clone https://github.com/emilybache/Theatrical-Players-Refactoring-Kata.git
```
Install all the dependencies using composer:
```sh
cd ./Theatrical-Players-Refactoring-Kata/php
composer install
```
## Dependencies
The project uses composer to install:
- [PHPUnit](https://phpunit.de/)
- [ApprovalTests.PHP](https://github.com/approvals/ApprovalTests.php)
- [PHPStan](https://github.com/phpstan/phpstan)
- [Easy Coding Standard (ECS)](https://github.com/symplify/easy-coding-standard)
- [PHP CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer/wiki)
## Folders
- `src` - Contains the **StatementPrinter** Class along with the setup classes. Only **StatementPrinter.php** is
refactored.
- `tests` - Contains the corresponding tests. There should be no need to amend the test.
- `approvals` - Contains the text output for the tests. There should be no need to amend.
## Testing
PHPUnit is used to run tests, to help this can be run using a composer script. To run the unit tests, from the root of
the project run:
```shell script
composer test
```
On Windows a batch file has been created, similar to an alias on Linux/Mac (e.g. `alias pu="composer test"`), the same
PHPUnit `composer test` can be run:
```shell script
pu
```
### Tests with Coverage Report
To run all test and generate a html coverage report run:
```shell script
composer test-coverage
```
The coverage report is created in /builds, it is best viewed by opening **index.html** in your browser.
The [XDEbug](https://xdebug.org/download) extension is required for coverage report generating.
## Code Standard
Easy Coding Standard (ECS) is used to check for style and code standards,
**[PSR-12](https://www.php-fig.org/psr/psr-12/)** is used. As the code is constantly being refactored only run code
standard checks once the chapter is complete.
### Check Code
To check code, but not fix errors:
```shell script
composer check-cs
```
On Windows a batch file has been created, similar to an alias on Linux/Mac (e.g. `alias cc="composer check-cs"`), the
same ECS `composer check-cs` can be run:
```shell script
cc
```
### Fix Code
Many code fixes are automatically provided by ECS, if advised to run --fix, the following script can be run:
```shell script
composer fix-cs
```
On Windows a batch file has been created, similar to an alias on Linux/Mac (e.g. `alias fc="composer fix-cs"`), the same
ECS `composer fix-cs` can be run:
```shell script
fc
```
## Static Analysis
PHPStan is used to run static analysis checks. As the code is constantly being refactored only run static analysis
checks once the chapter is complete.
```shell script
composer phpstan
```
On Windows a batch file has been created, similar to an alias on Linux/Mac (e.g. `alias ps="composer phpstan"`), the
same PHPStan `composer phpstan` can be run:
```shell script
ps
```
**Happy coding**!
+1
View File
@@ -0,0 +1 @@
composer check-cs
+25 -5
View File
@@ -2,8 +2,12 @@
"name": "sam/theatrical", "name": "sam/theatrical",
"type": "project", "type": "project",
"require-dev": { "require-dev": {
"phpunit/phpunit": "^9", "phpunit/phpunit": "^8.5",
"approvals/approval-tests": "^1.4" "approvals/approval-tests": "^1.4",
"phpstan/phpstan": "^0.12.25",
"phpstan/phpstan-phpunit": "^0.12.8",
"symplify/easy-coding-standard": "^7.3",
"symplify/phpstan-extensions": "^7.3"
}, },
"authors": [ "authors": [
{ {
@@ -12,11 +16,27 @@
} }
], ],
"require": { "require": {
"php": "^7.4" "php": "^7.2",
"ext-intl": "*"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Theatrical\\": "src/" "Theatrical\\": "src/"
} }
} },
} "autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"scripts": {
"checkcode": "phpcs src tests --standard=PSR12",
"fixcode": "phpcbf src tests --standard=PSR12",
"test": "phpunit",
"tests": "phpunit",
"test-coverage": "phpunit --coverage-html build/coverage",
"check-cs": "ecs check src tests --ansi",
"fix-cs": "ecs check src tests --fix --ansi",
"phpstan": "phpstan analyse --ansi"
}
}
+3507 -297
View File
File diff suppressed because it is too large Load Diff
+12
View File
@@ -0,0 +1,12 @@
parameters:
sets:
- 'psr12'
- 'php71'
- 'symplify'
- 'common'
- 'clean-code'
line_ending: "\n"
# 4 spaces
indentation: " "
+1
View File
@@ -0,0 +1 @@
composer fix-cs
+28 -3
View File
@@ -1,4 +1,29 @@
<?php <?php
require __DIR__ . '/vendor/autoload.php'; declare(strict_types=1);
use Theatrical\HtmlStatement;
use Theatrical\Invoice;
use Theatrical\Performance;
use Theatrical\Play;
require __DIR__ . '/vendor/autoload.php';
$plays = [
"hamlet" => new Play("Hamlet", "tragedy"),
"as-like" => new Play("As You Like It", "comedy"),
"othello" => new Play("Othello", "tragedy")
];
$performances = [
new Performance("hamlet", 55),
new Performance("as-like", 35),
new Performance("othello", 40)
];
$invoice = new Invoice("BigCo", $performances);
echo "<h1>Html Statement</h1>";
// Uncomment the following two line once the HtmlStatement Class is written (Ch.1 page 31)
//$statementPrinter = new HtmlStatement();
//echo $statementPrinter->print($invoice, $plays);
+26
View File
@@ -0,0 +1,26 @@
includes:
- vendor/symplify/phpstan-extensions/config/config.neon
- vendor/phpstan/phpstan-phpunit/extension.neon
parameters:
paths:
- src
- tests
# The level 8 is the highest level
level: 8
# Larstan recommendation:
checkMissingIterableValueType: false
ignoreErrors:
# buggy
# mixed
# cache buggy
# tests
# iterable
+1
View File
@@ -0,0 +1 @@
composer phpstan
+1
View File
@@ -0,0 +1 @@
composer test
+13 -5
View File
@@ -1,16 +1,24 @@
<?php <?php
declare(strict_types=1);
namespace Theatrical; namespace Theatrical;
class Invoice class Invoice
{ {
public string $customer; /**
public array $performances; * @var string
*/
public $customer;
public function __construct($customer, $performances) /**
* @var array
*/
public $performances;
public function __construct(string $customer, array $performances)
{ {
$this->customer = $customer; $this->customer = $customer;
$this->performances = $performances; $this->performances = $performances;
} }
}
}
+19 -5
View File
@@ -1,15 +1,29 @@
<?php <?php
declare(strict_types=1);
namespace Theatrical; namespace Theatrical;
class Performance class Performance
{ {
public string $play_id; /**
public int $audience; * @var string
*/
public $play_id;
public function __construct($play_id, $audience) /**
* @var int
*/
public $audience;
/**
* @var Play
*/
public $play;
public function __construct(string $play_id, int $audience)
{ {
$this->play_id = $play_id; $this->play_id = $play_id;
$this->audience = $audience; $this->audience = $audience;
} }
} }
+14 -5
View File
@@ -1,13 +1,22 @@
<?php <?php
declare(strict_types=1);
namespace Theatrical; namespace Theatrical;
class Play class Play
{ {
public string $name; /**
public string $type; * @var string
*/
public $name;
public function __construct($name, $type) /**
* @var string
*/
public $type;
public function __construct(string $name, string $type)
{ {
$this->name = $name; $this->name = $name;
$this->type = $type; $this->type = $type;
@@ -17,4 +26,4 @@ class Play
{ {
return (string) $this->name . ' : ' . $this->type; return (string) $this->name . ' : ' . $this->type;
} }
} }
+27 -28
View File
@@ -1,63 +1,62 @@
<?php <?php
declare(strict_types=1);
namespace Theatrical; namespace Theatrical;
use Theatrical\Play;
use Theatrical\Invoice; use Error;
use Theatrical\Performance; use NumberFormatter;
class StatementPrinter class StatementPrinter
{ {
public function print(Invoice $invoice, array $plays) public function print(Invoice $invoice, array $plays): string
{ {
$totalAmount = 0; $totalAmount = 0;
$volumeCredits = 0; $volumeCredits = 0;
$result = 'Statement for ' . $invoice->customer . '\n'; $result = "Statement for {$invoice->customer}\n";
$format = new NumberFormatter('en_US', NumberFormatter::CURRENCY);
foreach($invoice->performances as $performance) foreach ($invoice->performances as $performance) {
{
$play = $plays[$performance->play_id]; $play = $plays[$performance->play_id];
$thisAmount = 0; $thisAmount = 0;
switch($play->type) switch ($play->type) {
{ case 'tragedy':
case "tragedy":
$thisAmount = 40000; $thisAmount = 40000;
if($performance->audience > 30) if ($performance->audience > 30) {
{
$thisAmount += 1000 * ($performance->audience - 30); $thisAmount += 1000 * ($performance->audience - 30);
} }
break; break;
case "comedy": case 'comedy':
$thisAmount = 30000; $thisAmount = 30000;
if($performance->audience > 20) if ($performance->audience > 20) {
{
$thisAmount += 10000 + 500 * ($performance->audience - 20); $thisAmount += 10000 + 500 * ($performance->audience - 20);
} }
$thisAmount += 300 * $performance->audience; $thisAmount += 300 * $performance->audience;
break; break;
default: default:
throw new \Error("Unknow type: $play->type"); throw new Error("Unknown type: {$play->type}");
} }
// add volume credits
$volumeCredits += max($performance->audience - 30, 0); $volumeCredits += max($performance->audience - 30, 0);
if($play->type == 'comedy') // add extra credit for every ten comedy attendees
{ if ($play->type === 'comedy') {
$volumeCredits += floor($performance->audience / 5); $volumeCredits += floor($performance->audience / 5);
} }
$thisFinalAmount = $thisAmount / 100;
$result = "$play->name: $thisFinalAmount ($performance->audience seats)\n"; // print line for this order
$result .= " {$play->name}: {$format->formatCurrency($thisAmount / 100, 'USD')} ";
$result .= "({$performance->audience} seats)\n";
$totalAmount += $thisAmount; $totalAmount += $thisAmount;
} }
$finalTotal = ($totalAmount / 100); $result .= "Amount owed is {$format ->formatCurrency($totalAmount / 100, 'USD')}\n";
$result .= "Amount owed is $finalTotal\n"; $result .= "You earned {$volumeCredits} credits";
$result .= "You earned $volumeCredits credits\n";
return $result; return $result;
} }
} }
+23 -22
View File
@@ -1,50 +1,51 @@
<?php <?php
use PHPUnit\Framework\TestCase; declare(strict_types=1);
use ApprovalTests\Approvals;
use Theatrical\StatementPrinter; namespace Tests;
use Theatrical\Play;
use Theatrical\Performance; use ApprovalTests\Approvals;
use Error;
use PHPUnit\Framework\TestCase;
use Theatrical\Invoice; use Theatrical\Invoice;
use Theatrical\Performance;
use Theatrical\Play;
use Theatrical\StatementPrinter;
final class StatementPrinterTest extends TestCase final class StatementPrinterTest extends TestCase
{ {
public function testCanPrintInvoice() : void public function testCanPrintInvoice(): void
{ {
$plays = [ $plays = [
"hamlet" => new Play("Hamlet", "tragedy"), 'hamlet' => new Play('Hamlet', 'tragedy'),
"as-like" => new Play("As You Like It", "comedy"), 'as-like' => new Play('As You Like It', 'comedy'),
"othello" => new Play("Othello", "tragedy") 'othello' => new Play('Othello', 'tragedy'),
]; ];
$performances = [ $performances = [
new Performance("hamlet", 55), new Performance('hamlet', 55),
new Performance("as-like", 35), new Performance('as-like', 35),
new Performance("othello", 40) new Performance('othello', 40),
]; ];
$invoice = new Invoice("BigCo", $performances); $invoice = new Invoice('BigCo', $performances);
$statementPrinter = new StatementPrinter(); $statementPrinter = new StatementPrinter();
$result = $statementPrinter->print($invoice, $plays); $result = $statementPrinter->print($invoice, $plays);
Approvals::verifyString($result); Approvals::verifyString($result);
} }
public function testNewPlayTypes() : void public function testNewPlayTypes(): void
{ {
$plays = [ $plays = [
"henry-v" => new Play("Henry V", "history"), 'henry-v' => new Play('Henry V', 'history'),
"as-like" => new Play("As You Like It", "comedy"), 'as-like' => new Play('As You Like It', 'comedy'),
]; ];
$performances = [ $performances = [new Performance('henry-v', 53), new Performance('as-like', 55)];
new Performance("henry-v", 53),
new Performance("as-like", 55)
];
$invoice = new Invoice("BigCo", $performances); $invoice = new Invoice('BigCo', $performances);
$statementPrinter = new StatementPrinter(); $statementPrinter = new StatementPrinter();
$this->expectException(\Error::class); $this->expectException(Error::class);
$statementPrinter->print($invoice, $plays); $statementPrinter->print($invoice, $plays);
} }
} }
@@ -1,3 +1,6 @@
Othello: 500 (40 seats) Statement for BigCo
Amount owed is 1730 Hamlet: $650.00 (55 seats)
You earned 47 credits As You Like It: $580.00 (35 seats)
Othello: $500.00 (40 seats)
Amount owed is $1,730.00
You earned 47 credits