/** * Handle the actual write to CsvRow * @param object $dataRow * @param CsvRow $csvRow * @param string $arrayParentId * @param string $column * @param string $dataType * @param string $type * @return void */ protected function parseField(\stdClass $dataRow, CsvRow $csvRow, $arrayParentId, $column, $dataType, $type) { // TODO safeColumn should be associated with $this->struct[$type] // (and parentCols -> create in parse() where the arr is created) // Actually, the csvRow should REALLY have a pointer to the real name (not validated), // perhaps sorting the child columns on its own? // (because keys in struct don't contain child objects) $safeColumn = $this->createSafeName($column); // skip empty objects & arrays to prevent creating empty tables // or incomplete column names if (!isset($dataRow->{$column}) || is_null($dataRow->{$column}) || empty($dataRow->{$column}) && !is_scalar($dataRow->{$column})) { // do not save empty objects to prevent creation of ["obj_name" => null] if ($dataType != 'object') { $csvRow->setValue($safeColumn, null); } return; } if ($dataType == "NULL") { // Throw exception instead? Any usecase? TODO get rid of it maybe? $this->log->log("WARNING", "Encountered data where 'NULL' was expected from previous analysis", ['type' => $type, 'data' => $dataRow]); $csvRow->setValue($column, json_encode($dataRow)); return; } if ($this->getStruct()->isArrayOf($dataType)) { if (!is_array($dataRow->{$column})) { $dataRow->{$column} = [$dataRow->{$column}]; } $dataType = 'array'; } switch ($dataType) { case "array": $csvRow->setValue($safeColumn, $arrayParentId); $this->parse($dataRow->{$column}, $type . "." . $column, $arrayParentId); break; case "object": $childRow = $this->parseRow($dataRow->{$column}, $type . "." . $column, [], $arrayParentId); foreach ($childRow->getRow() as $key => $value) { // FIXME createSafeName is duplicated here $csvRow->setValue($this->createSafeName($safeColumn . '_' . $key), $value); } break; default: // If a column is an object/array while $struct expects a single column, log an error if (is_scalar($dataRow->{$column})) { $csvRow->setValue($safeColumn, $dataRow->{$column}); } else { $jsonColumn = json_encode($dataRow->{$column}); $this->log->log("ERROR", "Data parse error in '{$column}' - unexpected '" . $this->analyzer->getType($dataRow->{$column}) . "' where '{$dataType}' was expected!", ["data" => $jsonColumn, "row" => json_encode($dataRow)]); $csvRow->setValue($safeColumn, $jsonColumn); } break; } }
public function testArrayOfNull() { $analyzer = new Analyzer($this->getLogger('analyzer', true)); $analyzer->getStruct()->setAutoUpgradeToArray(true); $analyzer->analyze([(object) ['val' => ['stringArr'], 'obj' => [(object) ['key' => 'objValue']]], (object) ['val' => [null], 'obj' => [null]]], 's2null'); $analyzer->analyze([(object) ['val' => ['stringArr'], 'obj' => [(object) ['key' => 'objValue']]], (object) ['val' => [null], 'obj' => [null]]], 'null2s'); self::assertEquals(['s2null' => ['val' => 'arrayOfscalar', 'obj' => 'arrayOfobject'], 's2null.val' => ['data' => 'scalar'], 'null2s' => ['val' => 'arrayOfscalar', 'obj' => 'arrayOfobject'], 'null2s.val' => ['data' => 'scalar'], 's2null.obj' => ['key' => 'scalar'], 'null2s.obj' => ['key' => 'scalar']], $analyzer->getStruct()->getStruct()); }