Newer
Older
Rodrigo Goncalves
committed
<?php
namespace Ingress\Command\TikiWiki;
use Console_CommandLine;
Rodrigo Goncalves
committed
use Ingress\Command\BaseCommand;
use Ingress\Services\Logger;
use Ingress\Services\smartdataapi\SmartDataContextApiClient;
use Ingress\Services\smartdataapi\SmartDataUnits;
Rodrigo Goncalves
committed
use Ingress\Services\tikiwiki\TikiWIkiConfig;
use Ingress\Services\tikiwiki\TikiWikiDB;
/**
* Imports context data for vehicles and manitenance from TikiWiki trackers to the SmartDataContext API
*
* Configuration for which trackers to use and the certificates is retrieved from ./config/tikiki.json file
*
* Author: Rodrigo Gonçalves
* Version: 2024.08.27
*/
Rodrigo Goncalves
committed
class ImportCommand extends BaseCommand
{
public static function process(array $args, array $params) {
$domain = $args['domain'];
$db = new TikiWikiDB();
$trackerList = TikiWikiConfig::getTrackers($domain);
list($api, $certificatePath, $certificateKeyPath) = TikiWikiConfig::getApiConfig($domain);
$apiClient = new SmartDataContextApiClient($api, $certificatePath, $certificateKeyPath);
$vehicleMap = static::importVehicles($db, $apiClient, $trackerList['vehicleList']);
static::importMaintenancePlans($db, $apiClient, $trackerList['vehicleMaintenancePlan'], $vehicleMap);
$maintenanceReports = static::importMaintenanceReports($db, $trackerList['vehicleMaintenanceReport'], $vehicleMap);
$maintenanceReports = static::importMaintenanceReportsErrorCodes($db, $trackerList['vehicleMaintenanceReportErrorCodes'], $maintenanceReports);
foreach ($maintenanceReports as $maintenanceId => $maintenace) {
static::persistMaintenanceReport($maintenanceId, $apiClient, $maintenace);
}
}
Rodrigo Goncalves
committed
private const MAINTENANCE_REPORT_TRACKER_MAP = [
'rpmServiceNumber' => 'maintenanceServiceNumber',
'rpmPersonResponsible' => 'maintenanceResponsiblePerson',
'rpmMileage' => ['vehicleMileage', 'static::convertKM'],
'rpmOperationalStatus' => ['vehicleOperationalStatus', 'static::convertOperationalStatus'],
'rpmMotivation' => ['maintenanceMotivation', 'static::convertMotivation'],
'rpmWarrantyStatus' => ['vehicleWarrantyStatus', 'static::convertWarrantyStatus'],
'rpmOwner' => ['currentOwnwerCount', 'static::convertOwnerCount'],
'rpmDateOfLastService' => ['lastServiceData', 'static::convertDate'],
'rpmNextScheduledService' => ['nextScheduledService', 'static::convertDate'],
'rpmAverageKmLInTheLastYear' => ['averageKMPerLiter', 'static::convertKMLiter'],
'rpmMajorRepairs' => 'majorRepairsReport',
'rpmPartsReplaced' => 'partsReplacedReport',
'rpmServicesAndFinishes' => 'servicesAndFinishesReport',
];
private const MAINTENANCE_PLAN_TRACKER_FREQUENCY_MAP = [
'vehiclemaintenancereportInspectionOfInje_tricMotor' => 'ENGINE_INSPECTION',
'vehiclemaintenancereportSuspensionCheck' => 'SUSPENSION_CHECK',
'vehiclemaintenancereportTransmissionFluidChange' => 'TRANSMISSION_FLUID_CHANGE',
'vehiclemaintenancereportTimingBeltReplacement' => 'BELT_REPLACEMENT',
'vehiclemaintenancereportSparkPlugReplacement' => 'SPARK_PLUG_REPLACEMENT',
'vehiclemaintenancereportFrequencyForTireRotation' => 'TIRE_ROTATION',
'vehiclemaintenancereportFrequencyForBrak_nspection' => 'BREAK_INSPECTION',
'vehiclemaintenancereportFrequencyForFluidCheck' => 'FLUID_CHECK',
'vehiclemaintenancereportFrequencyForComp_nspection' => 'COMPLETE_VEHICLE_INSPECTION',
'vehiclemaintenancereportFrequencyForEmissionsTest' => 'EMISSIONS_TEST',
'vehiclemaintenancereportBatteryTest' => 'BATTERY_TEST',
'vehiclemaintenancereportFrequencyForOilA_terChange' => 'OIL_FILTER_CHANGE'
];
Rodrigo Goncalves
committed
private const OPERATIONAL_STATUS_MAP = [
'no apparent issues' => 'NO_APPARENT_ISSUES',
'maintenance required (please specify)' => 'MAINTENANCE_REQUIRED'
Rodrigo Goncalves
committed
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
];
private const MAINTENANCE_MOTIVATION_MAP = [
'Periodic review' => 'PERIODIC_REVIEW',
'Specific failure' => 'SPECIFIC_FAILURE',
'Major failure' => 'MAJOR_FAILURE',
'Vehicle unavailability' => 'VEHICLE_UNAVAILABILITY'
];
private const WARRANTY_STATUS_MAP = [
'Under warranty' => 'UNDER_WARRANTY',
'Extended warranty' => 'EXTENDED_WARRANTY',
'Out of warranty' => 'OUT_OF_WARRANTY'
];
private const MAINTENANCE_REPORT_SERVICE_MAP = [
'rpmInspectionOfInjectionCombustionSystem_tricMotor' => 'ENGINE_INSPECTION',
'rpmSuspensionCheck' => 'SUSPENSION_CHECK',
'rpmTransmissionFluidChange' => 'TRANSMISSION_FLUID_CHANGE',
'rpmBeltReplacement' => 'BELT_REPLACEMENT',
'rpmSparkPlugReplacement' => 'SPARK_PLUG_REPLACEMENT',
'rpmTireRotation' => 'TIRE_ROTATION',
'rpmBrakeInspection' => 'BREAK_INSPECTION',
'rpmFluidCheck' => 'FLUID_CHECK',
'rpmEmissionsTest' => 'EMISSIONS_TEST',
'rpmBatteryTest' => 'BATTERY_TEST',
'rpmOilAndFilterChange' => 'OIL_FILTER_CHANGE'
];
private const VEHICLE_TRACKER_MAP = [
'vlVehicleModel' => 'signature',
'vlYear' => 'year',
'vlVehicleBrand' => 'model',
'vlSignature' => 'signature',
];
private const MAINTENANCE_REPORT_ERROR_CODE_MAP = [
'ffmProblem' => 'problemDescription',
'ffmDTCCode' => 'dtcCode'
];
private const USAGE_PATTERN_MAP = [
'personal vehicle' => 'PERSONAL_VEHICLE',
'fleet' => 'FLEET',
'service' => 'SERVICE'
];
private static function convertKM($value) {
// Convert the kilometers values to meters
return ["valueI32" => $value * 1000, "unit" => SmartDataUnits::METER];
}
private static function convertOwnerCount($value) {
return preg_replace('/\D/', '', $value);
}
private static function convertDate($value) {
// Saves the epoch value as a time
return ["valueI64" => $value, "unit" => SmartDataUnits::TIME];
}
private static function convertKMLiter($value) {
// Convert KM/L to M/L
return ["valueD32" => $value, "unit" => SmartDataUnits::METER];
}
private static function convertValueMap($value, $map) {
if (array_key_exists($value, $map)) {
return $map[$value];
} else {
return null;
}
}
private static function convertOperationalStatus($value) {
return static::convertValueMap($value, static::OPERATIONAL_STATUS_MAP);
}
private static function convertMotivation($value) {
return static::convertValueMap($value, static::MAINTENANCE_MOTIVATION_MAP);
}
Rodrigo Goncalves
committed
private static function convertWarrantyStatus($value) {
return static::convertValueMap($value, static::WARRANTY_STATUS_MAP);
Rodrigo Goncalves
committed
}
private static function convertServiceFrequency($key, $value)
{
$numericValue = preg_replace('/\D/', '', $value);
if (str_contains($value, "km")) {
return ["kind" => $key, 'internal' => ['unit' => SmartDataUnits::METER, 'valueI32' => $numericValue * 1000]];
} else {
return ["kind" => $key, 'internal' => ['unit' => SmartDataUnits::TIME, 'valueI32' => $numericValue * SmartDataUnits::MONTH_TO_TIME_MULTIPLIER]];
}
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
}
private static function persistMaintenanceReport($tikiwikiid, $api, $data)
{
$identifier = "tikiwiki-vehicle-maintenancereport-$tikiwikiid";
$id = $api->getIdByIdentifier($identifier);
if ($id) {
Logger::log("Updating existing Vehicle Maintenance Report $identifier context $id");
$api->updateSmartDataContext($id, ["content" => $data]);
} else {
Logger::log("Creating Vehicle Maintenance Report $identifier context");
$result = $api->createSmartDataContext(["content" => $data, "features" => ["identifier" => $identifier, "tags" => ["vehicle-maintenance-report"]]]);
if (array_key_exists('result', $result)) {
Logger::log("Created Vehicle Maintenance Report $identifier context " . $result['result']['smartDataContextId']);
$id = $result['result']['smartDataContextId'];
} else {
throw new Exception(json_encode($result['errors']));
}
}
$result = $api->associateSmartDataContext(['smartDataContextIds' => $id, 'smartDataSources' => [$data['vehicle']['signature']]]);
if (array_key_exists('result', $result)) {
Logger::log("Associated context to signature ". $data['vehicle']['signature']);
} else {
throw new Exception(json_encode($result['errors']));
}
}
private static function importMaintenanceReportsErrorCodes(TikiWikiDB $db, string $trackerName, array $maintenanceReportsMap)
Rodrigo Goncalves
committed
{
$maintenanceReportsErrorCodes = static::findTrackerItems($db, $trackerName);
foreach ($maintenanceReportsErrorCodes as $maintenanceReportsErrorCode) {
$maintenanceReportsMap = self::importMaintenanceReportsErrorCode($maintenanceReportsMap, $maintenanceReportsErrorCode);
}
return $maintenanceReportsMap;
}
private static function importMaintenanceReportsErrorCode(array $maintenanceReportsMap, mixed $maintenanceReportsErrorCodeData)
{
$maintenanceReportsErrorCode = static::buildJson(static::MAINTENANCE_REPORT_ERROR_CODE_MAP, $maintenanceReportsErrorCodeData);
$maintenanceReportId = $maintenanceReportsErrorCodeData['ffmVehicleMaintenanceReport']['fieldValue'];
if (array_key_exists($maintenanceReportId, $maintenanceReportsMap)) {
$maintenanceReportsMap[$maintenanceReportId]['vehicleFailures'][] = $maintenanceReportsErrorCode;
}
return $maintenanceReportsMap;
}
private static function importMaintenanceReports(TikiWikiDB $db, string $trackerName, array $vehicleMap) {
Rodrigo Goncalves
committed
$maintenanceReportsData = static::findTrackerItems($db, $trackerName);
$maintenanceReports = [];
foreach ($maintenanceReportsData as $maintenanceReportDatum) {
$maintenanceReports[$maintenanceReportDatum['tikiwikiid']] = static::importMaintenanceReport($maintenanceReportDatum, $vehicleMap);
}
return $maintenanceReports;
}
private static function importMaintenanceReport(array $maintenanceReportDatum, array $vehicleMap) {
$maintenanceReport = static::buildJson(static::MAINTENANCE_REPORT_TRACKER_MAP, $maintenanceReportDatum);
$maintenanceReport["vehicle"] = $vehicleMap[$maintenanceReportDatum['rpmVehicle']['fieldValue']];
foreach ($maintenanceReportDatum as $fieldName => $field) {
if (array_key_exists($fieldName, static::MAINTENANCE_REPORT_SERVICE_MAP)) {
if ($field['fieldValue'] == 'y') {
$maintenanceReport['executedServices'][] = static::MAINTENANCE_REPORT_SERVICE_MAP[$fieldName];
}
}
}
return $maintenanceReport;
}
private static function importMaintenancePlans(TikiWikiDB $db, SmartDataContextApiClient $api, string $trackerName, array $vehicleMap) {
Rodrigo Goncalves
committed
$maintenancePlansData = static::findTrackerItems($db, $trackerName);
$maintenancePlans = [];
foreach ($maintenancePlansData as $tikiwikiid => $maintenancePlansDatum) {
Rodrigo Goncalves
committed
$maintenancePlan = ["vehicle" => $vehicleMap[$maintenancePlansDatum['vehiclemaintenancereportVehicle']['fieldValue']]];
foreach ($maintenancePlansDatum as $fieldName => $field) {
if (array_key_exists($fieldName, static::MAINTENANCE_PLAN_TRACKER_FREQUENCY_MAP)) {
$maintenancePlan['servicesFrequencies'][] = static::convertServiceFrequency(static::MAINTENANCE_PLAN_TRACKER_FREQUENCY_MAP[$fieldName], $field['fieldValue']);
}
}
static::persistMaintenancePlan($tikiwikiid, $api, $maintenancePlan);
Rodrigo Goncalves
committed
$maintenancePlans[] = $maintenancePlan;
}
Rodrigo Goncalves
committed
return $maintenancePlans;
}
private static function persistMaintenancePlan($tikiwikiid, $api, $data)
Rodrigo Goncalves
committed
{
$identifier = "tikiwiki-vehicle-maintenanceplan-$tikiwikiid";
$id = $api->getIdByIdentifier($identifier);
if ($id) {
Logger::log("Updating existing Vehicle Maintenance Plan $identifier context $id");
$api->updateSmartDataContext($id, ["content" => $data]);
} else {
Logger::log("Creating Vehicle Maintenance Plan $identifier context");
$result = $api->createSmartDataContext(["content" => $data, "features" => ["identifier" => $identifier, "tags" => ["vehicle-maintenance-plan"]]]);
if (array_key_exists('result', $result)) {
Logger::log("Created Vehicle Maintenance Plan $identifier context " . $result['result']['smartDataContextId']);
$id = $result['result']['smartDataContextId'];
} else {
throw new Exception(json_encode($result['errors']));
}
}
$result = $api->associateSmartDataContext(['smartDataContextIds' => $id, 'smartDataSources' => [$data['vehicle']['signature']]]);
if (array_key_exists('result', $result)) {
Logger::log("Associated context to signature ". $data['vehicle']['signature']);
} else {
throw new Exception(json_encode($result['errors']));
}
Rodrigo Goncalves
committed
}
private static function importVehicles(TikiWikiDB $db, SmartDataContextApiClient $api, string $trackerName) {
Rodrigo Goncalves
committed
$vehicles = static::findTrackerItems($db, $trackerName);
$result = [];
foreach ($vehicles as $vehicle) {
$result[$vehicle['tikiwikiid']] = static::importVehicle($vehicle);
static::persistVehicle($api, $vehicle['tikiwikiid'], $result[$vehicle['tikiwikiid']]);
Rodrigo Goncalves
committed
}
return $result;
}
private static function importVehicle($vehicleTrackerData) {
$vehicle = static::buildJson(static::VEHICLE_TRACKER_MAP, $vehicleTrackerData);
$vehicle['usagePatterns'] = static::convertUsagePatern($vehicleTrackerData['vlUsagePatterns']['fieldValue']);
return $vehicle;
}
private static function persistVehicle(SmartDataContextApiClient $api, $tikiwikiid, $data)
{
$identifier = "tikiwiki-vehicle-$tikiwikiid";
$id = $api->getIdByIdentifier($identifier);
if ($id) {
Logger::log("Updating existing Vehicle $identifier context $id");
$api->updateSmartDataContext($id, ["content" => $data]);
} else {
Logger::log("Creating Vehicle $identifier context");
$result = $api->createSmartDataContext(["content" => $data, "features" => ["identifier" => $identifier, "tags" => ["vehicle-record"]]]);
if (array_key_exists('result', $result)) {
$id = $result['result']['smartDataContextId'];
Logger::log("Created vehicle $identifier context " . $id);
} else {
throw new Exception(json_encode($result['errors']));
}
}
$result = $api->associateSmartDataContext(['smartDataContextIds' => $id, 'smartDataSources' => [$data['signature']]]);
if (array_key_exists('result', $result)) {
Logger::log("Associated context to signature");
} else {
throw new Exception(json_encode($result['errors']));
}
}
Rodrigo Goncalves
committed
private static function convertUsagePatern($patterns) {
$patternList = [];
foreach (preg_split('/,/', $patterns) as $pattern) {
$pattern = trim($pattern);
if (array_key_exists($pattern, static::USAGE_PATTERN_MAP)) {
$patternList[] = static::USAGE_PATTERN_MAP[$pattern];
}
}
return $patternList;
}
/**
* Loads tracker data from the database
*/
Rodrigo Goncalves
committed
private static function findTrackerItems(TikiWikiDB $db, string $trackerName) {
$trackerData = $db->getTrackerData($trackerName);
return static::_extractItems($trackerData);
}
/**
* Maps an associative array of field values to a json structure
*/
Rodrigo Goncalves
committed
private static function buildJson(array $mapping, array $row): array
{
$result = [];
foreach ($mapping as $fieldName => $parameters) {
if (is_array($parameters)) {
$jsonPath = $parameters[0];
$convFunc = $parameters[1];
} else {
$jsonPath = $parameters;
}
if (!isset($row[$fieldName])) {
Rodrigo Goncalves
committed
}
$value = $row[$fieldName];
$keys = explode('.', $jsonPath);
$current = &$result;
foreach ($keys as $key) {
if (!isset($current[$key])) {
$current[$key] = [];
}
$current = &$current[$key];
}
$current = isset($convFunc) ? call_user_func($convFunc, $value['fieldValue']): $value['fieldValue'];
}
return $result;
}
/**
* Converts a database result to an associative array based on the tikiwiki item id
*/
Rodrigo Goncalves
committed
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
private static function _extractItems(array $rows): array
{
$result = [];
foreach ($rows as $row) {
$itemId = $row['item_id'];
$fieldName = $row['fieldName'];
if (!isset($result[$itemId])) {
$result[$itemId] = ['tikiwikiid' => $itemId];
}
$result[$itemId][$fieldName] = [
'fieldValue' => $row['fieldValue'],
'attachment_name' => $row['attachment_name'],
'attachment_size' => $row['attachment_size'],
'attachment_type' => $row['attachment_type'],
'attachment_data' => $row['attachment_data']
];
}
return $result;
}
public static function register(Console_CommandLine $commandLine, array $commandMap)
{
$cmd = BaseCommand::addCommand($commandLine, 'tikiwiki-import', 'Imports tracker data from a domain to SmartDataContext entities',
'Ingress\Command\TikiWiki\ImportCommand::process'
);
BaseCommand::addArgument($cmd, 'domain', 'Define the domain to import the data');
}
}