<?php
/** профессия менеджер */
const MANAGER = "manager";
/** профессия маркетолог */
const MARKETER = "marketer";
/** профессия инженер */
const ENGINEER = "engineer";
/** профессия аналитик */
const ANALYST = "analyst";
/** Исключение метода сортировки */
class UsortErrorException extends Exception {}
/** Исключение метода создания сотрудника */
class CreateEmployeeErrorException extends Exception {}
/** Исключение метода получения коллекции */
class CreateCollectionErrorException extends Exception {}
/** Класс сотрудник */
class Employee
{
/** @var string $profession профессия */
protected $profession;
/** @var int $rate ставка */
protected $rate;
/** @var int $litresOfCoffee выпитые литры кофе */
protected $litresOfCoffee;
/** @var int $pgsOfDocs кол-во страниц */
protected $pgsOfDocs;
/** @var int $rank ранг */
protected $rank;
/** @var bool $boss босс или не босс */
protected $boss;
/**
* Конструктор класса Сотрудник
* @param string $profession профессия
* @param int $rate ставка
* ...
*/
final public function __construct(string $profession, int $rate, int $litresOfCoffee, int $pgsOfDocs, int $rank, bool $boss = false){
$this->profession = $profession;
$this->rate = $rate;
$this->litresOfCoffee = $litresOfCoffee;
$this->pgsOfDocs = $pgsOfDocs;
$this->rank = $rank;
$this->boss = $boss;
}
/**
* Вернуть профессию
* @return string
*/
final public function getProfession():string {
return $this->profession;
}
/**
* Получить ставку
* @return int
*/
final public function getRate():int {
return $this->rate;
}
/**
* Получить ставку с учетом ранга
* @return float
*/
public function getRateWithRank():float {
switch ($this->rank) {
case 1:
$rateWithRank = $this->rate;
break;
case 2:
$rateWithRank = $this->rate * 1.25;
break;
case 3:
$rateWithRank = $this->rate * 1.50;
break;
}
if ($this->boss)
$rateWithRank *= 1.50;
return $rateWithRank;
}
/**
* ...
* ...
*/
public function getCoffee():int {
if ($this->boss) {
return $this->litresOfCoffee * 2;
} else {
return $this->litresOfCoffee;
}
}
public function getPages():int {
if ($this->boss) {
return 0;
} else {
return $this->pgsOfDocs;
}
}
final public function getRank():int {
return $this->rank;
}
final public function isBoss():bool {
return $this->boss;
}
final public function setProfession(string $profession){
$this->profession = $profession;
}
final public function setRate(int $rate){
$this->rate = $rate;
}
final public function setCoffee(int $litresOfCoffee){
$this->litresOfCoffee = $litresOfCoffee;
}
final public function setPages(int $pages){
$this->pgsOfDocs = $pages;
}
/**
* Установить ранг
* @param int $rank Ранг
* @throws InvalidArgumentException
*/
final public function setRank(int $rank){
if($rank > 0 and $rank < 4){
$this->rank = $rank;
} else {
throw new InvalidArgumentException("Ранг должен быть равен значению от 1 до 3!\n");
}
}
final public function setBossStatus(bool $bossStatus){
$this->boss = $bossStatus;
}
}
/**
* Класс Коллекция Сотрудников
*/
class Collection
{
/** @var array $employees массив сотрудников */
private $employees;
/** как закомментить константу я не знаю( */
const ALL = -1;
/**
* Конструктор класса коллекции
* @param array $employees массив сотрудников
*/
public function __construct
(array $employees){ $this->employees = $employees;
}
/**
* метод для сортировки сотрудников
* работает аналогично usort
* @param callable $sortFunction callback ф-я
* @throws UsortErrorException
* @return $this
*/
public function sort(callable
$sortFunction):Collection
{ if (usort($this->employees, $sortFunction)) { } else {
throw new UsortErrorException("Функция usort() не была выполнена!\n");
}
return $this;
}
/**
* метод для фильтрации сотрудников
* работает аналогично array_filter
* @param callable $filterFunction callback ф-я
* @return $this
*/
public function filter(callable $filterFunction):Collection {
$selectedEmployees = [];
$selectedEmployees = array_filter($this->employees, $filterFunction); $this->employees = $selectedEmployees;
return $this;
}
/**
* метод позволяет взять X сотрудников, начиная с Y
* @param int $num сколько взять
* @param int $from начиная со скольки
* @throws InvalidArgumentException
* @return $this
*/
public function takeNumItems(int $num, int $from = 1):Collection {
$numOfEmpls = count($this->employees); if ($numOfEmpls == 0) {
return $this;
}
if ($from <= 0 or $from > $numOfEmpls) {
throw new InvalidArgumentException("Аргумент \$from не должен быть меньше 1 и больше чем общее число сотрудников!\n");
}
if ($num > ($numOfEmpls - $from) + 1 or $num <= 0) {
throw new InvalidArgumentException("Взять ({$num}) сотрудников, начиная с ({$from}) из (" . $numOfEmpls . ") нельзя!\n");
}
$numEmployees = [];
for($i = 0, $key = --$from; $i < $num; $i++, $key++){
$numEmployees[] = $this->employees[$key];
}
$this->employees = $numEmployees;
return $this;
}
/**
* Извлечь копии сотрудников
* @param int $number сколько сотрудников
* @throws InvalidArgumentException
* @return array
*/
public function extractNumEmployees
(int
$number = self::ALL):array { $clonedEmployees = [];
$numOfEmpls = count($this->employees); if ($numOfEmpls == 0) {
return [];
}
if (($number <= 0 and $number != -1) or $number > $numOfEmpls) {
throw new InvalidArgumentException("\$number должен быть больше 0 и не больше кол-ва элементов в коллекции!\n");
}
if ($number == self::ALL) {
$number = count($this->employees); }
for($i = 0; $i < $number; $i++){
$clonedEmployees[] = clone $this->employees[$i];
}
return $clonedEmployees;
}
/**
* Извлечь копию первого элемента
* @return array
*/
public function extractFirstEmployee
():array { if (empty($this->employees)) { return [];
}
return [clone $this->employees[0]];
}
/**
* Получить массив сотрудников
* @return array
*/
public function getEmployees
():array { return $this->employees;
}
/**
* Посчитать элементы коллекции
* @return int
*/
public function countItems():int {
return count($this->employees); }
}
class Department
{
/** @var string $name Имя департамента */
private $name;
/** @var array $employees массив сотрудников */
private $employees = [];
/** ... */
public function __construct(string $name){
$this->name = $name;
}
/**
* Создать сотрудника
* @param int $number число сотрудников данного типа
* @param string $employeeClassName имя класса-сотрудника
* @param string $profession профессия
* @param int $rate ставка
* ...
* @throws CreateEmployeeErrorException
*/
public function createEmployee(int $number, string $employeeClassName, string $profession, int $rate, int $litresOfCoffee, int $pgsOfDocs, int $rank, bool $boss = false){
if (class_exists($employeeClassName) and
is_a($employeeClassName, "Employee", true)){ for ($i = 0; $i < $number; $i++) {
$this->employees[] = new $employeeClassName($profession, $rate, $litresOfCoffee, $pgsOfDocs, $rank, $boss);
}
} else {
throw new CreateEmployeeErrorException("Ошибка создания сотрудника!\n");
}
}
/**
* Добавить сотрудников
* @param array $newEmployees массив объектов типа Employee
*/
public function addEmployees
(array $newEmployees){ if (empty($this->employees)) { $this->employees = $newEmployees;
} else {
foreach ($newEmployees as $newEmployee) {
foreach ($this->employees as $employee) {
if ($newEmployee === $employee) {
continue 2;
}
$this->employees[] = $newEmployee;
}
}
}
}
/**
* Получить коллекцию
* @return Collection
* @throws CreateCollectionErrorException
*/
public function getCollection():Collection {
if (empty($this->employees)) { throw new CreateCollectionErrorException("В департаменте нет сотрудников! Коллекция не может быть создана!\n");
}
return new Collection($this->employees);
}
/**
* Удалить сотрудника
* @param Collection $colection удаляемая коллекция
*/
public function fireEmployees(Collection $collection){
$firedEmployees = $collection->getEmployees();
foreach ($firedEmployees as $firedEmployee) {
foreach ($this->employees as $key => $employee) {
if ($employee === $firedEmployee) {
unset($this->employees[$key]); break;
}
}
}
}
/**
* Изменить сотрудников
* @param Collection $collection коллекция для изменения
* @param callable $changeFunction callback ф-я
*/
public function changeEmployees(Collection $collection, callable $changeFunction){
foreach ($collection->getEmployees() as $employee) {
$changeFunction($employee);
}
}
/**
* Разжаловать босса
*/
public function devoteBoss(){
foreach ($this->employees as $employee) {
if ($employee->isBoss()) {
$employee->setBossStatus(false);
}
}
}
/**
* Получить имя департамента
* @return string
*/
public function getName():string {
return $this->name;
}
/**
* число сотрудников в департаменте
* @return int
*/
public function getNumOfEmployees():int {
return count($this->employees); }
/**
* ...
*/
public function getSalaryOfEmployees():float {
$salary = 0;
foreach ($this->employees as $employee) {
$salary += $employee->getRateWithRank();
}
return $salary;
}
public function getCoffee():int {
$coffee = 0;
foreach ($this->employees as $employee) {
$coffee += $employee->getCoffee();
}
return $coffee;
}
public function getPages():int {
$pages = 0;
foreach ($this->employees as $employee) {
$pages += $employee->getPages();
}
return $pages;
}
public function getTugricsPerPage():float {
if ($this->getPages() == 0) {
return 0;
} else {
return round($this->getSalaryOfEmployees() / $this->getPages(), 1); }
}
}
class Company
{
/** @var string $name имя компании */
private $name;
/** @var array $departments массив департаментов */
private $departments;
/**
* Конструктор класса Компании
* @param string $name имя компании
* @param Department $departments,... департаменты через запятую
*/
public function __construct(string $name, Department ...$departments){
$this->name = $name;
$this->departments = $departments;
}
public function __clone(){
foreach ($this->departments as $department) {
$clonedEmployees = [];
foreach ($department->getCollection()->getEmployees() as $employee) {
$clonedEmployees[] = clone $employee;
}
$clonedDepartment = new Department($department->getName());
$clonedDepartment->addEmployees($clonedEmployees);
$clonedDepartments[] = $clonedDepartment;
}
$this->departments = $clonedDepartments;
}
public function getName():string {
return $this->name;
}
public function getDepartments
():array { return $this->departments;
}
}
/**
* Добавить пады справа
* @param string $string форматируемая строка
* @param int $widthOfCol ширина колонки
*/
function padRight($string, $widthOfCol){
if ($lengthOfString <= $widthOfCol) {
$formattedString = $string . str_repeat(" ", $widthOfCol - $lengthOfString); return $formattedString;
} else {
}
}
/**
* Добавить пады слева
* @param string $string форматируемая строка
* @param int $widthOfCol ширина колонки
*/
function padLeft($string, $widthOfCol){
if ($lengthOfString <= $widthOfCol) {
$formattedString = str_repeat(" ", $widthOfCol - $lengthOfString) . $string; return $formattedString;
} else {
}
}
/**
* Вывести отчет по компании
* @param Company $company объект-компания
*/
function displayReport(Company $company){
$col1 = 15;
$col2 = 10;
$col3 = 10;
$col4 = 10;
$col5 = 10;
$col6 = 12;
echo padRight("Департамент", $col1) .
padLeft("Сотр.", $col2) .
padLeft("Тугр.", $col3) .
padLeft("Кофе", $col4) .
padLeft("Стр.", $col5) .
padLeft("Тугр./стр.", $col6) . "\n\n";
$allEmployees = 0;
$allSalary = 0;
$allCoffee = 0;
$allPages = 0;
$allTugPerPgs = 0;
foreach ($company->getDepartments() as $department) {
echo padRight($department->getName(), $col1) .
padLeft($department->getNumOfEmployees(), $col2) .
padLeft($department->getSalaryOfEmployees(), $col3) .
padLeft($department->getCoffee(), $col4) .
padLeft($department->getPages(), $col5) .
padLeft($department->getTugricsPerPage(), $col6) . "\n";
$allEmployees += $department->getNumOfEmployees();
$allSalary += $department->getSalaryOfEmployees();
$allCoffee += $department->getCoffee();
$allPages += $department->getPages();
$allTugPerPgs += $department->getTugricsPerPage();
}
$numOfDepartments = count($company->getDepartments());
echo padRight("Среднее", $col1) .
padLeft
(round(($allEmployees / $numOfDepartments),1), $col2) . padLeft
(round(($allSalary / $numOfDepartments), 1), $col3) . padLeft
(round(($allCoffee / $numOfDepartments), 1), $col4) . padLeft
(round(($allPages / $numOfDepartments), 1), $col5) . padLeft
(round(($allTugPerPgs / $numOfDepartments), 1), $col6) . "\n";
echo padRight("Всего", $col1) .
padLeft($allEmployees, $col2) .
padLeft($allSalary, $col3) .
padLeft($allCoffee, $col4) .
padLeft($allPages, $col5) .
padLeft($allTugPerPgs, $col6) . "\n\n";
}
//департаменты
$procurementDep = new Department("Закупок");
$salesDep = new Department("Продаж");
$advDep = new Department("Рекламы");
$logstcDep = new Department("Логистики1234567");
//добавим сотруников в департаменты
$procurementDep->createEmployee(9, "Employee", MANAGER, 500, 20, 200, 1);
$procurementDep->createEmployee(3, "Employee", MANAGER, 500, 20, 200, 2);
$procurementDep->createEmployee(2, "Employee", MANAGER, 500, 20, 200, 3);
$procurementDep->createEmployee(2, "Employee", MARKETER, 400, 15, 150, 1);
$procurementDep->createEmployee(1, "Employee", MANAGER, 500, 20, 200, 2, true);
$salesDep->createEmployee(12, "Employee", MANAGER, 500, 20, 200, 1);
$salesDep->createEmployee(6, "Employee", MARKETER, 400, 15, 150, 1);
$salesDep->createEmployee(3, "Employee", ANALYST, 800, 50, 5, 1);
$salesDep->createEmployee(2, "Employee", ANALYST, 800, 50, 5, 2);
$salesDep->createEmployee(1, "Employee", MARKETER, 400, 15, 150, 2, true);
$advDep->createEmployee(15, "Employee", MARKETER, 400, 15, 150, 1);
$advDep->createEmployee(10, "Employee", MARKETER, 400, 15, 150, 2);
$advDep->createEmployee(8, "Employee", MANAGER, 500, 20, 200, 1);
$advDep->createEmployee(2, "Employee", ENGINEER, 200, 5, 50, 1);
$advDep->createEmployee(1, "Employee", MARKETER, 400, 15, 150, 3, true);
$logstcDep->createEmployee(13, "Employee", MANAGER, 500, 20, 200, 1);
$logstcDep->createEmployee(5, "Employee", MANAGER, 500, 20, 200, 2);
$logstcDep->createEmployee(5, "Employee", ENGINEER, 200, 5, 50, 1);
$logstcDep->createEmployee(1, "Employee", MANAGER, 500, 20, 200, 1, true);
$company = new Company("Вектор", $procurementDep, $salesDep, $advDep, $logstcDep);
//Копии для опробирования мер
$company1 = clone $company;
$company2 = clone $company;
$company3 = clone $company;
//Начальные данные
echo "Начальные данные:\n";
displayReport($company);
//План 1
foreach ($company1->getDepartments() as $department) {
$collection = $department->getCollection()->filter(function($e){return $e->getProfession() == ENGINEER
;})->sort(function($e1,$e2){return ($e1->getRank() <=> $e2->getRank());}); $numOfFired = round($collection->countItems() * 0.40); if ($numOfFired != 0) {
$collection = $collection->takeNumItems($numOfFired);
$department->fireEmployees($collection);
}
}
echo "План 1:\n";
displayReport($company1);
//План 2
foreach ($company2->getDepartments() as $department) {
$analysts = $department->getCollection()->filter(function($e){return $e->getProfession() == ANALYST
;})->sort(function($e1,$e2){return -($e1->getRank() <=> $e2->getRank());}); $department->changeEmployees($analysts, function($e){$e->setRate(1100);$e->setCoffee(75);});
$bossAndNotAnalyst = $department->getCollection()->filter(function($e){return ($e->isBoss() and $e->getProfession() != ANALYST);});
if ($bossAndNotAnalyst->countItems() and $analysts->countItems()) {
$department->devoteBoss();
$higherAnalyst = $analysts->takeNumItems(1);
$department->changeEmployees($higherAnalyst, function($e){$e->setBossStatus(true);});
}
}
echo "План 2:\n";
displayReport($company2);
//План 3
foreach ($company3->getDepartments() as $department) {
$oneAndTwoRankManagers = $department->getCollection()->filter(function($e){return ($e->getRank() == 1 or $e->getRank() == 2) and $e->getProfession() == MANAGER;});
$half = round($oneAndTwoRankManagers->countItems() * 0.50); if ($half != 0) {
$raisedManagers = $oneAndTwoRankManagers->takeNumItems($half);
$department->changeEmployees($raisedManagers, function($e){$e->setRank($e->getRank() + 1);});
}
}
echo "План 3:\n";
displayReport($company3);