# Learn PHP
## Roadmap
сентябрь
- готовим список технических вопросов и ответов на них
октябрь
- первые 2 недели гоняем собесы
- вторые 2 неделеи проходишь интервью на head hunter
## Установка проекта
git clone git@gitlab.com:v.turosinskiy/learn-php.git
Команды git
git status - проверка статусу
git diff - проверка изменений в файлах
git add - добавление изменений в индекс git
git commit - фиксация изменений в виде комита
git commit --amend - добавление изменений к предыдущему комиту
git pull - пулл изменений из удаленной ветки
git push - пуш изменений в удаленную ветку
git reset {hash} - откат изменений к хешу комита
git checkout -b {branch} - создание новой ветки
git branch -D {branch} - удаление локальной ветки
## Добавление новых изменений в существующий комит
git add .
git commit --amend
Выполняем для сохранения комита
```
:wq
```
git push -f origin TASK-X
## composer
php8.0 /usr/local/bin/composer init
php8.0 /usr/local/bin/composer install
php8.0 /usr/local/bin/composer require symfony/console:"^6.0"
## Весрии PHP
php 5.6
php 7.0 7.1 7.2 7.3 7.4
php 8.0 8.1 8.2
https://onlinephp.io/ - sandbox
https://pressable.com/knowledgebase/differences-between-php-versions/?nab=0
## Задание 1
1. Создать модели
2. Character https://rickandmortyapi.com/documentation/#character
3. Location https://rickandmortyapi.com/documentation/#location
4. Episode https://rickandmortyapi.com/documentation/#episode
2. Добавить json с примерами моделей
7. Character - character.json
8. Location - location.json
8. Episode - epizode.json
3. Добавить команды для вывода информации о
7. Character
8. Location
8. Episode
4. разница у php версий
5. Инициализация проекта
6. Выполнить composer init
7. Выполнить git init
8. Заполнить.gitignore
9. Создать папку src
10. Добавить класс App
11. Заполнить composer.json
10. autoload
12. php8.0 /usr/local/bin/composer require symfony/console:"^6.0"
Задание 2
1. Изучить DateTime
2. Изучить extends
3. Изучить private/protected/public
4. Изучить статические методы у классов
5. Изучить CRUD(create/read/update/delete)
6. Написать консольные команды для
7. Character - character.json
8. Location - location.json
8. Episode - epizode.json
7. "air_date": "December 9, 2013",
8. в json храним в формате December 9, 2013
9. в create/update команде передаем 2013-12-09
10. в модели храним в виде datetime
11. но модели пока в командах можно не использовать
-----
2 = 3
4 = 7
3 = 7
5 = 15
8 = 15
175 =
256 = 511
1 = 1
2 = 3
3-4 = 7/8-высота
5-8 = 15
9-16 = 31
...
1. Нужно посчитать количество строк, опираясь на количество участников
2. Нужно вывести в цикле N строк
3. Нужно вывести поочередно друг за другом 1-n участников с промежутком в пустую строку
Для 3
1 -
1 -
2 -
3
3 -
3 -
0 -
Для 2
1 -
1
2 -
S
Для 4
1 -
1 -
2 -
3
3 -
3 -
4 -
2
Для 5
1 -
1 -
0 -
2 -
2 -
2 -
0 -
2
3 -
3 -
0 -
3 -
4 -
4 -
5 -
<?php
/**
Для 2
1 -
1
2 -
Для 4
1 -
1 -
2 -
3
3 -
3 -
4 -
Для 5
1 -
1 -
0 -
2 -
2 -
2 -
0 -
2
3 -
3 -
0 -
3 -
4 -
4 -
5 -
**/
$a = [];
$champCount = 16;
$champions = range(1, $champCount);
$lines = $champCount * 2 - 1;
$width = $champCount * 2;
for ($i=0; $i<$lines; $i++){
$a[$i] = [];
for ($g=0; $g<$width; $g++){
$a[$i][$g] = '-';
}
}
$fill = [];
$space = ($i + $charKey) % ($champCount/2) === 2;
foreach ($a as $i => $chars){
foreach ($chars as $charKey=>$char){
if (($i + $charKey) % 2 === 0 && !in_array($i,$fill)){
$fill[] = $i;
echo $char;
}
else {
echo ' ';
}
}
echo PHP_EOL;
}
-----
Задание Arena
1. Доработать команду чтобы увеличивалась случайна характеристика
2. Доработать нужно метод process класс Arena
2. Доработать вывод команды Arena
Вывод должен быть:
До:
Чемпион - {name}
Здоровье: {$health} 10-100
Атака: {$attack} 1-10
Критический шанс: {$critChance} 1-30
Критический урон: {$critDamage} 10-50
3. Написать ChampionFactory который будет генерировать случайного чемпиона
Чемпион - {name}
Здоровье: {$health} 10-100
Атака: {$attack} 1-10
Критический шанс: {$critChance} 1-30
Критический урон: {$critDamage} 10-50
4. Написать ArenaFactory который будет генерировать случайную арену
Арена - {name}
Здоровье: {$health} 10-100
Атака: {$attack} 1-10
Критический шанс: {$critChance} 1-30
Критический урон: {$critDamage} 10-50
--- fight command
$critChance = $champion->getCritChance();
$hasCrit = $critChance > rand(0,100);
$damage = $hasCrit === true ? $attack * (100 + $critDamage) / 100 : $attack;
$champion->setXp($champion->getXp() - $damage);
while($xp1 > 0 || $xp2 > 0){
}
Ударяют одновременно, если у обоих hp меньше 0, то победил тот у кого hp больше, пример у 1 осталось -10hp у второго -4hp, то победил второй. Если у обоих одинаково, то победил случайный.
Начался бой
Раунд 1.
{$name1} наносит {$damage} урона {$name2} / {$name1} наносит критом {$damage} урона {$name2}
{$name2} наносит {$damage} урона {$name1} / {$name2} наносит критом {$damage} урона {$name1}
У $name1 осталось $xp1 здоровья
у $name2 осталось $xp2 здоровья
Раунд 2.
...
Бой закончен
Победитель $name1
----
if(){
}elseif(){
}else{
}
$a = 'a';
switch(true){
case $a === 'a':
break;
case $a === 'b':
break;
}
----
Задание
1. Переписать арена сервиса на увеличение статистик чемпионов по свойствам арены
2. Написать генератор сетки
3. Написать бой чемпионов
4. Добавить Entity Weapon($id, $name, $minAttack, $maxAttack)
5. Заменить поле $attack у чемпиона на обьект Weapon
6. Написать генератор имен чемпионов, оружия, арен
7. состоит из 2 слов
----
Разобрать:
1. Чем отличается static от self
2. https://www.w3resource.com/php-exercises/php-for-loop-exercises.php
## Работа с БД
Создание дифа миграции
php8.2 bin/console doctrine:migrations:diff
Создание фикстуры
php8.2 bin/console make:fixtures
Загрузка фикстур:
php8.2 bin/console doctrine:fixtures:load
Задание:
*1. Создать Entity User(id, username)
*2. Добавить шаблоны в твиге по аналогии с чемпионом
*3. Добавить миграции (команда diff) - чтобы появился файл с миграцией create table
*4. Выполнить миграции (команда create) - чтобы появилась таблица в базе
*5. Добавить контроллер по аналогии с чемпионами
*6. Добавить UserFixture (команда make:fixtures - doctrine:fixtures:load) которое сгенерирует 100 user
*7. Добавить UserFactory
*8. Добавить UserRepositiry
----
Бой:
1. Игрок может вызвать другого игрока на бой
2. Один из чемпионов побеждает/Один проигрывает
3. Выводим топ 5 чемпионов по победам
4. Выводим топ 5 игроков по победам
----
1. Нужно чемпионов привязать к пользователям
2. CRUD над чемпионами
3. CRUD над пользователями
----
----
Задание
1. Написать crud по аналогии с Champion для User
2. Не нужно сохранять список чемпионов
2. Добавить поле login/password
2. Добавить поля health/critdamage/critchance в форму создания/изменения
3. Добавить таблицу weapon
4. Добавить crud для weapon
3. Привязка weapon к чемпиону
---
Далее:
1. phpstan/csfixer/phpunit
1. javascript
2. Регистрация/Авторизация
5. Пользователь может редактировать и просматривать только своих чемпионов
3. Базовые знания по работе с бд
4. Апи методы
//удаление связей
1. Перед удалением просим текущего пользователя убрать оружие у других чемпионов
2. Удалить чемпиона
3. Сделать поле пустым/заменить на базовое оружие
Задание:
1. Изучить команды
- make csfix
- make phpstan
- make phpunit
2. Написать тесты для User/Weapon/Champion
3. Написать crud api методы для User/Weapon/Champion
4. Добавить scratches и проверить работу методов
GET http://localhost:8181/api/champion/102
###
DELETE http://localhost:8181/api/champion/101
###
POST http://localhost:8181/api/champion/102
{"name":"test"}
###
POST http://localhost:8181/api/champion
{
"name":"test"
}
------ 2 июля
Роли и права
Администратор
- может делать все действия
Авторизованные пользователи
- Могут использовать crud (api/web методы) для своих чемпионов
Неавторизованные
- Могут просматривать профили пользователей и чемпионов
Теория по БД:
select * from table where condition(id = 1) order by id ASC group by user_id limit 10
Основные операторы
user id,name
champion id,name,user_id
user join champion -> user_id,user_name,champion_id,champion_name
where user.name = 'вася' and champion_name = 'петя'
select u.user_name, count(c.id) from "user" u left join "champion" c on u.id = c.user_id group by u.id order by count(c.id) DESC limit 5;
Нужно:
1. Научиться делать select по нескольким таблицам
2. Использовать group by
3. Сортировать по полям
4. Использовать join (разобраться в разнице left/right/inner)
5. Использовать limit
Задание:
1. Пометить все классы в src как final по примеру arenaFactory
2. Добавить сущность бой Fight id|one|two|winner_id|
3. Написать фикстуры для сущности бой
- Поле win/loss зависит от кол-ва записей в таблице fight
4. Написать следующие запросы
*1. Вывести здоровье чемпиона по id
- select health from champion where id = 205;
*2. Вывести id 5 чемпионов с максимальным количеством побед

*2. Вывести id 10 чемпионов у которых кол-во побед больше поражений

3. Вывести id по одному чемпиону от каждого пользователя с максимальным количеством здоровья
select u.id as user_id, c.id as champion_id, c.health from user u inner join champion c where c.health in (select health from champion where health = max(health) limit 1) group by u.id
user_id champion_id health
1. 1 100
1. 2 120
2. 3 120
user_id champion_id health
1. 2 120
1. 3 120
select c.id from user u inner join champion group by u.id where c.id in (select c.id where c.health = max(c.health))
(добавить сортировку)4. Вывести id 10 чемпионов с наибольшим количеством здоровья отсортировав их по кол-ву побед ()
 - order by c.health desc/asc
---
user_id champion_id won
1 1 1
1 2 3
user_id won
1 4
Агрегирующая функция - sum/count/average/min/max
Вывести кол-во побед у всех чемпионов пользователя
select user_id, sum(won) from champion group by user_id where sum(loss) = 0
select user_id, max(won) from champion group by user_id
select user_id, count(*) from champion group by user_id
---
Индексы
1. Внутренние (index) - для оптимизации select запросов
- создание/удаление/обновление данных замедляется при использовании индексов так как перестраивается дерево индексов
2. Первичный (primary key) - главное поле в таблице
2. Внешний (foreign key) - нужны 2 таблицы
user
id, ...
champion
id, user_id,
user.id -> champion.user_id -> one to many
champion.user_id -> user.id -> many to one
post
id, ...
tag
id,
post_has_tags
post_id, tag_id -> составной первичный индекс post_id_tag_id
select * from post_has_tag where post_id = 1 and tag_id = 1
//сработает индекс(post_id_tag_id) по полю post и полю tag_id
select * from post_has_tag where tag_id = 1 and post_id = 1
//не сработает индекс(post_id_tag_id) - для таких случаев иногда вешают отдельный индекс на поле tag_id
//сработает индекс(post_id_tag_id) по полю post и полю tag_id
select * from post_has_tag where status="active" and post_id = 1 and tag_id = 1
//не сработает индекс(post_id_tag_id) - для таких случаев иногда
select * from champion c -> c.health
select c.health from champion c -> c.health
Оптимизация БД:
1. Добавление индексов
2. Оптмизация условий where
3. Оптимизация конструкций
4. Оптимизация выбираемых данных
post_has_tag.post_id -> post.id
post_has_tag.tag_id -> tag.id
post - tag -> many to many
1
2
3
4
5
COUNT(32) -> 32 шага
степень от 2, 32 -> 2 в 5 -> 5 шагов
дерево против обычной выборки 64 против 6
3
2 4
1 5
---
*5. Вывести id чемпионов которые ни с кем не сражались

6. Вывести id последних 5 чемпионов которые победили в последних боях
*7. Вывести id чемпионов которые ни разу не победили и здоровье которых меньше 150

8. Вывести id чемпионов которые принадлежат пользователю с userName = 'test';

9. Вывести 5 пользователей чемпионы которых суммарно победили больше всего за последние 30 боев
*10. Вывести id пользователей чемпионы которых ниразу не проигрывали
(Добавить group by)[](https://hackmd.io/_uploads/BywDP0mFh.png)
c left u -> u + c -> c right u
11. Вывести кол-во уникальных боев чемпионов
*12. Вывести оружие с максимальным значением суммы мин + макс атаки

$maxSumAttack = select max(min_attack + max_attack) where limit 1;
select * where min_attack + max_attack = $maxSumAttack
select * where min_attack + max_attack = (select max(min_attack + max_attack) where limit 1)
Примеры
select u.user_name, count(c.id) from champion c inner join "user" u on c.user_id = u.id group by u.id;
select u.user_name, c.name as champion_name, c.won from champion c inner join "user" u on c.user_id = u.id;
# Задача
1. Скопировать весь проект mc в petstore
2. Добавить роуты - все в ответе возвращают {"status": "ok"}
3. Добавить Entity
4. Добавить таблицы/миграции
5. Добавить фикстуры
6. Дописать api методы
- Сначало get методы
- Потом post
- Потом delete
- Потом put
------
4 августа, задачи:
*1. Добавить POST /api/pet/{petId}
*2. Дописать PUT /api/pet
*3. Убрать закоментированный код и вызовы var_dump
*4. OrderApiController переименовать в StoreApiController
*5. Удалить /order/inventory
*Пример /store/inventory
```
{
"placed":30,
"approved":10,
"delivered:10
}
```
*6. Добавить методы User
createWithArray
createWithList
7. Прочитать видеокурс про паттерны https://proglib.io/p/ponyatnyy-videokurs-o-design-patterns-na-primere-yazyka-php-2019-12-03
8. Написать тесты для Entuty
9. Напистаь тесты для Controller
10. Написать тесты для Service
---
1. *Убрать закоментированный код или прописать todo //
2. *Переименовтаь $tag_ в $items/item
3. *Если тег не найден, то его создаем в методе put и post при создании/изменении пета
4. */api/store/inventory/ добавить в order repository sql запрос вида
SELECT status, count(*) FROM order_test group by status;
https://onecompiler.com/postgresql/3zj4u9t3r
5. *Убрать все var_dump в папке src
6. *Методы пишем в camelCase, нужно переименовать create_with_list/create_with_array
7. *Переименовтаь $user_
8. При создании записей использовать deserialize
$user = $this->serializer->deserialize($parameters, User::class, 'json');
9. Зазубрить SOLID - расшифровка 5 принципов и описание своими словами
10. *Добавить интерфейсы к Service и Repositiry
---
0. Поправить ошибки phpstan `make phpstan`
1. Поправить ошибки csfix `make csfix`
2. *Заменить isset в src
3. *Заменить & на &&
4. Настроить сохранение тегов
- получаем теги по имени
- если тег не существует то сохраняем
- иначе используем тот что есть
5. То же самое для category
6. Удалить setId у всех записей
7. *Методы пишем в camelCase, нужно переименовать create_with_list/create_with_array
8. *Переименовтаь $user_
9. Заменить в конструкторах у контролеров реализации на интерфейсы
---