Skip to content

Commit

Permalink
ДЗ №19: Работа с очередью
Browse files Browse the repository at this point in the history
  • Loading branch information
shabanovvv committed Mar 11, 2024
1 parent f5c02a7 commit a4529f1
Show file tree
Hide file tree
Showing 19 changed files with 452 additions and 0 deletions.
5 changes: 5 additions & 0 deletions hw19/.docker/nginx/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM nginx

WORKDIR /var/www/html

COPY ngnix.conf /etc/nginx/nginx.conf
25 changes: 25 additions & 0 deletions hw19/.docker/nginx/ngnix.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
worker_processes 1;

events {
worker_connections 1024;
}

http {
server {
listen 80;
server_name localhost;
root /var/www/html/public/;

location / {
index index.php;
try_files $uri $uri/ /index.php?$query_string;
}

location ~ \.php$ {
fastcgi_pass php-fpm:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
}
11 changes: 11 additions & 0 deletions hw19/.docker/php-fpm/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM php:8.2-fpm

RUN apt-get update && apt-get install -y \
libzip-dev \
&& docker-php-ext-install zip sockets

RUN chown -R www-data:www-data /var/www/html

WORKDIR /var/www/html

CMD ["php-fpm"]
12 changes: 12 additions & 0 deletions hw19/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Работа с очередью

## Отправка данных
1. Для генерации банковской выписки за указанные даты перейдите в браузере на главную страницу http://localhost/
2. Выберите нужный интервал дат
3. Нажмите кнопку отправить
4. После чего форма вас переадресует на страницу обработчика формы /formHandler, в котором даты отправятся через RabbitMQ Producer в очередь

## Получение данных
1. Чтобы считать данную очередь, вам нужно зайти в консоль и запуcтить команду php bin/console rabbitmq:consumer
2. Теперь в консоли вы можете видеть отправленные из браузерной формы даты
3. Также в консольной команде после вывода данных на экран происходит отправка письма.
36 changes: 36 additions & 0 deletions hw19/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
version: "3"
services:
nginx:
container_name: nginx-otusphp
build: ./.docker/nginx
ports:
- "80:80"
volumes:
- ./www:/var/www/html
depends_on:
- php-fpm
networks:
- otusphp

php-fpm:
container_name: php-fpm-otusphp
build: ./.docker/php-fpm/
volumes:
- ./www:/var/www/html
depends_on:
- rabbitmq
networks:
- otusphp

rabbitmq:
container_name: rabbitmq-otusphp
image: rabbitmq:3.10.7-management
ports:
- 15672:15672
- 5672:5672
networks:
- otusphp

networks:
otusphp:
driver: bridge
16 changes: 16 additions & 0 deletions hw19/www/bin/console
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env php
<?php
declare(strict_types=1);

require __DIR__ . '/../vendor/autoload.php';

use Shabanov\Otusphp\Command\ConsumerCommand;
use Symfony\Component\Console\Application;

$application = new Application();
$application->add(new ConsumerCommand());
try {
$application->run();
} catch (Exception $e) {
throw new \Exception($e->getMessage());
}
20 changes: 20 additions & 0 deletions hw19/www/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "shabanov/otusphp",
"autoload": {
"psr-4": {
"Shabanov\\Otusphp\\": "src/"
}
},
"authors": [
{
"name": "Vyacheslav Shabanov",
"email": "[email protected]"
}
],
"require": {
"php-amqplib/php-amqplib": "^3.6",
"symfony/console": "^7.0",
"symfony/mailer": "^7.0",
"phpmailer/phpmailer": "^6.9"
}
}
13 changes: 13 additions & 0 deletions hw19/www/public/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

Check failure on line 1 in hw19/www/public/index.php

View workflow job for this annotation

GitHub Actions / phpcs

Header blocks must be separated by a single blank line
declare(strict_types=1);

require_once __DIR__ . '/../vendor/autoload.php';

use Shabanov\Otusphp\App;

try {
$app = new App();
$app();
} catch(Exception $e) {

Check failure on line 11 in hw19/www/public/index.php

View workflow job for this annotation

GitHub Actions / phpcs

Expected 1 space(s) after CATCH keyword; 0 found
throw new Exception($e->getMessage());
}
15 changes: 15 additions & 0 deletions hw19/www/src/App.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

Check failure on line 1 in hw19/www/src/App.php

View workflow job for this annotation

GitHub Actions / phpcs

Header blocks must be separated by a single blank line
declare(strict_types=1);

namespace Shabanov\Otusphp;

class App
{
public function __construct()
{}

Check failure on line 9 in hw19/www/src/App.php

View workflow job for this annotation

GitHub Actions / phpcs

Closing brace must be on a line by itself

public function __invoke(): void
{
(new Route($_SERVER['REQUEST_URI']))->run();
}
}
87 changes: 87 additions & 0 deletions hw19/www/src/Command/ConsumerCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php

Check failure on line 1 in hw19/www/src/Command/ConsumerCommand.php

View workflow job for this annotation

GitHub Actions / phpcs

Header blocks must be separated by a single blank line
declare(strict_types=1);

namespace Shabanov\Otusphp\Command;

use PhpAmqpLib\Channel\AbstractChannel;
use PhpAmqpLib\Channel\AMQPChannel;
use Shabanov\Otusphp\Connection\ConnectionInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class ConsumerCommand extends Command
{
private string $connectClient = 'Shabanov\Otusphp\Connection\RabbitMqConnect';
private string $queue = 'otus';
private AMQPChannel|AbstractChannel $channel;
private ConnectionInterface $connect;

protected function configure(): void
{
$this->setName('rabbitmq:consumer')
->setDescription('RabbitMQ consumer обработчик формы');
}

protected function initialize(InputInterface $input, OutputInterface $output): void
{
$this->connect = new $this->connectClient();
$this->channel = $this->connect->getClient();
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$callback = function ($msg) use ($output) {
/**
* Выведим в консоль поступившую строку
*/
$output->writeln('<info>[x] ' . $msg->body . '</info>');
/**
* Отправим строку на Email
*/
$this->sendEmail($msg->body);
};

$this->channel->basic_consume(
$this->queue,
'',
false,
true,
false,
false,
$callback
);

while ($this->channel->is_consuming()) {
$this->channel->wait();
}

$this->channel->close();
$this->connect->close();

return Command::SUCCESS;
}

protected function sendEmail(string $body): void
{
$mail = new \PHPMailer(true);

try {
$mail->isSMTP();
$mail->Host = 'smtp.yandex.ru';
$mail->SMTPAuth = true;
$mail->Username = 'saveliy';
$mail->Password = 'password';
$mail->Port = 465;

$mail->setFrom('[email protected]', 'Sender');
$mail->addAddress('[email protected]', 'Recipient');

$mail->Subject = 'Новое сообщение';
$mail->Body = $body;

$mail->send();
} catch (Exception $e) {
echo 'Ошибка отправки письма: ' . $mail->ErrorInfo;
}
}
}
10 changes: 10 additions & 0 deletions hw19/www/src/Connection/ConnectionInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Shabanov\Otusphp\Connection;

interface ConnectionInterface
{
public function getClient();

public function close(): void;
}
32 changes: 32 additions & 0 deletions hw19/www/src/Connection/RabbitMqConnect.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Shabanov\Otusphp\Connection;

use Exception;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Channel\AbstractChannel;

class RabbitMqConnect implements ConnectionInterface
{
private AMQPStreamConnection $connect;
/**
* @throws Exception
*/
public function __construct()
{
$this->connect = new AMQPStreamConnection('rabbitmq', 5672, 'guest', 'guest');
}
public function getClient(): AMQPChannel|AbstractChannel
{
return $this->connect->channel();
}

/**
* @throws Exception
*/
public function close(): void
{
$this->connect->close();
}
}
24 changes: 24 additions & 0 deletions hw19/www/src/Controller/PageController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Shabanov\Otusphp\Controller;

use Shabanov\Otusphp\Producer\RabbitMqProducer;
use Shabanov\Otusphp\Render\FormRender;
use Shabanov\Otusphp\Render\FormSuccessRender;

class PageController
{
public function main(): void
{
echo (new FormRender())->show();
}

public function formHandler(): void
{
if (!empty($_REQUEST['send']) && !empty($_REQUEST['date_from'])) {
$message = 'Date from: ' . $_REQUEST['date_from'] . ' Date to: ' . $_REQUEST['date_to'];
(new RabbitMqProducer())->send($message);
echo (new FormSuccessRender())->show();
}
}
}
46 changes: 46 additions & 0 deletions hw19/www/src/Producer/RabbitMqProducer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

Check failure on line 1 in hw19/www/src/Producer/RabbitMqProducer.php

View workflow job for this annotation

GitHub Actions / phpcs

Header blocks must be separated by a single blank line
declare(strict_types=1);

namespace Shabanov\Otusphp\Producer;

use PhpAmqpLib\Channel\AbstractChannel;
use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Exchange\AMQPExchangeType;
use PhpAmqpLib\Message\AMQPMessage;
use Shabanov\Otusphp\Connection\ConnectionInterface;

class RabbitMqProducer
{
private string $connectClient = 'Shabanov\Otusphp\Connection\RabbitMqConnect';
private AMQPChannel|AbstractChannel $channel;
private string $exchange = 'shabanov';
private string $queue = 'otus';
private ConnectionInterface $connect;

public function __construct()
{
$this->connect = new $this->connectClient();
$this->channel = $this->connect->getClient();
}

public function send(string $message): void
{
$this->channel->queue_declare($this->queue, false, true, false, false);
$this->channel->exchange_declare($this->exchange, AMQPExchangeType::DIRECT, false, true, false);
$this->channel->queue_bind($this->queue, $this->exchange);

$this->messagePublish($message);

$this->channel->close();
$this->connect->close();
}

private function messagePublish(string $message): void
{
$message = new AMQPMessage($message, [
'content_type' => 'text/plain',
'delivery_mode' => AMQPMessage::DELIVERY_MODE_NON_PERSISTENT
]);
$this->channel->basic_publish($message, $this->exchange);
}
}
19 changes: 19 additions & 0 deletions hw19/www/src/Render/Error404Render.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Shabanov\Otusphp\Render;

class Error404Render implements RenderInterface
{
public function __construct() {}

Check failure on line 7 in hw19/www/src/Render/Error404Render.php

View workflow job for this annotation

GitHub Actions / phpcs

Opening brace should be on a new line

Check failure on line 7 in hw19/www/src/Render/Error404Render.php

View workflow job for this annotation

GitHub Actions / phpcs

Closing brace must be on a line by itself
public function show(): string
{
ob_start();
?>
<img src="https://www.freeparking.co.nz/learn/wp-content/uploads/2023/06/768x385-21.png">
<p>404 Not Found</p>
<?php
$content = ob_get_contents();
ob_end_clean();
return $content;
}
}
Loading

0 comments on commit a4529f1

Please sign in to comment.