Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Init #1

Merged
merged 25 commits into from
Mar 10, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e0244cf
Init commit
Mar 10, 2024
163c9a9
Refactor UnitFacing rule to accept specific values. Add unit facing o…
Mar 10, 2024
871c935
Refactor CSV and schema file paths in the test cases.
Mar 10, 2024
a40d4cf
Refactor CSV structure definition and validation rules
Mar 10, 2024
14a7c6b
Refactor IsUuid4 class name and add test for IsUuid4 validator.
Mar 10, 2024
08c8596
Add CSV schema examples to README.md and update dependencies in compo…
Mar 10, 2024
a63e1d4
Add spoiler functionality to README.md
Mar 10, 2024
c3382b8
Update readme: Add more descriptive titles for examples and file form…
Mar 10, 2024
8dcaed9
Refactor CSV schema column rules' YAML and JSON representations
Mar 10, 2024
a7fc230
Refactor CSV validation methods
Mar 10, 2024
ae75c74
Refactor CsvFile constructor and add additional methods to ErrorSuite
Mar 10, 2024
bfcbcfa
Add support for rendering errors as a plain list.
Mar 10, 2024
e646c1b
Fix typo in file paths in MiscTest.php tests
Mar 10, 2024
8daa1fe
Validate CSV file by applying schema rules. If errors are found, disp…
Mar 10, 2024
94179dc
Refactor workflows to focus on demos
Mar 10, 2024
f0a9c13
Fix typo in Makefile command and update PHP version to 8.3 in workflo…
Mar 10, 2024
35001b8
Refactor workflow file for better readability and maintenance
Mar 10, 2024
c53f7bf
Refactor Makefile to add support for ANSI output in demo-github task
Mar 10, 2024
c57d003
Refactor makefile build command for consistent output
Mar 10, 2024
56edbc9
Update PHP array format in README and test case for PHP format in Blu…
Mar 10, 2024
ea82d7d
PHPStan fixed!
Mar 10, 2024
b20e4eb
PHPStan fixed!
Mar 10, 2024
8592314
Phan fixed!
Mar 10, 2024
36fa39e
Codestyle!
Mar 10, 2024
7e41368
Codestyle!
Mar 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Refactor CSV validation methods
Refactored CSV validation methods to use ErrorSuite for better error handling and reporting. Updated validation logic for specific rules like min, max, regex, and format to provide more descriptive error messages. Updated the CsvFile's validate method to return an ErrorSuite.
  • Loading branch information
Denis Smet committed Mar 10, 2024
commit a7fc230d36781309783dfbd6fb526a58b25e484b
63 changes: 31 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,41 +155,40 @@ return [
'encoding' => 'utf-8',
'bom' => false,
],
'columns' => [
'columns' => [
[
'name' => 'csv_header_name',
'description' => 'Lorem ipsum',
'rules' =>
[
'not_empty' => true,
'exact_value' => 'Some string',
'allow_values' => ['y', 'n', ''],
'regex' => '/^[\\d]{2}$/',
'min_length' => 1,
'max_length' => 10,
'only_trimed' => true,
'only_lowercase' => true,
'only_uppercase' => true,
'only_capitalize' => true,
'min' => 10,
'max' => 100.5,
'precision' => 2,
'date_format' => 'Y-m-d',
'min_date' => '2000-01-02',
'max_date' => '+1 day',
'is_bool' => true,
'is_int' => true,
'is_float' => true,
'is_ip' => true,
'is_url' => true,
'is_email' => true,
'is_domain' => true,
'is_uuid4' => true,
'is_latitude' => true,
'is_longitude' => true,
'cardinal_direction' => true,
'usa_market_name' => true,
],
'rules' => [
'not_empty' => true,
'exact_value' => 'Some string',
'allow_values' => ['y', 'n', ''],
'regex' => '/^[\\d]{2}$/',
'min_length' => 1,
'max_length' => 10,
'only_trimed' => true,
'only_lowercase' => true,
'only_uppercase' => true,
'only_capitalize' => true,
'min' => 10,
'max' => 100.5,
'precision' => 2,
'date_format' => 'Y-m-d',
'min_date' => '2000-01-02',
'max_date' => '+1 day',
'is_bool' => true,
'is_int' => true,
'is_float' => true,
'is_ip' => true,
'is_url' => true,
'is_email' => true,
'is_domain' => true,
'is_uuid4' => true,
'is_latitude' => true,
'is_longitude' => true,
'cardinal_direction' => true,
'usa_market_name' => true,
],
],
],
];
Expand Down
3 changes: 2 additions & 1 deletion src/Csv/Column.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
namespace JBZoo\CsvBlueprint\Csv;

use JBZoo\CsvBlueprint\Utils;
use JBZoo\CsvBlueprint\Validators\ErrorSuite;
use JBZoo\CsvBlueprint\Validators\Validator;
use JBZoo\Data\Data;

Expand Down Expand Up @@ -104,7 +105,7 @@ public function getInherit(): string
return $this->column->getString('inherit', self::FALLBACK_VALUES['inherit']);
}

public function validate(string $cellValue, int $line): array
public function validate(string $cellValue, int $line): ErrorSuite
{
return (new Validator($this))->validate($cellValue, $line);
}
Expand Down
60 changes: 32 additions & 28 deletions src/Csv/CsvFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
namespace JBZoo\CsvBlueprint\Csv;

use JBZoo\CsvBlueprint\Schema;
use JBZoo\CsvBlueprint\Validators\Error;
use JBZoo\CsvBlueprint\Validators\ErrorSuite;
use League\Csv\ByteSequence;
use League\Csv\Reader as LeagueReader;
use League\Csv\Statement;
Expand All @@ -35,9 +37,9 @@ public function __construct(string $csvFilename, null|array|string $csvSchemaFil
}

$this->csvFilename = \realpath($csvFilename);
$this->schema = new Schema($csvSchemaFilenameOrArray);
$this->structure = $this->schema->getCsvStructure();
$this->reader = $this->prepareReader();
$this->schema = new Schema($csvSchemaFilenameOrArray);
$this->structure = $this->schema->getCsvStructure();
$this->reader = $this->prepareReader();
}

public function getCsvFilename(): string
Expand Down Expand Up @@ -72,11 +74,15 @@ public function getRecordsChunk(int $offset = 0, int $limit = -1): \League\Csv\R
return Statement::create(null, $offset, $limit)->process($this->reader, $this->getHeader());
}

public function validate(bool $quickStop = false): array
public function validate(bool $quickStop = false): ErrorSuite
{
return $this->validateHeader() +
$this->validateEachCell($quickStop) +
$this->validateAggregateRules($quickStop);
$errors = new ErrorSuite();

$errors->addErrorSuit($this->validateHeader())
->addErrorSuit($this->validateEachCell($quickStop))
->addErrorSuit($this->validateAggregateRules($quickStop));

return $errors;
}

private function prepareReader(): LeagueReader
Expand Down Expand Up @@ -105,27 +111,32 @@ private function prepareReader(): LeagueReader
return $reader;
}

private function validateHeader(): array
private function validateHeader(): ErrorSuite
{
$errors = new ErrorSuite();

if (!$this->getCsvStructure()->isHeader()) {
return [];
return $errors;
}

$errorAcc = [];

foreach ($this->schema->getColumns() as $column) {
if ($column->getName() === '') {
$errorAcc[] = "Property \"name\" is not defined for column id={$column->getId()} " .
"in schema: {$this->schema->getFilename()}";
$error = new Error(
'csv_structure.header',
"Property \"name\" is not defined in schema: {$this->schema->getFilename()}",
$column->getHumanName(),
);

$errors->addError($error);
}
}

return $errorAcc;
return $errors;
}

private function validateEachCell(bool $quickStop = false): array
private function validateEachCell(bool $quickStop = false): ErrorSuite
{
$errorAcc = [];
$errors = new ErrorSuite();

foreach ($this->getRecords() as $line => $record) {
$columns = $this->schema->getColumnsMappedByHeader($this->getHeader());
Expand All @@ -135,25 +146,18 @@ private function validateEachCell(bool $quickStop = false): array
continue;
}

$errorAcc = $this->appendErrors($errorAcc, $column->validate($record[$column->getKey()], $line));
if ($quickStop && \count($errorAcc) > 0) {
$errors->addErrorSuit($column->validate($record[$column->getKey()], $line));
if ($quickStop && $errors->count() > 0) {
return $errorAcc;
}
}
}

return $errorAcc;
return $errors;
}

private function validateAggregateRules(bool $quickStop = false): array
private function validateAggregateRules(bool $quickStop = false): ErrorSuite
{
return [];
}

private function appendErrors(array $errorAcc, array $newErrors): array
{
$errorAcc += \array_filter($newErrors);

return $errorAcc;
return new ErrorSuite();
}
}
2 changes: 1 addition & 1 deletion src/Validators/Error.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ final class Error
public function __construct(
private string $ruleCode,
private string $message,
private string $columnName,
private string $columnName = '',
private int $line = 0,
) {
}
Expand Down
92 changes: 92 additions & 0 deletions src/Validators/ErrorSuite.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

/**
* JBZoo Toolbox - Csv-Blueprint.
*
* This file is part of the JBZoo Toolbox project.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT
* @copyright Copyright (C) JBZoo.com, All rights reserved.
* @see https://github.com/JBZoo/Csv-Blueprint
*/

declare(strict_types=1);

namespace JBZoo\CsvBlueprint\Validators;

final class ErrorSuite
{
public const MODE_PLAIN_TEXT = 'plain';

/** @var Error[] */
private array $errors = [];

public function __toString(): string
{
return $this->render(self::MODE_PLAIN_TEXT);
}

public function render(string $mode = self::MODE_PLAIN_TEXT): string
{
if ($this->count() === 0) {
return '';
}

if ($mode === self::MODE_PLAIN_TEXT) {
return $this->renderPlainText();
}

throw new Exception('Unknown error render mode: ' . $mode);
}

/**
* @return Error[]
*/
public function getErrors(): array
{
return $this->errors;
}

public function addError(null|Error $error): self
{
if ($error === null) {
return $this;
}

$this->errors[] = $error;
return $this;
}

public function addErrorSuit(null|self $errorSuite): self
{
if ($errorSuite === null) {
return $this;
}

$this->errors = \array_merge($this->getErrors(), $errorSuite->getErrors());
return $this;
}

private function renderPlainText(): string
{
$result = [];

foreach ($this->errors as $error) {
$result[] = (string)$error;
}

return \implode("\n", $result);
}

public function count(): int
{
return \count($this->errors);
}

public function get(int $index): ?Error
{
return $this->errors[$index] ?? null;
}
}
6 changes: 3 additions & 3 deletions src/Validators/Ruleset.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ public function createRule(string $ruleName, null|array|bool|float|int|string $o
throw new Exception("Rule \"{$ruleName}\" not found. Expected class: {$classname}");
}

public function validate(?string $cellValue, int $line): array
public function validate(?string $cellValue, int $line): ErrorSuite
{
$errors = [];
$errors = new ErrorSuite();

foreach ($this->rules as $rule) {
$errors[] = $rule->validate($cellValue, $line);
$errors->addError($rule->validate($cellValue, $line));
}

return $errors;
Expand Down
2 changes: 1 addition & 1 deletion src/Validators/Validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public function __construct(Column $column)
/**
* @return Error[]
*/
public function validate(?string $cellValue, int $line): array
public function validate(?string $cellValue, int $line): ErrorSuite
{
return $this->ruleset->validate($cellValue, $line);
}
Expand Down
Loading