<?php
define("MARKETER", "marketer"); define("ENGINEER", "engineer");
class CollectionException extends Exception {}
class DepartmentException extends Exception {}
//Класс сотрудник
class Employee
{
protected $profession;
protected $rate;
protected $litresOfCoffee;
protected $pgsOfDocs;
protected $rank;
protected $boss;
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;
}
final public function getProfession():string {
return $this->profession;
}
final public function getRate():int {
return $this->rate;
}
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;
}
final public function setRank(int $rank):bool {
if($rank > 0 and $rank < 4){
$this->rank = $rank;
return true;
} else {
return false;
}
}
final public function setBossStatus(bool $bossStatus){
$this->boss = $bossStatus;
}
}
//Класс коллекция сотрудников - сортирует, отбирает, исключает, берет процент, берет число сотрудников, извлекает копии класса сотрудников. Возвращает объект коллекцию.
class Collection
{
private $employees;
private $method;
private $sortFlag;
const ASC = 1;//сортировка по возрастанию
const DESC = 2;//сортировка по убыванию
const ALL = 3;//все копии
const RATE = 4;
const COFFEE = 5;
const PAGES = 6;
const RANK = 7;
const SALARY = 8;
const PROFESSION = 9;
const BOSS = 10;
public function __construct(Employee ...$employees){
$this->employees = $employees;
}
//Сортировка по параметрам
public function sort(int
$sortProperty, int
$sortFlag = self::ASC):Collection
{ if ($sortFlag == self::ASC or $sortFlag == self::DESC) {
$this->sortFlag = $sortFlag;
} else {
throw new CollectionException("Флаг сортировки должен принимать значения: Collection::ASC, Collection::DESC\n");
}
if ($this->setMethod($sortProperty) and ($sortProperty < self::PROFESSION)) {
return usort($this->employees, array($this, "sortByProperty")) ?
$this : throw new CollectionException("Сортировка не произошла!\n");
})
;
} else {
throw new CollectionException("Сортировка возможна по параметрам: Collection::RATE, Collection::COFFEE, Collection::PAGES, Collection::RANK, Collection::SALARY\n");
}
}
//Выбор по параметрам
public function select(int $property, $value) {
if ($this->setMethod($property)) {
$selectedEmployees = [];
foreach ($this->employees as $employee) {
$method = $this->method;
if($employee->$method() === $value)
$selectedEmployees[] = $employee;
}
if (empty($selectedEmployees)) { throw new CollectionException("Элементы не найдены!\n");
} else {
$this->employees = $selectedEmployees;
return $this;
}
} else {
throw new CollectionException("Выбор возможен по параметрам: Collection::RATE, Collection::COFFEE, Collection::PAGES, Collection::RANK, Collection::SALARY, Collection::PROFESSION, Collection::BOSS");
}
}
//Исключение по параметрам
public function exclude(int $property, $value):Collection {
if ($this->setMethod($property)) {
$neededEmployees = [];
$method = $this->method;
foreach ($this->employees as $employee) {
if($employee->$method() != $value)
$neededEmployees[] = $employee;
}
if (empty($neededEmployees)) { throw new CollectionException("Исключены все элементы!\n");
} else {
$this->employees = $neededEmployees;
return $this;
}
} else {
throw new CollectionException("Исключение возможно по параметрам: Collection::RATE, Collection::COFFEE, Collection::PAGES, Collection::RANK, Collection::SALARY, Collection::PROFESSION, Collection::BOSS");
}
}
//Взять процент от числа сотрудников
public function takePercent(int $percent):Collection {
if ($percent > 0) {
$neededEmployees = [];
$percent = $percent / 100;
$numOfEmpl = count($this->employees); $neededNumOfEmpl = round($numOfEmpl * $percent); if ($neededNumOfEmpl == 0) {
throw new CoolectionException("Взять данный процент от числа сотрудников не возможно!\n");
}
for($i = 0; $i < $neededNumOfEmpl; $i++){
$neededEmployees[] = $this->employees[$i];
}
$this->employees = $neededEmployees;
return $this;
} else {
return false;
}
}
//Извлечь из коллекции копии объектов класса Сотрудник
public function extractEmployees(int $number = self::ALL) {
$clonedEmployees = [];
$numOfEmpls = count($this->employees); if ($number == self::ALL) {
foreach ($this->employees as $employee) {
$clonedEmployees[] = clone $employee;
}
return $clonedEmployees;
} else {
if ($number > $numOfEmpls) {
throw new CollectionException("{$number} сотрудников не может быть извлечено, в коллекции {$numOfEmpls} сотрудников!\n");
} elseif($number == 1) {
return $this->extractEmployee();
} else {
for($i = 0; $i < $numOfEmpls; $i++){
$clonedEmployees[] = clone $this->employees[$i];
}
return $clonedEmployees;
}
}
}
//Извлечь одну копию объекта класса Сотрудник
public function extractEmployee():Employee {
return clone $this->employees[0];
}
//Получить коллекцию из $num элементов
public function takeNumItems(int $num):Collection {
$numOfItems = count($this->employees); if ($num > $numOfItems) {
throw new CollectionException("Коллекция из {$num} элементов не может быть создана, в коллекции {$numOfItems} элементов!\n");
} elseif($num == 1) {
return $this->takeOneItem();
} else {
$collectionOfNumItems = [];
for($i = 0; $i < $num; $i++){
$collectionOfNumItems[] = $this->employees[$i];
}
$this->employees = $collectionOfNumItems;
return $this;
}
}
//Получить коллекцию из одного элемента
public function takeOneItem():Collection {
$oneItemCollection[] = $this->employees[0];
$this->employees = $oneItemCollection;
return $this;
}
//Выбор гет-метода свойства по которому происходит сортировка, выборка и т.п.
private function setMethod(int $property):bool {
switch($property){
case self::RATE:
$this->method = "getRate";
return true;
case self::COFFEE:
$this->method = "getCoffee";
return true;
case self::PAGES:
$this->method = "getPages";
return true;
case self::RANK:
$this->method = "getRank";
return true;
case self::SALARY:
$this->method = "getRateWithRank";
return true;
case self::PROFESSION:
$this->method = "getProfession";
return true;
case self::BOSS:
$this->method = "isBoss";
return true;
default:
return false;
}
}
//Универсальная ф-я сортировки
private function sortByProperty(Employee $employee1, Employee $employee2):int {
$method = $this->method;
if ($this->sortFlag == self::ASC) {
return ($employee1->$method() <=> $employee2->$method());
} else {
return -($employee1->$method() <=> $employee2->$method());
}
}
}
class Department
{
const UPRANK = "up";//повысить ранг
const DOWNRANK = "down";//понизить ранг
private $name;
private $employees = [];
public function __construct(string $name){
$this->name = $name;
}
//Создать сотрудника
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 DepartmentException("Ошибка создания сотрудника!\n");
}
}
//Получить коллекцию
public function getCollection(){
if (empty($this->employees)) { throw new DepartmentException("В департаменте нет сотрудников! Коллекция не может быть создана!\n");
}
return new Collection(...$this->employees);
}
//Удалить сотрудника, принимает на вход коллекцию, удаляет сотрудников идентичных сотрудникам из коллекции(сравнение полей)
public function fireEmployees(Collection $collection){
$samples = $collection->extractEmployees();
foreach ($samples as $sample) {
foreach ($this->employees as $key => $realEmployee) {
if ($realEmployee == $sample) {
unset($this->employees[$key]); break;
}
}
}
}
//Добавить сотрудников из коллекции
public function addEmployees(Collection $collection){
foreach ($collection->extractEmployees() as $employee) {
$this->employees[] = $employee;
}
}
//Изменить сотрудников, работает аналогично ф-ии удаления
public function changeEmployees(Collection $collection, int $property, $value){
switch($property){
case Collection::RATE:
$method = "setRate";
break;
case Collection::COFFEE:
$method = "setCoffee";
break;
case Collection::PAGES:
$method = "setPages";
break;
case Collection::RANK:
$method = "setRank";
break;
case Collection::PROFESSION:
$method = "setProfession";
break;
case Collection::BOSS:
$method = "setBossStatus";
break;
default:
throw new DepartmentException("Свойство для изменения должно быть следующим: Collection::RATE, Collection::COFFEE, Collection::PAGES, Collection::RANK, Collection::PROFESSION, Collection::BOSS\n");
}
$samples = $collection->extractEmployees();
if ($method == "setRank") {
foreach ($samples as $sample) {
foreach ($this->employees as $realEmployee) {
if ($realEmployee == $sample) {
if ($value == self::UPRANK) {
$rank = $realEmployee->getRank();
$value = (++$rank > 3) ? --$rank : $rank;
}
if ($value == self::DOWNRANK){
$rank = $realEmployee->getRank();
$value = (--$rank == 0) ? ++$rank : $rank;
}
if($realEmployee->$method($value)){
break;
} else {
throw new DepartmentException("Значения ранга должно быть от 1 до 3!\n");
}
}
}
}
} else {
foreach ($samples as $sample) {
foreach ($this->employees as $realEmployee) {
if ($realEmployee == $sample) {
$realEmployee->$method($value);
break;
}
}
}
}
}
public function getName():string {
return $this->name;
}
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
{
private $name;
private $departments;
private $backupDepartments = [];//клоны департаментов - для восстановления
public function __construct(string $name, Department ...$departments){
$this->departments = $departments;
}
public function getName():string {
return $this->name;
}
public function getDepartments
():array { return $this->departments;
}
//клонирует департаменты(вместе с сотрудниками)
private function cloneDepartments
(array $baseDepartments):array { $copiedDepartments = [];
foreach ($baseDepartments as $department) {
$collection = $department->getCollection();
$backupDepartment = new Department($department->getName());
$backupDepartment->addEmployees($collection);
$copiedDepartments[] = $backupDepartment;
}
return $copiedDepartments;
}
//клонирует исходный массив департаментов
public function backup(){
$this->backupDepartments = $this->cloneDepartments($this->departments);
}
//восстанавливает исходный массив
public function restore(){
$this->departments = $this->cloneDepartments($this->backupDepartments);
}
}
function padRight($string, $widthOfCol){
if ($lengthOfString < $widthOfCol) {
$formattedString = $string . str_repeat(" ", $widthOfCol - $lengthOfString); return $formattedString;
} else {
return false;
}
}
function padLeft($string, $widthOfCol){
if ($lengthOfString < $widthOfCol) {
$formattedString = str_repeat(" ", $widthOfCol - $lengthOfString) . $string; return $formattedString;
} else {
return false;
}
}
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("Логистики");
//добавим сотруников в департаменты
$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);
$company->backup();
//Начальные данные
echo "Начальные данные:\n";
displayReport($company);
//План 1
foreach($company->getDepartments() as $department){
try {
$firedLowRankEngineers = $department->getCollection()->select(Collection
::PROFESSION, ENGINEER
)->sort(Collection
::RANK)->exclude(Collection
::BOSS, true)->takePercent(40); $department->fireEmployees($firedLowRankEngineers);
} catch(CollectionException $e){
//echo "В департаменте " . $department->getName() . " " . $e->getMessage();
continue;
} catch(DepartmentException $e){
echo $e->getMessage();
}
}
echo "План 1:\n";
displayReport($company);
$company->restore();
//План 2
foreach ($company->getDepartments() as $department) {
try {
$analysts = $department->getCollection()->select(Collection::PROFESSION, ANALYST);
$department->changeEmployees($analysts, Collection::RATE, 1100);
$department->changeEmployees($analysts, Collection::COFFEE, 75);
$oldBoss = $department->getCollection()->select(Collection::BOSS, true);
if ($oldBoss->extractEmployee()->getProfession() != ANALYST) {
$department->changeEmployees($oldBoss, Collection::BOSS, false);
$highRankAnalyst = $department->getCollection()->select(Collection
::PROFESSION, ANALYST
)->sort(Collection
::RANK, Collection
::DESC)->takeOneItem(); $department->changeEmployees($highRankAnalyst, Collection::BOSS, true);
}
} catch(CollectionException $e){
//echo $e->getMessage();
continue;
} catch(DepartmentException $e){
echo $e->getMessage();
}
}
echo "План 2:\n";
displayReport($company);
$company->restore();
//План 3
foreach ($company->getDepartments() as $department) {
try {
$oneTwoRankManagers = $department->getCollection()->select(Collection::PROFESSION, MANAGER)->exclude(Collection::RANK, 3)->takePercent(50);
$department->changeEmployees($oneTwoRankManagers, Collection::RANK, Department::UPRANK);
} catch(CollectionException $e){
//echo $e->getMessage();
continue;
} catch(DepartmentException $e){
echo $e->getMessage();
}
}
echo "План 3:\n";
displayReport($company);
$company->restore();