/**
  * Загружает список статей бюджета
  * @param User $user
  * @param DateTime $startDate - дата начала текущего месяца
  * @throws myBudgetWrongStartDateException
  */
 public function load(User $user, DateTime $startDate)
 {
     if ($startDate->format('d') !== '01') {
         throw new myBudgetWrongStartDateException(sprintf('Дата должна быть первым числом месяца, получена %s', $startDate->format('Y-m-d')));
     }
     //получим операции за этот месяц - для подсчета текущего бюджета,
     //и за предыдущие - для подсчета среднего показателя
     //средний показатель рассчитываем по трем предыдущим месяцам
     $meanRateMonthsAmount = 3;
     $beginDate = date_sub(clone $startDate, new DateInterval("P" . $meanRateMonthsAmount . "M"));
     //дата конца - последнее число заданного месяца, т.е. "начало месяца + 1 месяц - 1 день"
     $endDate = date_sub(date_add(clone $startDate, new DateInterval("P1M")), new DateInterval("P1D"));
     //получим выборку операций за рассчитанный период
     $operations = new OperationCollection($user);
     $operations->setPeriodStartDate($beginDate)->setPeriodEndDate($endDate)->fill();
     //получим бюджет на месяц (коллекцию статей бюджета на заданный месяц)
     $budget = new Budget();
     $budget->fill($user, $startDate);
     $calculator = new BudgetArticleIncrementCalculator($startDate, $user->getCurrency(), $meanRateMonthsAmount);
     //TODO: всю логику подсчета можно вынести в отдельный калькулятор бюджета и тестить его уже модульно,
     //без привлечения базы, передавая готовые операции и статьи бюджета
     //по каждой операции определим ее вклад в соотв. статью бюджета или средний показатель
     foreach ($operations->getOperations() as $operation) {
         $category = $operation->getCategory();
         // отсутствие категории -- штатная ситуация
         // например, перевод или неподтвежденная операция в календаре
         if ($category) {
             //определяем, к какой категории относится операция, и по ней определяем статью бюджета
             //категорию берем не напрямую из связи операции, а вычисляем для корректного учета переводов
             //если категория не запланирована, создается и возвращается пустая
             $currentBudgetArticle = $budget->getBudgetArticleByCategory($category);
             $increment = $calculator->calculate($operation);
             $increment->apply($currentBudgetArticle);
         }
     }
     //возвращаем уже заполненные категории
     return $budget->getBudgetArticles();
 }