1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
| abstract class CSV
{
protected string $delimiter = ',';
protected string $protection = '"';
protected string $escape = '\\';
protected ?int $fieldsNumber = null;
protected ?array $headers = null;
public function setDelimiter(string $delimiter):void {
$this->delimiter = $delimiter;
}
protected function HasHeaders():bool {
return (bool) $this->headers;
}
protected abstract function checkFieldsNumber(int $fieldsNumber):bool;
}
interface ReaderInterface
{
public function getReader();
}
class CSVReader extends CSV implements ReaderInterface
{
protected $handle;
public function __construct($handle)
{
if ( gettype($handle) !== 'resource' || get_resource_type($handle) !== 'stream' )
throw new InvalidArgumentException();
$this->handle = $handle;
}
public function getReader() {
// on détermine le nombre de colonnes d'après l'entête ou la première ligne de donneés
if ( $this->headers ) {
$this->fieldsNumber = count($this->headers);
} else {
if ( false !== $fields = fgetcsv($this->handle, 1024, $this->delimiter) ) {
$this->fieldsNumber = count($fields);
yield $fields;
}
}
while ( false !== $fields = fgetcsv($this->handle, 1024, $this->delimiter) ) {
if ( $this->checkFieldsNumber(count($fields)) ) {
yield $fields;
} else {
throw new Exception('Invalid number of fields');
}
}
}
public function setHeaders() {
if ( $this->handle ) {
if ( false !== $headers = fgetcsv($this->handle, 1024, $this->delimiter) ) {
$this->headers = $headers;
}
}
}
public function getHeaders():?array {
return $this->headers;
}
protected function checkFieldsNumber(int $fieldsNumber):bool {
return $this->fieldsNumber === $fieldsNumber;
}
}
interface ValidatorInterface
{
public function validate($value):bool;
}
class FieldValidator implements ValidatorInterface
{
protected $constraints;
public function __construct($constraints) {
$this->constraints = $constraints;
}
public function validate($value):bool {
foreach ($this->constraints as $constraint) {
if ( $constraint($value) === false ) {
return false;
}
}
return true;
}
}
class RowValidator implements ValidatorInterface
{
protected $validators;
public function __construct(array $validators) {
$this->validators = $validators;
}
public function validate($fields):bool {
foreach ($fields as $k => $field) {
if ( $this->validators[$k]->validate($field) === false ) {
return false;
}
}
return true;
}
}
$data = <<<'EOD'
SESAID;ALTERNATEIDS;PLATFORM
SE100008;(none);Software Engineering
SESA10038;(none);Software Engineering
SESA100675;(none);Software Engineering
SESA101072;(none);Software Engineering
SESA101549;(none);Software Engineering
SESA101659;(none);Software Engineering
SESA101844;(none);Software Engineering
EOD;
$url = 'data:text/plain,' . $data;
if ( false === $handle = fopen($url, 'rb') ) {
throw new Exception('impossible d\'ouvrir le fichier');
}
$reader = new CSVReader($handle);
$reader->setDelimiter(';');
$reader->setHeaders();
$genRow = $reader->getReader();
print_r($reader->getHeaders());
$rowValidator = new RowValidator([
new FieldValidator([
fn($v) => (bool) preg_match('/\ASESA[0-9]{5}\z/', $v) // le résultat doit être un booléen (preg_match renvoie 0)
//fn($v) => (1==1)
]),
new FieldValidator([
fn($v) => (1==0) //cette fonction devrait renvoyer false
]),
new FieldValidator([
fn($v) => (1==1)
])
]); /* le tableau passé à la classe RowValidator contient 3 items qui sont 3 instances de la classe FieldValidator. A chaque instance, je passe un tableau constitué d'un seul item. Pour le premier, c'est l'évaluation d'une regexp ; pour le 2e, une fonction qui retourne toujours false et pour la 3e, une fonction qui retourne toujours true. Bien sûr, c'est que pour le test !*/
$nl = PHP_EOL; // ou '<br>'
$i = 0;
foreach ($genRow as $fields) {
echo "ligne ", $i, $nl;
var_dump($fields);
if ( !$rowValidator->validate($fields) ) {
echo "ligne".$i++." non valide";
} else {
echo "ligne".$i++." valide";
}
echo str_repeat($nl, 2);
} |
Partager