Ok, So I ave implemented a Date of Birth into the user registration. What I want to do now is take that date of birth and check to see if they are above a certain age (13) before they register. They way I did DOB is kinda weird, but it works. I have 3 field dob1, dob2, dob3. CodeIgniter: Tank Auth, Adding Date of Birth Issues here is how i implemented it if anyone is interested. Anyway, this is what I have been trying so far: EDIT: the syntax the user puts in is mm dd yyyy
function is_old_enough($input, $dob1, $dob2) {
$dob = $dob1.$dob2.$input;
$date = date('md').(date('Y')-13);
if ((int)$dob < (int)$date)
$this->form_validation->set_message('is_old_enough', 'You are not old enough to have an account on this site.');
return $input;
}
And here is what is inside the register() function.
$this->form_validation->set_rules('dob1', 'Date of Birth Month', 'trim|required|xss_clean|exact_length[2]');
$this->form_validation->set_rules('dob2', 'Date of Birth Day', 'trim|required|xss_clean|exact_length[2]');
$this->form_validation->set_rules('dob3', 'Date of Birth Year', 'trim|required|xss_clean|exact_length[4]|callback_is_old_enough[dob1||dob2]');
Am I close? Am i way off? Anyone help? Right now all it does is pretends like I never created this callback and puts the user in even if the user is too young. I know it is calling the function correctly as I had some issues with the variables. Help?
EDIT: Brendan's answer helped me a lot, but the main issue was a logic error. So here is how I have it working right now:
//Check if user is old enough
function is_old_enough($input) {
$dob = $this->input->post('dob3').$this->input->post('dob1').$this->input->post('dob2');
$date = (date('Y')-13).date('md');
if ((int)$dob > (int)$date) {
$this->form_validation->set_message('is_old_enough', 'You are not old enough to register on this site.');
return FALSE;
}
return TRUE;
}
$this->form_validation->set_rules('dob1', 'Date of Birth Month', 'trim|required|xss_clean|exact_length[2]');
$this->form_validation->set_rules('dob2', 'Date of Birth Day', 'trim|required|xss_clean|exact_length[2]');
$this->form_validation->set_rules('dob3', 'Date of Birth Year', 'trim|required|xss_clean|exact_length[4]|callback_is_old_enough[]');
First of all, you can only pass up to two arguments in a callback. Second, if you return a non-boolean value from a callback, whatever is returned will replace the value of the field you ran the callback on.
If you're trying to check if something is valid, the way it works (essentially) is:
function _callback_for_field($input)
{
// check if $input is valid based on your own logic
if($input == YOUR_LOGIC_HERE)
{
return TRUE;
}
return FALSE;
}
But for what you're doing, specifically:
// Birthdate rules
$this->form_validation->set_rules('birthdate-month','Birthdate Month','required|is_natural_no_zero|greater_than[0]|less_than[13]');
$this->form_validation->set_rules('birthdate-day','Birthdate Day','required|is_natural_no_zero|greater_than[0]|less_than[32]');
$this->form_validation->set_rules('birthdate-year','Birthdate Year','required|is_natural_no_zero|greater_than[1930]|less_than['.(date("Y") - 18).']');
I purposely don't go to great lengths to prevent someone that's barely under the age of 18 to register, because if they want to, they'll do it anyway. It is impossible to restrict registration based on age if the person is determined to, and since you're not checking some government database on citizens, it's not really within your scope of responsibility. A simple age check is all that's required.
I had a second thought -- If you still want to accurately check, you can reference $this->input->post() for each of the fields in your callback function. You can even run the callback function with no arguments, since you will be circumventing that restriction.
Related
I have a form that asks a user how long they are planning to stay. I have two fields: number of the stay and the unit of this number i.e. 5 days, 1 week and so on.
I pass two variables: value_stay and unit_stay.
I want to validate them with the special business rules such as "maximum of 3 months of stay is allowed":
$this->form_validation->set_rules('unit_stay', 'stay unit', 'trim|required');
if(isset($_POST['unit_stay'])) {
if($_POST['unit_stay'] === 'month') {
$this->form_validation->set_rules('value_stay', 'stay value', 'less_than_equal_to[3]');
}
}
$this->form_validation->set_rules('value_stay', 'stay value', 'trim|required|integer|greater_than_equal_to[1]');
My problem is that I have redundant check for value_stay. And the second set_rules() overrides the one in the conditions.
In the CI Form Validation documentation there is no recommendation for such dependencies.
Do you guys have special tricks to refactor this kind of special validation? Specifically if the validation for value_stay that depends on value_unit can be shortened into a more compact and un-redundant hack compared to what I did.
You can use a callback function:
http://www.codeigniter.com/user_guide/libraries/form_validation.html#callbacks-your-own-validation-methods
Your callback function might be something like:
$this->form_validation->set_rules('value_stay', 'stay value', 'trim|required|callback_stayToUnitCheck')
Then in the same controller:
private function stayToUnitCheck($stay)
{
$results = FALSE;
// get the units
// you have to get this additional one from the post variable
if(!empty($_POST['unit_stay']))
{
$unit = $_POST['unit_stay'];
switch ($stay)
{
case 'month':
// do your test on stay and unit
if ($unit <= 3) $result = TRUE;
break;
case 'week':
// more tests
}
return $result;
}
Callbacks are very powerful when you get the hang of them. You can even set different messages for the callback error too:
$this->form_validation->set_message('stayToUnitCheck', 'For a stay of months you can only book a maximum of three months at a time.');
Which you can set within the switch for each different kind of stay, or use a default message when a case is not matched.
Hope that helps,
Paul.
I have a website on magento framework. When i logged in admin panel click on Customer > Manage customer then all the customer detail are showing with ( Name, Email, Avtar, Group Phone No , ZIP, Country, State, Customer since, Action )
When user sign up on 2 OCT 2015 then the date is showing in Customer since is Feb, 10,2015. It is picking month as a date and date as a month.
Will you please tell me how can i change the format of Customer Since tab
try this
magento have date format in app/code/core/Mage/core/Model/Date.php file. if you want to change in format you can do that by overriding the model.
Note : never modify core files
I closely looking the issue and found that your month and date are swapping with each other.
try this
You can copy the file to \app\code\local\Mage\Eav\Model\Entity\Attribute\Backend\Time\Created.php and modify the functions necessary, once modified and uploaded it will take precedence over the core file and no worries about being overwritten during an update (though, if they update and that file is part of it, I would hope it would be to fix the problem)
the update to that file is here, so nobody needs to hop pages to find it
Replace beforeSave with this:
public function beforeSave($object)
{
$attributeCode = $this->getAttribute()->getAttributeCode();
$date = $object->getData($attributeCode);
if (is_null($date)) {
if ($object->isObjectNew()) {
$object->setData($attributeCode, Varien_Date::now());
}
} else {
// ADD THIS
$date = strtotime($date);
// convert to UTC
$zendDate = Mage::app()->getLocale()->utcDate(null, $date, true, $this->_getFormat($date));
$object->setData($attributeCode, $zendDate->getIso());
}
return $this;
}
This also needs to be corrected on the way out of the database. Replace afterLoad with this:
public function afterLoad($object)
{
$attributeCode = $this->getAttribute()->getAttributeCode();
$date = $object->getData($attributeCode);
// ADD THIS
if (!is_null($date)) {
$date = strtotime($date);
}
$zendDate = Mage::app()->getLocale()->storeDate(null, $date, true, $this->_getFormat($date));
$object->setData($attributeCode, $zendDate->getIso());
parent::afterLoad($object);
return $this;
}
I think this might help you.
I'd like to have a field inside a form, which has a format like dd.MM.yyyy HH:mm. I've done this with the date validator.
But now I have the problem, that the user always have to enter a time, not only the specified day. Is it possible automatically set the time to 00:00 when the user only enters the date?
Thanks for your help.
protected function beforeSave()
{
if ( strpos(trim(this->date_field), ' ') !== false ) {
$this->date_field = sprintf('%s 00:00', $this->date_field);
}
return parent::beforeSave();
}
I have checked all the questions of similar kind, and none of them are solving my problem, using CI 2.1.3, and HMVC from Wiredesignz.
I have in my form_validation.php config file the following rule:
array(
'field' => 'eta-renpal-1',
'label' => 'Renpal number (1)',
'rules' => 'required|callback_check_eta_group'
),
And in my ETA controller, I have this function (currently set to ALWAYS be invalid while testing):
public function check_eta_group($reference)
{
// Internal function for use by form validation system to check if the ETA group requirements are met.
$this->form_validation->set_message('check_eta_group', 'Other values in the group ' . $reference . ' are also required.');
return false;
}
For some reason, the "required" function works, but the callback does not. I have tried all other similar suggested solutions, and can't get them to work. Please help?
Edit: The callback does not appear to be called at all. I even did var_dump() in the callback to see if there is output on the screen - none...
Edit2:: See last comment by myself - using that work-around solves the problem, but it is not exactly what I wanted. So - if you have a better solution, please share :-)
See my last comment under the question
(Using a workaround explained here, stackoverflow.com/questions/3029717/…, it works. It is not the way I want it to work with callbacks, but as long as it works, it is probably alright. Thanks anyways.)
Thanks Frosty for your comments.
make sure your function checks are inside the same controller that you are actually running the custom checks in (i.e. it should be able to be called with self::check_eta_group)
I had trouble getting validation working with my checks inside of MY_Controller for instance.
But when i moved them into the extended controller it worked fine.
here are two checks and how I called them (all within the same controller)
// custom form validators for datepicker and timepicker
public function date_valid($date){
$month = (int) substr($date, 0, 2);
$day = (int) substr($date, 3, 2);
$year = (int) substr($date, 6, 4);
$this->form_validation->set_message('date_valid', 'The %s field is not a valid date');
return checkdate($month, $day, $year);
}
public function time_valid($time){
$this->form_validation->set_message('time_valid', 'The %s field is not a valid time');
if (preg_match("/^(1[0-2]|0?[1-9]):[0-5][0-9] (AM|PM)$/i", $time)) {
return TRUE;
} else {
return FALSE;
}
}
public function create_custom(){
// load models and libraries
$this->load->helper(array('form', 'url'));
$this->load->library('form_validation');
// set form validation rules
$this->form_validation->set_rules('schedule_date', 'Schedule Date', 'required|callback_date_valid');
$this->form_validation->set_rules('schedule_time', 'Schedule Time', 'required|callback_time_valid');
....
if ($this->form_validation->run() == FALSE) { // failed validation
error_log("validation_errors: ".validation_errors());
}
I am trying to update the DOB of a customer from the backend of magneto. The year of DOB I am going to set is 1967. Ok, Well, The record is updated successfully but when I go inside the database table and see the DOB it contains the year 2067. I am surprised how this happened.
I again go in to the backend and set it to 1971 and update the customer record. But this time DOB is ok in the database table. It is 1971.
I reached at the conclusion that the DOB less than 1970 is stored wrongly in the database.
Is it magento bug or something wrong with my magento copy.
Thanks
This is a bug in Magento, and there's some chance that this bug will be fixed in next release 1.5.0.0. But I'd not rely on that.
Currently there's no easy way to cope with it, as logic for this is hidden and separated across abstract EAV and Customer attributes models. The basic approach is to
1) Show date in backend in medium format with YYYY instead of YY
and then either
2) Write your custom input validation filter that will validate date in medium format for DOB
3) Change input validation filter from default 'date' to yours (it's done in table customer_eav_attribute)
or
2) write code to set _dateFilterFormat of 'dob' attribute to medium
As of 1.5.1 this still applies. Andrey may be correct but does not provide any details on how to implement that. I've tried to do it and since I can't comment on his answer yet I'll post it here:
In app\code\core\Mage\Adminhtml\Block\Widget\Form.php _setFieldset where it says "FORMAT_TYPE_MEDIUM" add afterwards
if($attribute->getName() == 'dob') $element->setFormat(Mage::app()->getLocale()->getDateFormat(Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM));
In app\code\core\Mage\Customer\Model\Attribute\Data\Abstract.php _dateFilterFormat after is_null($format)
$a = $this->getAttribute();
if(!empty($a) && $a->getName() == 'dob') {
$this->_dateFilterFormat = Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM;
return Mage::app()->getLocale()->getDateFormat($this->_dateFilterFormat);
}
Changing app\code\core\Mage\Customer\Block\Widget\Dob.php getDateFormat to FORMAT_TYPE_MEDIUM doesn't really help. The JavaScript will still accept two number years because the validation replaces the date pattern's "y" ignoring case and uses "new Date()" which interprets a two number year just the same. The year sanity check then works on the interpreted year which will be at least 1901.
If you want hard coded four number years just uncomment (in 1.5.1) the part in js\varien\js.js in DateElement.validate where it says year<1900 and throw out the !this.validateData. Or if you want to make sure you only affect DOB use this:
Varien.DOB = Class.create();
Varien.DOB.prototype = {
initialize: function(selector, required, format) {
var el = $$(selector)[0];
var container = {};
container.day = Element.select(el, '.dob-day input')[0];
container.month = Element.select(el, '.dob-month input')[0];
container.year = Element.select(el, '.dob-year input')[0];
container.full = Element.select(el, '.dob-full input')[0];
container.advice = Element.select(el, '.validation-advice')[0];
this.child = new Varien.DateElement('container', container, required, format);
container.day.validate = this.validate.bind(this);
container.month.validate = this.validate.bind(this);
container.year.validate = this.validate.bind(this);
},
validate: function() {
if(this.child.validate()) {
var year = parseInt(this.child.year.value, 10);
if (!isNaN(year) && (year<1900 || year>this.child.curyear) ) {
errorType = this.child.validateDataErrorType;
valueError = this.child.validateDataErrorText;
error = valueError;
try {
error = Translator.translate(error);
}
catch (e) {}
this.child.advice.innerHTML = this.child.errorTextModifier(error);
this.child.advice.show();
return false;
}
return true;
}
return false;
},
};
Finally Magento will still not be able to output a DOB smaller than 13th December 1901 in the frontend because it overflows the return value of strtotime. So you'll have to change app\code\core\Mage\Customer\Block\Widget\Dob.php functions:
public function setDate($date)
{
$this->setTime($date ? strtotime($date) : false);
$this->setData('date', $date);
try {
$this->setDateTime(new DateTime($date));
}catch(Exception $e){}
return $this;
}
public function getDay()
{
return $this->getTime() ? date('d', $this->getTime()) : ($this->getDateTime() ? $this->getDateTime()->format('d') : '');
}
public function getMonth()
{
return $this->getTime() ? date('m', $this->getTime()) : ($this->getDateTime() ? $this->getDateTime()->format('m') : '');
}
public function getYear()
{
return $this->getTime() ? date('Y', $this->getTime()) : ($this->getDateTime() ? $this->getDateTime()->format('Y') : '');
}
I hope I got everything... though it still isn't a very clean way to do this ;).