Select Git revision
manage_data.php
-
Benoît Harrault authoredBenoît Harrault authored
manage_data.php 11.16 KiB
<?php
function dump(string $string)
{
echo $string . PHP_EOL;
}
function write_data(array $data, string $filename)
{
\file_put_contents($filename, \json_encode($data));
}
function array_clean(array $array)
{
$output = \array_unique($array);
\sort($output);
return $output;
}
function ask(string $prompt)
{
dump($prompt);
$input = \rtrim(\fgets(STDIN));
return $input;
}
function find_missing_associations(array $mappingItems, array $categories, array $items)
{
$missing = [];
foreach ($items as $item) {
$set = \array_merge(
$mappingItems[$item]['is'],
$mappingItems[$item]['isnot'],
$mappingItems[$item]['na'],
);
foreach ($categories as $category) {
if (!\in_array($category, $set)) {
$missing[] = [
'item' => $item,
'category' => $category,
];
}
}
}
return $missing;
}
function find_exclusions(array $exclusions, string $searchedCategory)
{
$output = [];
foreach ($exclusions as $exclusionSet) {
if (\is_array($exclusionSet) && \in_array($searchedCategory, $exclusionSet)) {
foreach ($exclusionSet as $candidate) {
if ($candidate !== $searchedCategory) {
$output[] = $candidate;
}
}
}
}
return $output;
}
function clean_item_mappings(array $itemMappings)
{
$itemMappings['is'] = array_clean($itemMappings['is']);
$itemMappings['isnot'] = array_clean($itemMappings['isnot']);
$itemMappings['na'] = array_clean($itemMappings['na']);
// remove duplicates
$itemMappings['is'] = array_clean($itemMappings['is']);
$tmpArray = [];
foreach (array_clean($itemMappings['isnot']) as $itemIsNot) {
if (!\in_array($itemIsNot, $itemMappings['is'])) {
$tmpArray[] = $itemIsNot;
}
}
$itemMappings['isnot'] = $tmpArray;
$tmpArray = [];
foreach (array_clean($itemMappings['na']) as $itemNa) {
if (!\in_array($itemNa, $itemMappings['is']) && !\in_array($itemNa, $itemMappings['isnot'])) {
$tmpArray[] = $itemNa;
}
}
$itemMappings['na'] = $tmpArray;
return $itemMappings;
}
if ($argc != 2) {
dump('Need data json file as parameter.');
die;
}
$jsonDataFile = $argv[1];
$data = [];
if (is_file($jsonDataFile)) {
$data = \json_decode(\file_get_contents($jsonDataFile), true);
}
if (!is_writable($jsonDataFile)) {
dump('Output data json file is not writable.');
die;
}
$categories = (\array_key_exists('categories', $data) && \is_array($data['categories'])) ? $data['categories'] : [];;
$items = (\array_key_exists('items', $data) && \is_array($data['items'])) ? $data['items'] : [];;
// Manage categories exclusions
$exclusions = (\array_key_exists('exclusions', $data) && \is_array($data['exclusions'])) ? $data['exclusions'] : [];
// Merge categories with categories found in exclusions
foreach ($exclusions as $exclusionSet) {
foreach ($exclusionSet as $category) {
$categories[] = $category;
}
}
$categories = array_clean($categories);
$items = array_clean($items);
$data['categories'] = $categories;
$data['items'] = $items;
$data['exclusions'] = $exclusions;
dump('');
dump('Found ' . \count($categories) . ' unique categories.');
dump('Found ' . \count($items) . ' unique items.');
dump('Found ' . \count($exclusions) . ' exclusions sets.');
// Get/init mapping data
$mapping = (\array_key_exists('mapping', $data) && \is_array($data['mapping'])) ? $data['mapping'] : [];
$mappingItems = (\array_key_exists('items', $mapping) && \is_array($mapping['items'])) ? $mapping['items'] : [];
foreach ($items as $item) {
if (!\array_key_exists($item, $mappingItems)) {
$mappingItems[$item] = [];
}
if (!\array_key_exists('is', $mappingItems[$item]) || !\is_array($mappingItems[$item])) {
$mappingItems[$item]['is'] = [];
}
if (!\array_key_exists('isnot', $mappingItems[$item]) || !\is_array($mappingItems[$item])) {
$mappingItems[$item]['isnot'] = [];
}
if (!\array_key_exists('na', $mappingItems[$item]) || !\is_array($mappingItems[$item])) {
$mappingItems[$item]['na'] = [];
}
$mappingItems[$item] = clean_item_mappings($mappingItems[$item]);
}
// TODO: Should check/add unkown items from current mapping
\ksort($mappingItems);
$data['mapping'] = [
'items' => $mappingItems,
];
function showCategories($categories)
{
dump(\join("\n", $categories));
}
function showItems($items)
{
dump(\join("\n", $items));
}
function showExclusions($exclusions)
{
foreach ($exclusions as $exclusionSet) {
dump(\join(', ', $exclusionSet));
}
}
function showMappings($mappingItems)
{
$columnsWidths = [
'items' => 0,
];
$items = \array_keys($mappingItems);
$categories = [];
foreach ($mappingItems as $item => $mapping) {
if ($columnsWidths['items'] < \mb_strlen($item)) {
$columnsWidths['items'] = \mb_strlen($item);
}
foreach (\array_merge($mapping['is'], $mapping['isnot'], $mapping['na']) as $category) {
if (!\in_array($category, $categories)) {
$categories[] = $category;
if (!\array_key_exists($category, $columnsWidths)) {
$columnsWidths[$category] = 0;
}
if ($columnsWidths[$category] < \mb_strlen($category)) {
$columnsWidths[$category] = \mb_strlen($category);
}
}
}
}
$strIs = '✅';
$strIsNot = '❌';
$strNa = '⛔';
// separator
$line = [
\mb_str_pad('', $columnsWidths['items'], '-', STR_PAD_BOTH),
];
foreach ($categories as $category) {
$line[] = \mb_str_pad('', $columnsWidths[$category], '-', STR_PAD_BOTH);
}
dump('--' . \join('---', $line) . '--');
// header
$line = [
\mb_str_pad('', $columnsWidths['items'], ' ', STR_PAD_BOTH),
];
foreach ($categories as $category) {
$line[] = \mb_str_pad($category, $columnsWidths[$category], ' ', STR_PAD_BOTH);
}
dump('| ' . \join(' | ', $line) . ' |');
// separator
$line = [
\mb_str_pad('', $columnsWidths['items'], '-', STR_PAD_BOTH),
];
foreach ($categories as $category) {
$line[] = \mb_str_pad('', $columnsWidths[$category], '-', STR_PAD_BOTH);
}
dump('|-' . \join('-|-', $line) . '-|');
foreach ($items as $item) {
$line = [
\mb_str_pad($item, $columnsWidths['items'], ' ', STR_PAD_RIGHT),
];
foreach ($categories as $category) {
$value = '';
if (\in_array($category, $mappingItems[$item]['is'])) {
$value = $strIs;
} elseif (\in_array($category, $mappingItems[$item]['isnot'])) {
$value = $strIsNot;
} elseif (\in_array($category, $mappingItems[$item]['na'])) {
$value = $strNa;
}
$line[] = \mb_str_pad($value, $columnsWidths[$category], ' ', STR_PAD_BOTH);
}
dump('| ' . \join(' | ', $line) . ' |');
}
// separator
$line = [
\mb_str_pad('', $columnsWidths['items'], '-', STR_PAD_BOTH),
];
foreach ($categories as $category) {
$line[] = \mb_str_pad('', $columnsWidths[$category], '-', STR_PAD_BOTH);
}
dump('--' . \join('---', $line) . '--');
}
function editMappings($mappingItems, $categories, $items, $exclusions)
{
// Set missing associations
$exitEditMappings = false;
$missing = find_missing_associations($mappingItems, $categories, $items);
while ((\count($missing) !== 0) && ($exitEditMappings === false)) {
dump('');
dump('Missing associations: ' . \count($missing));
dump('');
$picked = $missing[mt_rand(0, \count($missing) - 1)];
$item = $picked['item'];
$category = $picked['category'];
$question = 'Is "' . $item . '" can be categorised as "' . $category . '"?';
$ex = find_exclusions($exclusions, $category);
if (\count($ex) !== 0) {
$question .= ' (and apply accordingly to "' . join('" and "', $ex) . '")';
}
dump($question);
$answer = ask('1: yes ; 2: no ; 3: n/a ; 0: exit');
switch ($answer) {
case '0':
$exitEditMappings = true;
break;
case '1':
dump(' -> "' . $item . '" is "' . $category . '"');
$mappingItems[$item]['is'][] = $category;
// apply "is not" to each other
foreach ($ex as $exclusion) {
dump(' -> "' . $item . '" is not "' . $exclusion . '"');
$mappingItems[$item]['isnot'][] = $exclusion;
}
break;
case '2':
dump(' -> "' . $item . '" is not "' . $category . '"');
$mappingItems[$item]['isnot'][] = $category;
// apply "is" only if one exclusion
if (\count($ex) === 1) {
foreach ($ex as $exclusion) {
dump(' -> "' . $item . '" is "' . $exclusion . '"');
$mappingItems[$item]['is'][] = $exclusion;
}
}
break;
case '3':
dump(' -> "' . $item . '" does not apply as "is or is not" "' . $category . '"');
$mappingItems[$item]['na'][] = $category;
foreach ($ex as $exclusion) {
dump(' -> "' . $item . '" does not apply as "is or is not" "' . $category . '"');
$mappingItems[$item]['na'][] = $category;
}
break;
default:
dump('wut? skipping...');
break;
}
$mappingItems[$item] = clean_item_mappings($mappingItems[$item]);
$missing = find_missing_associations($mappingItems, $categories, $items);
}
return $mappingItems;
}
// Main loop
$exitMainLoop = false;
while ($exitMainLoop === false) {
dump('');
$missing = find_missing_associations($mappingItems, $categories, $items);
$menu = [
'0: exit',
'',
'1: show categories (' . \count($categories) . ' found)',
'2: show items (' . \count($items) . ' found)',
'3: show exclusions (' . \count($exclusions) . ' found)',
'4: show mappings (' . \count($mappingItems) . ' found)',
'',
'5: complete mappings (' . \count($missing) . ' missing)',
];
$answer = ask(\join("\n", $menu));
switch ($answer) {
case '0':
$exitMainLoop = true;
break;
case '1':
showCategories($categories);
break;
case '2':
showItems($items);
break;
case '3':
showExclusions($exclusions);
break;
case '4':
showMappings($mappingItems);
break;
case '5':
$data['mapping']['items'] = editMappings($mappingItems, $categories, $items, $exclusions);
break;
default:
break;
}
}
write_data($data, $jsonDataFile);
echo "ok, done." . PHP_EOL;