<?php
header("Content-Type: text/plain");
// ООП. Вектор и антикризичные меры
// Класс сотрудника
class Employee
{
private $rank = 1; // ранг
private $chief = 0; // статус руководителя
private $profession; // профессия
private $salaryRate = 0;// индивидуальная ставка работника
private $coffeeRate = 0;// индивидуальное потребление кофе
// Коофициенты зарплаты для ранга
private $rankSalary = array(1 => 1, 2 => 1.25,
3 => 1.5);
// Коофициенты зарплаты для начальников
private $chiefSalary = array(0 => 1, 1 => 1.5);
// Коофициенты потребления кофе для начальников
private $chiefCoffee = array(0 => 1, 1 => 2);
// Коофициенты продуктивности для начальников
private $chiefProduct = array(0 => 1, 1 => 0);
public function __construct(Profession $profession, $rank, $chief)
{
// Присвоение профессии сотруднику
$this->profession = $profession;
// Присвоение ранга сотруднику
$this->rank = $rank;
// Присвоение статуса начальник
$this->chief = $chief;
}
// Присвоение профессии сотруднику
public function addProfession(Profession $profession)
{
$this->profession = $profession;
// Сбрасываем ставку при смене профессии
$this->salaryRate = 0;
// Сбрасываем потребление кофе
$this->coffeeRate = 0;
}
// Возвращает ранг сотрудника
public function getRank()
{
return $this->rank;
}
// Присвоение ранга
public function setRank($rank)
{
$this->rank = $rank;
}
// Изменение статуса начальника
public function setСhief($chief)
{
$this->chief = $chief;
}
// Изменение ставки
public function setSalaryRate($salary)
{
$this->salaryRate = $salary;
}
// Изменение кол-во выпиваемого кофе
public function setCoffeeRate($coffee)
{
$this->coffeeRate = $coffee;
}
// Возвращаем название профессии сотрудника
public function getProfession()
{
return $this->profession;
}
// Возвращаем статус шафа сотрудника
public function getChief()
{
return $this->chief;
}
// Расчет зарплаты
public function getSalary()
{
// Профессия
$profession = $this->profession;
// Ставка, берем из данного класса если поле переопределено, иначе берем из профессии
if ($this->salaryRate != 0) {
$salaryRate = $this->salaryRate;
} else {
$salaryRate = $profession->getSalaryRate();
}
// Узнаем коэффициент согласно рангу сотрудника
$salaryMultiplier = $this->rankSalary[$this->rank];
// Узнаем коэффициент для начальника
$chiefSalaryMultiplier = $this->chiefSalary[$this->chief];
// Расчет зарплаты
$salary = $salaryRate * $salaryMultiplier * $chiefSalaryMultiplier;
return $salary;
}
// Расчет потребления кофе
public function getCoffee()
{
// Профессия
$profession = $this->profession;
// Потребление кофе
// Берем из данного класса если поле переопределено, иначе берем из профессии
if ($this->coffeeRate != 0) {
$coffeeRate = $this->coffeeRate;
} else {
$coffeeRate = $profession->getCoffeeRate();
}
// Вычисляем коэффициент для начальника
$tmpchiefCoffee = $this->chiefCoffee[$this->chief];
// Расчет потребления кофе
$coffee = $coffeeRate * $tmpchiefCoffee;
return $coffee;
}
// Расчет продуктивности
public function getProduct()
{
// Профессия
$profession = $this->profession;
// Продуктивность по профессии
$productRate = $profession->getProduct();
// Вычисляем коэффициент для начальника
$tmpchiefProduct = $this->chiefProduct[$this->chief];
// Расчет продуктивности
$product = $productRate * $tmpchiefProduct;
return $product;
}
}
// Абстрактный класс профессии
abstract class Profession
{
// Возвращает имя
public function getName()
{
}
abstract public function getSalaryRate();
abstract public function getCoffeeRate();
abstract public function getProduct();
}
// Класс менджер
class Manager extends Profession
{
public function getSalaryRate()
{
return 500;
}
public function getCoffeeRate()
{
return 20;
}
public function getProduct()
{
return 200;
}
}
// Класс маркетолог
class Marketer extends Profession
{
public function getSalaryRate()
{
return 400;
}
public function getCoffeeRate()
{
return 15;
}
public function getProduct()
{
return 150;
}
}
// Класс инженер
class Engineer extends Profession
{
public function getSalaryRate()
{
return 200;
}
public function getCoffeeRate()
{
return 5;
}
public function getProduct()
{
return 50;
}
}
// Класс аналитик
class Analyst extends Profession
{
public function getSalaryRate()
{
return 800;
}
public function getCoffeeRate()
{
return 50;
}
public function getProduct()
{
return 5;
}
}
// Класс департамента
class Departament
{
public $name = ""; // название
private $employees = array(); // сотрудники
public function __construct($name)
{
$this->name = $name;
}
// Клонирование департамента
public function __clone()
{
$employeesClones = array(); // клоны работников
foreach ($this->employees as $employee) {
$employee = clone $employee;
$departamentsClones[] = $employee;
}
// Заменяем массив работников массивом клонов
$this->employees = $departamentsClones;
}
// Прием сотрудника на работу
public function addEmployee(Employee $employee)
{
$this->employees[] = $employee;
}
// Расчет количества сотрудников по профессии, не указанный параметр возвращает общее кол-во
public function countEmployees($profession = null)
{
$employeesNumber = 0; // число сотрудников
// Если профессия не задана
if (!$profession) {
return count($this->employees); }
// Если считаем сотрудников определенной профессии
foreach ($this->employees as $employee) {
// Если сотрудник не соответствует профессии
if ($employee->getProfession()->getName() != $profession) {
continue;
}
// Счетчик
$employeesNumber++;
}
return $employeesNumber;
}
// Возвращаем сотрудников массивом
public function getEmployees()
{
return $this->employees;
}
// Возвращает сотрудников заданной профессии массивом
public function findEmployees($profession)
{
$employees = array(); // массив Сотрудников
// Перебираем всех сотрудников
foreach ($this->employees as $employee) {
// Если название класса профессии сотрудника соответствует профессии
if (get_class ($employee->getProfession()) == $profession) { $employees[] = $employee;
}
}
// Возвращаем Сотрудников
return $employees;
}
// Возвращает шефа департамента
public function getChief()
{
// Фильтруем работников по признаку шефства
$chief = array_filter ($this->employees, function ($e) { return ($e->getChief()==1) ;}); // Сбрасываем индексы массива
return $chief[0];
}
// Увольнение сотрудника
public function dismissEmployee($employee)
{
$employeeKey = array_search($employee, $this->employees, TRUE); unset ($this->employees[$employeeKey]); }
// Замена шефа департамента
public function replaceChief(Employee $employee)
{
// Ищем переданного работника в данном департаменте
$employeeKey = array_search($employee, $this->employees, TRUE); // Если в департаменте не существует переданного работника
if ($employeeKey == null) {
// Выкидываем исключение
throw new Exception ("Переданный работник не найден");
}
// Возвращаем текущего шефа к обычной работе
$chief = $this->getChief(); // метод поиска шефа
$chief->setСhief(0);
// Назначаем работника шефом
$this->employees[$employeeKey]->setСhief(1);
}
// Расходы на зарплату
public function getTotalCoffee()
{
$totalCoffee = 0; // сумарное потребление кофе
// Для каждого сотрудника
foreach ($this->employees as $employee) {
// Запрашиваем потребление кофе у сотрудника и суммируем результат
$totalCoffee += $employee->getCoffee();
}
return $totalCoffee;
}
// Рассход кофе
public function getAverageCostPerProduct()
{
// Средняя стоимость 1 страницы = суммарная зарплата / сумарное количество страниц
$avrCostPerProduct = $this->getTotalSalary() / $this->getTotalProduct();
return $avrCostPerProduct;
}
// Суммарная производительность
public function getTotalSalary()
{
$totalSalary = 0; // сумарная зарплата
// Для каждого сотрудника
foreach ($this->employees as $employee) {
// Запрашиваем зп у сотрудника и суммируем результат
$totalSalary += $employee->getSalary();
}
return $totalSalary;
}
// Средний расход тугриков на одну страницу
public function getTotalProduct()
{
$totalProduct = 0; // сумарная продуктивность
// Для каждого сотрудника
foreach ($this->employees as $employee) {
// Запрашиваем продуктивность у сотрудника и суммируем результат
$totalProduct += $employee->getProduct();
}
return $totalProduct;
}
}
// Класс компании
class Company
{
public $name = ""; // название
private $departaments = array(); // департаменты
public function __construct($name)
{
$this->name = $name;
}
// Клонирование компании
public function __clone()
{
$departamentsClones = array(); // клоны департаментов
foreach ($this->departaments as $departament) {
$departament = clone $departament;
$departamentsClones[] = $departament;
}
// Заменяем массив департаментов массивом клонов
$this->departaments = $departamentsClones;
}
// Создание департамента
public function createDepartament($name)
{
$this->departaments[$name] = new Departament ($name);
}
// Возвращает все департаменты массивом
public function getAllDepartments ()
{
return $this->departaments;
}
// Поиск департамента по названию,
// если название не определено, возращает все департааменты
public function findDepartamentByName($name = null)
{
$result = null; // ссылка на департамент или массив департаментов
// Ищем департамент в массиве по названию
if ($name) {
$result = $this->departaments[$name];
} else {
// Возвращаем все департаменты массивом
foreach ($this->departaments as $name => $departament) {
$result[$name] = $departament;
}
}
// Если ничего не нашли
if ($result == null) {
// Ничего не возвращам, выкидываем исключение
throw new Exception ( "Департамент не найден" ) ;
}
return $result;
}
// Сумарное количество работников
public function getAverageEmployees()
{
// Среднее количество работников = суммарное кол-во работников / кол-во департаментов
$avrEmployees = $this->getTotalEmployees() / count($this->departaments);
return $avrEmployees;
}
// Расходы на зарплату в сумме
public function getTotalEmployees()
{
$totalEmployees = 0;
// Для каждого департамента
foreach ($this->departaments as $departament) {
// Сумируем работников всех департаментов
$totalEmployees += $departament->countEmployees();
}
return $totalEmployees;
}
// Рассход кофе в сумме
public function getAverageSalary()
{
// Средняя зарплата = суммарная зарплата / кол-во департаментов
$avrSalary = $this->getTotalSalary() / count($this->departaments);
return $avrSalary;
}
// Суммарная производительность
public function getTotalSalary()
{
$salary = 0;
// Для каждого департамента
foreach ($this->departaments as $departament) {
// Сумируем зп всех департаментов
$salary += $departament->getTotalSalary();
}
return $salary;
}
// Среднее количество работников по департаментам
public function getAverageCoffee()
{
// Среднее потребление кофе = суммарная потребление кофе / кол-во департаментов
$avrCoffee = $this->getTotalCoffee() / count($this->departaments);
return $avrCoffee;
}
// Средняя зарплата по департаментам
public function getTotalCoffee()
{
$coffee = 0;
// Для каждого департамента
foreach ($this->departaments as $departament) {
// Суммируем расход кофе у департаментов
$coffee += $departament->getTotalCoffee();
}
return $coffee;
}
// Среднее потребление кофе по департаментам
public function getAverageProduct()
{
// Средняя производительность = суммарная производительность / кол-во департаментов
$avrProduct = $this->getTotalProduct() / count($this->departaments);
return $avrProduct;
}
// Средняя производительность по департаментам
public function getTotalProduct()
{
$product = 0;
// Для каждого департамента
foreach ($this->departaments as $departament) {
// Суммируем производительность каждого департамента
$product += $departament->getTotalProduct();;
}
return $product;
}
// Средний расход тугриков на одну страницу по департаментам
public function getAverageCostPerProduct()
{
$avrCostPerProduct = 0;
// Для каждого департамента
foreach ($this->departaments as $departament) {
// Сумируем средний расход
$avrCostPerProduct += $departament->getAverageCostPerProduct();
}
// Средняя стоимость 1 страницы = cредняя стоимость всех департ / кол-во департаментов
$avrCostPerProduct = $avrCostPerProduct / count($this->departaments);
return $avrCostPerProduct;
}
}
// Антикризисный коммитет
class AnticrisisCommittee
{
/*
* Сократить в каждом департаменте 40% (округляя в большую сторону) инженеров,
* преимущественно самого низкого ранга. Если инженер является боссом,
* вместо него надо уволить другого инженера, не босса.
* */
public function dismissEngineers($company)
{
// Запрашивавем все департаменты в компании
$departaments = $company->getAllDepartments();
// Перебираем все департаменты в компании
foreach ($departaments as $departamentName => $departament) {
// Берем всех работников определенной профессии
$engineers = $departament->findEmployees(get_class (new Engineer
)); // Если таковых нет, переходим к следующему департаменту
if (!$engineers) continue;
// Исключаем из списка босса
$engineers = array_filter($engineers, function ($engineer) { return ($engineer->getChief() == 0);
});
/*
foreach ($engineers as $key => $engineer) {
if ($engineer->getChief() == 1) {
unset($engineers[$key]);
}
}*/
//sort($engineers);
// Сортируем массив работников по рангу по возрастанию
usort ($engineers, function ($engineer1, $engineer2) { $rank1 = $engineer1->getRank();
$rank2 = $engineer2->getRank();
if ($rank1 == $rank2) return 0;
return ($rank1 > $rank2) ? -1 : 1;
});
// Берем первые 40% через array_slice
$dismissingEngineers = floor(count($engineers) * 0.6); $engineers = array_slice($engineers, $dismissingEngineers);
// Увольняем сотрудников
foreach ($engineers as $engineer) {
$departament->dismissEmployee($engineer);
}
}
}
/*
* Увеличить в целях стимуляции умственной деятельности базовую ставку аналитика с 800 до 1100 тугриков,
* а количество выпиваемого им кофе с 50 до 75 литров.
* */
public function increaseSalaryRate($company)
{
// Запрашивавем все департаменты в компании
$departaments = $company->getAllDepartments();
// Перебираем все департаменты в компании
foreach ($departaments as $departamentName => $departament) {
// Запрашиваем работников
$analysts = $departament->findEmployees(get_class (new Analyst
)); //var_dump($analysts);
// Если таковых нет, переходим к следующему департаменту
if (!$analysts) continue;
// Перебираем $analysts
foreach ($analysts as $analyst) {
// Повышаем ставку
$analyst->setSalaryRate(1100);
// Повышаем количество выпиваемого им кофе
$analyst->setCoffeeRate(75);
}
}
}
/*
* В тех департаментах, где руководитель не является аналитиком,
* заменить его на аналитика самого высшего ранга из этого департамента
* (а бывшего руководителя вернуть к обычной работе)
* */
public function setAnalystAsChief($company)
{
// Запрашивавем все департаменты в компании
$departaments = $company->getAllDepartments();
// Перебираем все департаменты в компании
foreach ($departaments as $departamentName => $departament) {
// Находим шефа в компании
$chiefEmployee = $departament->getChief(); //findEmployee("all", "all", 1);
// Узнаем профессию
$professionName = $chiefEmployee->getProfession()->getName();
// Если профессия не Аналитик, начинаем переназначение
if ($professionName != "Analyst") {
// Берем всех аналитиков
$analysts = $departament->findEmployees(get_class (new Analyst
));
// Если в Департаменте нет аналитиков, переходим к след. департаменту
if (!isset($analysts[0])) continue;
// Сортируем по рангу, по убыванию
usort ($analysts, function($a, $b) {
$a = $a->getRank();
$b = $b->getRank();
if ($a==$b) return 0;
return ($a > $b) ? 1 : -1;
});
//var_dump($analysts);
// Заменяем шефа аналитиком
$departament->replaceChief($analysts[0]);
}
}
}
/*
* В каждом департаменте повысить 50% (округляя в большую сторону)
* менеджеров 1-го и 2-го ранга на один ранг с целью расширить их полномочия.
* */
public function liftManager($company)
{
// Запрашивавем все департаменты в компании
$departaments = $company->getAllDepartments();
// Перебираем все департаменты в компании
foreach ($departaments as $departamentName => $departament) {
// Берем всех работников определенной профессии
$employees = $departament->findEmployees(get_class (new Manager
)); // Если таковых нет, переходим к следующему департаменту
if (!$employees) continue;
// Исключаем из списка менеджеров вышые 2ого ранга
foreach ($employees as $key => $employee) {
if ($employee->getRank() > 2) {
}
}
// Берем 50% через array_slice
$enhancingEmployees = ceil(count($employees) * 0.5); $employees = array_slice($employees, $enhancingEmployees);
// Повышаем сотрудников
foreach ($employees as $employee) {
$currentRank = $employee->getRank();
$employee->setRank($currentRank + 1);
}
}
}
}
// Функция создания компании
function createCompany($name)
{
// Создаем новый класс компании
$vector = new Company('$name');
// Создаем классы департаментов
$vector->createDepartament('Департамент закупок');
$vector->createDepartament('Департамент продаж');
$vector->createDepartament('Департамент рекламы');
$vector->createDepartament('Департамент логистики');
// Создаем классы профессий
$me = new Manager();
$ma = new Marketer();
$en = new Engineer();
$an = new Analyst();
// Добавляем профессии в масив для последующего создания сотрудников пачкой
$professions['me'] = $me;
$professions['ma'] = $ma;
$professions['en'] = $en;
$professions['an'] = $an;
// Лист вакансий: департамент => группы вакансий: кол-во|профессия|ранг|статус_начальника
'Департамент закупок' => array('9me1', '3me2', '2me3', '2ma1', '1me2boss'), 'Департамент продаж' => array('12me1', '6ma1', '3an1', '2an2', '1ma2boss'), 'Департамент рекламы' => array('15ma1', '10ma2', '8me1', '2en1', '1ma3boss'), 'Департамент логистики' => array('13me1', '5me2', '5en1', '1me1boss') );
// Для каждого департамента
foreach ($vacancies as $depName => $vacancyGroup) {
// Для каждой группы вакансий
foreach ($vacancyGroup as $vacancy) { //($vacancyGroup as $vacancyName => $vacancyQuantity)
// Достаем кол-во, профессию, ранг и статус боса из вакансии
preg_match ('/(\d+)?(\D+)?(\d)?(\w+)?/', $vacancy, $matches); $vacancyQuantity = (int)$matches[1];
$professionIndex = $matches[2];
$rank = (int)$matches[3];
if (isset($matches[4]) and
$matches[4]=='boss') { $chief = 1;
} else {
$chief = 0;
}
// Назначаем профессию
$profession = $professions[$professionIndex];
// Создаем столько сотрудников, сколько вакансий в группе
for ($id = 1; $id <= $vacancyQuantity; $id++) {
// Создаем сотрудника
$employee = new Employee($profession, $rank, $chief);
// Запрашиваем в Компании нужный департамент
$departament = $vector->findDepartamentByName($depName);
// Добавляем сотрудника в этот Департамент
$departament->addEmployee($employee);
}
}
}
// Возвращаем объект Компания
return $vector;
}
// Класс строки таблицы, хранит не фарматированную строку
class TableRow
{
private $columns = array(); // строка это массив из колонок
// Конструктор принимает массив колонок
public function __construct($columns)
{
$this->columns = $columns;
}
// Метод возвращает содержимое строки (все ее колоночки)
public function getColumns()
{
return $this->columns;
}
}
// Класс таблицы
class Table
{
private $tableRows = array(); // массив объектов Строк private $length = 15; // ширина колонок
// Добавление строки в таблицу, принимает массив
public function addRow($row)
{
// Создаем новую строку
$this->tableRows[] = new TableRow($row);
}
// Печать таблицы
public function printTable()
{
$caption = 1; // первая строка - заголовок таблицы
// Перебираем массив объектов Строк
foreach ($this->tableRows as $row) {
$stringRow = ""; // строка для печати
$columnNumber = 0; // счетчик колонок
// Извлекаем колонки из строки
$columns = $row->getColumns();
// Форматируем каждую колонку в строке
foreach ($columns as $column) {
// Округляем числа до 2х знаков после запятой
$column = round($column, 2); }
// Добавляем отступы справа для первой колонки
if ($columnNumber == 0) {
$stringRow .= "\n" . $this->padRight($column, $this->length);
// Добавляем оступы слева для остальных колонок
} else {
$stringRow .= $this->padLeft($column, $this->length);
}
$columnNumber++;
}
// Добавляем черту после заголовка
if ($caption == 1) {
$stringRow .= "\n" . $this->formatCaption($columnNumber, $this->length);
}
// Выводим строку на печать
echo "{$stringRow}";
$caption--; // останется только один заголовок
}
}
// Добавление пробелов слева
private function padRight($string, $length)
{
// Разница между переданной строкой и шириной колонки
$lenghtDifference = $length - mb_strlen($string); // Проверка на отрицательное значение при вычитании
if ($lenghtDifference >= 0) {
// Заполняем разницу пробелами
} else {
// Если таки отрицательное, обрезаем край строки до ширины колонки
}
return $string;
}
// Добавление пробелов справа
private function padLeft($string, $length)
{
// Разница между переданной строкой и шириной колонки
$lenghtDifference = $length - mb_strlen($string); // Проверка на отрицательное значение при вычитании
if ($lenghtDifference >= 0) {
// Заполняем разницу пробелами
$string = str_repeat(" ", $lenghtDifference) . $string; } else {
// Если таки отрицательное, обрезаем край строки до ширины колонки
}
return $string;
}
// Делаем горизонтальную черту
private function formatCaption($columnNumber, $length)
{
$string = str_repeat("-", $length * $columnNumber); return $string;
}
}
/* Вывод таблицы результатов */
// Функция вывода статистики по компании
function printStatistics($company, $caption)
{
// Создаем таблицу
$table = new Table();
// Заголовок таблицы
$table->addRow(array("Департамент", "сотр.",
"тугр.",
"кофе",
"стр.",
"тугр./стр.."));
// Статистика по департаентам
$departaments = $company->getAllDepartments();
// Каждый департамент строка
foreach ($departaments as $departament) {
unset($columns); // обнуляем массив // Заполняем массив строк
$columns[] = $departament->countEmployees();
$columns[] = $departament->getTotalSalary();
$columns[] = $departament->getTotalCoffee();
$columns[] = $departament->getTotalProduct();
$columns[] = $departament->getAverageCostPerProduct();
// Добавляем строку в таблицу
$table->addRow($columns);
}
// Пустая строка
unset($columns); // обнуляем массив $columns[] = ' ';
// Добавляем строку в таблицу
$table->addRow($columns);
// Среднее для всей компании
unset($columns); // обнуляем массив // Заполняем массив строк
$columns[] = 'Среднее';
$columns[] = $company->getAverageEmployees();
$columns[] = $company->getAverageSalary();
$columns[] = $company->getAverageCoffee();
$columns[] = $company->getAverageProduct();
$columns[] = $company->getAverageCostPerProduct();
// Добавляем строку в таблицу
$table->addRow($columns);
// Всего для всей компании
unset($columns); // обнуляем массив // Заполняем массив строк
$columns[] = 'Всего';
$columns[] = $company->getTotalEmployees();
$columns[] = $company->getTotalSalary();
$columns[] = $company->getTotalCoffee();
$columns[] = $company->getTotalProduct();
// Добавляdем строку в таблицу
$table->addRow($columns);
// Выводим на печать заголовок
echo "{$caption}\n";
// Выводим таблицу на печать
$table->printTable();
echo "\n\n";
}
// Клонирует компанию
function cloneCompany($company)
{
return clone $company;
}
// Регистрируем Vector Inc на Сейшельских островах
$vector = createCompany('Vector');
printStatistics($vector, "Докризисная статистика");
// Создаем антикризисный коммитет
$anticrisisCommittee = new AnticrisisCommittee();
// Первый набор Антикризисных мер
$vector1 = cloneCompany($vector);
$anticrisisCommittee->dismissEngineers($vector1);
printStatistics($vector1, "Антикризисные меры 1");
// Второй набор Антикризисных мер
$vector2 = cloneCompany($vector);
$anticrisisCommittee->increaseSalaryRate($vector2);
$anticrisisCommittee->setAnalystAsChief($vector2);
printStatistics($vector2, "Антикризисные меры 2");
// Третий набор Антикризисных мер
$vector3 = cloneCompany($vector);
$anticrisisCommittee->liftManager($vector3);
printStatistics($vector3, "Антикризисные меры 3");
//var_dump ($vector);
?>