File: /home/aliazzsr/api.crm.vqode.com/models/search/ProjectsStatistics.php
<?php
namespace app\models\search;
use app\components\formatters\DateFormatter;
use app\components\helpers\FormatHelper;
use app\models\core\Project;
use app\models\enums\ProjectsStatisticsGroup as Group;
use app\models\enums\StatisticsPeriod as Period;
use yii\behaviors\AttributeTypecastBehavior;
use yii\db\ActiveQuery;
use yii\db\Expression;
use yii\db\Query;
use yii\helpers\ArrayHelper;
class ProjectsStatistics extends Project
{
/** @var string */
public $group;
/** @var string */
public $period;
protected $joinTable;
protected $andWhere;
protected $_joinAlias;
protected $_bd;
protected $_ed;
public function init()
{
parent::init();
$this->_joinAlias = 'grptab01';
}
public function formName()
{
return '';
}
public function rules()
{
return [
[['group', 'period'], 'required'],
[['group', 'period'], 'string'],
[['group_id'], 'integer'],
[['period'], 'validatePeriod'],
[['group'], 'in', 'range' => Group::getConstantsByName(), 'message' => 'Unknown group.'],
[['group', 'period', 'group_id'], 'safe'],
];
}
/**
* Validates period and extracts interval limits
*/
public function validatePeriod()
{
if (in_array($this->period, Period::getConstantsByName())) {
return;
}
$dateFormat = '/^\d{2}\/\d{2}\/\d{4}$/';
list($bd, $ed) = explode('-', $this->period);
if (preg_match($dateFormat, $bd) && preg_match($dateFormat, $ed)) {
$this->_bd = DateFormatter::toMysql($bd);
$this->_ed = DateFormatter::toMysql($ed);
} else {
$this->addError('period', 'Invalid period.');
}
}
/**
* @inheritdoc
*/
public function safeAttributes()
{
return [
'group_id', 'group', 'period',
];
}
/**
* @inheritdoc
*/
public function attributes()
{
return array_merge(parent::attributes(), [
'group_id', 'group_name',
'count', 'count_percentage',
'value', 'value_percentage',
'edv', 'edv_percentage',
'efv', 'efv_percentage',
]);
}
/**
* @inheritdoc
*/
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['projects_statistics'] = [
'class' => AttributeTypecastBehavior::className(),
'attributeTypes' => [
'group_id' => AttributeTypecastBehavior::TYPE_INTEGER,
'edv' => AttributeTypecastBehavior::TYPE_FLOAT,
'efv' => AttributeTypecastBehavior::TYPE_FLOAT,
'value' => AttributeTypecastBehavior::TYPE_FLOAT,
'count' => AttributeTypecastBehavior::TYPE_INTEGER,
'edv_percentage' => [FormatHelper::className(), 'toPercent'],
'efv_percentage' => [FormatHelper::className(), 'toPercent'],
'value_percentage' => [FormatHelper::className(), 'toPercent'],
'count_percentage' => [FormatHelper::className(), 'toPercent'],
],
'typecastAfterValidate' => true,
'typecastBeforeSave' => true,
'typecastAfterFind' => true,
];
return $behaviors;
}
/**
*
* @return array
*/
public function search()
{
$this->resolveJoinTable();
$query = self::find();
$query->joinWith($this->joinTable . ' as ' . $this->_joinAlias);
$query->andWhere($this->getPeriodWhereClause());
return $this->group_id ? $this->listProjects($query) : $this->aggregateProjects($query);
}
/**
* Returns projects by search parameters loaded
* @param Query $query
* @return array
*/
protected function listProjects(Query $query)
{
$query->andWhere([$this->_joinAlias . '.id' => $this->group_id]);
return $query->all();
}
/**
* Returns projects statistics by search parameters loaded
* @param Query $query
* @return array
*/
protected function aggregateProjects(Query $query)
{
$aggAlias = 'aggsq01';
$aggregateQuery = clone $query;
$aggregateQuery->select([
'count' => 'count(*)',
'value' => 'sum({{project}}.value)',
'edv' => 'sum({{project}}.edv)',
'efv' => 'sum({{project}}.efv)',
]);
$query->select([
'group_id' => $this->_joinAlias . '.id',
'group_name' => 'max(' . $this->_joinAlias . '.name)',
'count' => 'count(*)',
'value' => 'sum({{project}}.value)',
'edv' => 'sum({{project}}.edv)',
'efv' => 'sum({{project}}.efv)',
'count_percentage' => '1.0 * count(*) / ' . $aggAlias . '.count',
'value_percentage' => '1.0 * sum({{project}}.value) / ' . $aggAlias . '.value',
'edv_percentage' => '1.0 * sum({{project}}.edv) / ' . $aggAlias . '.edv',
'efv_percentage' => '1.0 * sum({{project}}.efv) / ' . $aggAlias . '.efv',
]);
$query->innerJoin([$aggAlias => $aggregateQuery]);
$query->groupBy([
$this->_joinAlias . '.id',
]);
return $query->all();
}
/**
* @return ActiveQuery
*/
protected function getActiveStage()
{
return $this->getStage()->andWhere(['active' => true]);
}
/**
* @return ActiveQuery
*/
protected function getInactiveStage()
{
return $this->getStage()->andWhere(['active' => false]);
}
/**
* Sets this.joinTable by this.group loaded
*/
protected function resolveJoinTable()
{
$tablesMap = [
Group::RIBA => 'riba',
Group::SECTOR => 'sector',
Group::STAGE => 'stage',
Group::STAGE_ACTIVE => 'activeStage',
Group::STAGE_INACTIVE => 'inactiveStage',
Group::USER => 'creator',
Group::COMPANY => 'companies',
];
$this->joinTable = ArrayHelper::getValue($tablesMap, $this->group);
}
/**
* @return array
*/
protected function getPeriodWhereClause()
{
$arbitraryClauses = ['BETWEEN', '{{project}}.created', $this->_bd, $this->_ed];
$clausesMap = [
Period::MONTH => [
'MONTH({{project}}.created)' => new Expression('MONTH(NOW())'),
'YEAR({{project}}.created)' => new Expression('YEAR(NOW())'),
],
Period::YEAR => [
'YEAR({{project}}.created)' => new Expression('YEAR(NOW())'),
],
Period::TOTAL => [
],
];
return ArrayHelper::getValue($clausesMap, $this->period, $arbitraryClauses);
}
}