Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
serkin committed May 30, 2015
2 parents 32675ed + fb34f33 commit 2cc93b2
Show file tree
Hide file tree
Showing 32 changed files with 401 additions and 964 deletions.
16 changes: 16 additions & 0 deletions src/DummyLogger.php
@@ -0,0 +1,16 @@
<?php

namespace Volan;

class DummyLogger extends \Monolog\Logger
{



public function warning($message, array $context = array()){return;}

public function info($message, array $context = array()){return;}



}
97 changes: 61 additions & 36 deletions src/Volan.php
Expand Up @@ -6,7 +6,7 @@

namespace Volan;

use \Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;

class Volan
{
Expand All @@ -18,7 +18,7 @@ class Volan
/**
* @var \Psr\Log\LoggerInterface
*/
private $logger = null;
private $logger;


/**
Expand All @@ -29,7 +29,7 @@ class Volan
private $requiredMode = true;

/**
* If set to false we not check wether field is required or not. Default is true
* If set to false allows excessive keys in array. Default is true
*
* @var bool
*/
Expand Down Expand Up @@ -68,6 +68,9 @@ public function __construct($schema, $strictMode = true)
{
$this->schema = $schema;
$this->strictMode = $strictMode;

$log = new DummyLogger('volan');
$this->setLogger($log);
}

/**
Expand All @@ -85,11 +88,14 @@ public function setLogger(LoggerInterface $logger)
$this->logger = $logger;
}

public function log($message)
/**
* Gets current logger
*
* @return \Psr\Log\LoggerInterface
*/
private function getLogger()
{
if (!is_null($this->logger)):
$this->logger->info($message);
endif;
return $this->logger;
}

/**
Expand All @@ -98,7 +104,11 @@ public function log($message)
*/
private function setError($message, $code)
{
$this->error = ['code' => $code, 'error' => $message];
$this->error = [
'code' => $code,
'error' => $message,
'node' => $this->currentNode
];
}

/**
Expand All @@ -109,21 +119,22 @@ private function setError($message, $code)
public function validate($arr)
{
$returnValue = true;
$this->currentNode = 'root';

try {

if (empty($this->schema['root'])):
throw new \Exception('Sorry no root element in schema', self::ERROR_SCHEMA_HAS_NO_ROOT_ELEMENT);
throw new \Exception('No root element in schema', self::ERROR_SCHEMA_HAS_NO_ROOT_ELEMENT);
endif;

if ($this->isChildElementHasStrictKeys(new CustomArrayObject($this->schema['root']), $arr)):
throw new \Exception("Sorry root element has excessive keys", self::ERROR_NODE_HAS_EXCESSIVE_KEYS);
if ($this->strictMode && $this->isChildElementHasStrictKeys(new CustomArrayObject($this->schema['root']), $arr)):
throw new \Exception("root element has excessive keys", self::ERROR_NODE_HAS_EXCESSIVE_KEYS);
endif;

$this->validateNode('root', new CustomArrayObject($this->schema), $arr);
} catch (\Exception $exc) {
$this->setError($exc->getMessage(), $exc->getCode());
$this->log($exc->getMessage());
$this->getLogger()->warning($exc->getMessage());

$returnValue = false;
}
Expand All @@ -145,7 +156,7 @@ private function validateNode($node, CustomArrayObject $schema, $element = [])
foreach ($nodeSchema->getArrayKeys() as $key):

$this->currentNode = $node.'.'.$key;
$this->log("We in element: {$this->currentNode}");
$this->getLogger()->info("We are in element: {$this->currentNode}");

$nodeData = isset($element[$key]) ? $element[$key] : null;

Expand All @@ -158,19 +169,19 @@ private function validateNode($node, CustomArrayObject $schema, $element = [])
$isRequired = $this->requiredMode ? $validator->isRequired() : false;

if ($isRequired === false && empty($nodeData)):
$this->log("Element: {$this->currentNode} has empty nonrequired data. We skip other check");
$this->getLogger()->info("Element: {$this->currentNode} has empty nonrequired data. We skip other check");
continue;
endif;

$this->validatingExcessiveKeys($validator, new CustomArrayObject($nodeSchema[$key]), $nodeData);

$this->validateField($validator, $nodeData);

$this->validateNestedField($validator, $nodeData);
$this->validateNesting($validator, $nodeData);
$this->validateField($validator, $nodeData);

if ($validator->isNested()):

$this->log("Element: {$this->currentNode} is has children");
$this->getLogger()->info("Element: {$this->currentNode} is has children");

foreach ($nodeData as $record):
$this->validateNode($key, $nodeSchema, $record);
Expand All @@ -180,7 +191,7 @@ private function validateNode($node, CustomArrayObject $schema, $element = [])
$this->validateNode($key, $nodeSchema, $nodeData);
endif;

$this->log("Element: {$this->currentNode} finished checking successfully.");
$this->getLogger()->info("Element: {$this->currentNode} finished checking successfully.");

endforeach;
}
Expand All @@ -197,7 +208,7 @@ private function isChildElementHasStrictKeys(\Volan\CustomArrayObject $nodeSchem

if (!empty($nodeData) && is_array($nodeData)):
$schemaKeys = $nodeSchema->getArrayKeys();
$dataKeys = array_keys($nodeData);
$dataKeys = count(array_filter(array_keys($nodeData), 'is_string')) ? array_keys($nodeData) : [];
$returnValue = (bool) array_diff($dataKeys, $schemaKeys);
endif;

Expand All @@ -209,22 +220,36 @@ private function isChildElementHasStrictKeys(\Volan\CustomArrayObject $nodeSchem
* @param \Volan\CustomArrayObject $schema
* @param mixed $nodeData
*
* @throws \Exception
*/
private function validatingExcessiveKeys(\Volan\Validator\AbstractValidator $validator, CustomArrayObject $schema, $nodeData = null)
{
if (!$validator->isNested() && $this->strictMode && $this->isChildElementHasStrictKeys($schema, $nodeData)):
throw new \Exception("Sorry {$this->currentNode} element has excessive keys", self::ERROR_NODE_HAS_EXCESSIVE_KEYS);
if($this->strictMode === false):
return;
endif;

if (!$validator->isNested()):
$this->validatingChildExcessiveKeys($schema, $nodeData);
endif;

if ($validator->isNested() && $this->strictMode):
if ($validator->isNested()):
foreach ($nodeData as $record):
if ($this->isChildElementHasStrictKeys($schema, $record)):
throw new \Exception("Sorry children of element: {$this->currentNode} has excessive keys", self::ERROR_NODE_HAS_EXCESSIVE_KEYS);
endif;
$this->validatingChildExcessiveKeys($schema, $record);
endforeach;
endif;
}

/**
* @param \Volan\CustomArrayObject $schema
* @param mixed $nodeData
*
* @throws \Exception
*/
private function validatingChildExcessiveKeys($schema, $nodeData)
{
if($this->isChildElementHasStrictKeys($schema, $nodeData)):
throw new \Exception("{$this->currentNode} element has excessive keys", self::ERROR_NODE_HAS_EXCESSIVE_KEYS);
endif;
}

/**
* @param array $node
Expand All @@ -234,10 +259,10 @@ private function validatingExcessiveKeys(\Volan\Validator\AbstractValidator $val
private function validatingTypeField($node)
{
if (empty($node['_type'])):
throw new \Exception("Sorry element: {$this->currentNode} has no compulsory field: _type", self::ERROR_NODE_HAS_NO_FIELD_TYPE);
throw new \Exception("Element: {$this->currentNode} has no compulsory field: _type", self::ERROR_NODE_HAS_NO_FIELD_TYPE);
endif;

$this->log("Element: {$this->currentNode} has field: _type");
$this->getLogger()->info("Element: {$this->currentNode} has field: _type");
}

/**
Expand All @@ -252,10 +277,10 @@ private function validateRequiredField(\Volan\Validator\AbstractValidator $valid
$isRequired = $this->requiredMode ? $validator->isRequired() : false;

if ($isRequired && empty($nodeData)):
throw new \Exception("Sorry {$this->currentNode} element has flag *required*", self::ERROR_REQUIRED_FIELD_IS_EMPTY);
throw new \Exception("{$this->currentNode} element has flag *required*", self::ERROR_REQUIRED_FIELD_IS_EMPTY);
endif;

$this->log('*required* check passed');
$this->getLogger()->info('*required* check passed');
}

/**
Expand All @@ -280,13 +305,13 @@ private function getClassValidator($node)
foreach ($classNames as $className):
if(class_exists($className)):
$validatorClass = new $className();
$this->log("validatot class $className exists");
$this->getLogger()->info("Class validator $className exists");
endif;
endforeach;


if (is_null($validatorClass)):
throw new \Exception("Sorry validator class {$classNames[0]}/{$classNames[1]} not found", self::ERROR_VALIDATOR_CLASS_NOT_FOUND);
throw new \Exception("Class validator {$classNames[0]}/{$classNames[1]} not found", self::ERROR_VALIDATOR_CLASS_NOT_FOUND);
endif;

return $validatorClass;
Expand Down Expand Up @@ -321,7 +346,7 @@ private function getPSRCompatibleClassName($string)
private function validateField(\Volan\Validator\AbstractValidator $validator, $nodeData = null)
{
if ($validator->isValid($nodeData) === false):
throw new \Exception("Sorry {$this->currentNode} element has invalid associated data", self::ERROR_NODE_IS_NOT_VALID);
throw new \Exception("{$this->currentNode} element has invalid associated data", self::ERROR_NODE_IS_NOT_VALID);
endif;
}

Expand All @@ -331,9 +356,9 @@ private function validateField(\Volan\Validator\AbstractValidator $validator, $n
*
* @throws \Exception
*/
private function validateNestedField(\Volan\Validator\AbstractValidator $validator, $nodeData)
private function validateNesting(\Volan\Validator\AbstractValidator $validator, $nodeData)
{
if ($validator->isNested() && !is_array($nodeData[0])):
if ($validator->isNested() && (!isset($nodeData[0]) || !is_array($nodeData[0]))):
throw new \Exception("{$this->currentNode} element supposed to be nested but it is not", self::ERROR_NESTED_ELEMENT_NOT_VALID);
endif;
}
Expand Down
65 changes: 65 additions & 0 deletions tests/fixture.php
@@ -0,0 +1,65 @@
<?php


$schema = [
'root' => [
'title' => [
'_type' => 'required_string'
],
'author' => [
'_type' => 'required_string'
],
'price' => [
'_type' => 'number'
],
'tags' => [
'_type' => 'array'
],
'instock' => [
'_type' => 'required_boolean'
],
'reserved' => [
'_type' => 'boolean'
],
'protagonist' => [
'_type' => 'required_array',
'name' => [
'_type' => 'required_string'
],
],
'comments' => [
'_type' => 'nested_array',
'comment' => [
'_type' => 'required_string'
],
'userid' => [
'_type' => 'required_number'
],
'rating' => [
'_type' => 'number'
]
]
]
];

$arr = [
'title' => 'The Idiot',
'instock' => true,
'author' => 'Leo Tolstoy',
'reserved' => false,
'price' => 60,
'protagonist' => ['name' => 'Lev Nikolayevich Myshkin'],
'tags' => ['novel', 'Fyodor Dostoyevsky'],
'comments' => [
[
'comment' => 'Good book',
'userid' => 1,
'rating' => 10
],
[
'comment' => 'I love it',
'userid' => 2,
'rating' => 10
],
]
];
13 changes: 0 additions & 13 deletions tests/fixture/fixture1.php

This file was deleted.

27 changes: 0 additions & 27 deletions tests/fixture/fixture10.php

This file was deleted.

0 comments on commit 2cc93b2

Please sign in to comment.