FluentValidation allow null OR specify length? - fluentvalidation

I have a rule like this:
RuleFor(m => m.Title).Length(1, 75);
However, if the Title is null, I still get the validation stating the Title length must be between 1 and 75 characters, you entered 0.
How can I change the rule so it allows for null title, but if one is specified it must be between 1 and 75 characters? Thanks.

I'm working on a bit of an assumption here, but I'm guessing your title isn't set to null but to string.Empty. You can add particular clauses to any rule by doing the following:
public class Thing
{
public string Title { get; set; }
}
public class ThingValidator : AbstractValidator<Thing>
{
public ThingValidator()
{
this.RuleFor(s => s.Title).Length(1, 75).When(s => !string.IsNullOrEmpty(s.Title));
}
}

As suggested by Yannick Meeus in above post, we need to add 'When' condition to check for not null.
It resolved the issue.
Here I wanted to allow Phone number to be null, but if specified then it should contain ONLY digits.
RuleFor(x => x.PhoneNumber).Must(IsAllDigits).When(x => !string.IsNullOrEmpty(x.AlternateNumber)).WithMessage("PhoneNumber should contain only digits");

Related

phalcon resultset complex direct use

I have two tables and I am using phalcon's phql to join them.
In my controller i have:
$oBuilder = $this->modelsManager->createBuilder();
$oBuilder->columns(['Tabone.*', 'Tabtwo.*']);
$oBuilder->from(['Tabone']);
$oBuilder->join('Tabtwo', 'Tabone.id = Tabtwo.id');
$oBuilder->where('Tabone.id = 1');
$aRecords = $oBuilder->getQuery()->execute();
/** #var Phalcon\Mvc\Model\Resultset\Complex $aRecords */
//this doesnt work as expected
$aRecords[0]->tabone->setVal(2);
echo "2 != ".$aRecords[0]->tabone->getVal()."<br>";
echo get_class($aRecords[0]->tabone).'<br>';
//this works as expected
$aRecords->getFirst()->tabone->setVal(2);
echo "2 == ".$aRecords->getFirst()->tabone->getVal()."<br>";
So, with the Phalcon's Complex Traversable resultset I am able to set properties using :
$resultset->getFirst()->tabone->setVal(2);
echo $resultset->getFirst()->tabone->getVal();
But when i try :
echo get_class($aRecords[0]->tabone); // Says tabone
$resultset[0]->tabone->setVal(2);
echo $resultset[0]->tabone->getVal();
the value remains unchanged. even though $aRecords[0]->tabone is the class Tabone.
These are my models
class Tabone extends \Phalcon\Mvc\Model
{
public $id;
public $val;
public function columnMap() {
return array( 'id' => 'id', 'val' => 'val' );
}
public function setVal($val) { $this->val = $val; }
public function getVal() { return $this->val; }
}
class Tabtwo extends \Phalcon\Mvc\Model
{
public $id;
public function columnMap() {
return array( 'id' => 'id' );
}
}
these are the mysql tables and values
CREATE TABLE tabone (
id INT(11) NOT NULL AUTO_INCREMENT,
val INT(11) NOT NULL DEFAULT '0',
PRIMARY KEY (id)
);
CREATE TABLE tabtwo (
id INT(11) NOT NULL,
PRIMARY KEY (id)
);
INSERT INTO tabone (id, val) VALUES (1, 1);
INSERT INTO tabtwo (id) VALUES (1);
Why are the setters/getters no working when using [0] ?
Am i doing something i shouldn't ? ...
because it is how it works. you have methods for these things available like:
offsetGet() // Gets row in a specific position of the resultset
getFirst() // Get first row in the resultset
getLast() // Get last row in the resultset
all methods are here: http://docs.phalconphp.com/en/latest/api/Phalcon_Mvc_Model_Resultset_Complex.html
it's good practice to not use array's key, to keep it simple imagine this:
you are using setters & getters, instead simply setting var's value. But when you want to implement new validation for some input field, you have to go through all the code where you set value, not only just edit your setter. i believe it has some same logic going on here, but i am not developing core of the phalcon, i if you want to get more details you should go check their C code here: https://github.com/phalcon/cphalcon
With information found on:
http://forum.phalconphp.com/discussion/945/why-properties-of-models-are-lost-
(...) when a resultset is traversed, only just one record is kept in memory,
if you modify a record changes will lost, because the record is freed
once it is not used anymore. This scheme is very efficient if you are
traversing big resultsets (...)
and on
Scala: What is the difference between Traversable and Iterable traits in Scala collections?
(...) complying with the Traversable interface does not require
keeping state
So, the reason why [0] does not set properties is because traversable means just
that, it only traverses the object, any values set directly in the traversed object
will be lost, because the object state is not kept.
This makes perfect sense especially when you are talking about large result sets
as it will save tons of memory.

How can I validate a currency field?

I have an ASP.NET MVC-4 application with this currency field:
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:c}", ConvertEmptyStringToNull = true)]
[DataType(DataType.Currency)]
public decimal? Price { get; set; }
This is the corresponding part in my view:
#Html.EditorFor(model => model.Price)
#Html.ValidationMessageFor(model => model.Price)
If the price is 100 Euro the text field in the view shows:
100,00 €
This is nice.
But I am having problems as soon as I try to do a Postback. The validator pops up and says that the price field needs to be a number.
I can only fix this if (1) I delete the € symbol and (2) replace the decimal separator (replace comma with a dot).
If there is no better solution, I guess I could change the DataFormatString = "{0:F2}" in order to avoid the currency symbol.
But how do I make the validator accept the comma as decimal separator instead of the (American) dot?
Thanks for your help, guys!
So, I was able to solve my problem with jQuery's Globalization plugin from http://github.com/jquery/globalize.
I added the following files to my /scripts folder:
/scripts/globalize.js
/scripts/cultures/globalize.cultures.js
/sctipts/cultures/globalize.culture.de-DE.js
In BundleConfig.cs:
bundles.Add(new ScriptBundle("~/bundles/scripts/globalization").Include(
"~/Scripts/globalize*",
"~/Scripts/cultures/globalize*"));
In _Layout.cshtml:
#Scripts.Render("~/bundles/scripts/globalization")
and in the script section of _Layout.cshtml:
$.validator.methods.number = function (value, element) {
return this.optional(element) || !isNaN(Globalize.parseFloat(value));
}
$.validator.methods.range = function (value, element, param) {
return this.optional(element) || (Globalize.parseFloat(value) >= param[0] && Globalize.parseFloat(value) <= param[1]);
}
However, I couldn't make the currency symbol to work with the client validation, so I also changed the data annotation as follows:
[DisplayFormat(ApplyFormatInEditMode = false, DataFormatString = "{0:c}", ConvertEmptyStringToNull = true)]
But that was it. No other changes necessary. I can now enter values like "1,49" or "18,77" and everything gets stored properly in my database.

Remove default 0 from numeric textbox

My model has an EditorFor that binds to a not null numeric field in a database. I wish to keep this field blank so that users can enter or scan numbers into the field. Unfortunately, it defaults to a 0. Is there an easy way to remove the 0 while keeping the field not null?
#Html.EditorFor(model => model.RackNumber, new { id = "RackNumber"})
Change model property type to nullable: public int? RackNumber {get;set;}
You can provide the Value attribute like this:
#Html.EditorFor(model => model.RackNumber, new { Value = Model.RackNumber == 0 ? "" : Model.RackNumber.ToString(), id = "RackNumber"})

limit email domain - vaidation yii

I have email field in signup form ,
I want to validate email domain with database e.g
Email adress is : example#work.com or etc#etc.com
Now I want validate that work.com or etc.com is listed in db or not , if not then it should not be vaidate.!
Can Anyone help me with this ?
Code:
public function validate($attributes = null, $clearErrors = true) {
parent::validate($attributes, $clearErrors);
if (!$this->hasErrors('email')) {
$a = explode('#', $this->email);
if (isset($a[1])) {
$record = AllowedDomains::model()->findByAttributes(array('domain'=>$a[1]));
if ($record === null) {
$this->addError('email', "This domain isn't allowed");
}
}
}
return !$this->hasErrors();
}
Notes:
put this code in the model
email - the field holding the email address
AllowedDomains - the CActiveRecord of the table that holds the allowed domains
domain - replace with the correct database field
don't forget to add the e-mail validator in the rules() function. This will filter out invalid email addresses and the above code will not run if something's wrong
You could accomplish this by adding a custom yii validator in the rules section of your Model. Here is some example code:
public $email; // This is the field where the email is stored
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
return array(
array('email', 'checkDomain'),
);
}
Afterwards, you can add the custom validation function
public function checkDomain($attribute,$params)
{
$sEmailDomain = substr(strrchr($this->email, "#"), 1);
// Check if the domain exists
...
// If the domain exists, add the error
$this->addError('email', 'Domain already exists in the database');
}
More information can be found here: http://www.yiiframework.com/wiki/168/create-your-own-validation-rule/

NHibernate does not filter data base on COORECT TYPE of meta data

I have an interface (IContactable) which is realizing by 3 classes : Person, Department, RestUnit
public interface IContactable
{
Contact Contact { get; set; }
string Title { get; }
int? Id { get; set; }
}
public class Person:IContactable
public class Department:IContactable
public class RestUnit:IContactable
There is another class, Contact, which should maintain which one of these objects are the owner of the contact entity.
A part of Contact mapping which does the job is:
ReferencesAny(p => p.Contactable)
.EntityTypeColumn("ContactableType")
.EntityIdentifierColumn("ContactableId")
.IdentityType<int>()
.AddMetaValue<Person>("Person")
.AddMetaValue<Department>("Department")
.AddMetaValue<RestUnit>("RestUnit");
So that Contact records in database would be like (The types are being saved as string):
X Y ContactableType ContactableId
... ... Person 123
... ... Person 124
... ... Department 59879
... ... RestUnit 65
... ... Person 3333
... ... Department 35564
Everything works just fine but filtering data. When I want to get some particular Contacts, say with Department type, I would write something like :
var contacts = Repository<Contact>.Find(p=>p is Department);
Nhibernate tries to filter data based on ContactableType field with an integer value but the ContactableType column is nvarchar
Generated query by NHibernate :
select .......... from contact.[Contact] where ContactableType=1
Expected query:
select .......... from contact.[Contact] where ContactableType='Department'
So NHibernate kinda using a wrong type. int instead of string.
I think NH is using the index of the object in list which AddMetaValue("Department") has added department type into...
I hope the explanation would be clear enough
I'm using NH3....
any idea?
Have you tried to add an extra line:
ReferencesAny(p => p.Contactable)
.MetaType<string>()