fork download
  1. <?php
  2.  
  3. /** профессия менеджер */
  4. const MANAGER = "manager";
  5. /** профессия маркетолог */
  6. const MARKETER = "marketer";
  7. /** профессия инженер */
  8. const ENGINEER = "engineer";
  9. /** профессия аналитик */
  10. const ANALYST = "analyst";
  11.  
  12. /** Исключение метода сортировки */
  13. class UsortErrorException extends Exception {}
  14. /** Исключение метода создания сотрудника */
  15. class CreateEmployeeErrorException extends Exception {}
  16. /** Исключение метода получения коллекции */
  17. class CreateCollectionErrorException extends Exception {}
  18.  
  19. /** Класс сотрудник */
  20. class Employee
  21. {
  22. /** @var string $profession профессия */
  23. protected $profession;
  24. /** @var int $rate ставка */
  25. protected $rate;
  26. /** @var int $litresOfCoffee выпитые литры кофе */
  27. protected $litresOfCoffee;
  28. /** @var int $pgsOfDocs кол-во страниц */
  29. protected $pgsOfDocs;
  30. /** @var int $rank ранг */
  31. protected $rank;
  32. /** @var bool $boss босс или не босс */
  33. protected $boss;
  34.  
  35. /**
  36. * Конструктор класса Сотрудник
  37. * @param string $profession профессия
  38. * @param int $rate ставка
  39. * ...
  40. */
  41. final public function __construct(string $profession, int $rate, int $litresOfCoffee, int $pgsOfDocs, int $rank, bool $boss = false){
  42. $this->profession = $profession;
  43. $this->rate = $rate;
  44. $this->litresOfCoffee = $litresOfCoffee;
  45. $this->pgsOfDocs = $pgsOfDocs;
  46. $this->rank = $rank;
  47. $this->boss = $boss;
  48. }
  49.  
  50. /**
  51. * Вернуть профессию
  52. * @return string
  53. */
  54. final public function getProfession():string {
  55. return $this->profession;
  56. }
  57.  
  58. /**
  59. * Получить ставку
  60. * @return int
  61. */
  62. final public function getRate():int {
  63. return $this->rate;
  64. }
  65.  
  66. /**
  67. * Получить ставку с учетом ранга
  68. * @return float
  69. */
  70. public function getRateWithRank():float {
  71. switch ($this->rank) {
  72. case 1:
  73. $rateWithRank = $this->rate;
  74. break;
  75. case 2:
  76. $rateWithRank = $this->rate * 1.25;
  77. break;
  78. case 3:
  79. $rateWithRank = $this->rate * 1.50;
  80. break;
  81. }
  82. if ($this->boss)
  83. $rateWithRank *= 1.50;
  84. return $rateWithRank;
  85. }
  86.  
  87. /**
  88. * ...
  89. * ...
  90. */
  91. public function getCoffee():int {
  92. if ($this->boss) {
  93. return $this->litresOfCoffee * 2;
  94. } else {
  95. return $this->litresOfCoffee;
  96. }
  97. }
  98.  
  99. public function getPages():int {
  100. if ($this->boss) {
  101. return 0;
  102. } else {
  103. return $this->pgsOfDocs;
  104. }
  105. }
  106.  
  107. final public function getRank():int {
  108. return $this->rank;
  109. }
  110.  
  111. final public function isBoss():bool {
  112. return $this->boss;
  113. }
  114.  
  115. final public function setProfession(string $profession){
  116. $this->profession = $profession;
  117. }
  118.  
  119. final public function setRate(int $rate){
  120. $this->rate = $rate;
  121. }
  122.  
  123. final public function setCoffee(int $litresOfCoffee){
  124. $this->litresOfCoffee = $litresOfCoffee;
  125. }
  126.  
  127. final public function setPages(int $pages){
  128. $this->pgsOfDocs = $pages;
  129. }
  130. /**
  131. * Установить ранг
  132. * @param int $rank Ранг
  133. * @throws InvalidArgumentException
  134. */
  135. final public function setRank(int $rank){
  136. if($rank > 0 and $rank < 4){
  137. $this->rank = $rank;
  138. } else {
  139. throw new InvalidArgumentException("Ранг должен быть равен значению от 1 до 3!\n");
  140. }
  141. }
  142.  
  143. final public function setBossStatus(bool $bossStatus){
  144. $this->boss = $bossStatus;
  145. }
  146. }
  147.  
  148. /**
  149.  * Класс Коллекция Сотрудников
  150.  */
  151. class Collection
  152. {
  153. /** @var array $employees массив сотрудников */
  154. private $employees;
  155.  
  156. /** как закомментить константу я не знаю( */
  157. const ALL = -1;
  158.  
  159. /**
  160. * Конструктор класса коллекции
  161. * @param array $employees массив сотрудников
  162. */
  163. public function __construct(array $employees){
  164. $this->employees = $employees;
  165. }
  166.  
  167. /**
  168. * метод для сортировки сотрудников
  169. * работает аналогично usort
  170. * @param callable $sortFunction callback ф-я
  171. * @throws UsortErrorException
  172. * @return $this
  173. */
  174. public function sort(callable $sortFunction):Collection {
  175. if (usort($this->employees, $sortFunction)) {
  176. } else {
  177. throw new UsortErrorException("Функция usort() не была выполнена!\n");
  178. }
  179. return $this;
  180. }
  181.  
  182. /**
  183. * метод для фильтрации сотрудников
  184. * работает аналогично array_filter
  185. * @param callable $filterFunction callback ф-я
  186. * @return $this
  187. */
  188. public function filter(callable $filterFunction):Collection {
  189. $selectedEmployees = [];
  190. $selectedEmployees = array_filter($this->employees, $filterFunction);
  191. $this->employees = $selectedEmployees;
  192. return $this;
  193. }
  194.  
  195. /**
  196. * метод позволяет взять X сотрудников, начиная с Y
  197. * @param int $num сколько взять
  198. * @param int $from начиная со скольки
  199. * @throws InvalidArgumentException
  200. * @return $this
  201. */
  202. public function takeNumItems(int $num, int $from = 1):Collection {
  203. $numOfEmpls = count($this->employees);
  204. if ($numOfEmpls == 0) {
  205. return $this;
  206. }
  207. if ($from <= 0 or $from > $numOfEmpls) {
  208. throw new InvalidArgumentException("Аргумент \$from не должен быть меньше 1 и больше чем общее число сотрудников!\n");
  209. }
  210. if ($num > ($numOfEmpls - $from) + 1 or $num <= 0) {
  211. throw new InvalidArgumentException("Взять ({$num}) сотрудников, начиная с ({$from}) из (" . $numOfEmpls . ") нельзя!\n");
  212. }
  213. $numEmployees = [];
  214. $this->employees = array_values($this->employees);
  215. for($i = 0, $key = --$from; $i < $num; $i++, $key++){
  216. $numEmployees[] = $this->employees[$key];
  217. }
  218. $this->employees = $numEmployees;
  219. return $this;
  220. }
  221.  
  222. /**
  223. * Извлечь копии сотрудников
  224. * @param int $number сколько сотрудников
  225. * @throws InvalidArgumentException
  226. * @return array
  227. */
  228. public function extractNumEmployees(int $number = self::ALL):array {
  229. $clonedEmployees = [];
  230. $numOfEmpls = count($this->employees);
  231. if ($numOfEmpls == 0) {
  232. return [];
  233. }
  234. if (($number <= 0 and $number != -1) or $number > $numOfEmpls) {
  235. throw new InvalidArgumentException("\$number должен быть больше 0 и не больше кол-ва элементов в коллекции!\n");
  236. }
  237. if ($number == self::ALL) {
  238. $number = count($this->employees);
  239. }
  240. for($i = 0; $i < $number; $i++){
  241. $clonedEmployees[] = clone $this->employees[$i];
  242. }
  243. return $clonedEmployees;
  244. }
  245.  
  246. /**
  247. * Извлечь копию первого элемента
  248. * @return array
  249. */
  250. public function extractFirstEmployee():array {
  251. if (empty($this->employees)) {
  252. return [];
  253. }
  254. return [clone $this->employees[0]];
  255. }
  256.  
  257. /**
  258. * Получить массив сотрудников
  259. * @return array
  260. */
  261. public function getEmployees():array {
  262. return $this->employees;
  263. }
  264.  
  265. /**
  266. * Посчитать элементы коллекции
  267. * @return int
  268. */
  269. public function countItems():int {
  270. return count($this->employees);
  271. }
  272. }
  273.  
  274. class Department
  275. {
  276. /** @var string $name Имя департамента */
  277. private $name;
  278. /** @var array $employees массив сотрудников */
  279. private $employees = [];
  280. /** ... */
  281. public function __construct(string $name){
  282. $this->name = $name;
  283. }
  284.  
  285. /**
  286. * Создать сотрудника
  287. * @param int $number число сотрудников данного типа
  288. * @param string $employeeClassName имя класса-сотрудника
  289. * @param string $profession профессия
  290. * @param int $rate ставка
  291. * ...
  292. * @throws CreateEmployeeErrorException
  293. */
  294. public function createEmployee(int $number, string $employeeClassName, string $profession, int $rate, int $litresOfCoffee, int $pgsOfDocs, int $rank, bool $boss = false){
  295. if (class_exists($employeeClassName) and is_a($employeeClassName, "Employee", true)){
  296. for ($i = 0; $i < $number; $i++) {
  297. $this->employees[] = new $employeeClassName($profession, $rate, $litresOfCoffee, $pgsOfDocs, $rank, $boss);
  298. }
  299. } else {
  300. throw new CreateEmployeeErrorException("Ошибка создания сотрудника!\n");
  301. }
  302. }
  303.  
  304. /**
  305. * Добавить сотрудников
  306. * @param array $newEmployees массив объектов типа Employee
  307. */
  308. public function addEmployees(array $newEmployees){
  309. if (empty($this->employees)) {
  310. $this->employees = $newEmployees;
  311. } else {
  312. foreach ($newEmployees as $newEmployee) {
  313. foreach ($this->employees as $employee) {
  314. if ($newEmployee === $employee) {
  315. continue 2;
  316. }
  317. $this->employees[] = $newEmployee;
  318. }
  319. }
  320. }
  321. }
  322.  
  323. /**
  324. * Получить коллекцию
  325. * @return Collection
  326. * @throws CreateCollectionErrorException
  327. */
  328. public function getCollection():Collection {
  329. if (empty($this->employees)) {
  330. throw new CreateCollectionErrorException("В департаменте нет сотрудников! Коллекция не может быть создана!\n");
  331. }
  332. return new Collection($this->employees);
  333. }
  334.  
  335. /**
  336. * Удалить сотрудника
  337. * @param Collection $colection удаляемая коллекция
  338. */
  339. public function fireEmployees(Collection $collection){
  340. $firedEmployees = $collection->getEmployees();
  341. foreach ($firedEmployees as $firedEmployee) {
  342. foreach ($this->employees as $key => $employee) {
  343. if ($employee === $firedEmployee) {
  344. unset($this->employees[$key]);
  345. break;
  346. }
  347. }
  348. }
  349. $this->employees = array_values($this->employees);
  350. }
  351.  
  352. /**
  353. * Изменить сотрудников
  354. * @param Collection $collection коллекция для изменения
  355. * @param callable $changeFunction callback ф-я
  356. */
  357. public function changeEmployees(Collection $collection, callable $changeFunction){
  358. foreach ($collection->getEmployees() as $employee) {
  359. $changeFunction($employee);
  360. }
  361. }
  362.  
  363. /**
  364. * Разжаловать босса
  365. */
  366. public function devoteBoss(){
  367. foreach ($this->employees as $employee) {
  368. if ($employee->isBoss()) {
  369. $employee->setBossStatus(false);
  370. }
  371. }
  372. }
  373.  
  374. /**
  375. * Получить имя департамента
  376. * @return string
  377. */
  378. public function getName():string {
  379. return $this->name;
  380. }
  381.  
  382. /**
  383. * число сотрудников в департаменте
  384. * @return int
  385. */
  386. public function getNumOfEmployees():int {
  387. return count($this->employees);
  388. }
  389.  
  390. /**
  391. * ...
  392. */
  393. public function getSalaryOfEmployees():float {
  394. $salary = 0;
  395. foreach ($this->employees as $employee) {
  396. $salary += $employee->getRateWithRank();
  397. }
  398. return $salary;
  399. }
  400.  
  401. public function getCoffee():int {
  402. $coffee = 0;
  403. foreach ($this->employees as $employee) {
  404. $coffee += $employee->getCoffee();
  405. }
  406. return $coffee;
  407. }
  408.  
  409. public function getPages():int {
  410. $pages = 0;
  411. foreach ($this->employees as $employee) {
  412. $pages += $employee->getPages();
  413. }
  414. return $pages;
  415. }
  416.  
  417. public function getTugricsPerPage():float {
  418. if ($this->getPages() == 0) {
  419. return 0;
  420. } else {
  421. return round($this->getSalaryOfEmployees() / $this->getPages(), 1);
  422. }
  423. }
  424.  
  425. }
  426.  
  427. class Company
  428. {
  429. /** @var string $name имя компании */
  430. private $name;
  431. /** @var array $departments массив департаментов */
  432. private $departments;
  433.  
  434. /**
  435. * Конструктор класса Компании
  436. * @param string $name имя компании
  437. * @param Department $departments,... департаменты через запятую
  438. */
  439. public function __construct(string $name, Department ...$departments){
  440. $this->name = $name;
  441. $this->departments = $departments;
  442. }
  443.  
  444. public function __clone(){
  445. foreach ($this->departments as $department) {
  446. $clonedEmployees = [];
  447. foreach ($department->getCollection()->getEmployees() as $employee) {
  448. $clonedEmployees[] = clone $employee;
  449. }
  450. $clonedDepartment = new Department($department->getName());
  451. $clonedDepartment->addEmployees($clonedEmployees);
  452. $clonedDepartments[] = $clonedDepartment;
  453. }
  454. $this->departments = $clonedDepartments;
  455. }
  456.  
  457. public function getName():string {
  458. return $this->name;
  459. }
  460.  
  461. public function getDepartments():array {
  462. return $this->departments;
  463. }
  464. }
  465.  
  466. /**
  467.  * Добавить пады справа
  468.  * @param string $string форматируемая строка
  469.  * @param int $widthOfCol ширина колонки
  470.  */
  471. function padRight($string, $widthOfCol){
  472. $lengthOfString = mb_strlen($string);
  473. if ($lengthOfString <= $widthOfCol) {
  474. $formattedString = $string . str_repeat(" ", $widthOfCol - $lengthOfString);
  475. return $formattedString;
  476. } else {
  477. return mb_substr($string, 0, $widthOfCol);
  478. }
  479. }
  480.  
  481. /**
  482.  * Добавить пады слева
  483.  * @param string $string форматируемая строка
  484.  * @param int $widthOfCol ширина колонки
  485.  */
  486. function padLeft($string, $widthOfCol){
  487. $lengthOfString = mb_strlen($string);
  488. if ($lengthOfString <= $widthOfCol) {
  489. $formattedString = str_repeat(" ", $widthOfCol - $lengthOfString) . $string;
  490. return $formattedString;
  491. } else {
  492. return mb_substr($string, 0, $widthOfCol);
  493. }
  494. }
  495.  
  496. /**
  497.  * Вывести отчет по компании
  498.  * @param Company $company объект-компания
  499.  */
  500. function displayReport(Company $company){
  501.  
  502. $col1 = 15;
  503. $col2 = 10;
  504. $col3 = 10;
  505. $col4 = 10;
  506. $col5 = 10;
  507. $col6 = 12;
  508.  
  509. echo padRight("Департамент", $col1) .
  510. padLeft("Сотр.", $col2) .
  511. padLeft("Тугр.", $col3) .
  512. padLeft("Кофе", $col4) .
  513. padLeft("Стр.", $col5) .
  514. padLeft("Тугр./стр.", $col6) . "\n\n";
  515.  
  516. $allEmployees = 0;
  517. $allSalary = 0;
  518. $allCoffee = 0;
  519. $allPages = 0;
  520. $allTugPerPgs = 0;
  521.  
  522. foreach ($company->getDepartments() as $department) {
  523.  
  524. echo padRight($department->getName(), $col1) .
  525. padLeft($department->getNumOfEmployees(), $col2) .
  526. padLeft($department->getSalaryOfEmployees(), $col3) .
  527. padLeft($department->getCoffee(), $col4) .
  528. padLeft($department->getPages(), $col5) .
  529. padLeft($department->getTugricsPerPage(), $col6) . "\n";
  530.  
  531. $allEmployees += $department->getNumOfEmployees();
  532. $allSalary += $department->getSalaryOfEmployees();
  533. $allCoffee += $department->getCoffee();
  534. $allPages += $department->getPages();
  535. $allTugPerPgs += $department->getTugricsPerPage();
  536. }
  537.  
  538. $numOfDepartments = count($company->getDepartments());
  539.  
  540. echo padRight("Среднее", $col1) .
  541. padLeft(round(($allEmployees / $numOfDepartments),1), $col2) .
  542. padLeft(round(($allSalary / $numOfDepartments), 1), $col3) .
  543. padLeft(round(($allCoffee / $numOfDepartments), 1), $col4) .
  544. padLeft(round(($allPages / $numOfDepartments), 1), $col5) .
  545. padLeft(round(($allTugPerPgs / $numOfDepartments), 1), $col6) . "\n";
  546.  
  547. echo padRight("Всего", $col1) .
  548. padLeft($allEmployees, $col2) .
  549. padLeft($allSalary, $col3) .
  550. padLeft($allCoffee, $col4) .
  551. padLeft($allPages, $col5) .
  552. padLeft($allTugPerPgs, $col6) . "\n\n";
  553. }
  554.  
  555. //департаменты
  556. $procurementDep = new Department("Закупок");
  557. $salesDep = new Department("Продаж");
  558. $advDep = new Department("Рекламы");
  559. $logstcDep = new Department("Логистики1234567");
  560.  
  561. //добавим сотруников в департаменты
  562.  
  563. $procurementDep->createEmployee(9, "Employee", MANAGER, 500, 20, 200, 1);
  564. $procurementDep->createEmployee(3, "Employee", MANAGER, 500, 20, 200, 2);
  565. $procurementDep->createEmployee(2, "Employee", MANAGER, 500, 20, 200, 3);
  566. $procurementDep->createEmployee(2, "Employee", MARKETER, 400, 15, 150, 1);
  567. $procurementDep->createEmployee(1, "Employee", MANAGER, 500, 20, 200, 2, true);
  568.  
  569. $salesDep->createEmployee(12, "Employee", MANAGER, 500, 20, 200, 1);
  570. $salesDep->createEmployee(6, "Employee", MARKETER, 400, 15, 150, 1);
  571. $salesDep->createEmployee(3, "Employee", ANALYST, 800, 50, 5, 1);
  572. $salesDep->createEmployee(2, "Employee", ANALYST, 800, 50, 5, 2);
  573. $salesDep->createEmployee(1, "Employee", MARKETER, 400, 15, 150, 2, true);
  574.  
  575. $advDep->createEmployee(15, "Employee", MARKETER, 400, 15, 150, 1);
  576. $advDep->createEmployee(10, "Employee", MARKETER, 400, 15, 150, 2);
  577. $advDep->createEmployee(8, "Employee", MANAGER, 500, 20, 200, 1);
  578. $advDep->createEmployee(2, "Employee", ENGINEER, 200, 5, 50, 1);
  579. $advDep->createEmployee(1, "Employee", MARKETER, 400, 15, 150, 3, true);
  580.  
  581. $logstcDep->createEmployee(13, "Employee", MANAGER, 500, 20, 200, 1);
  582. $logstcDep->createEmployee(5, "Employee", MANAGER, 500, 20, 200, 2);
  583. $logstcDep->createEmployee(5, "Employee", ENGINEER, 200, 5, 50, 1);
  584. $logstcDep->createEmployee(1, "Employee", MANAGER, 500, 20, 200, 1, true);
  585.  
  586. $company = new Company("Вектор", $procurementDep, $salesDep, $advDep, $logstcDep);
  587.  
  588. //Копии для опробирования мер
  589. $company1 = clone $company;
  590. $company2 = clone $company;
  591. $company3 = clone $company;
  592. //Начальные данные
  593. echo "Начальные данные:\n";
  594. displayReport($company);
  595. //План 1
  596. foreach ($company1->getDepartments() as $department) {
  597. $collection = $department->getCollection()->filter(function($e){return $e->getProfession() == ENGINEER;})->sort(function($e1,$e2){return ($e1->getRank() <=> $e2->getRank());});
  598. $numOfFired = round($collection->countItems() * 0.40);
  599. if ($numOfFired != 0) {
  600. $collection = $collection->takeNumItems($numOfFired);
  601. $department->fireEmployees($collection);
  602. }
  603. }
  604. echo "План 1:\n";
  605. displayReport($company1);
  606. //План 2
  607. foreach ($company2->getDepartments() as $department) {
  608. $analysts = $department->getCollection()->filter(function($e){return $e->getProfession() == ANALYST;})->sort(function($e1,$e2){return -($e1->getRank() <=> $e2->getRank());});
  609. $department->changeEmployees($analysts, function($e){$e->setRate(1100);$e->setCoffee(75);});
  610. $bossAndNotAnalyst = $department->getCollection()->filter(function($e){return ($e->isBoss() and $e->getProfession() != ANALYST);});
  611. if ($bossAndNotAnalyst->countItems() and $analysts->countItems()) {
  612. $department->devoteBoss();
  613. $higherAnalyst = $analysts->takeNumItems(1);
  614. $department->changeEmployees($higherAnalyst, function($e){$e->setBossStatus(true);});
  615. }
  616. }
  617. echo "План 2:\n";
  618. displayReport($company2);
  619. //План 3
  620. foreach ($company3->getDepartments() as $department) {
  621. $oneAndTwoRankManagers = $department->getCollection()->filter(function($e){return ($e->getRank() == 1 or $e->getRank() == 2) and $e->getProfession() == MANAGER;});
  622. $half = round($oneAndTwoRankManagers->countItems() * 0.50);
  623. if ($half != 0) {
  624. $raisedManagers = $oneAndTwoRankManagers->takeNumItems($half);
  625. $department->changeEmployees($raisedManagers, function($e){$e->setRank($e->getRank() + 1);});
  626. }
  627. }
  628. echo "План 3:\n";
  629. displayReport($company3);
Success #stdin #stdout 0.02s 24644KB
stdin
Standard input is empty
stdout
Начальные данные:
Департамент         Сотр.     Тугр.      Кофе      Стр.  Тугр./стр.

Закупок                17    9612.5       350      3100         3.1
Продаж                 24     13550       610      3325         4.1
Рекламы                36     16300       575      5450           3
Логистики123456        24     11375       425      3850           3
Среднее              25.3   12709.4       490    3931.3         3.3
Всего                 101   50837.5      1960     15725        13.2

План 1:
Департамент         Сотр.     Тугр.      Кофе      Стр.  Тугр./стр.

Закупок                17    9612.5       350      3100         3.1
Продаж                 24     13550       610      3325         4.1
Рекламы                35     16100       570      5400           3
Логистики123456        22     10975       415      3750         2.9
Среднее              24.5   12559.4     486.3    3893.8         3.3
Всего                  98   50237.5      1945     15575        13.1

План 2:
Департамент         Сотр.     Тугр.      Кофе      Стр.  Тугр./стр.

Закупок                17    9612.5       350      3100         3.1
Продаж                 24   15637.5       795      3470         4.5
Рекламы                36     16300       575      5450           3
Логистики123456        24     11375       425      3850           3
Среднее              25.3   13231.3     536.3    3967.5         3.4
Всего                 101     52925      2145     15870        13.6

План 3:
Департамент         Сотр.     Тугр.      Кофе      Стр.  Тугр./стр.

Закупок                17   10487.5       350      3100         3.4
Продаж                 24     14300       610      3325         4.3
Рекламы                36     16800       575      5450         3.1
Логистики123456        24     12625       425      3850         3.3
Среднее              25.3   13553.1       490    3931.3         3.5
Всего                 101   54212.5      1960     15725        14.1