Skip to content

Instantly share code, notes, and snippets.

@ArtemioVegas
Last active April 28, 2023 10:12
Show Gist options
  • Save ArtemioVegas/ccf9c9c1e6de7bab726a19c3cf791830 to your computer and use it in GitHub Desktop.
Save ArtemioVegas/ccf9c9c1e6de7bab726a19c3cf791830 to your computer and use it in GitHub Desktop.
Модификация списка товаров
<?php
final class Cart
{
private array $items = [];
public function getItems(): array
{
// some code
}
public function getItemsCount(): int
{
// some code
}
public function addItem($item): void
{
// some code
}
public function deleteItem($item): void
{
// some code
}
public function calculateTotalSum(): int
{
// some code
}
}
final class OrderRepository
{
public function load(){/*...*/ }
public function save(){/*...*/ }
public function update(){/*...*/ }
public function delete(){/*...*/ }
}
final class OrderView
{
public function printOrder(){/*...*/ }
public function showOrder(){/*...*/ }
}
/// COMPOSER
1) клонируем репозиторий библиотеки через git
2) создаем ветку в в репозитории библиотеки, в нее коммитим нужные нам доработки, например "my-feature"
3) Пушим ветку на сервер
4) в проекте создаем новую ветку от мастера, в файле composer.json меняем версию пакета на названия ветки которую пушили в либу,с префиксом "dev" например - "dev-my-feature"
5) обновляем билиотеку в нашем проекте - composer update test-vendor/test-library
6) Локально на проекте запускаем тесты, чтобы проверить что ничего не поломалось
7) После того как наши изменения для библиотеки влиты мейнтенером, подтягиваем обновленный пакет через composer composer update test-vendor/test-library
предварительно указав корректные constraint (возможно был мажорный апдейт)
7) После того как изменения на проекте успешно протестировано, мерджим ветку проекта в мастер
8) в гитлабе создаем новый тэг от свежего мастера, выкатываем его на прод
version: '3'
services:
db:
image: mysql:8
version: '3'
networks:
nginx-php-network:
services:
nginx:
image: nginx:alpine
container_name: app-nginx
ports:
- "8090:8090"
- "443:443"
volumes:
- ./:/var/www
- .docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
networks:
- nginx-php-network
links:
- php-fpm
php-fpm:
image: php:8.2-fpm
container_name: app-php
ports:
- "9000:9000"
volumes:
- ./app:/var/www/project
networks:
- nginx-php-network
links:
- db
db:
platform: linux/x86_64
image: mysql:5.6.47
container_name: app-db
ports:
- "3306:3306"
volumes:
- ./etc/infrastructure/mysql/my.cnf:/etc/mysql/my.cnf
- ./etc/database/base.sql:/docker-entrypoint-initdb.d/base.sql
networks:
- nginx-php-network
– предоставить авторизованному пользователю возможность добавлять продукты в избранное
/products/favorite метод POST
{
"productId" : 1
}
Пример ответа
HTTP/1.1 200 OK
- пользователь так же должен иметь возможность просматривать список избранных продуктов отдельно
/products/favorite метод GET
Пример Ответа от сервера
[
{
"id": 1,
"name": "Example product 1",
"image_url": "https://cdn.market.com/images/products/product_1.png",
},
{
"id": 4,
"name": "Example product 4",
"image_url": "https://cdn.market.com/images/products/product_4.png",
},
]
- избранные продукты должны отображаться с соответствующей пометкой в общем списке всех продуктов
(добавляем новое свойство "isFavorite" тип boolean),
а так же добавляем возможность отображать массив картинок для товара
GET /products?category=category-1&sort=name HTTP/1.1
Пример Ответа от сервера
[
{
"id": 1,
"name": "Example product 1",
"description": "Example product 1 description",
"image_url": "https://cdn.market.com/images/products/product_1.png",
"category": "category-1",
"isFavorite": true,
"image_list": [
"https://cdn.market.com/images/products/product_1.png",
"https://aws-s3.com.com/images/products/product_5.png",
"https://aws-s3.com/images/products/product_6.png"
]
},
{
"id": 4,
"name": "Example product 4",
"description": "Example product 4 description",
"image_url": "https://cdn.market.com/images/products/product_4.png",
"category": "category-1",
"isFavorite": false,
"image_list": [
"https://cdn.market.com/images/products/product_4.png",
"https://aws-s3.com.com/images/products/product_7.png",
"https://aws-s3.com/images/products/product_8.png"
]
}
]
<?php
interface StorageRepositoryInterface
{
public function getUrl(string $fileName): ?string;
}
final class AwsStorageConcrete implements AwsStorageInterface
{
/////
}
final class FileCommonStorageRepository implements StorageRepositoryInterface
{
private FileStorageRepository $fileStorageRepository;
public function __construct(FileStorageRepository $fileStorageRepository)
{
$this->fileStorageRepository = $fileStorageRepository;
}
public function getUrl(string $fileName): ?string
{
$result = $this->fileStorageRepository->getImageUrl($fileName);
return $result;
}
}
// насколько я понял из текста задания, у приведенной библиотеки для работы с aws, нет метода проверка существования файла...
final class AwsStorageRepository implements StorageRepositoryInterface
{
private AwsStorageInterface $awsStorageInterface;
private LoggerInterface $logger;
public function __construct(
AwsStorageInterface $awsStorageInterface,
LoggerInterface $logger
){
$this->awsStorageInterface = $awsStorageInterface;
}
public function getUrl(string $fileName): ?string
{
try {
$response = $this->awsStorageInterface->getUrl($fileName);
$result = (string) $response;
} catch (Throwable $t) {
$result = null;
$this->logger->warning('Failed to get file from AWS. Error message: '. $t->getMessage());
}
return $result;
}
}
final class StorageRepositoryChain
{
/** @var StorageRepositoryInterface[] */
private array $repositories;
public function addRepository(StorageRepositoryInterface $repository): void
{
$this->repositories[$repository::class] = $repository;
}
public function getUrl(string $fileName): ?string
{
foreach ($this->repositories as $repository) {
$url = $repository->getUrl($fileName);
if (null !== $url) {
return $url;
}
}
return null;
}
}
// namespace Market;
class Product
{
/**
* @var string
*/
private string $imageFileName;
/** @var string[] */
private array $newImages = [];
public function __construct(StorageRepositoryChain $chain)
{
$this->chain = $chain;
}
public function getImageList(): array
{
return array_merge([$this->imageFileName], $this->newImages);
}
}
// namespace Market;
class ProductImageService
{
private StorageRepositoryChain $chain;
public function __construct(StorageRepositoryChain $chain)
{
$this->chain = $chain;
}
public function getImageListForProduct(Product $product): array
{
$result = [];
foreach ($product->getImageList() as $fileName) {
$url = $this->chain->getUrl($fileName);
if (null === $url) {
continue;
}
$result[] = $url;
}
return $result;
}
}
// client code
$chain = new StorageRepositoryChain();
$chain->addRepository(new FileCommonStorageRepository(new FileStorageRepository()));
$chain->addRepository(new AwsStorageRepository(
new AwsStorageConcrete(),
new Logger()
));
$productImageService = new ProductImageService($chain);
$productImageList = $productImageService->getImageListForProduct($product);
Тестирование
1) написать юнит тест, что в новый метод "getImageList" у класса Product возвращает и старые и новые имена файлов
2) написать юнит тест на класс AwsStorageRepository, кейсы - если файл получен | если файл не может получить
3) написать юнит тест на класс FileCommonStorageRepository, кейсы - если файл получен | если файл не может получить
4) написать юнит тест на класс StorageRepositoryChain, репозиторий вернул url | репозиторий не вернул url
5) написать юнит тест на класс ProductImageService, метод getImageListForProduct, замокав ответ от StorageRepositoryChain нашими данными
-- SQL: Оценки студентов
SELECT m.name, m.mark,
CASE
WHEN g.grade < 8 THEN 'low'
ELSE g.grade
END AS grade
FROM marks AS m
INNER JOIN grade AS g ON m.mark BETWEEN g.min_mark AND g.max_mark
ORDER BY g.grade DESC,
CASE WHEN g.grade BETWEEN 8 AND 10 THEN m.name END ASC,
CASE WHEN g.grade BETWEEN 1 AND 7 THEN m.mark END ASC
---- B. Модификация DDL
Можно попробовать поле grade добавить в таблицу marks, вычисляя его значение перед вставкой в таблицу.
Чтобы не делать каждый раз join при запросах, руководуствуясь логикой что операций чтения намного чаще происходят чем вставки новых записей.
<?php
declare(strict_types=1);
interface TicketRepositoryInterface
{
public function load($ticketID): Ticket;
public function save($ticket): void;
public function update($ticket): void;
public function delete($ticket): void;
}
final class TicketDatabaseRepository implements TicketRepositoryInterface
{
public function __construct(private DbConnection $connection)
{
}
public function load($ticketID): Ticket
{
// получаем данные из БД
}
public function save($ticket): void
{
// сохраняем билет в БД
}
public function update($ticket): void
{
// обновляем билет в БД
}
public function delete($ticket): void
{
// удаляем билет в БД
}
}
final class TicketApiRepository implements TicketRepositoryInterface
{
public function __construct(private ApiClient $client)
{
}
public function load($ticketID): Ticket
{
// посылаем запрос в API на получение билета
}
public function save($ticket): void
{
// посылаем запрос в API на сохранение билета
}
public function update($ticket): void
{
// посылаем запрос в API на обновление билета
}
public function delete($ticket): void
{
// посылаем запрос в API на удаление билета
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment