generated from dev/symfony-5-cli-template
29 changed files with 1740 additions and 424 deletions
-
8README.md
-
14composer.json
-
1639composer.lock
-
2config/bundles.php
-
11config/packages/dev/monolog.yaml
-
7config/packages/prod/deprecations.yaml
-
16config/packages/prod/monolog.yaml
-
12config/packages/test/monolog.yaml
-
2config/packages/test/twig.yaml
-
2config/packages/twig.yaml
-
1config/services.yaml
-
2devops/dist/.env-dist
-
4devops/docker/.env
-
4devops/docker/php/Dockerfile
-
1devops/docker/redis/redis.conf
-
29docker-compose.yaml
-
42src/Controller/IndexController.php
-
24src/Form/WeatherFormType.php
-
57src/Service/Endpoint/WeatherHistory.php
-
14src/Service/Endpoint/WeatherHistoryInterface.php
-
59symfony.lock
-
66templates/base.html.twig
-
10tests/_support/ApiTester.php
-
9tests/_support/Helper/Api.php
-
2tests/acceptance.suite.yml
-
60tests/acceptance/Controller/IndexControllerCest.php
-
23tests/acceptance/Controller/PageControllerCest.php
-
8tests/api.suite.yml
-
36tests/api/Controller/PageControllerCest.php
1639
composer.lock
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,11 @@ |
|||||
|
monolog: |
||||
|
handlers: |
||||
|
main: |
||||
|
type: stream |
||||
|
path: "%kernel.logs_dir%/%kernel.environment%.log" |
||||
|
level: debug |
||||
|
channels: ["!event"] |
||||
|
console: |
||||
|
type: console |
||||
|
process_psr_3_messages: false |
||||
|
channels: ["!event", "!doctrine", "!console"] |
@ -0,0 +1,7 @@ |
|||||
|
monolog: |
||||
|
channels: [deprecation] |
||||
|
handlers: |
||||
|
deprecation: |
||||
|
type: stream |
||||
|
channels: [deprecation] |
||||
|
path: "%kernel.logs_dir%/%kernel.environment%.deprecations.log" |
@ -0,0 +1,16 @@ |
|||||
|
monolog: |
||||
|
handlers: |
||||
|
main: |
||||
|
type: fingers_crossed |
||||
|
action_level: error |
||||
|
handler: nested |
||||
|
excluded_http_codes: [404, 405] |
||||
|
buffer_size: 50 |
||||
|
nested: |
||||
|
type: stream |
||||
|
path: "%kernel.logs_dir%/%kernel.environment%.log" |
||||
|
level: debug |
||||
|
console: |
||||
|
type: console |
||||
|
process_psr_3_messages: false |
||||
|
channels: ["!event", "!doctrine"] |
@ -0,0 +1,12 @@ |
|||||
|
monolog: |
||||
|
handlers: |
||||
|
main: |
||||
|
type: fingers_crossed |
||||
|
action_level: error |
||||
|
handler: nested |
||||
|
excluded_http_codes: [404, 405] |
||||
|
channels: ["!event"] |
||||
|
nested: |
||||
|
type: stream |
||||
|
path: "%kernel.logs_dir%/%kernel.environment%.log" |
||||
|
level: debug |
@ -0,0 +1,2 @@ |
|||||
|
twig: |
||||
|
strict_variables: true |
@ -0,0 +1,2 @@ |
|||||
|
twig: |
||||
|
default_path: '%kernel.project_dir%/templates' |
@ -1,4 +1,4 @@ |
|||||
APP_ENV=dev |
APP_ENV=dev |
||||
APP_SECRET=a1def1573d162b7d97ed994df9d37949 |
APP_SECRET=a1def1573d162b7d97ed994df9d37949 |
||||
|
|
||||
DATABASE_URL=mysql://root:rootroot@mysql:3306/template?serverVersion=5.7 |
|
||||
|
WEATHER_HISTORY_SERVER=http://weather_history_nginx_1:80 |
@ -1 +0,0 @@ |
|||||
bind 0.0.0.0 |
|
@ -0,0 +1,24 @@ |
|||||
|
<?php |
||||
|
|
||||
|
declare(strict_types=1); |
||||
|
|
||||
|
namespace App\Form; |
||||
|
|
||||
|
use Symfony\Component\Form\AbstractType; |
||||
|
use Symfony\Component\Form\Extension\Core\Type\DateType; |
||||
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType; |
||||
|
use Symfony\Component\Form\FormBuilderInterface; |
||||
|
|
||||
|
class WeatherFormType extends AbstractType |
||||
|
{ |
||||
|
public function buildForm(FormBuilderInterface $builder, array $options) |
||||
|
{ |
||||
|
$builder |
||||
|
->add('date', DateType::class, [ |
||||
|
'widget' => 'single_text', |
||||
|
'format' => 'yyyy-MM-dd', |
||||
|
]) |
||||
|
->add('send', SubmitType::class) |
||||
|
; |
||||
|
} |
||||
|
} |
@ -0,0 +1,57 @@ |
|||||
|
<?php |
||||
|
|
||||
|
declare(strict_types=1); |
||||
|
|
||||
|
namespace App\Service\Endpoint; |
||||
|
|
||||
|
use DateTime; |
||||
|
use GuzzleHttp\Client; |
||||
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; |
||||
|
|
||||
|
class WeatherHistory implements WeatherHistoryInterface |
||||
|
{ |
||||
|
private Client $client; |
||||
|
|
||||
|
private string $weatherHistoryServer; |
||||
|
|
||||
|
public function __construct(ParameterBagInterface $parameterBag) |
||||
|
{ |
||||
|
$this->client = new Client(); |
||||
|
|
||||
|
$this->weatherHistoryServer = $parameterBag->get('weather_history_server'); |
||||
|
} |
||||
|
|
||||
|
public function getByDate(DateTime $date): array |
||||
|
{ |
||||
|
$url = sprintf('%s/json-rpc', $this->weatherHistoryServer); |
||||
|
$response = $this->client->request('POST', $url, [ |
||||
|
'headers' => [ |
||||
|
'Accept-Encoding' => 'gzip', |
||||
|
'Content-Type' => 'text/plain', |
||||
|
], |
||||
|
'body' => sprintf( |
||||
|
'{"jsonrpc": "2.0", "method": "weather.getByDate", "params": {"date": "%s"}, "id": 1}', |
||||
|
$date->format('Y-m-d') |
||||
|
), |
||||
|
]); |
||||
|
|
||||
|
return json_decode($response->getBody()->getContents(), true); |
||||
|
} |
||||
|
|
||||
|
public function getHistory(int $numberOfDays = 30): array |
||||
|
{ |
||||
|
$url = sprintf('%s/json-rpc', $this->weatherHistoryServer); |
||||
|
$response = $this->client->request('POST', $url, [ |
||||
|
'headers' => [ |
||||
|
'Accept-Encoding' => 'gzip', |
||||
|
'Content-Type' => 'text/plain', |
||||
|
], |
||||
|
'body' => sprintf( |
||||
|
'{"jsonrpc": "2.0", "method": "weather.getHistory", "params": {"lastDays": %d}, "id": 1}', |
||||
|
$numberOfDays |
||||
|
), |
||||
|
]); |
||||
|
|
||||
|
return json_decode($response->getBody()->getContents(), true); |
||||
|
} |
||||
|
} |
@ -0,0 +1,14 @@ |
|||||
|
<?php |
||||
|
|
||||
|
declare(strict_types=1); |
||||
|
|
||||
|
namespace App\Service\Endpoint; |
||||
|
|
||||
|
use DateTime; |
||||
|
|
||||
|
interface WeatherHistoryInterface |
||||
|
{ |
||||
|
public function getByDate(DateTime $date): array; |
||||
|
|
||||
|
public function getHistory(int $numberOfDays = 30): array; |
||||
|
} |
@ -0,0 +1,66 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<meta charset="UTF-8"> |
||||
|
<title>{% block title %}Welcome!{% endblock %}</title> |
||||
|
{% block stylesheets %}{% endblock %} |
||||
|
|
||||
|
{% block javascripts %}{% endblock %} |
||||
|
</head> |
||||
|
<body> |
||||
|
{% block body %} |
||||
|
{% if weatherForm is defined and weatherForm %} |
||||
|
<h3>Погода за день</h3> |
||||
|
|
||||
|
{{ form_errors(weatherForm) }} |
||||
|
{{ form_start(weatherForm) }} |
||||
|
{{ form_widget(weatherForm) }} |
||||
|
{{ form_end(weatherForm) }} |
||||
|
|
||||
|
{% if weather.error.code is defined and weather.error.code |
||||
|
and weather.error.message is defined and weather.error.message |
||||
|
%} |
||||
|
<p> {{ weather.error.code }} {{ weather.error.message }}.</p> |
||||
|
{% else %} |
||||
|
{% if weather.result.temp is defined and weather.result.temp %} |
||||
|
<p>Температура {{ weather.result.temp }} градусов</p> |
||||
|
{% else %} |
||||
|
<p>Температура за указанный день не указана</p> |
||||
|
{% endif %} |
||||
|
{% endif %} |
||||
|
{% endif %} |
||||
|
|
||||
|
{% if history is defined and history %} |
||||
|
<h3>Погода за последние 30 дней</h3> |
||||
|
{% if history.error.code is defined and history.error.code |
||||
|
and history.error.message is defined and history.error.message |
||||
|
%} |
||||
|
<p>{{ history.error.code }} {{ history.error.message }}</p> |
||||
|
{% else %} |
||||
|
{% if history.result is defined and history.result %} |
||||
|
<table border="1"> |
||||
|
<tr> |
||||
|
<th>Дата</th> |
||||
|
<th>Температура</th> |
||||
|
</tr> |
||||
|
{% for element in history.result %} |
||||
|
<tr> |
||||
|
<td> |
||||
|
{% if element.date_at is defined and element.date_at %} |
||||
|
{{ element.date_at }} |
||||
|
{% endif %} |
||||
|
</td> |
||||
|
<td> |
||||
|
{% if element.temp is defined and element.temp %} |
||||
|
{{ element.temp }} |
||||
|
{% endif %} |
||||
|
</td> |
||||
|
</tr> |
||||
|
{% endfor %} |
||||
|
</table> |
||||
|
{% endif %} |
||||
|
{% endif %} |
||||
|
{% endif %} |
||||
|
{% endblock %} |
||||
|
</body> |
||||
|
</html> |
@ -1,10 +0,0 @@ |
|||||
<?php |
|
||||
|
|
||||
declare(strict_types=1); |
|
||||
|
|
||||
namespace App\Tests; |
|
||||
|
|
||||
class ApiTester extends \Codeception\Actor |
|
||||
{ |
|
||||
use _generated\ApiTesterActions; |
|
||||
} |
|
@ -1,9 +0,0 @@ |
|||||
<?php |
|
||||
|
|
||||
declare(strict_types=1); |
|
||||
|
|
||||
namespace App\Tests\Helper; |
|
||||
|
|
||||
class Api extends \Codeception\Module |
|
||||
{ |
|
||||
} |
|
@ -0,0 +1,60 @@ |
|||||
|
<?php |
||||
|
|
||||
|
declare(strict_types=1); |
||||
|
|
||||
|
namespace App\Tests\acceptance\Controller; |
||||
|
|
||||
|
use App\Tests\AcceptanceTester; |
||||
|
use Codeception\Example; |
||||
|
use DateTime; |
||||
|
|
||||
|
class IndexControllerCest |
||||
|
{ |
||||
|
private AcceptanceTester $tester; |
||||
|
|
||||
|
public function _before(AcceptanceTester $tester): void |
||||
|
{ |
||||
|
$this->tester = $tester; |
||||
|
} |
||||
|
|
||||
|
public function testBaseAvailability(): void |
||||
|
{ |
||||
|
$this->tester->amOnPage('/'); |
||||
|
$this->tester->seeResponseCodeIs(200); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @dataProvider dataDateForm |
||||
|
*/ |
||||
|
public function testDateForm(Example $example): void |
||||
|
{ |
||||
|
$this->tester->amOnPage('/'); |
||||
|
$this->tester->fillField("//input[@id='weather_form_date']", $example['fillField']); |
||||
|
$this->tester->click('Send'); |
||||
|
$this->tester->seeCurrentUrlEquals('/'); |
||||
|
$this->tester->seeResponseCodeIs(200); |
||||
|
$this->tester->see($example['see']); |
||||
|
} |
||||
|
|
||||
|
protected function dataDateForm(): array |
||||
|
{ |
||||
|
return [ |
||||
|
[ |
||||
|
'fillField' => (new DateTime())->format('Y-m-d'), |
||||
|
'see' => 'градусов', |
||||
|
], |
||||
|
[ |
||||
|
'fillField' => '9999-01-01', |
||||
|
'see' => 'Температура за указанный день не указана', |
||||
|
], |
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
public function testWeatherTable(): void |
||||
|
{ |
||||
|
$this->tester->amOnPage('/'); |
||||
|
$this->tester->see('Погода за последние 30 дней'); |
||||
|
$this->tester->see('Дата', '//th'); |
||||
|
$this->tester->see('Температура', '//th'); |
||||
|
} |
||||
|
} |
@ -1,23 +0,0 @@ |
|||||
<?php |
|
||||
|
|
||||
declare(strict_types=1); |
|
||||
|
|
||||
namespace App\Tests\acceptance\Controller; |
|
||||
|
|
||||
use App\Tests\AcceptanceTester; |
|
||||
|
|
||||
class PageControllerCest |
|
||||
{ |
|
||||
private AcceptanceTester $tester; |
|
||||
|
|
||||
public function _before(AcceptanceTester $tester): void |
|
||||
{ |
|
||||
$this->tester = $tester; |
|
||||
} |
|
||||
|
|
||||
public function testBaseAvailability(): void |
|
||||
{ |
|
||||
$this->tester->amOnPage('/'); |
|
||||
$this->tester->seeResponseCodeIs(400); |
|
||||
} |
|
||||
} |
|
@ -1,8 +0,0 @@ |
|||||
actor: ApiTester |
|
||||
modules: |
|
||||
enabled: |
|
||||
- REST: |
|
||||
url: http://nginx/ |
|
||||
depends: PhpBrowser |
|
||||
part: Json |
|
||||
- \App\Tests\Helper\Api |
|
@ -1,36 +0,0 @@ |
|||||
<?php |
|
||||
|
|
||||
declare(strict_types=1); |
|
||||
|
|
||||
namespace App\Tests\api\Controller; |
|
||||
|
|
||||
use App\Tests\ApiTester; |
|
||||
use Codeception\Example; |
|
||||
use Iterator; |
|
||||
|
|
||||
class PageControllerCest |
|
||||
{ |
|
||||
private ApiTester $tester; |
|
||||
|
|
||||
public function _before(ApiTester $tester): void |
|
||||
{ |
|
||||
$this->tester = $tester; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* @dataProvider dataTestBaseAvailability |
|
||||
*/ |
|
||||
public function testBaseAvailability(Example $example): void |
|
||||
{ |
|
||||
$this->tester->sendGet($example['url']); |
|
||||
$this->tester->seeResponseCodeIs(400); |
|
||||
$this->tester->seeResponseIsJson(); |
|
||||
} |
|
||||
|
|
||||
protected static function dataTestBaseAvailability(): Iterator |
|
||||
{ |
|
||||
yield [ |
|
||||
'url' => '/', |
|
||||
]; |
|
||||
} |
|
||||
} |
|
Reference in new issue