custom validator in symfony - php

I would like create custom validator for Symfony 1.4, for example check length name. I know that it exist, but i would like own.
I create /myapp/lib/validator/sfValidatorName.class.php
Must be there:
class sfValidatorName extends sfValidatorBase
{
protected function configure($options = array(),
$messages = array()) {
$this->addMessage('invalid', 'Invalid name!');
}
protected function doClean($value) {
}
}
and how can i add for this my function, for example:
if (count($letters) < 3) {
return 'too small';
} else if (count($letters) > 43) {
return 'too long';
}

Open /lib/validator/sfValidatorString.class.php
Model your validator after that one.

Since your example is exactly what sfValidatorString does, why don't you go look at it's source? Basically you just throw a validation error with the relevant error code (eg. invalid, min_length, max_length, ...).
By default any validator has the errors 'invalid' and 'required', but you can add your own with addMessage().
For this specific example, a much smarter choice is to configure or extend sfValidatorString.

Related

Take user input in Yii2 console command

I want to create a console command in Yii2 where I can take the input from the user.
I have looked into the Yii2 documentation here-
http://www.yiiframework.com/doc-2.0/guide-tutorial-console.html
But I could not find anything helpful.
I have also searched on Google and StackOverflow with no luck.
CLI command prompt for any user string:
class CronController extends yii\console\Controller
{
public function actionSendTestmail()
{
$emailTo = \yii\helpers\BaseConsole::input("Recipient email: ");
...
}
}
or just ask for confirmation [yes|no]:
class CronController extends yii\console\Controller
{
public function actionSendTestmail()
{
$emailTo = Yii::$app->params["email.to"];
if(!$this->confirm("Send email to {$emailTo}?")){
exit("Sending email interrupted.\n")
}
...
}
}
Check out yii\helpers\BaseConsole helper class method input().
input('Enter your name');
Will prompt you for your name.
Or you can define arguments for the action method to pass values to the action.
static function actionDoSomething (arg1, arg2, ...);
You can use the method prompt() provided in the yii\console\Controller that calls the yii\helpers\BaseConsole::prompt() and gives you additional control to validate the input too after the user enters or just mark it as required so that it is not empty
$code = $this->prompt(
'Enter 4-Chars-Pin',
[
'required' => true,
'validator' => function ($input, &$error) {
if (strlen($input) !== 4) {
$error = 'The Pin must be exactly 4 chars!';
return false;
}
return true;
},
]
);

Laravel validate request as a whole

I would like to validate given lecture. There are some validation rules but I want to extend it somehow with validation function which takes 3 attributes as arguments and check others lectures in database and return valid if none of lectures overlap. Lectures have start, end DateTime attributes.
Validation function is
private function noOtherLecturesOnGivenTime($start, $end, $hall)
{
if(!$start instanceof Carbon) {
$start = new Carbon($start);
}
if(!$end instanceof Carbon) {
$end = new Carbon($end);
}
if(is_null($hall)) {
return true; // if there is no hall defined, all times are acceptable
}
if(!$hall instanceof Model) {
/** #var Hall $hall */
$hall = Hall::find($hall);
}
$overlappingLectures = $hall->lectures()->get()->filter(function ($lecture) use ($start, $end) {
// (Ts < e) and (Te > s)
return $start->lt($lecture->end) and $end->gt($lecture->start);
});
return $overlappingLectures->count() === 0;
}
I don't know how and where to put this function so Laravel's validator throws exception and I could specify error message with i18n.
Thanks
Check out the documentation about custom validation rules.
From creating the rule to specifiying error messages, there is a full exemple there :
Laravel custom validation rules documentation
For your case, you can fetch the parameters from the request in the validation method.
I think the validation rule will still occur even if other parameters aren't set, don't forget to check if they are in the request

Is there a way to centrally preprocess all logs created by monolog?

I am currently working on a big application that uses monolog for logging and was asked to hide any sensitive information like passwords.
What I tried to do, was extending monolog so it would automatically replace sensitive information with asterics, but even though the data seems to be altered, in the end the original text gets logged.
use Monolog\Handler\AbstractProcessingHandler;
class FilterOutputHandler extends AbstractProcessingHandler
{
private $filteredFields = [];
public function __construct(array $filteredFields = [], $level = Monolog\Logger::DEBUG, $bubble = true)
{
$this->filteredFields = array_merge($filteredFields, $this->filteredFields);
parent::__construct($level, $bubble);
}
protected function write(array $record)
{
foreach($record['context'] as $key=>$value){
if(in_array($key, $this->filteredFields)){
$record['context'][$key] = '*****';
}
}
return $record;
}
}
And when I initialize my logger I do this:
$logger->pushHandler(new FilterOutputHandler(['username', 'password']));
$logger->debug('Sensitive data incoming', ['username'=> 'Oh noes!', 'password'=> 'You shouldn\'t be able to see me!']);
I also tried overridding the handle and processRecord methods of the AbstractProcessingHandler interface but in vain. Can this be done in monolog?
Looks like I was trying the wrong thing.
Instead of adding a new handler to my logger, I had to add a new processor by using the pushProcessor(callable) method.
So, in my specific use case, I can add filters to my context like this:
function AddLoggerFilteringFor(array $filters){
return function ($record) use($filters){
foreach($filters as $filter){
if(isset($record['context'][$filter])){
$record['context'][$filter] = '**HIDDEN FROM LOG**';
}
}
return $record;
};
}
And later I can add filters simply by
(init)
$logger->pushProcessor(AddLoggerFilteringFor(['username', 'password']));
...
(several function definition and business logic later)
$logger->debug('Some weird thing happened, better log it', ['username'=> 'Oh noes!', 'password'=> 'You shouldn\'t be able to see me!']);

Is this correct use of Exception handling in PHP / Symfony2

I'm creating a service to fetch some user data
class ExampleService{
// ...
public function getValueByUser($user)
{
$result = $this->em->getRepository('SomeBundle:SomeEntity')->getValue($user);
if (!$result instanceof Entity\SomeEntity) {
throw new Exception\InvalidArgumentException("no value found for that user");
}
return $result;
}
}
Then in my controller I have
// ...
$ExampleService = $this->get('example_serivce');
$value = $ExampleService->getValueByUser($user);
Should I be using an exception here to indicate that no value was found for that user in the database?
If I should, how do I handle what is returned from $ExampleService->getValueByUser($user) in the controller - let's say I just want to set a default value if nothing is found (or exception returned)
Here is how I do it. Let's use a user service and a controller as an example. It's not an exceptional condition in the service layer — it just returns the result without checking it:
class UserService
{
public function find($id)
{
return $this->em->getRepository('UserBundle:User')->find($id);
}
}
But in the controllers layer I throw an exception if the requested user not found:
class UserController
{
public function viewAction($id)
{
$user = $this->get('user.service')->find($id);
if (!$user) {
throw $this->createNotFoundException(
$this->get('translator')->trans('user.not_found')
);
}
// ...
}
}
Where you want to handle the exception is kind of up to you, however I would handle it in the controller (and throw it in the model). I usually try to call a different template if there is an error so as to avoid a bunch of conditionals, but sometimes you just have to put extra logic in your template instead.
Also, you have to ask yourself if this is really an exceptional condition - it might be easier to return null and handle that return value in your controller. I can't really tell from the data objects (value, service, and user) whether this is something that will happen all the time or not.

Symfony Form: Set default/value on error?

My crazy designer would like the message "Required" displaying (in red) inside a field if the form has been submitted and it is invalid because of an empty field.
The form in question is a login prompt and I'm using a custom class that extends sfGuardFormSignin
I've managed to set the value and add a class with..
$this->widgetSchema['username']->setAttribute('class','red');
$this->widgetSchema['username']->setDefault('Required');
..but how do I do this only when the username field is invalid and because of the Required error?
I assume it's the same for the password field?
Many thanks in advance
EDIT:
Thanks for the advice greg0ire. I've had a play with that but the formatRow method of sfWidgetFormSchemaFormatter doesn't seem to be getting hit. Is this because my form extends sfGuardFormSignin and using the sfGuardAuth plugin?
class FrontendsfGuardFormSignin extends sfGuardFormSignin
{
public function configure()
{
parent::configure();
// This works!
$this->widgetSchema['username']->setLabel('Email');
// I copied this from the link you pasted
$decorator = new myWidgetFormSchemaFormatterCustom($this->getWidgetSchema());
$this->widgetSchema->addFormFormatter('custom', $decorator);
$this->widgetSchema->setFormFormatterName('custom');
}
}
/lib/widget/myWidgetFormSchemaFormatterCustom.class.php
class myWidgetFormSchemaFormatterCustom extends sfWidgetFormSchemaFormatter
{
public function __construct(sfWidgetFormSchema $widgetSchema)
{
parent::__construct($widgetSchema);
}
public function formatRow($label, $field, $errors = array(), $help = '', $hiddenFields = null)
{
// Nothing happens!?
var_dump($errors);
die();
parent::formatRow($label, $field, $errors, $help, $hiddenFields);
}
}
$widget->render(array('value' => $widget->getError()));
Designers have such crazy ideas...
You'll have to write a custom schema formatter to do this. You'll probably have to override the formatRow() method to achieve this.
Analyse the $errors array argument of this method, and if you spot the "Required" error in it, then do your special stuff. You won't need to use the code you posted in your question.

Categories