fork(1) download
  1. <?php
  2.  
  3.  
  4.  
  5. /*
  6. * Introduction
  7. */
  8. $asciiArt = <<<EOT
  9.  __ ________ _____ _______ ____ _____
  10.  \ \ / / ____/ ____|__ __/ __ \| __ \
  11.   \ \ / /| |__ | | | | | | | | |__) |
  12.   \ \/ / | __|| | | | | | | | _ /
  13. \ / | |___| |____ | | | |__| | | \ \
  14. \/ |______\_____| |_| \____/|_| \_\
  15. EOT;
  16.  
  17.  
  18. /*
  19. * General exception class necessary for scalar type hinting.
  20. */
  21. class WrongDataException extends Exception
  22. {
  23. private $expectedType;
  24.  
  25. public function __construct($expectedType,
  26. $message = "Wrong data type. Expected ",
  27. $code = 1,
  28. Exception $previous = null)
  29. {
  30. parent::__construct($message, $code, $previous);
  31. $this->expectedType = $expectedType;
  32. }
  33.  
  34. public function __toString()
  35. {
  36. return __CLASS__ . "{$this->code}: {$this->message}" .
  37. "{$this->expectedType}\n" ;
  38. }
  39. }
  40.  
  41.  
  42. /*
  43. * Helper class necessary for an appropriate grid view representation.
  44. */
  45. class PrettyPrinter
  46. {
  47. private $head = [
  48. "col0" => "№",
  49. "col1" => "департамент",
  50. "col2" => "Σрабов",
  51. "col3" => "Σтугриков",
  52. "col4" => "Σкофе",
  53. "col5" => "Σстраниц",
  54. "col6" => "тугриков/страниц"
  55. ];
  56. private $foot = [
  57. "col0" => " ",
  58. "col1" => "Итого",
  59. "col2" => NULL,
  60. "col3" => NULL,
  61. "col4" => NULL,
  62. "col5" => NULL,
  63. "col6" => NULL
  64. ];
  65. private $trail = [];
  66. private $padder;
  67.  
  68. private $prettyData = [];
  69. private $printableResult;
  70.  
  71. public function __construct($inputArr)
  72. {
  73. $this->setPadder();
  74. $this->setHeadTrials();
  75.  
  76. $enum = range(1, count($inputArr));
  77. for($i = 0; $i < count($inputArr); $i++) {
  78. $inputArr[$i] = array_merge(["№" => $enum[$i]], $inputArr[$i]);
  79. $this->fillPrettyData($inputArr[$i]);
  80. }
  81.  
  82. $this->setPrintableHeader();
  83. $this->initFooter($inputArr);
  84. $this->setPrintableFoot();
  85. foreach($this->prettyData as $row) {
  86. $this->setPrintableResult($row);
  87. }
  88. }
  89.  
  90. private function setPrintableHeader()
  91. {
  92. foreach(array_values($this->head) as $header) {
  93. $this->printableResult .= (string)($header);
  94. $this->printableResult .= " ";
  95. }
  96. $this->printableResult .= ("\n" . str_repeat("-", $this->padder) . "\n");
  97. }
  98.  
  99. private function setHeadTrials()
  100. {
  101. foreach($this->head as $col=>$str) {
  102. $this->trail[$col] = mb_strlen($str);
  103. }
  104. }
  105.  
  106. private function setPadder()
  107. {
  108. $func = function($value) {
  109. return mb_strlen((string)$value);
  110. };
  111. $this->padder = array_sum(array_map($func, array_values($this->head))) +
  112. count(array_values($this->head)) - 1;
  113. }
  114.  
  115. private function fillPrettyData($arr)
  116. {
  117. $func = function($value) {
  118. return mb_strlen((string)$value);
  119. };
  120. $dataLens = [];
  121. $temp = array_combine(array_values($this->trail),
  122. array_map($func, array_values($arr)));
  123.  
  124. foreach($temp as $len1=>$len2) {
  125. $len = abs($len1 - $len2);
  126. $data = str_repeat(" ", $len);
  127. array_push($dataLens, $data);
  128. }
  129. $prettyChunk = array_combine(array_values($arr),
  130. $dataLens);
  131.  
  132. array_push($this->prettyData, $prettyChunk);
  133. }
  134.  
  135. private function setPrintableResult($arr)
  136. {
  137. foreach($arr as $data=>$padding) {
  138. $res = (string)$data . (string)$padding;
  139. $this->printableResult .= $res;
  140. $this->printableResult .= " ";
  141. }
  142. $this->printableResult .= ("\n" . str_repeat("-", $this->padder) . "\n");
  143. }
  144.  
  145. public function __toString()
  146. {
  147. return $this->printableResult;
  148. }
  149.  
  150. private function initFooter($arr)
  151. {
  152. $allWorkers = 0;
  153. $allCoffee = 0;
  154. $allSalary = 0;
  155. $allPages = 0;
  156. $allAvg = [];
  157.  
  158. foreach($arr as $subarr) {
  159. $cur_vals = array_values($subarr);
  160. $allWorkers += $cur_vals[2];
  161. $allSalary += $cur_vals[3];
  162. $allCoffee += $cur_vals[4];
  163. $allPages += $cur_vals[5];
  164. array_push($allAvg, $cur_vals[6]);
  165. }
  166.  
  167. $this->foot["col2"] = $allWorkers;
  168. $this->foot["col3"] = $allSalary;
  169. $this->foot["col4"] = $allCoffee;
  170. $this->foot["col5"] = $allPages;
  171. $this->foot["col6"] = array_sum($allAvg) / count($allAvg);
  172. }
  173.  
  174. private function setPrintableFoot()
  175. {
  176. $this->fillPrettyData($this->foot);
  177. }
  178. }
  179.  
  180.  
  181. /*
  182. * Helper class necessary for parsing input data and producing associative array.
  183. * Example:
  184. * INPUT: ["9*ме1", "3*ме2"]
  185. * RESULT: ["менеджер" => ["ранг" => "1" "количество" => "9"]], [(int) => ["ранг" => "2" "количество" => "3"]]
  186. * It is possible to add new PCRE => workers relations throug "addNewTypeRel($rel)" method.
  187. * Example: addNewTypeRel(["дв" => "дворник"])
  188. */
  189. class InitDataParser
  190. {
  191. private $temp = 0;
  192. private $depInit = [];
  193. private $depBoss = [];
  194.  
  195. private static $reAmt = "(\d+)(\×)";
  196. private static $reType = ["ан", "ин", "ма", "ме"];
  197. private static $reRank = "(\d+)";
  198.  
  199. /*
  200. * RESULT:
  201. * "/(\d+)(\×)(ан|ин|ма|ме)(\d+)/ui"
  202. */
  203. private $pattern;
  204. /*
  205. * RESULT:
  206. * "/(\d+)\×)(ан|ин|ма|ме)(\d+)/ui"
  207. */
  208. private $bossPattern;
  209.  
  210. private static $typesDispatcher = [
  211. "ан" => "аналитик",
  212. "ин" => "инженер",
  213. "ма" => "маркетолог",
  214. "ме" => "менеджер"
  215. ];
  216.  
  217. public function __construct($inputArr, $boss)
  218. {
  219. $this->initRePatterns();
  220.  
  221. if(!is_array($inputArr)) {
  222. throw new WrongDataException("array");
  223. }
  224.  
  225. if(!is_string($boss)) {
  226. throw new WrongDataException("string");
  227. }
  228.  
  229. foreach($inputArr as $single) {
  230. if(!is_string($single)) {
  231. throw new WrongDataException("string");
  232. }
  233. $this->parseInit($single);
  234.  
  235. if($boss) {
  236. $this->parseBoss($boss);
  237. }
  238. }
  239. }
  240.  
  241. private function initRePatterns()
  242. {
  243. $this->pattern = "/" . self::$reAmt .
  244. "(" . implode("|", self::$reType) . ")" .
  245. self::$reRank . "/ui";
  246. $this->bossPattern = "/" .
  247. "(" . implode("|", self::$reType) . ")" .
  248. self::$reRank . "/ui";
  249. }
  250.  
  251. private function parseInit($shorty)
  252. {
  253. if(preg_match($this->pattern, $shorty, $matches)) {
  254. //var_dump($matches);
  255. $amt = $matches[1];
  256. $workType = $matches[3];
  257. $rank = $matches[4];
  258. } else {
  259. throw new Exception("Wrong format.");
  260. }
  261.  
  262. if(!in_array(self::$typesDispatcher[$workType], array_keys($this->depInit))) {
  263. $this->depInit[self::$typesDispatcher[$workType]] = [
  264. "ранг" => (int)$rank,
  265. "количество" => (int)$amt
  266. ];
  267. } else {
  268. $part = [
  269. "ранг" => (int)$rank,
  270. "количество" => (int)$amt
  271. ];
  272.  
  273. /*
  274. * We should somehow get over array_key duplications.
  275. * Therefore following code is going to check the type of array_keys.
  276. * This following checking succids only in case if type is "int".
  277.   * Random bottom boundary should guarantee that it would be greater than
  278.   * amt of specializiatons (e.g. managers, analysts).
  279. */
  280. $bottom = rand(100, 10000);
  281. if ($this->temp !== $bottom) {
  282. $this->depInit[$bottom] = $part;
  283. } else {
  284. $this->depInit[$bottom + 1] = $part;
  285. }
  286. $this->temp = $bottom;
  287. }
  288. }
  289.  
  290. private function parseBoss($str)
  291. {
  292. if(preg_match($this->bossPattern, $str, $matches)) {
  293. $workType = $matches[1];
  294. $rank = $matches[2];
  295. } else {
  296. throw new Exception("Wrong format.");
  297. }
  298. $this->depBoss = [
  299. "квалификация" => self::$typesDispatcher[$workType],
  300. "ранг" => (int)$rank
  301. ];
  302. }
  303.  
  304. public function getMatchedDepInit()
  305. {
  306. return $this->depInit;
  307. }
  308.  
  309. public function getMatchedDepBoss()
  310. {
  311. return $this->depBoss;
  312. }
  313.  
  314. public static function addNewTypeRel($rel)
  315. {
  316. self::$typesDispatcher = array_merge(self::$typesDispatcher, $rel);
  317. array_push(self::$reType, array_keys($rel)[0]);
  318. }
  319. }
  320.  
  321. /*
  322. * General class for all the employees, holding data and operations general for all subclasses.
  323. */
  324. abstract class Worker
  325. {
  326. protected $salary;
  327. protected $coffeeAmount;
  328. protected $rank;
  329. protected $bossHonors = [];
  330. protected $workDone;
  331.  
  332. public function getSalary()
  333. {
  334. return $this->salary + $this->salary * ($this->rank / 100);
  335. }
  336.  
  337. public function setSalary($num)
  338. {
  339. if(is_numeric($num)) {
  340. $this->salary = (int)$num;
  341. } else {
  342. throw new WrongDataException("int");
  343. }
  344.  
  345. }
  346.  
  347. public function getCoffee()
  348. {
  349. return $this->coffeeAmount;
  350. }
  351.  
  352. public function setCoffee($amount)
  353. {
  354. if(is_numeric($amount)) {
  355. $this->coffeeAmount = (int)$amount;
  356. } else {
  357. throw new WrongDataException("int");
  358. }
  359. }
  360.  
  361. public function getRank()
  362. {
  363. return $this->rank;
  364. }
  365.  
  366. public function setRank($num)
  367. {
  368. if(is_numeric($num)) {
  369. $this->rank = (int)$num;
  370. } else {
  371. throw new WrongDataException("int");
  372. }
  373.  
  374. }
  375.  
  376. public function getWorkResults()
  377. {
  378. return $this->workDone;
  379. }
  380.  
  381. public function setWorkResults($num)
  382. {
  383. if(is_numeric($num)) {
  384. $this->workDone = (int)$num;
  385. } else {
  386. throw new WrongDataException("int");
  387. }
  388. }
  389.  
  390. public function isBoss()
  391. {
  392. if(!empty($this->bossHonors)) {
  393. return true;
  394. }
  395. return false;
  396. }
  397.  
  398. public function getBossSalary()
  399. {
  400. $baseSalary = $this->salary + $this->salary * ($this->rank / 100);
  401. return $baseSalary + $baseSalary * ($this->bossHonors["зарплата"] / 100);
  402. }
  403.  
  404. public function getBossCoffee()
  405. {
  406. return $this->coffeeAmount * $this->bossHonors["кофе"];
  407. }
  408.  
  409. public function getBossWork()
  410. {
  411. return $this->bossHonors["страницы"];
  412. }
  413.  
  414. public function setBossHonors($honors)
  415. {
  416. $this->bossHonors = $honors;
  417. }
  418. }
  419.  
  420.  
  421. class Manager extends Worker
  422. {
  423.  
  424. }
  425.  
  426.  
  427. class Analyst extends Worker
  428. {
  429.  
  430. }
  431.  
  432.  
  433. class Engineer extends Worker
  434. {
  435.  
  436. }
  437.  
  438.  
  439. class Marketer extends Worker
  440. {
  441.  
  442. }
  443.  
  444.  
  445. class Accountant extends Worker
  446. {
  447.  
  448. }
  449.  
  450.  
  451. /*
  452. * Factory class that uses dispatchers to initialize a "Worker" subclasses' object.
  453. */
  454. class WorkersCreator
  455. {
  456. /*
  457. * Workers' condition's dispatchers.
  458. */
  459. protected static $commonRanks = [1 => 0, 2 => 25, 3 => 50];
  460. protected static $condsDispatcher = [
  461. "аналитик" =>
  462. [
  463. "зарплата" => 800,
  464. "ранги" => NULL,
  465. "кофе" => 50,
  466. "страницы" => 5
  467. ],
  468. "инженер" =>
  469. [
  470. "зарплата" => 200,
  471. "ранги" => NULL,
  472. "кофе" => 5,
  473. "страницы" => 50
  474. ],
  475. "менеджер" =>
  476. [
  477. "зарплата" => 500,
  478. "ранги" => NULL,
  479. "кофе" => 20,
  480. "страницы" => 200
  481. ],
  482. "маркетолог" =>
  483. [
  484. "зарплата" => 400,
  485. "ранги" => NULL,
  486. "кофе" => 15,
  487. "страницы" => 150
  488. ],
  489. ];
  490. protected static $clsDispatcher = [
  491. "аналитик" => "Analyst",
  492. "инженер" => "Engineer",
  493. "маркетолог" => "Marketer",
  494. "менеджер" => "Manager",
  495. ];
  496. /*
  497. * Boss's honor's dispatcher.
  498. */
  499. protected static $genHonors = [
  500. "зарплата" => 50,
  501. "кофе" => 2,
  502. "страницы" => 0
  503. ];
  504. protected static $bossConds = [];
  505.  
  506. /*
  507. * Array, populated with "Worker" subclasses' objects.
  508. */
  509. protected $depWorkers = [];
  510.  
  511. public function __construct($inDepInit, $inBoss)
  512. {
  513. if(!is_array($inDepInit)) {
  514. throw new WrongDataException("array");
  515. }
  516. if(!is_string($inBoss)) {
  517. throw new WrongDataException("string");
  518. }
  519.  
  520. $parsedWorkers = new InitDataParser($inDepInit, $inBoss);
  521. $depInit = $parsedWorkers->getMatchedDepInit();
  522. $boss = $parsedWorkers->getMatchedDepBoss();
  523.  
  524. self::initRanks();
  525.  
  526. if (!empty($boss)) {
  527. $bossConds["привилегии"] = self::$genHonors;
  528. self::$bossConds = array_merge($bossConds, $boss);
  529. $short = $boss["квалификация"];
  530. $this->initBoss($short);
  531. }
  532.  
  533. $this->initDepWorkers($depInit);
  534. }
  535.  
  536. private static function initRanks()
  537. {
  538. foreach(array_keys(self::$condsDispatcher) as $title) {
  539. self::$condsDispatcher[$title]["ранги"] = self::$commonRanks;
  540. }
  541. }
  542.  
  543. private function initDepWorkers($depInit)
  544. {
  545. $cls = self::$clsDispatcher;
  546. $cond = self::$condsDispatcher;
  547.  
  548. for ($i = 0; $i < count(array_keys($depInit)); $i++) {
  549. $shortName = array_keys($depInit)[$i];
  550.  
  551. // Explicit and silent converting of ints to previous string value.
  552. // This tricky way helps excluding key duplicates in an array.
  553. if (!is_string($shortName)) {
  554. $shortName = $temp;
  555. } else {
  556. $temp = $shortName;
  557. }
  558. $tempRank = array_values($depInit)[$i]["ранг"];
  559. $rank = $cond[$shortName]["ранги"][$tempRank];
  560. $limit = array_values($depInit)[$i]["количество"];
  561. if (in_array($shortName, array_keys($cls)) && in_array($shortName, array_keys($cond))) {
  562. $this->initWorkersClass($cls[$shortName], $cond[$shortName], $rank, $limit);
  563. } else {
  564. throw new Exception("String doesn't match to class");
  565. }
  566. }
  567. }
  568.  
  569. protected function initWorkersClass($workerCls, $workersCond, $rank, $limit)
  570. {
  571. for($i = 0; $i < $limit; $i++) {
  572. $worker = new $workerCls;
  573. $worker->setSalary($workersCond["зарплата"]);
  574. $worker->setCoffee($workersCond["кофе"]);
  575. $worker->setRank($rank);
  576. $worker->setWorkResults($workersCond["страницы"]);
  577. array_push($this->depWorkers, $worker);
  578. }
  579. }
  580.  
  581. public function initBoss($short)
  582. {
  583. $cls = self::$clsDispatcher;
  584. $cond = self::$condsDispatcher;
  585. if (in_array($short, array_keys($cls))) {
  586. $bossCls = $cls[$short];
  587. $basicConds = $cond[$short];
  588. } else {
  589. throw new Exception("String doesn't match to class");
  590. }
  591.  
  592. $boss = new $bossCls;
  593. $boss->setSalary($basicConds["зарплата"]);
  594. $tempRank = self::$bossConds["ранг"];
  595. $boss->setRank($cond[$short]["ранги"][$tempRank]);
  596. $boss->setCoffee($cond[$short]["кофе"]);
  597. $boss->setBossHonors(self::$bossConds["привилегии"]);
  598.  
  599. array_push($this->depWorkers, $boss);
  600. }
  601.  
  602. public static function addClassRel($title, $classname)
  603. {
  604. self::$clsDispatcher[$title] = $classname;
  605. }
  606.  
  607. public static function addCondRel($title, $cond)
  608. {
  609. self::$condsDispatcher[$title] = $cond;
  610. }
  611.  
  612. public static function changeSalary($victim, $newVal)
  613. {
  614. self::$condsDispatcher[$victim]["зарплата"] = $newVal;
  615. }
  616.  
  617. public static function changeBossRank($newVal)
  618. {
  619. self::$bossConds["ранг"] = $newVal;
  620. }
  621. }
  622.  
  623.  
  624. /*
  625. * Additional functionality provides ways to generate and fecth statistical data
  626. * (e.g. total department salary).
  627. */
  628. class Department extends WorkersCreator
  629. {
  630. private $totalSalary = [];
  631. private $totalCoffeeAmount = [];
  632. private $totalWorkDone = [];
  633. private $statData = [];
  634.  
  635. private static $depName;
  636.  
  637. function __construct($inDepInit, $inBoss, $depName)
  638. {
  639. if(!is_string($depName)) {
  640. throw new WrongDataException("string");
  641. }
  642. self::$depName = $depName;
  643.  
  644. parent::__construct($inDepInit, $inBoss);
  645.  
  646. $this->fillTotals();
  647. $this->initStatData();
  648. }
  649.  
  650. public function fillTotals()
  651. {
  652. foreach($this->depWorkers as $worker) {
  653. if(!is_object($worker)) {
  654. throw new WrongDataException("object");
  655. break;
  656. }
  657. if($worker->isBoss()) {
  658. array_push($this->totalSalary, $worker->getBossSalary());
  659. array_push($this->totalCoffeeAmount, $worker->getBossCoffee());
  660. array_push($this->totalWorkDone, $worker->getBossWork());
  661. } else {
  662. array_push($this->totalCoffeeAmount, $worker->getCoffee());
  663. array_push($this->totalWorkDone, $worker->getWorkResults());
  664. array_push($this->totalSalary, $worker->getSalary());
  665. }
  666. }
  667. }
  668.  
  669. public function getTotalSalary()
  670. {
  671. return array_sum($this->totalSalary);
  672. }
  673.  
  674. public function getTotalPages()
  675. {
  676. return array_sum($this->totalWorkDone);
  677. }
  678.  
  679. public function getTotalCoffee()
  680. {
  681. return array_sum($this->totalCoffeeAmount);
  682. }
  683.  
  684. public function countDepWorkers()
  685. {
  686. return count($this->depWorkers);
  687. }
  688.  
  689. public function initStatData()
  690. {
  691. $this->statData["Департамент"] = self::$depName;
  692. $this->statData["Всего рабов"] = $this->countDepWorkers();
  693. $this->statData["Общая з/п"] = $this->getTotalSalary();
  694. $this->statData["Всего кофе"] = $this->getTotalCoffee();
  695. $this->statData["Всего страниц"] = $this->getTotalPages();
  696. $this->statData["Тугриков на страницу"] = number_format(($this->getTotalSalary() /
  697. $this->getTotalPages()), 3);
  698. }
  699.  
  700. public function getStatData()
  701. {
  702. return $this->statData;
  703. }
  704.  
  705. public function getWorkers()
  706. {
  707. return $this->depWorkers;
  708. }
  709.  
  710. public static function addNewWorkerType($newWorker)
  711. {
  712. $title = $newWorker[0];
  713. $clsname = $newWorker[1];
  714. $shortTitle = $newWorker[2];
  715. $conds = $newWorker[3];
  716.  
  717. if(!is_string($title) || !is_string($clsname) || !is_string($shortTitle)) {
  718. throw new WrongDataException("string");
  719. }
  720.  
  721. if(!is_array($conds)) {
  722. throw new WrongDataException("array");
  723. }
  724.  
  725. parent::addClassRel($title, $clsname);
  726. parent::addCondRel($title, $conds);
  727. InitDataParser::addNewTypeRel([$shortTitle => $title]);
  728. }
  729.  
  730. public static function changeWorkerCond($newConds)
  731. {
  732. $victim = $newConds[0];
  733. $condKey = $newConds[1];
  734. $newVal = $newConds[2];
  735.  
  736. if(!is_string($victim) || !is_string($condKey)) {
  737. throw new WrongDataException("string");
  738. }
  739.  
  740. if(!is_numeric($newVal)) {
  741. throw new WrongDataException("int");
  742. }
  743.  
  744. switch ($condKey) {
  745. case "зарплата":
  746. parent::changeSalary($victim, $newVal);
  747. break;
  748. default:
  749. throw new Exception("Not implemented yet.");
  750. }
  751. }
  752.  
  753. public function setNewWorkers($arr)
  754. {
  755. $this->depWorkers = $arr;
  756. }
  757.  
  758.  
  759. public function __clone()
  760. {
  761. //$this->depName = $this->depName;
  762. $this->totalSalary = [];
  763. $this->totalCoffeeAmount = [];
  764. $this->totalWorkDone = [];
  765. $this->statData = [];
  766. }
  767.  
  768. public function addWorker($title, $amt, $rank)
  769. {
  770. //var_dump($title);
  771. $cls = parent::$clsDispatcher[$title];
  772. $conds = parent::$condsDispatcher[$title];
  773. $rank = $conds["ранги"][$rank];
  774. //var_dump($rank);
  775. $this->initWorkersClass($cls, $conds, $rank, $amt);
  776. //initWorkersClass($workerCls, $workersCond, $rank, $limit)
  777. }
  778. }
  779.  
  780.  
  781. /*
  782. * Testing of general initialization and basic structure.
  783. */
  784. function testingBasic()
  785. {
  786. $purchaseDepInput = ["9×ме1", "3×ме2", "2×ме3", "2×ма1"];
  787. $purchaseDepBossInput = "ме2";
  788. $purchaseDepName = "покупок";
  789.  
  790. $saleDepInput = ["12×ме1", "6×ма1", "3×ан1", "2×ан2"];
  791. $saleDepBossInput = "ма2";
  792. $saleDepName = "продаж";
  793.  
  794. $adsDepInput = ["15×ма1", "10×ма2", "8×ме1", "2×ин1"];
  795. $adsDepBossInput = "ма3";
  796. $adsDepName = "рекламы";
  797.  
  798. $logisticsDepInput = ["13×ме1", "5×ме2", "5×ин1"];
  799. $logisticsDepBossInput = "ме1";
  800. $logisticsDepName = "логистики";
  801.  
  802. $purchaseDep = new Department($purchaseDepInput, $purchaseDepBossInput, $purchaseDepName);
  803. $saleDep = new Department($saleDepInput, $saleDepBossInput, $saleDepName);
  804. $adsDep = new Department($adsDepInput, $adsDepBossInput, $adsDepName);
  805. $logisticsDep = new Department($logisticsDepInput, $logisticsDepBossInput, $logisticsDepName);
  806.  
  807.  
  808. $purchaseDepData = $purchaseDep->getStatData();
  809. $saleDepData = $saleDep->getStatData();
  810. $adsDepData = $adsDep->getStatData();
  811. $logisticsDepData = $logisticsDep ->getStatData();
  812.  
  813. $allDeps = [$purchaseDepData, $saleDepData, $adsDepData, $logisticsDepData];
  814.  
  815. $data = new PrettyPrinter($allDeps);
  816. echo $data;
  817. }
  818.  
  819.  
  820. /*
  821. * Testing of addition of new employee and
  822. * testing of changes made to analyst's inital conditions.
  823. */
  824. function testingAddedChanges()
  825. {
  826. /*
  827. * New Worker type - Accountant. And his/her conditions.
  828. */
  829. $accConds = [
  830. "зарплата" => 300,
  831. "ранги" => NULL,
  832. "кофе" => 10,
  833. "страницы" => 25
  834. ];
  835.  
  836. $newWorker = ["бухгалтер", "Accountant", "бу", $accConds];
  837.  
  838. /*
  839. * Let's reduce analysts salary to 100 T.
  840. */
  841. $crisis = ["аналитик", "зарплата", 700];
  842.  
  843.  
  844. $saleDepInputBef = ["12×ме1", "6×ма1", "3×ан1", "2×ан2"];
  845. $saleDepBossInputBef = "ма2";
  846. $saleDepNameBef = "продаж";
  847. $saleDepBef = new Department($saleDepInputBef, $saleDepBossInputBef, $saleDepNameBef);
  848. $before = $saleDepBef->getTotalSalary();
  849.  
  850. echo "\n";
  851. echo "Тестирование добавления нового рабочего. Бухгалтер: з.п => 300, кол-во => 3\n";
  852. echo "На дворе кризис. Срежем з/п аналитиков до 700 у.е.\n";
  853. echo "\n";
  854.  
  855. Department::addNewWorkerType($newWorker);
  856. Department::changeWorkerCond($crisis);
  857.  
  858. $testDepInput = ["12×ме1", "6×ма1", "3×ан1", "2×ан2", "3×бу1"];
  859. $testDepBoss = "ма2";
  860. $testDepName = "тестовый";
  861.  
  862. $saleDepInput = ["12×ме1", "6×ма1", "3×ан1", "2×ан2"];
  863. $saleDepBossInput = "ма2";
  864. $saleDepName = "продаж";
  865.  
  866. $testDep = new Department($testDepInput, $testDepBoss, $testDepName);
  867. $saleDep = new Department($saleDepInput, $saleDepBossInput, $saleDepName);
  868.  
  869. $testDepData = $testDep->getStatData();
  870. $saleDepData = $saleDep->getStatData();
  871.  
  872. $data = new PrettyPrinter([$testDepData, $saleDepData]);
  873.  
  874. $newWorkerTest = $testDep->getTotalSalary() - $saleDep->getTotalSalary();
  875. $crisisTest = $saleDepBef->getTotalSalary() - $saleDep->getTotalSalary();
  876.  
  877. echo $data . "\n";
  878. echo "Результаты разниц до и после.\n";
  879. echo "Верно: 1. 300*3 = 900";
  880. echo " 2. 100*3 + 100*2 + 100*(25/100)*2 = 550\n";
  881. echo "1. Σтугриков (тестовый) - " . "Σтугриков (продаж) " . "= " . "{$newWorkerTest}\n";
  882. echo "2. Σтугриков (до кризиса) - " . "Σтугриков (после) " . "= " . "{$crisisTest}\n";
  883. }
  884.  
  885.  
  886. class CrisisModel
  887. {
  888. private $allDeps;
  889. private $newModelWorkers = [];
  890. private $purchaseDep;
  891. private $saleDep;
  892. private $adsDep;
  893. private $logisticsDep;
  894. private $newDeps = [];
  895. private $newStatData = [];
  896.  
  897. public function __construct($model)
  898. {
  899. $this->initBase();
  900.  
  901. if($model === 1) {
  902. foreach($this->allDeps as $depWorkers) {
  903. $this->tryModel1($depWorkers);
  904. }
  905. } elseif($model === 2) {
  906. foreach($this->allDeps as $depWorkers) {
  907. $this->tryModel2($depWorkers);
  908. }
  909. } elseif($model === 3) {
  910. //var_dump(count($this->allDeps));
  911. foreach($this->allDeps as $depWorkers) {
  912. $this->tryModel3($depWorkers);
  913. }
  914. }
  915. $this->setNewWorkers($this->newModelWorkers);
  916. $this->setNewStatData();
  917. $this->showModel();
  918. }
  919.  
  920. private function initBase()
  921. {
  922. $purchaseDepInput = ["9×ме1", "3×ме2", "2×ме3", "2×ма1"];
  923. $purchaseDepBossInput = "ме2";
  924. $purchaseDepName = "покупок";
  925.  
  926. $saleDepInput = ["12×ме1", "6×ма1", "3×ан1", "2×ан2"];
  927. $saleDepBossInput = "ма2";
  928. $saleDepName = "продаж";
  929.  
  930. $adsDepInput = ["15×ма1", "10×ма2", "8×ме1", "2×ин1"];
  931. $adsDepBossInput = "ма3";
  932. $adsDepName = "рекламы";
  933.  
  934. $logisticsDepInput = ["13×ме1", "5×ме2", "5×ин1"];
  935. $logisticsDepBossInput = "ме1";
  936. $logisticsDepName = "логистики";
  937.  
  938. $this->purchaseDep = new Department($purchaseDepInput, $purchaseDepBossInput, $purchaseDepName);
  939. $this->saleDep = new Department($saleDepInput, $saleDepBossInput, $saleDepName);
  940. $this->adsDep = new Department($adsDepInput, $adsDepBossInput, $adsDepName);
  941. $this->logisticsDep = new Department($logisticsDepInput, $logisticsDepBossInput, $logisticsDepName);
  942.  
  943. $this->allDeps = [$this->purchaseDep, $this->saleDep, $this->adsDep, $this->logisticsDep];
  944. }
  945.  
  946. public function tryModel1($dep)
  947. {
  948. $depWorkers = $dep->getWorkers();
  949. $lim = count($depWorkers);
  950. $limit = 0;
  951. foreach($depWorkers as $worker) {
  952. if(get_class($worker) === "Engineer") {
  953. $limit++;
  954. }
  955. }
  956. foreach($depWorkers as $worker) {
  957. if(get_class($worker) === "Engineer" && $worker->isBoss() === false) {
  958. unset($depWorkers[array_search($worker, $depWorkers)]);
  959. }
  960. }
  961. array_push($this->newModelWorkers, $depWorkers);
  962. }
  963.  
  964. public function tryModel2($dep)
  965. {
  966. $depWorkers = $dep->getWorkers();
  967. foreach($depWorkers as $worker) {
  968. if(get_class($worker) === "Analyst") {
  969. $worker->setSalary(1100);
  970. $worker->setCoffee(75);
  971. }
  972. }
  973. array_push($this->newModelWorkers, $depWorkers);
  974. }
  975.  
  976. public function tryModel3($dep)
  977. {
  978. $depWorkers = $dep->getWorkers();
  979. $rankOne = [];
  980. $rankTwo = [];
  981. foreach($depWorkers as $worker) {
  982. if(get_class($worker) === "Manager" && $worker->isBoss() === false) {
  983. if($worker->getRank() === 0) {
  984. array_push($rankOne, $worker);
  985. } elseif($worker->getRank() === 25) {
  986. array_push($rankTwo, $worker);
  987. }
  988. }
  989. }
  990. $lim1 = round(count($rankOne)/2);
  991. $dep->addWorker("менеджер", $lim1, 2);
  992. $lim2 = round(count($rankTwo)/2);
  993. $dep->addWorker("менеджер", $lim2, 3);
  994. //var_dump($lim1);
  995. //var_dump($lim2);
  996. //var_dump(count($depWorkers));
  997. //var_dump(count($dep->getWorkers()));
  998. array_push($this->newModelWorkers, $dep->getWorkers());
  999. }
  1000.  
  1001. public function setNewWorkers($newArr)
  1002. {
  1003. $newPD = clone $this->purchaseDep;
  1004. $newPD->setNewWorkers($newArr[0]);
  1005. $newPD->fillTotals();
  1006. $newSD = clone $this->saleDep;
  1007. $newSD->setNewWorkers($newArr[1]);
  1008. $newSD->fillTotals();
  1009. $newAD = clone $this->adsDep;
  1010. $newAD->setNewWorkers($newArr[2]);
  1011. $newAD->fillTotals();
  1012. $newLD = clone $this->logisticsDep;
  1013. $newLD->setNewWorkers($newArr[3]);
  1014. $newLD->fillTotals();
  1015. $this->newDeps = [$newPD, $newSD, $newAD, $newLD];
  1016. }
  1017.  
  1018. public function setNewStatData()
  1019. {
  1020. foreach($this->newDeps as $dep) {
  1021. $dep->initStatData();
  1022. array_push($this->newStatData, $dep->getStatData());
  1023. }
  1024. }
  1025.  
  1026. public function showModel()
  1027. {
  1028. $data = new PrettyPrinter($this->newStatData);
  1029. echo $data;
  1030. }
  1031. }
  1032.  
  1033.  
  1034. echo "{$asciiArt}";
  1035. echo "\n\n";
  1036. testingBasic();
  1037. testingAddedChanges();
  1038. echo "\n\n";
  1039. echo "Подборка моделей антикризисных ситуаций\n";
  1040. echo "Начальные данные вывведены в 1 таблице\n";
  1041. echo "\n\n";
  1042. $crisisModel1 = new CrisisModel(1);
  1043. $crisisModel2 = new CrisisModel(2);
  1044. $crisisModel3 = new CrisisModel(3);
  1045.  
Success #stdin #stdout 0.03s 24448KB
stdin
Standard input is empty
stdout
 __      ________ _____ _______ ____  _____  
 \ \    / /  ____/ ____|__   __/ __ \|  __ \ 
  \ \  / /| |__ | |       | | | |  | | |__) |
   \ \/ / |  __|| |       | | | |  | |  _  / 
	\  /  | |___| |____   | | | |__| | | \ \ 
	 \/   |______\_____|  |_|  \____/|_|  \_\

№ департамент Σрабов Σтугриков Σкофе Σстраниц тугриков/страниц 
--------------------------------------------------------------
1 покупок     17     9612.5    350   3100     3.101            
--------------------------------------------------------------
2 продаж      24     13550     610   3325     4.075            
--------------------------------------------------------------
3 рекламы     36     16300     575   5450     2.991            
--------------------------------------------------------------
4 логистики   24     11375     425   3850     2.955            
--------------------------------------------------------------
  Итого       101    50837.5   1960  15725    3.2805           
--------------------------------------------------------------

Тестирование добавления нового рабочего. Бухгалтер: з.п => 300, кол-во => 3
На дворе кризис. Срежем з/п аналитиков до 700 у.е.

№ департамент Σрабов Σтугриков Σкофе Σстраниц тугриков/страниц 
--------------------------------------------------------------
1 тестовый    27     13900     640   3400     4.088            
--------------------------------------------------------------
2 продаж      24     13000     610   3325     3.910            
--------------------------------------------------------------
  Итого       51     26900     1250  6725     3.999            
--------------------------------------------------------------

Результаты разниц до и после.
Верно: 1. 300*3 = 900       2. 100*3 + 100*2 + 100*(25/100)*2 = 550
1. Σтугриков (тестовый) - Σтугриков (продаж) = 900
2. Σтугриков (до кризиса) - Σтугриков (после) = 550


Подборка моделей антикризисных ситуаций
Начальные данные вывведены в 1 таблице


№ департамент Σрабов Σтугриков Σкофе Σстраниц тугриков/страниц 
--------------------------------------------------------------
1 логистики   17     9612.5    350   3100     3.101            
--------------------------------------------------------------
2 логистики   24     13000     610   3325     3.910            
--------------------------------------------------------------
3 логистики   34     15900     565   5350     2.972            
--------------------------------------------------------------
4 логистики   19     10375     400   3600     2.882            
--------------------------------------------------------------
  Итого       94     48887.5   1925  15375    3.21625          
--------------------------------------------------------------
№ департамент Σрабов Σтугриков Σкофе Σстраниц тугриков/страниц 
--------------------------------------------------------------
1 логистики   17     9612.5    350   3100     3.101            
--------------------------------------------------------------
2 логистики   24     15200     735   3325     4.571            
--------------------------------------------------------------
3 логистики   36     16300     575   5450     2.991            
--------------------------------------------------------------
4 логистики   24     11375     425   3850     2.955            
--------------------------------------------------------------
  Итого       101    52487.5   2085  15725    3.4045           
--------------------------------------------------------------
№ департамент Σрабов Σтугриков Σкофе Σстраниц тугриков/страниц 
--------------------------------------------------------------
1 логистики   24     14237.5   490   4500     3.164            
--------------------------------------------------------------
2 логистики   30     16750     730   4525     3.702            
--------------------------------------------------------------
3 логистики   40     18800     655   6250     3.008            
--------------------------------------------------------------
4 логистики   34     18000     625   5850     3.077            
--------------------------------------------------------------
  Итого       128    67787.5   2500  21125    3.23775          
--------------------------------------------------------------