Commit 16dfe17b authored by Avris's avatar Avris

Merge branch 'v4.0' into 'master'

v4.0

See merge request !2
parents 39090659 fc9264d4
Pipeline #16673593 passed with stage
in 7 seconds
tests/_output/*
vendor/*
.idea/*
/.idea/*
**/.DS_Store
/vendor/*
/tests/_output/*
phpunit:
ci_tests:
script:
- composer install --dev
- vendor/bin/phpunit
- vendor/bin/phpcs --standard=PSR2 src/
This diff is collapsed.
{
"name": "avris/micrus-forms",
"name": "avris/forms",
"type": "library",
"description": "Forms module for the Micrus Framework",
"description": "Simple forms abstraction",
"license": "MIT",
"homepage": "https://micrus.avris.it",
"authors": [{
"name": "Avris",
"email": "andre@avris.it",
"homepage": "https://avris.it"
}],
"require": {
"avris/micrus-localizator": "^3.0"
"avris/container": "^1.0",
"avris/localisator": "^4.0",
"avris/http": "^4.0",
"twig/twig": "^2.4"
},
"require-dev": {
"avris/micrus": "^3.0",
"phpunit/phpunit": "~4.8",
"symfony/var-dumper": "^3.2"
"symfony/var-dumper": "^4.0",
"phpunit/phpunit": "^6.4",
"squizlabs/php_codesniffer": "^3.2",
"avris/micrus": "^4.0-dev"
},
"suggest": {
"avris/micrus": "Web framework that this library was created for, provides abstraction for UploadedFile"
"avris/micrus": "Web framework that this library was created for"
},
"autoload": {
"psr-4": { "Avris\\Micrus\\Forms\\": "src" }
"psr-4": { "Avris\\Forms\\": "src" }
},
"autoload-dev": {
"psr-4": { "Avris\\Micrus\\Forms\\": "tests" }
"psr-4": { "Avris\\Forms\\": "tests" }
}
}
This diff is collapsed.
instanceof:
Avris\Forms\Widget\Widget:
public: true
factory: true
Avris\Forms\:
dir: '%MODULE_DIR%/src/'
exclude:
- '#^Assert/#'
- '#^Style/#'
Avris\Forms\Security\CsrfProviderInterface: 'Avris\Forms\Security\CsrfProvider'
Avris\Forms\Security\CsrfProvider:
public: true
Avris\Forms\WidgetFactory:
public: true
<?php
namespace Avris\Micrus\Forms;
namespace Avris\Forms;
use Avris\Bag\BagHelper;
class FormObject
class Accessor
{
/** @var object */
protected $original;
protected $object;
/**
* @param object|null $object
*/
public function __construct($object = null)
{
$this->original = $object ?: new \stdClass();
$this->object = $object ?: new \stdClass();
}
/**
* @return object
*/
public function getOriginal()
public function getObject()
{
return $this->original;
return $this->object;
}
/**
* @param string $key
* @param mixed $value
*/
public function __set($key, $value)
public function __set(string $key, $value)
{
if ($this->hasAccessor('set', $key)) {
$this->callAccessor('set', $key, $value);
......@@ -43,7 +39,7 @@ class FormObject
return;
}
$this->original->$key = $value;
$this->object->{$key} = $value;
return;
}
......@@ -53,7 +49,7 @@ class FormObject
$staying = array_uintersect(
BagHelper::toArray($current),
BagHelper::toArray($value),
function($a, $b) {
function ($a, $b) {
return strcmp(is_object($a) ? spl_object_hash($a) : $a, is_object($b) ? spl_object_hash($b) : $b);
}
);
......@@ -71,11 +67,7 @@ class FormObject
}
}
/**
* @param string $key
* @return mixed
*/
public function __get($key)
public function __get(string $key)
{
if ($this->hasAccessor('get', $key)) {
return $this->callAccessor('get', $key);
......@@ -93,84 +85,39 @@ class FormObject
return $this->callGenericAccessor('get', $key);
}
return isset($this->original->$key) ? $this->original->$key : null;
return isset($this->object->{$key}) ? $this->object->{$key} : null;
}
/**
* @return string
*/
public function getName()
protected function hasAccessor(string $type, string $key): bool
{
$class = get_class($this->original);
if (substr($class, 0, 10) == 'App\Model\\') {
$class = substr($class, 10);
}
return str_replace('\\', '_', $class);
return method_exists($this->object, $type . ucfirst($key));
}
/**
* @param string $type
* @param string $key
* @return bool
*/
protected function hasAccessor($type, $key)
protected function callAccessor(string $type, string $key, $value = null)
{
return method_exists($this->original, $type . ucfirst($key));
return call_user_func([$this->object, $type . ucfirst($key)], $value);
}
/**
* @param string $type
* @param string $key
* @param mixed|null $value
* @return mixed
*/
protected function callAccessor($type, $key, $value = null)
protected function hasGenericAccessor(string $type): bool
{
return call_user_func([$this->original, $type . ucfirst($key)], $value);
return method_exists($this->object, $type);
}
/**
* @param string $type
* @return bool
*/
protected function hasGenericAccessor($type)
protected function callGenericAccessor(string $type, string $key, $value = null)
{
return method_exists($this->original, $type);
return call_user_func([$this->object, $type], $key, $value);
}
/**
* @param string $type
* @param string $key
* @param mixed|null $value
* @return mixed
*/
protected function callGenericAccessor($type, $key, $value = null)
public static function get($object, string $key)
{
return call_user_func([$this->original, $type], $key, $value);
}
/**
* @param object $object
* @param string $key
* @return mixed
*/
public static function get($object, $key)
{
$formObject = new FormObject($object);
$formObject = new Accessor($object);
return $formObject->{$key};
}
/**
* @param object $object
* @param string $key
* @param mixed $value
* @return FormObject
*/
public static function set($object, $key, $value)
public static function set($object, string $key, $value): Accessor
{
$formObject = new FormObject($object);
$formObject = new Accessor($object);
$formObject->{$key} = $value;
return $formObject;
......
<?php
namespace Avris\Forms\Assert;
abstract class AbstractDateTime extends Assert
{
const FORMATS = [''];
public function validate($value): bool
{
$value = str_replace('T', ' ', $value);
try {
$obj = new \DateTime($value);
} catch (\Exception $e) {
return false;
}
foreach (static::FORMATS as $format) {
if ($obj->format($format) === $value) {
//dump($format, $obj->format($format), $value, '----');
return true;
}
}
return false;
}
}
<?php
namespace Avris\Micrus\Forms\Assert;
namespace Avris\Forms\Assert;
abstract class Assert
{
/** @var string */
protected $message;
/** @var string|null */
private $message;
public function __construct($message = false)
public function __construct(?string $message = null)
{
$this->message = $message;
}
/**
* @param $value
* @return true|string (returns true when valid, string with error message otherwise)
*/
abstract public function validate($value);
abstract public function validate($value): bool;
/**
* @return array
*/
public function getHtmlAttributes()
public function getHtmlAttributes(): array
{
return [];
}
/**
* @param string $value
* @return bool
*/
public static function isEmpty($value)
public static function isEmpty($value): bool
{
return $value === "" || $value === null || $value === false ||
(is_array($value) && !count($value));
return $value === "" || $value === null || $value === false || (is_array($value) && !count($value));
}
/**
* @return string
*/
public function getName()
public function getName(): string
{
return str_replace('\\', '.', preg_replace('#^.*\\\\Assert\\\\(.*)#U', '$1', get_class($this)));
return str_replace('\\', '.', get_class($this));
}
/**
* @return array
*/
public function getReplacements()
public function getMessage(): string
{
return $this->message ?: 'assert:' . $this->getName();
}
public function getReplacements(): array
{
return [];
}
......
<?php
namespace Avris\Forms\Assert;
final class Callback extends Assert
{
/** @var callable */
private $callback;
public function __construct(callable $callback, ?string $message = null)
{
$this->callback = $callback;
parent::__construct($message);
}
public function validate($value): bool
{
return call_user_func($this->callback, $value);
}
}
<?php
namespace Avris\Micrus\Forms\Assert;
namespace Avris\Forms\Assert;
class Choice extends Assert
final class Choice extends Assert
{
/** @var array */
protected $choices;
private $choices;
/** @var bool */
protected $multiple;
/**
* @param array $choices
* @param bool $multiple
* @param string|false $message
*/
public function __construct($choices, $multiple, $message = false)
private $multiple;
public function __construct(array $choices, bool $multiple, ?string $message = null)
{
$this->choices = $choices;
$this->multiple = $multiple;
parent::__construct($message);
}
public function validate($value)
public function validate($value): bool
{
if (!$this->multiple && is_array($value)) {
return $this->message;
return false;
}
if ($this->multiple && !is_array($value)) {
return $this->message;
return false;
}
if (!is_array($value)) {
......@@ -38,7 +33,7 @@ class Choice extends Assert
$allowed = array_keys($this->choices);
foreach ($value as $singleValue) {
if (!in_array($singleValue, $allowed)) {
return $this->message;
return false;
}
}
......
<?php
namespace Avris\Micrus\Forms\Assert;
namespace Avris\Forms\Assert;
class Contains extends Assert
final class Contains extends Assert
{
/** @var string */
protected $required;
private $required;
public function __construct($required, $message = false)
public function __construct($required, ?string $message = null)
{
$this->required = $required;
parent::__construct($message);
}
/**
* @param $value
* @return true|string (returns true when valid, string with error message otherwise)
*/
public function validate($value)
public function validate($value): bool
{
return mb_strpos($value, $this->required) === false ? $this->message : true;
return mb_strpos($value, $this->required) !== false;
}
public function getReplacements()
public function getReplacements(): array
{
return ['%value%' => $this->required];
}
......
<?php
namespace Avris\Micrus\Forms\Assert;
use Avris\Micrus\Model\User\UserInterface;
use Avris\Micrus\Tool\Security\CryptInterface;
use Avris\Micrus\Tool\Security\SecurityManager;
class CorrectPassword extends Assert implements IsRequired
{
/** @var callable */
protected $callback;
/** @var CryptInterface */
protected $crypt;
public function __construct($callback, CryptInterface $crypt, $message = false)
{
$this->callback = $callback;
$this->crypt = $crypt;
parent::__construct($message);
}
public function validate($value)
{
/** @var UserInterface $dbUser */
$dbUser = call_user_func($this->callback);
if (!$dbUser) {
return $this->message;
}
$auths = $dbUser->getAuthenticators(SecurityManager::AUTHENTICATOR_PASSWORD);
foreach ($auths as $auth) {
if ($this->crypt->validate($value, $auth->getPayload())) {
return true;
}
}
return $this->message;
}
}
<?php
namespace Avris\Micrus\Forms\Assert;
namespace Avris\Forms\Assert;
class Csrf extends Assert implements IsRequired
final class Csrf extends Assert implements IsRequired
{
public function validate($value)
/** @var string */
private $token;
public function __construct(string $token, ?string $message = null)
{
$this->token = $token;
parent::__construct($message);
}
public function validate($value): bool
{
return $value === $_SESSION['_csrf'] ? true : $this->message;
return $value === $this->token;
}
}
<?php
namespace Avris\Micrus\Forms\Assert;
namespace Avris\Forms\Assert;
class Date extends Assert
final class Date extends AbstractDateTime
{
public function validate($value)
{
try {
$obj = new \DateTime($value);
} catch (\Exception $e) {
return $this->message;
}
if ($obj->format('Y-m-d') !== $value) {
return $this->message;
}
return true;
}
const FORMATS = ['Y-m-d'];
public function getHtmlAttributes()
public function getHtmlAttributes(): array
{
return ['pattern="^\d{4}-\d{2}-\d{2}$"'];
return ['pattern' => '^\d{4}-\d{2}-\d{2}$'];
}
}
<?php
namespace Avris\Micrus\Forms\Assert;
namespace Avris\Forms\Assert;
class DateTime extends Assert
final class DateTime extends AbstractDateTime
{
public function validate($value)
{
$value = str_replace('T', ' ', $value);
try {
$obj = new \DateTime($value);
} catch (\Exception $e) {
return $this->message;
}
if ($obj->format('Y-m-d H:i') !== $value && $obj->format('Y-m-d H:i:s') !== $value) {
return $this->message;
}
return true;
}
const FORMATS = ['Y-m-d H:i', 'Y-m-d H:i:s'];
public function getHtmlAttributes()
public function getHtmlAttributes(): array
{
return [
'pattern="^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$"',
];
return ['pattern' => '^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$'];
}
}
<?php
namespace Avris\Micrus\Forms\Assert;
namespace Avris\Forms\Assert;
class Email extends Assert
final class Email extends Assert
{
public function validate($value)
public function validate($value): bool
{
return filter_var($value, FILTER_VALIDATE_EMAIL) ? true : $this->message;
return filter_var(strtolower(trim($value)), FILTER_VALIDATE_EMAIL);
}
}
<?php
namespace Avris\Micrus\Forms\Assert\File;
namespace Avris\Forms\Assert\File;
use Avris\Micrus\Controller\Http\UploadedFile;
use Avris\Micrus\Forms\Assert\Assert;
use Avris\Bag\BagHelper;
use Avris\Bag\Set;
use Avris\Http\Request\UploadedFile;
use Avris\Forms\Assert\Assert;
class Extension extends Assert
final class Extension extends Assert
{
protected $extension;
/** @var Set|string[] */
private $extension;
public function __construct($extension, $message = false)
public function __construct($extension, ?string $message = null)
{
$this->extension = is_array($extension) ? $extension : [$extension];
$this->message = $message;
$this->extension = new Set(BagHelper::toArray($extension), 'strtolower');
parent::__construct($message);
}