setName('feedback:report')
->setDescription('Report ended feedback results (votes) on records (set status-bits)')
->addOption('report', null, InputOption::VALUE_REQUIRED, "Report output format (all|condensed)", "all")
->addOption('min_date', null, InputOption::VALUE_REQUIRED, "Run only for feedbacks expired from this date (yyyy-mm-dd)", null)
->addOption('dry', null, InputOption::VALUE_NONE, "list records but don't apply.", null)
->setHelp("")
;
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
* @throws DBALException
* @throws \Throwable
*/
protected function doExecute(InputInterface $input, OutputInterface $output)
{
// add cool styles
$style = new OutputFormatterStyle('black', 'yellow'); // , array('bold'));
$output->getFormatter()->setStyle('warning', $style);
$this->input = $input;
$this->output = $output;
// config must be ok
//
try {
$this->config = new GlobalConfiguration(
$this->getConf(),
$this->container['twig'],
$this->container['phraseanet.appbox'],
$input->getOption('dry'),
$input->getOption('report')
);
}
catch(Exception $e) {
$output->writeln(sprintf("missing or bad configuration: %s", $e->getMessage()));
return -1;
}
if(!$this->config->isEnabled()) {
$output->writeln(sprintf("configuration is not enabled"));
return 0;
}
$min_date_filter = '';
if( ($min_date = $input->getOption('min_date')) !== null) {
$matches = [];
if(preg_match('/(\d\d\d\d)\D(\d\d)\D(\d\d)/', $min_date, $matches) !== 1) {
$output->writeln(sprintf("bad format for --min_date"));
return -1;
}
$min_date_filter = ' AND b.`created` >= \'' . $matches[1] . '-' . $matches[2] . '-' . $matches[3] . '\'';
}
$appbox = $this->getAppBox();
$sql_update = "UPDATE `BasketElements` SET `vote_expired` = :expired WHERE `id` = :id";
$stmt_update = $appbox->get_connection()->prepare($sql_update);
$sql_select = "SELECT q1.*,
b.name, b.`vote_created` AS `created`, b.`vote_expires` AS expired, b.`vote_initiator_id`,
be.id AS be_id, be.vote_expired AS be_vote_expired,
COUNT(bp.id) AS `voters_count`,
SUM(IF(ISNULL(`agreement`), 1 , 0)) AS `votes_unvoted`,
SUM(IF((`agreement`=0), 1, 0)) AS `votes_no`,
SUM(IF((`agreement`=1), 1, 0)) AS `votes_yes`
FROM
(
SELECT SUBSTRING_INDEX(GROUP_CONCAT(b.`id` ORDER BY `vote_expires` DESC), ',', 1) AS `basket_id`,
be.`sbas_id`, be.`record_id`, CONCAT(be.`sbas_id`, '_', be.`record_id`) AS `sbid_rid`
FROM `BasketElements` AS be INNER JOIN `Baskets` AS b ON b.`id`=be.`basket_id`
WHERE b.`vote_expires` < NOW() " . $min_date_filter . "
GROUP BY `sbid_rid`
) AS q1
INNER JOIN `Baskets` AS b ON b.`id`=q1.`basket_id`
INNER JOIN `BasketElements` AS be ON be.basket_id=b.id AND be.sbas_id=q1.sbas_id AND be.record_id=q1.record_id
AND (ISNULL(be.`vote_expired`) OR b.`vote_expires` > be.`vote_expired`)
INNER JOIN `BasketParticipants` AS bp ON bp.`can_agree`=1 AND bp.`basket_id`=b.id
LEFT JOIN `BasketElementVotes` AS bv ON bv.`participant_id`=bp.`id` AND bv.`basket_element_id`=be.id
GROUP BY be.id";
$last_basket_id = null;
$condensed = null;
$vote_initiator = null;
$stmt_select = $appbox->get_connection()->query($sql_select);
while ($row = $stmt_select->fetch(PDO::FETCH_ASSOC)) {
if($row['basket_id'] !== $last_basket_id) {
$this->outputCondensed($condensed);
$condensed = [
'voters_count' => $row['voters_count'],
'records_count' => 0,
'votes_unvoted' => 0,
'votes_no' => 0,
'votes_yes' => 0,
];
$vote_initiator = $this->findUser($row['vote_initiator_id']);
$this->output->writeln(sprintf("basket \"%s\" (id %s), initiated on %s by %s (id %s), expired %s",
$row['name'],
$last_basket_id = $row['basket_id'],
$row['created'],
$vote_initiator ? $vote_initiator->getEmail() : "unknown",
$row['vote_initiator_id'] ?? 'null',
$row['expired'])
);
}
if($this->config->getReportFormat() === 'all') {
$this->output->writeln(sprintf("\tdatabox: %s, record id: %s", $row['sbas_id'], $row['record_id']));
}
if( ($databox = $this->config->getDatabox($row['sbas_id'])) === null) {
$this->output->writeln(sprintf("\t\tunknown databox (ignored)"));
continue;
}
try {
$record = $databox->get_record($row['record_id']);
}
catch(Exception $e) {
$this->output->writeln(sprintf("\t\tunknown record (ignored)"));
continue;
}
$condensed['records_count']++;
foreach(['votes_unvoted', 'votes_no', 'votes_yes'] as $k) {
if($this->config->getReportFormat() !== 'condensed') {
$this->output->writeln(sprintf("\t\t%s: %s", $k, $row[$k]));
}
$condensed[$k] += $row[$k];
}
$setMetasActions = [];
foreach($this->config->getActions($databox) as $action) {
$action->addAction(
$setMetasActions,
[
'initiator' => $vote_initiator,
'vote' => $row,
]
);
}
if(count($setMetasActions) > 0) {
$jsActions = json_encode($setMetasActions, JSON_PRETTY_PRINT);
if($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE) {
$this->output->writeln(sprintf("JS : %s", $jsActions));
}
if(!$this->config->isDryRun()) {
$record->setMetadatasByActions(json_decode($jsActions));
}
}
if(!$this->config->isDryRun()) {
$stmt_update->execute([
':expired' => $row['expired'],
':id' => $row['be_id']
]);
}
}
$this->outputCondensed($condensed);
$stmt_select->closeCursor();
return 0;
}
/**
* @return appbox
*/
private function getAppBox(): appbox
{
return $this->container['phraseanet.appbox'];
}
/**
* @return PropertyAccess
*/
protected function getConf()
{
return $this->container['conf'];
}
private function findUser($user_id)
{
/** @var UserRepository $repo */
$repo = $this->container['repo.users'];
try {
return $repo->find($user_id);
}
catch (Exception $e) {
return null;
}
}
/**
* @param array|null $condensed
* @return void
*/
private function outputCondensed($condensed)
{
if($condensed !== null && $this->config->getReportFormat() === 'condensed') {
foreach($condensed as $k => $v) {
$this->output->writeln(sprintf("\t%s: %s", $k, $v));
}
}
}
}