Рекомендации по моему первому коду PHP Laravel

177
26 сентября 2021, 02:30

Всем привет, написал свой небольшой проект на Laravel.

Можно ли от вас ребята получить небольшую обратную связь по моему первому коду в Laravel? По каким-то банальным моментам что то может не так сделал?

Основной код у меня в тут в модели User

<?php 
 
namespace App; 
 
use Carbon\Carbon; 
use Illuminate\Database\Eloquent\Model; 
use Illuminate\Support\Arr; 
use Illuminate\Support\Facades\DB; 
 
class User extends Model 
{ 
    protected $table = 'timetable_users'; 
 
    protected $fillable = [ 
        'user_id', 'morning_work_hours_from', 'morning_work_hours_before', 'afternoon_work_hours_from', 'afternoon_work_hours_before', 
    ]; 
 
    public function holiday() 
    { 
        return $this->hasMany(Holiday::class); 
    } 
 
    public function party() 
    { 
        return $this->hasMany(Party::class); 
    } 
 
    // Получение графика отпусков сотрудника 
    public function getHolidays($id) 
    { 
        $holidays = DB::table('timetable_holidays') 
            ->where('user_id', '=', $id) 
            ->get(); 
        return $holidays; 
    } 
 
    // Получение праздников России с названием 
    public function NameHolidaysRu() 
    { 
        $apiDate = json_decode(file_get_contents('https://www.googleapis.com/calendar/v3/calendars/russian__ru%40holiday.calendar.google.com/events?key=AIzaSyC8khrJO57yl4szjLOuyQrlW7R_CKgwaH0'), 1); 
        $holidayDates = Arr::pluck($apiDate['items'], 'start.date'); 
        $nameHolidayDates = Arr::pluck($apiDate['items'], 'summary'); 
        $count = count($holidayDates); 
 
        $dateAndName = array(); 
 
        for ($i = 0; $i < $count; $i++) 
        { 
            $dateAndName[] = [ 
                    "date" => $holidayDates[$i], 
                    "name_holiday" => $nameHolidayDates[$i] 
                ]; 
        } 
        return $dateAndName; 
    } 
 
    // Получение праздников России 
    public function getApiHolidays() 
    { 
        $apiDate = json_decode(file_get_contents('https://www.googleapis.com/calendar/v3/calendars/russian__ru%40holiday.calendar.google.com/events?key=AIzaSyC8khrJO57yl4szjLOuyQrlW7R_CKgwaH0'), 1); 
        $holidayDates = Arr::pluck($apiDate['items'], 'start.date'); 
 
        $array = array_filter($holidayDates, function ($var) { 
            return substr($var, 0, 4) === date("Y"); 
        }); 
        return $array; 
    } 
 
    // Получение периода дат из формы 
    public function getPeriodDateForm($startDate, $endDate) 
    { 
        $startDate = new Carbon($startDate); 
        $endDate = new Carbon($endDate); 
 
        $allDates = array(); 
 
        while ($startDate->lte($endDate)) { 
            $allDates[] = $startDate->toDateString(); 
            $startDate->addDay(); 
        } 
        return $allDates; 
    } 
 
// Добавление отпускных дат сотрудника в массив 
    public function getDateHolidayArr($holidaysEmployee) 
    { 
        $allHolidays = array(); 
 
        $count = count($holidaysEmployee); 
        if ($count == 0) 
        { 
            return $allHolidays; 
        } 
        for ($i = 0; $i < $count; $i++) 
        { 
            $holidaysFrom = $holidaysEmployee[$i]->holidays_from; 
            $holidaysBefore = $holidaysEmployee[$i]->holidays_before; 
 
            $startDate = new Carbon($holidaysFrom); 
            $endDate = new Carbon($holidaysBefore); 
 
            while ($startDate->lte($endDate)) { 
                $allHolidays[] = $startDate->toDateString(); 
 
                $startDate->addDay(); 
            } 
        } 
        return $allHolidays; 
    } 
 
    // Получение дат праздников которые будут удалены 
    public function delPartyDays() 
    { 
        $getAllParties = $this->allParties(); 
        $allTotalParties = array(); 
        $count = count($getAllParties); 
 
        if ($count == 0) { 
            return $allTotalParties; 
        } 
        for ($i = 0; $i < $count; $i++) { 
            $partiesFrom = $getAllParties[$i]['party_day_from']; 
            $partiesBefore = $getAllParties[$i]['party_day_before']; 
 
            $startDate = new Carbon($partiesFrom); 
            $endDate = new Carbon($partiesBefore); 
 
            while ($startDate->lte($endDate)) { 
                $allTotalParties[] = $startDate->toDateString(); 
                $startDate->addDay(); 
            } 
        } 
        $firstDate = Arr::pluck($getAllParties, ['party_day_from']); 
        $resultDate = array_diff($allTotalParties, $firstDate); 
 
        return $resultDate; 
    } 
 
    // Получение выходных дней 
    public function weekend($startDate, $endDate) 
    { 
        $start = strtotime($startDate); 
        $end = strtotime($endDate); 
        $result = array(); 
 
        while ($start <= $end) 
        { 
            if (date('N', $start) >= 6) 
            { 
                $current = date('Y-m-d', $start); 
                $result[] = $current; 
            } $start += 86400; 
        } 
        return $result; 
    } 
 
    // Получение расписания работника 
    public function calculate($id, $startDate, $endDate) 
    { 
        $periodDateForm = $this->getPeriodDateForm($startDate, $endDate); 
        $holidaysEmployee = $this->getHolidays($id); 
        $allDateHolidaysEmployee = $this->getDateHolidayArr($holidaysEmployee); 
        $allRuHolidays = $this->getApiHolidays(); 
        $allPartyDays = $this->delPartyDays(); 
        $allWekend = $this->weekend($startDate, $endDate); 
 
        return array_diff($periodDateForm, $allDateHolidaysEmployee, $allRuHolidays, $allPartyDays, $allWekend); 
    } 
 
    // Получение всех праздников компании 
    public function allParties() 
    { 
        $parties = Party::get(); 
 
        $subset = $parties->map(function ($party) { 
            return $party->only(['name', 'party_day_from', 'party_day_before', 'party_time_from', 'party_time_before']); 
        }); 
        return $subset; 
    } 
 
    // Формат даты для view 
    public function formatDate($date) 
    { 
        return date('d.m.Y', strtotime($date)); 
    } 
 
    // Проверка даты в JSON 
    public function checkDateJson($s) 
    { 
        $allParties = $this->allParties(); 
 
        foreach ($allParties as $party) { 
            $dateTimeParties = Arr::only($party, ['party_day_from', 'party_time_from']); 
 
            if ($s === $dateTimeParties['party_day_from']) { 
                $s = $dateTimeParties; 
            } 
        } 
        return $s; 
    } 
 
    // Поления первых дат праздников компании 
    public function partyDateJson($s) 
    { 
        $allParties = $this->allParties(); 
        $allDate = Arr::pluck($allParties, 'party_day_from'); 
 
        if (is_array($s) && in_array($s['party_day_from'], $allDate)) 
        { 
            return $s['party_day_from']; 
        } else { 
            return $s; 
        } 
    } 
 
    // Максимальное время первой половины дня 
    public function maxMorningHour() 
    { 
        $maxMorningHour = DB::table('timetable_users') 
            ->max('morning_work_hours_before'); 
        return $maxMorningHour; 
    } 
 
 
    // Время для JSON с учетом праздников 
    public function partyTimeJson($s, $range) 
    { 
        if (!is_array($s)) 
        { 
            return $range; 
        } 
        else { 
            foreach ($range as $val) 
            { 
                if ($s['party_time_from'] < $val['end'] 
                    && $s['party_time_from'] > $val['start'] 
                    && $this->maxMorningHour() > $s['party_time_from']) 
                { 
                    $range = [ 
                        ['start' => $this->morning_work_hours_from, 'end' => $s['party_time_from']], 
 
                    ]; 
                    return $range; 
                    break; 
                } 
                elseif ($s['party_time_from'] < $range[1]['end'] 
                    && $s['party_time_from'] > $range[1]['start']) 
                { 
                    $range = [ 
                        ['start' => $this->morning_work_hours_from, 'end' => $this->morning_work_hours_before], 
                        ['start' => $this->afternoon_work_hours_from, 'end' => $s['party_time_from']] 
                    ]; 
                    return $range; 
                    break; 
                } 
                return $range; 
            } 
        } 
    } 
 
    // Получить JSON 
    public function getJSON($shedule) 
    { 
        $range = [ 
                  ['start' => $this->morning_work_hours_from, 'end' => $this->morning_work_hours_before] , 
                  ['start' => $this->afternoon_work_hours_from, 'end' => $this->afternoon_work_hours_before] 
            ]; 
        $data = array_map(function($s) use ($range){ 
                     return [ 
                            'day' => $this->partyDateJson($this->checkDateJson($s)), 
                            'timeRangers' => $this->partyTimeJson($this->checkDateJson($s), $range) 
                        ]; 
                  }, $shedule); 
        $result = ['schedule' => $data]; 
        return json_encode($result, JSON_PRETTY_PRINT); 
    } 
}

Небольшой контроллер

<?php 
 
namespace App\Http\Controllers; 
 
use App\Holiday; 
use App\Party; 
use App\User; 
use Illuminate\Http\Request; 
 
class TimetableController extends Controller 
{ 
    public function index() 
    { 
        $countUser = User::All()->count(); 
        return view('timetable', compact('countUser')); 
    } 
 
    public function store(Request $request) 
    { 
        $rules = [ 
            'userId'=>'required|integer|exists:timetable_users,id', 
            'startDate' => 'required|date', 
            'endDate' => 'required|date|after:startDate' 
        ]; 
        $this->validate($request, $rules); 
 
        $id = $request['userId']; 
        $startDate = $request['startDate']; 
        $endDate = $request['endDate']; 
        $user = User::findOrFail($id); 
        $holidays = Holiday::findOrFail($id)->where("user_id", $id)->get()->sort(); 
        $parties = Party::all(); 
        $countUser = User::All()->count(); 
        $calculate = $user->calculate($id, $startDate, $endDate); 
 
        return view('timetable', compact('holidays', 'user', 'countUser', 'parties', 'calculate')); 
 
    } 
}

И вид

<!DOCTYPE html> 
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> 
    <head> 
        <meta charset="utf-8"> 
        <meta name="viewport" content="width=device-width, initial-scale=1"> 
        <title>Laravel</title> 
        <!-- Fonts--> 
        <link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet"> 
       <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> 
       <link href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet"> 
    </head> 
    <body> 
    <div class="container"> 
        <hr> 
            <h2>Расписание работника компании</h2> 
        <hr> 
        <h5>В вашей компании работает {{ $countUser }} сотрудников</h5> 
        <hr> 
        @if(count($errors) > 0) 
            <div class="alert  alert-danger"> 
                <ul> 
                    @foreach($errors->all() as $error) 
                        <li>{{ $error }}</li> 
                    @endforeach 
                </ul> 
            </div> 
        @endif 
            <br> 
        <form method="get"  action="{{ route('timetable.store') }}"> 
            <div class="row  align-items-end"> 
                <div class="form-group col"> 
                    <label>ID user</label> 
                    <input type="text" name="userId" class="form-control" placeholder="Name" value="{{ old('userId') }}" id="userId"> 
                </div> 
                <div class="form-group col"> 
                    <label>Дата, от</label> 
                    <input type="date" name="startDate" class="form-control" value="{{ old('startDate') }}" id="start_date"> 
                </div> 
                <div class="form-group col"> 
                    <strong>Дата, до</strong> 
                    <input type="date" name="endDate" class="form-control" value="{{ old('endDate') }}" id="end_date"> 
                </div> 
                <div class="form-group col"> 
                    <button class="btn btn-success btn-submit">Расчитать</button> 
                </div> 
            </div> 
        </form> 
            <br> 
            <br> 
        <hr> 
        <br> 
        @if ($user ?? '') 
        <div class="row"> 
            <div class="col-6"> 
                <h5 class="font-weight-bolder">Информация о работнике:</h5> 
                <table class="table mt-5"> 
                    <thead> 
                    </thead> 
                    <tbody> 
                    <tr> 
                        <td scope="row">IdUser</td> 
                        <td>{{ $user->id }}</td> 
                    </tr> 
                    <tr> 
                        <td scope="row">График работы:</td> 
                        <td>c {{ $user->morning_work_hours_from }} до {{ $user->morning_work_hours_before }} <br> 
                            c {{ $user->afternoon_work_hours_from }} до {{ $user->afternoon_work_hours_before }} 
                        </td> 
                    </tr> 
                    <tr> 
                        <td scope="row">Отпуск:</td> 
                        <td> 
                            @if($holidays->count() == 0) 
                                У данного сотрудника отпуск не указан 
                            @else 
                                @foreach ($holidays as $holiday) 
                                от {{  $user->formatDate($holiday->holidays_from) }} до {{ $user->formatDate($holiday->holidays_before) }} <br> 
                                @endforeach 
                            @endif 
                        </td> 
                    </tr> 
                    </tbody> 
                </table> 
                <br> 
                <table class="table mt-5"> 
                    <thead> 
                    <tr> 
                        <th scope="col">Праздник компании</th> 
                        <th scope="col">Начало</th> 
                        <th scope="col">Окончание</th> 
                    </tr> 
                    </thead> 
                    <tbody> 
                    @foreach ($parties as $party) 
                        <tr> 
                            <td>{{ $party->name }}</td> 
                            <td>{{ $user->formatDate($party->party_day_from) }} {{ $party->party_time_from }}</td> 
                            <td>{{ $user->formatDate($party->party_day_before) }} {{ $party->party_time_before }}</td> 
                        </tr> 
                    @endforeach 
                    </tbody> 
                </table> 
                <br> 
                <table class="table mt-5"> 
                    <thead> 
                    <tr> 
                        <th scope="col">Праздники России за 2019</th> 
                        <th scope="col">Дата</th> 
                    </tr> 
                    @foreach ($user->NameHolidaysRu() as $rusHoliday) 
                        <tr> 
                            @if ($rusHoliday['date'] > date("Y") && $rusHoliday['date'] < date('Y', strtotime('+1 years'))) 
                                <td> {{ $rusHoliday['name_holiday']}} </td> 
                                <td> {{ $user->formatDate($rusHoliday['date']) }} </td> 
                            @endif 
                        </tr> 
                    @endforeach 
                    </thead> 
                </table> 
            </div> 
            <div class="col-6"> 
                <h5 class="font-weight-bolder">JSON</h5> 
                <p>Выходные дни не учитываются</p> 
                 <pre> 
                     {{ $user->getJSON($calculate) }} 
                 </pre> 
            </div> 
 
        </div> 
        @endif 
    </div> 
    </body> 
</html>

Буду рад любым комментариям

PS на выходе то что требовалось реализовать по ТЗ все сделал, все работает.

Answer 1

Вся логика у вас в модели User. Это неверно, в модели должна быть только логика обработки полей модели.

Логику работы со сторонним сервисом лучше вынести в отдельный класс(например сервис GoogleApiService)

Логику выборок лучше вынести в отдельный класс, например UserRepository и реализовать в нем метод getUserHolidays()

Метод преобразования даты $user->formatDate($holiday->holidays_from) должен быть в модели Holiday

public function getFormatDate(): string
{
    return date('d.m.Y', strtotime($this->holidays_from));
}

Часть методов у вас с префиксом get(getHolidays), часть без(weekend, хотя тоже что то возвращает), часть с большой буквы(NameHolidaysRu) - надо определиться с неймингом.

Вместо кострукции

DB::table('timetable_holidays')->where('user_id', '=', $id)->get();

Лучше использовать

Holiday::query()->where('user_id', '=', $id)->get();

Чтобы не дублировать название таблицы, которое и так указано в модели.

Значения типа адреса сервиса https://www.googleapis.com/calendar/v3... и его параметры лучше вынести в конфиг(.env)

Не используйте название переменных, которые поймете только вы

public function partyDateJson($s)

Используйте type hinting

Валидацию в контроллере лучше вынести в Form Request https://laravel.com/docs/5.8/validation#form-request-validation

READ ALSO
Как создать контроллер в slim 4?

Как создать контроллер в slim 4?

В официальной документации slim 4 написано

71
symfony, зачем аннотации

symfony, зачем аннотации

Всем привет, я примерно 6-7 работаю бэкенд разработчиком, всегда писал на чистом php, работаю только с какими-то библиотеками из packagistНачал изучать...

136