Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ERybkin: Homework #15 (Code architecture #21) #894

Open
wants to merge 20 commits into
base: ERybkin/main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .env.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# General
PROJECT_PREFIX=otus-hw-15

# NGINX
NGINX_PORT=8080

# PostgreSQL
POSTGRES_VERSION=15
POSTGRES_PORT=5432
POSTGRES_DB=postgres
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
.DS_Store
.AppleDouble
.LSOverride
.env
24 changes: 24 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.PHONY: up down exec shell

include .env

up:
docker-compose up -d --build

down:
docker-compose down

exec:
docker exec -it ${PROJECT_PREFIX}-php-fpm $(ARGS)

shell:
make exec ARGS=bash

doctrine-validate:
make exec ARGS='php bin/console doctrine:schema:validate'

doctrine-diff:
make exec ARGS='php bin/console doctrine:migrations:diff'

doctrine-migrate:
make exec ARGS='php bin/console doctrine:migrations:migrate'
159 changes: 157 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,158 @@
# PHP_2024
# Урок 21. Архитектура кода (Д.З. 15)

Содержание:

- [Описание](#описание)
- [Использование](#использование)

## Описание

### Домашнее задание: система медиамониторинга

Вам нужно разработать REST API (только backend!) для системы, которая поможет собирать информацию и готовить
сводные отчёты о новостных публикациях в Интернете.

### Пользовательские сценарии:

**Добавление новости**.

В систему передаётся URL новостного материала в Интернете. Система скачивает HTML по этому URL и создаёт на его основе
сущность со следующими полями:

- дата (текущая дата)
- URL (нам его передали в запросе)
- название новости (его проще всего взять из тега title)

В ответ возвращается ID сущности.

**Получение списка новостей**.

Система возвращает список (массив) ранее созданных сущностей с полями:

- ID
- дата
- URL
- название новости

**Формирование сводного отчёта**.

В систему передаётся массив из нескольких ID. Система формирует и сохраняет на диск простой HTML-файл со списком
примерно такого вида:

```html

<ul>
<li><a href="...">Заголовок новости 1</a></li>
<li><a href="...">Заголовок новости 2</a></li>
</ul>
```

В ответ возвращается ссылка на этот файл.

### Важные замечания:

1) Вам нужно самостоятельно продумать всё, что касается архитектуры этого приложения. Если будут вопросы — задавайте. Не
бойтесь допускать ошибки: весь смысл домашки в том, чтобы потом их обсудить и исправить.

2) Вы можете взять за основу любой фреймворк, но обращаться к методам и классам фреймворка можно только на слое
Infrastructure. Другими словами, ни на слое Domain, ни на слое Application не должно использоваться ничего, кроме
написанных вами классов.

3) Для хранения сущностей вы можете использовать БД или файловую систему, это не принципиально, но — см. предыдущее
замечание.

## Использование

### Установка

Создание файла с переменными окружения:

```shell
cp .env.dist .env && cp app/.env.dist app/.env
```

Запустить Docker контейнеры:

```shell
make up
```

Установить зависимости:

```shell
make exec ARGS="composer install"
```

Запустить миграции:

```shell
make doctrine-migrate
```

### API

**Создание поста**

Пример запроса:

```http request
POST /api/v1/posts

{
"url": "https://google.com"
}
```

Пример ответа:

```json
{
"id": 1
}
```

**Получение списка постов**

Пример запроса:

```http request
GET /api/v1/posts
```

Пример ответа:

```json
[
{
"id": 1,
"title": "Google",
"date": {
"date": "2024-11-06 17:19:34.000000",
"timezone_type": 3,
"timezone": "UTC"
},
"url": "https://google.com"
}
]
```

**Генерация отчета**

Пример запроса:

```http request
POST /api/v1/reports

{
"postIds": [1]
}
```

Пример ответа:

```json
{
"url": "http://localhost:8080/var/export/reports/6737904239e89.html"
}
```

https://otus.ru/lessons/razrabotchik-php/?utm_source=github&utm_medium=free&utm_campaign=otus
11 changes: 11 additions & 0 deletions app/.env.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
APP_ENV=dev
APP_SECRET=696985760efc6419ad5a75ccb15ad7cb
APP_BASE_URL=http://localhost:8080/

DATABASE_HOST=postgres
DATABASE_PORT=5432
DATABASE_NAME=postgres
DATABASE_USER=postgres
DATABASE_PASSWORD=postgres
DATABASE_DRIVER=pdo_pgsql
DATABASE_SERVER_VERSION=15
10 changes: 10 additions & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

###> symfony/framework-bundle ###
/.env.local
/.env.local.php
/.env.*.local
/config/secrets/prod/prod.decrypt.private.php
/public/bundles/
/var/
/vendor/
###< symfony/framework-bundle ###
21 changes: 21 additions & 0 deletions app/bin/console
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env php
<?php

use App\Shared\Infrastructure\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;

if (!is_dir(dirname(__DIR__) . '/vendor')) {
throw new LogicException('Dependencies are missing. Try running "composer install".');
}

if (!is_file(dirname(__DIR__) . '/vendor/autoload_runtime.php')) {
throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".');
}

require_once dirname(__DIR__) . '/vendor/autoload_runtime.php';

return function (array $context) {
$kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);

return new Application($kernel);
};
82 changes: 82 additions & 0 deletions app/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{
"name": "rybkinevg/otus-homework-15",
"type": "project",
"license": "proprietary",
"minimum-stability": "stable",
"prefer-stable": true,
"require": {
"php": ">=8.2",
"ext-ctype": "*",
"ext-iconv": "*",
"doctrine/dbal": "^3",
"doctrine/doctrine-bundle": "^2.13",
"doctrine/doctrine-migrations-bundle": "^3.3",
"doctrine/orm": "^3.3",
"phpdocumentor/reflection-docblock": "^5.4",
"phpstan/phpdoc-parser": "^1.33",
"symfony/console": "7.1.*",
"symfony/css-selector": "7.1.*",
"symfony/dom-crawler": "7.1.*",
"symfony/dotenv": "7.1.*",
"symfony/flex": "^2",
"symfony/framework-bundle": "7.1.*",
"symfony/http-client": "7.1.*",
"symfony/mime": "7.1.*",
"symfony/property-access": "7.1.*",
"symfony/property-info": "7.1.*",
"symfony/runtime": "7.1.*",
"symfony/serializer": "7.1.*",
"symfony/validator": "7.1.*",
"symfony/yaml": "7.1.*"
},
"config": {
"allow-plugins": {
"php-http/discovery": true,
"symfony/flex": true,
"symfony/runtime": true
},
"sort-packages": true
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
}
},
"replace": {
"symfony/polyfill-ctype": "*",
"symfony/polyfill-iconv": "*",
"symfony/polyfill-php72": "*",
"symfony/polyfill-php73": "*",
"symfony/polyfill-php74": "*",
"symfony/polyfill-php80": "*",
"symfony/polyfill-php81": "*",
"symfony/polyfill-php82": "*"
},
"scripts": {
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd"
},
"post-install-cmd": [
"@auto-scripts"
],
"post-update-cmd": [
"@auto-scripts"
]
},
"conflict": {
"symfony/symfony": "*"
},
"extra": {
"symfony": {
"allow-contrib": false,
"require": "7.1.*",
"docker": false
}
}
}
Loading