i have created a custom validator but when I want to use it, it seems that it is never executed!
the validator :
class sfTestUrlValidator extends sfValidatorUrl {
public function initialize($context, $parameters = null) {
// Initialize parent
parent::initialize($context);
}
public function execute(&$value, &$error) {
if($value == "http://www.librosweb.es/")
{
//$error = "noooooooooooooo";
return true;
}
else return false;
}
}
in the configure method of a form, i do like that :
public function configure() {
.....
....
'url' => new sfTestUrlValidator(),
You need to override sfValidatorBase::doClean method and not some not-existent execute method and throw exception intead of returning true/false. Have a look at any validator class, e.g. sfValidatorString. However in your case, I would simply use sfValidatorChoice with one choice
public function configure()
{
'url' => new sfValidatorChoice(array('choices' => array(
'your.website.url',
)));
}
Related
Is there a way to create a new instance of a service and adding constructor parameters? I am a bit new to depency injection, and I find I can only add services as constructor parameters and not runtime variables through a factory.
The code I have looks similar to this:
Class MyService
{
private $name;
private $active;
public function __construct($name,$active)
{
$this->name = $name;
$this->active = $active;
}
}
$myService = $this->getServiceLocator()->get('MyService')
Yes there is a way by using the MutableCreationOptionsTrait trait in your factory.
class YourServiceFactory implements FactoryInterface, MutableCreationOptionsInterface
{
use MutableCreationOptionsTrait;
public function createService(ServiceLocatorInterface $serviceLocator)
{
if (isset($this->creationOptions['name'])) {
// do something with the name option
}
if (isset($this->creationOptions['active'])) {
// do something with the active option
}
$yourService = new YourService(
$this->creationOptions['active'],
$this->creationOptions['name']
);
return $yourService;
}
}
The above shown code implements the trait for creation options. With this trait you can handle an array of options in your factory. Call your service like in the following code.
$yourService = $this->getServiceLocator()->get(YourService::class, [
'active' => true,
'name' => 'Marcel',
]);
Easy as pie. ;)
Let's say your service exists:
Class MyService
{
private $name;
private $active;
public function __construct($name,$active)
{
$this->name = $name;
$this->active = $active;
}
}
If instead of ->get()'ing it, you could ->build() it :)
class SomeFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
return $container->build(MyService::class, ['name' => "Foo", 'active' => true]);
// Line below works as well, using a variable requested name, handy for an AbstractFactory of some kind (e.g. one that creates different adapters in the same way with same params)
// return $container->build($requestedName, ['name' => "Foo", 'active' => true]);
}
}
Check out the ServiceManager build() function
Note: Not sure since when it's present, this works in higher versions of ZF2 and all of ZF3.
Note 2: Both get() and build() call function doCreate(). Function declaration:
private function doCreate($resolvedName, array $options = null)
get() does: $object = $this->doCreate($name);
build() does: return $this->doCreate($name, $options);
My custom validation request:
<?php
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\Validator;
class AccountPostRequest extends Request
{
public function authorize() {
return true;
}
public function rules() {
return [
'username' => 'required|alpha_dash'
];
}
public function message() {
return [
'username.required' => 'input your email',
'username.alpha_dash' => 'email format error'
];
}
protected function formatErrors(Validator $validator) {
return $validator->errors()->all();
}
//here is my question, how to invoke this callback when the validation fails,
//or has any other function like the "before" or "after" filters
protected function callback(Validator $validator) {
if ($validator->fails()) {
//do some thing
} else {
//do some thins
}
}
}
?>
My controller:
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests\AccountPostRequest;
class AccountController extends Controller
{
public function login(AccountPostRequest $request) {
//...
}
}
As you know, if the request validate failed, it will not continue to execute the login function of AccountController.
My question is how to invoke the callback when the validation fails, or has any other function like the "before" or "after" filters?
All form request that are validated are going through a pipeline in Illuminate\Foundation\Http\FormRequest which uses a trait called Illuminate\Validation\ValidatesWhenResolvedTrait. This class has contains all the classes you may want to modify and overwrite.
For example, you can simply copy and paste the failedValidation method and customize it.
/**
* Handle a failed validation attempt.
*
* #param \Illuminate\Contracts\Validation\Validator $validator
* #return mixed
*/
protected function failedValidation(Validator $validator)
{
// Do something awesome...
}
I'v creatated a custom validator:
class MyValidator extends AbstractValidator
{
const ERROR_CONST = 'error';
protected $dbAdapter;
protected $messageTemplates = array(
self::ERROR_CONST => "Error msg for '%value%'."
);
public function __construct($dbAdapter)
{
$this->dbAdapter = $dbAdapter;
}
public function isValid($value, $context = null)
{
$this->setValue($value);
/**
* Do validation against db
*/
if(/* Not valid */){
$this->error(self::ERROR_CONST);
return false;
}
return true;
}
}
The validation work, I've been able to test it. What doesn't work is the output of the error message using
echo $this->formElementErrors($form->get('action'));
All that is outputted is an empty UL. Is this a translator issue? When I do a get_class on $this->getTranslator() in the validator I get the validator class name. When I var_dump $this->getTranslator() it outputs null. Do I need to set a translator for this to work and where would be the best place to set that translator so that it's system wide for my own validators?
Because you define a __construct method for your validator class, the parent __construct is not implicitly called:
http://php.net/manual/en/language.oop5.decon.php (see the note)
You should modify your __construct method:
public function __construct($dbAdapter)
{
$this->dbAdapter = $dbAdapter;
//parent::__construct($options);
parent::__construct(null); // or (void)
}
As you can see, $messageTemplates and $messageVariables are "loaded" from AbstractValidator::__construct, for being used in some methods ( error included):
https://github.com/zendframework/zf2/blob/master/library/Zend/Validator/AbstractValidator.php#L73-L79
Maybe you forgot to add messageVariables ?
/**
* Message variables
* #var array
*/
protected $messageVariables = array(
'value' => 'value',
);
I have a some view helpers throwing exceptions on error. That's ok for development, but for production I would like to configure PhpRenderer to catch and log the exception without braking the hole view file to render - simply return nothing.
The PhpRenderer has the method:
public function __call($method, $argv)
{
if (!isset($this->__pluginCache[$method])) {
$this->__pluginCache[$method] = $this->plugin($method);
}
if (is_callable($this->__pluginCache[$method])) {
return call_user_func_array($this->__pluginCache[$method], $argv);
}
return $this->__pluginCache[$method];
}
Is it enough to overwrite this method?
How can I replace the PhpRenderer with my own?
You can do it by writing your own view strategy.
First, register your new strategy in the configuration.
return array(
'factories' => array(
'MyStrategy' => 'Application\ViewRenderer\StrategyFactory',
)
'view_manager' => array(
'strategies' => array(
'MyStrategy'
),
),
);
Then, create your own strategy
namespace Application\ViewRenderer;
use Zend\View\Strategy\PhpRendererStrategy;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\FactoryInterface;
class StrategyFactory implements FactoryInterface
{
public function createService (ServiceLocatorInterface $serviceLocator)
{
$renderer = new Renderer ();
return new Strategy ($renderer);
}
}
and renderer.
namespace Application\ViewRenderer;
use Zend\View\Renderer\PhpRenderer;
class Renderer extends PhpRenderer
{
public function render($nameOrModel, $values = null) {
// this is just an example
// the actual implementation will be very much like in PhpRenderer
return 'x';
}
}
I am trying to setup ZfcUser to authenticate with a fallback to LDAP. My zfcuser.global.php contains:
'auth_adapters' => array(
100 => 'ZfcUser\Authentication\Adapter\Db',
99 => 'ZfcUser\Authentication\Adapter\Ldap',
),
I have created an Ldap.php as an AbstractAdapter with the following setup. I have eliminated function code for brevity:
namespace ZfcUser\Authentication\Adapter;
use DateTime;
use Zend\Authentication\Result as AuthenticationResult;
use Zend\ServiceManager\ServiceManagerAwareInterface;
use Zend\ServiceManager\ServiceManager;
use Zend\Session\Container as SessionContainer;
use ZfcUser\Authentication\Adapter\AdapterChainEvent as AuthEvent;
use ZfcUser\Mapper\User as UserMapperInterface;
use ZfcUser\Options\AuthenticationOptionsInterface;
class Ldap extends AbstractAdapter implements ServiceManagerAwareInterface
{
protected $mapper;
protected $serviceManager;
protected $options;
public function authenticate(AuthEvent $e)
{
...
}
public function getMapper()
{
...
}
public function setMapper(UserMapperInterface $mapper)
{
...
}
public function getServiceManager()
{
return $this->serviceManager;
}
public function setServiceManager(ServiceManager $serviceManager)
{
$this->serviceManager = $serviceManager;
}
public function setOptions(AuthenticationOptionsInterface $options)
{
$this->options = $options;
}
public function getOptions()
{
...
}
}
I have also included it as invokable in the Module.php file:
public function getServiceConfig()
{
return array(
'invokables' => array(
'ZfcUser\Authentication\Adapter\Db' => 'ZfcUser\Authentication\Adapter\Db',
'ZfcUser\Authentication\Adapter\Ldap' => 'ZfcUser\Authentication\Adapter\Ldap',
...
),
...
}
If I flip the priority values it changes who can log in. Whichever adapter is executed first allows logins but the other adapter never gets used. Anyone know how to make ZfcUser fall back to the next adapter if the first one fails?
Issue fixed here https://github.com/SocalNick/ScnSocialAuth/issues/123
For me I just i followed matwright(github) response (See https://github.com/matwright/ScnSocialAuth) so I replace two files :
socalnick/src/ScnSocialAuth/Controller/Plugin/ScnSocialAuthProvider.php by ScnSocialAuthProvider.php
socalnick/src/ScnSocialAuth/Controller/UserController.php by UserController.php
And in zfcuser.global.php :
'auth_adapters' => array(
100 => 'ZfcUser\Authentication\Adapter\Db',
),
Hope this help...