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 ;).
Related
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.
A little more than a month ago I did a post involving the extraction the values of from a URL.
https://stackoverflow.com/questions/21231390/extracting-the-values-from-a-xml-url
It was a good answer and helped me a lot, but is there a way to generalize the code for any parameter given? The testing parameters won't be part of a formula, and this plugin I'm developing is supposed to be handled by Moodle teachers. They won't have access to my code to manually alter the parameters themselves. Here is the link.
By changing the rs parameter, I change the course. p(even/odd) and tp(semestral/anual/trimestral courses) parameters are about semesters and year is the year.
This is what I currently have.
function buildURL($year, $period, $typeperiod,$course)
{
return 'https://clip.unl.pt/sprs?lg=pt&year='.$year.'&uo=97747&srv=rsu&p='.$period.'&tp='.$typeperiod.'&md=3&rs='.$course.'&it=1030123459';
}
function doRequest_with_FileGetContents($url)
{
return download_file_content($url);
}
function processXML($xmlContent)
{
$xmlObj= new SimpleXMLElement($xmlContent);
$result=array();
foreach($xmlObj->unidade_curricular->inscritos->aluno as $aluno)
{
$result[]= $aluno->identificador;
}
return $result;
}
Testing parameters:
$year='2014';
$period='1';
$typeperiod='s';
$course='8145';
$url=buildURL($year,$period,$typeperiod,$course);
$content_b = doRequest_with_FileGetContents($url);
$dataClip = processXML($content_b);
I've tried to associate the id number of the course (course / course edit Settings/course id number) to the parameter rs, by typing:
$course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
$idnumber = $course->idnumber;
and replace it in $url=buildURL($year,$period,$typeperiod,$idnumber); but the XML doesn't even process. Is this even possible to pull it off without a formal interface?
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.
I have a calendar set up and when viewing the month view I want to display the events which have been created by their ID and not the time they are due to start.
Is this possible? And if so, how would I go about changing the code to display the events in this manner?
Great solution!
I've used it and adapted it for my needs. I'm using JSON feeds.
Important: the first condition is to make sure all the events are sorted by start date.
Then, if you want to sort by title :
function segCmp(a, b) {
var tryCmp = (b.msLength - a.msLength) * 100 + (a.event.start - b.event.start);
if (tryCmp == 0) {
return (a.event.title.toLowerCase() >= b.event.title.toLowerCase()) ? 1: 0;
}
return tryCmp;
}
I've also used it another way.
I've added a custom attribute to each event of the JSON feed called 'colOrder'(it could be anything) and gave it integer values (1,2,3...). 1 is for the first event I want to see, 2 for the second...
Then I customized the function to use the colOrder attribute to sort the events.
function segCmp(a, b) {
var tryCmp = (b.msLength - a.msLength) * 100 + (a.event.start - b.event.start);
if (tryCmp == 0) {
if (!isNaN(a.event.colOrder) && !isNaN(b.event.colOrder))
return (a.event.colOrder - b.event.colOrder);
}
return tryCmp;
}
Add ORDER BY id ASC to your query.
no easy way to do this yet, but when this issue is implemented, should be easy:
http://code.google.com/p/fullcalendar/issues/detail?id=364
Long time since last post, but just in case someone need it (like me):
change in fullcalendar.js
function segCmp(a, b) {
return (b.msLength - a.msLength) * 100 + (a.event.start - b.event.start);
}
to
function segCmp(a, b) {
var tryCmp = (b.msLength - a.msLength) * 100 + (a.event.start - b.event.start);
if (tryCmp == 0)
return (a.event.id - b.event.id);
return tryCmp;
}
it worked for me
Using the Kohana framework, how would you validate a date of birth given 3 separate drop downs? If an error occurs, only one error should show.
you can setup additional custom prefilters and callbacks http://docs.kohanaphp.com/libraries/validation http://docs.kohanaphp.com/libraries/validation are you using ko3 or ko2?
<?
// somewhere in your controller
$form = $_POST;
$form['b_day'] = $form['year'].'-'.$form['month'].'-'.$form['day'];
unset($form['year'], $form['month'], $form['day']);
$orm->validate($form);
// somewhere in your model
public function validate(array & $array, $save = FALSE)
{
$array = Validation::factory($array)
->pre_filter('trim')
->add_rules('b_day', array($this, 'is_good_date'))
;
return parent::validate($array, $save);
}
private function is_good_date($day)
{
return (bool) ($day === 'is ok')
}
Without knowing the Kohana framework, I would probably not validate the first two drop downs, only the third which would take all of the values into consideration.