I'm trying for a couple of days now to limit the amount of comments that can be posted by a user.
So after the user submits a comment he should wait for example 5 minutes, to be able to post the next comment.
I know that this can be accomplished by the laravel validator with the 'after' rule. But I've tried a couple of things now and nothing worked out yet.
Here's the Code of the method:
public function storeComment($id, Request $request)
{
$user = User::with('newsComment')->find(Auth::user()->id);
if ($user->NewsComment->count() != 0)
{
$last_comment = NewsComment::where('author_id', Auth::user()->id)->orderBy('created_at', 'desc')->first();
$date_after = new \DateTime($last_comment->created_at);
$date_after->modify('+5 minutes');
} else {
$date_after = date("Y-m-d H:i:s", mktime(0, 0, 0, 00, 00, 0000));
}
$request->current_date = date("Y-m-d H:i:s");
$this->validate($request, [
'comment' => 'required|max:255|min:5',
'current_date' => 'after:'.$date_after->format("Y-m-d H:i:s"),
]);
$comment = new NewsComment;
$comment->news_article_id = $id;
$comment->author_id = Auth::user()->id;
$comment->comment = $request->comment;
$comment->save();
return $this->showArticle($id);
}
So, I know, that this code reads the correct time out of the database and adds the 5 minutes to the given date. In the template I added an empty, hidden form field named 'current_date'. In the method above I fill this variable with the current date and try to validate it with the 'after' validation rule.
But for some reason it won't work.
I hope some of you can help me with this.
I'm btw new to laravel so please bear with me.
Instead of $comment->save(); you can check if the comment is saved and flash in the Session the current timestamp then compare with "Now" after the validation.
if($comment->save()){
$request->session()->put('post_time', Carbon::now());
}
and after validation:
if ($request->session()->has('post_time')) {
if(Carbon::now()->diffInMinutes($request->session()->get('post_time')) < 5){
//stop execution
}
}
Related
I would like to retrieve the time taken by a user to complete a form when using Symfony form.
My current code is as follows ( I have an entity and its associated Form):
$entity = new Entity();
$form = $this->get('form.factory')->create(new EntityType(), $entity);
$begin_time = new \DateTime();
if ($form->handleRequest($request)->isValid() && $form->get('save')->isClicked()) {
$end_time = new \DateTime();
$delta_time = $end_time->diff($begin_time);
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
}
When I send the form, my variable $begin_date and $end_date are equal, thus my interval is null. Is this because the controller is reinitialized when sending the form and as a result, $begin_time is modified again ?
I also tried to create a condition when the form isn't being sent :
if(!$form->get('save')->isClicked()) {
$begin_time = new \DateTime();
}
However, I still obtain $begin_time equal to $end_time. So my question is, is it possible to obtain the interval of time needed by user to complete the form and how to do this in Symfony ?
Thanks for your suggestions.
Add a hidden input to the EntityType with the "data" parameter set to the current timestamp.
//Untested code
$builder->add('begin_date', HiddenType::class, array(
'data' => time(),
'mapped' => false
));
In the form submission handling, get the current timestamp on the server and substract the amount you received in the hidden input.
//Untested code
if ($form->handleRequest($request)->isValid() && $form->get('save')->isClicked()) {
$begin_time = $form->getData()['begin_date'];
$end_time = new \DateTime();
$delta_time = $end_time->diff($begin_time);
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
}
The important thing is that you need to get the $begin_data value from the form data, which contains the value that you set on the original request.
Now $delta_time should give you the time in seconds from the loading on the page and the submission (ignoring network transmission & browser render time).
If you want to measure from the time the user starts writing on the form you can bind a function to the "input" event on the form so it sets the hidden input the first time it is triggered.
I working on send email when user manually enrolled to course.,by now i can send a email when user enroll to the system what i want to know is send enrollment expire date with the email,so if i can get from database that will work for me..,(any other method which can get this insie enroll unction also fine)
this is where i try to pass this parameters
public function enrol_user(stdClass $instance, $userid, $roleid = NULL, $timestart = 0, $timeend = 0, $status = NULL, $recovergrades = NULL) {
global $DB;
$alreadyenroled = $DB->record_exists('user_enrolments', array('enrolid' => $instance->id, 'userid' => $userid));
parent::enrol_user($instance, $userid, $roleid, $timestart, $timeend, $status, $recovergrades);
if (!$alreadyenroled && $instance->customint4) {
// Don't email immediately - give the admin a chance to remove users
// who were added by mistake
$this->queue_welcome_message($instance->id, $userid,$timestart,$timeend);
}
}
protected function queue_welcome_message($instanceid, $userid,$timestart,$timeend) {
global $DB;
if ($DB->record_exists('enrol_manual_email', array('instanceid' => $instanceid,
'userid' => $userid,'ts' => $timestart,'te' => $timeend))) {
return;
}
$ins = new stdClass();
$ins->instanceid = $instanceid;
$ins->userid = $userid;
////edit lasitha
$ins->ts = $timestart;
$ins->te = $timeend;
$DB->insert_record('enrol_manual_email', $ins);
}
The best way to do this, so that it won't break when you update your Moodle site to a new version, would be to create a new local plugin ( http://docs.moodle.org/dev/Local_plugins ). Then you can make use of the Moodle events API ( http://docs.moodle.org/dev/Events_API ) to subscribe to 'user_enrolled' events.
The data you get from the events API will include the field 'timeend' (from the table mdl_user_enrolments) which is the timestamp of when the enrolment will expire. If this field is '0', then it means the enrolment will not expire. If it is any other value, then you can call:
userdate($data->timeend, get_string('strftimedate'));
to format this as a date.
(See '/lang/en/langconfig.php' for other time formats you can use - note also, this date will be based on the timezone of the current logged in user - you may need to use the 'timezone' parameter of 'userdate', if you want to make sure it is the right timezone for the receiving user).
This code helps me to get what i want to get
$user_enroll_data = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$user->id));
$normal_st_date=date('Y-m-d', $user_enroll_data->timestart);//course start date
$normal_end_date=date('Y-m-d',$user_enroll_data->timeend);//course end date
I'd like to validate form input that is datetime for article to be posted.
$model = new Post('update');
$model->attributes = $_POST['Post'];
if($model->validate()){
//But, validation fails...
}
This is the rule that I got to check if the input is datetime format or not.
I used this page(http://chris-backhouse.com/date-validation-in-yii/528) as reference.
But I get validation error for 'created'input.
public function rules()
{
return array(
//datetime validation
array('created', 'date', 'message' => '{attribute}: is not a datetime!', 'format' => 'YYYY-MM-DD HH:MM:SS'),
);
}
This is what I have in $models-attribute.
array(1) { ["created"]=> string(19) "2013-08-01 00:00:01" }
Could anyone knows how to make this work?
Thanks a lot in advance!!!
I would advice to use input formats in rule, since sometimes you want custom formats.
array('created', 'date', 'format'=>'yyyy-MM-dd hh:mm:ss', 'message'=>'{attribute} have wrong format'),
More about date formats here - http://www.yiiframework.com/doc/api/1.1/CDateTimeParser
On Yii 2.0.6 (and maybe Yii 1.x ?), the correct format is :
['creation_date', 'date', 'format'=>'yyyy-MM-dd HH:mm:ss']
It's not working if hours are not in CAPS.
Is this creation time of the post? Then you don't need to validate it at all and you should set it in beforeSave instead of sending it with POST
add this to your model:
public function beforeSave()
{
if($this->isNewRecord)
{
$this->created=new CDbExpression('NOW()');
}
return parent::beforeSave();
}
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 ;).
public function configure()
{
$this->widgetSchema['start_date'] = new sfWidgetFormInput();
$this->widgetSchema['end_date'] = new sfWidgetFormInput();
$this->validatorSchema->setPostValidator( new sfValidatorOr ( array(
new sfValidatorAnd( array
(new sfValidatorSchemaCompare('start_date', sfValidatorSchemaCompare::NOT_EQUAL, null),
new sfValidatorSchemaCompare('end_date', sfValidatorSchemaCompare::EQUAL, null)
)),
new sfValidatorSchemaCompare('start_date', sfValidatorSchemaCompare::LESS_THAN_EQUAL, 'end_date',
array('throw_global_error' => false), array('invalid' => 'The start date ("%left_field%") must be before the end date ("%right_field%")')))));
}
I've got following input dates which I want to check if the end date isn't before the start date:
Input: Start => 31/03/10 End=> 07/03/10
Output: The start date (2010-03-31) must be before the end date (2010-03-07)
Can you in some way change the date output? I need the error message to set the date format the same as the input.
Also my input fields are set with the wrong date format when the error appears.
Tried several things, but no luck at this moment. Didn't find a solution or information on symfony it self.
I'm using symfony version 1.2.11
I found a the solution together with a colleague.
After some tryouts, we found the solution to my initial problem. Instead of using that post validator, we wrote are own validator.
class StartBeforeEndDateValidator extends sfValidatorBase {
public function configure($options = array(), $messages = array()) {
parent::configure($options, $messages);
$this->addMessage('Invalid_daterange', 'Start date (%start%) must be before End date (%end%)!');
}
public function doClean($values) {
sfContext::getInstance()->getConfiguration()->loadHelpers('Date');
$timestampStart = sfContext::getInstance()->getI18N()->getTimestampForCulture($values['start_date'], sfContext::getInstance()->getUser()->getCulture());
$timestampEnd = sfContext::getInstance()->getI18N()->getTimestampForCulture($values['end_date'], sfContext::getInstance()->getUser()->getCulture());
if(format_date($timestampStart) > format_date($timestampEnd)){
throw new sfValidatorError($this, 'Invalid_daterange', array('start' => $values['start_date'], 'end' => $values['end_date']));
}
}
}
Usage of the validator in the symfony form:
public function configure() {
$this->widgetSchema['start_date'] = new sfWidgetFormInput();
$this->widgetSchema['end_date'] = clone $this->widgetSchema['start_date'];
$this->validatorSchema['start_date'] = new DateValidator();
$this->validatorSchema['end_date'] = clone $this->validatorSchema['start_date'];
$this->validatorSchema->setPostValidator(new StartBeforeEndDateValidator());
}
This was the solution to have always the same date format when it's being validated and when the validation is trigger with an error, the format of the date is correctly returned in the same date format as it was set.
Now one other "problem" that we encountered was when the save happened, the date format wasn't right for mysql. So we override the save function in our symfony form and apply the right date format.
example:
public function save($con = null){
$var = new Object();
if($this->taintedValues['id']!= ""){
$var->setId($this->taintedValues['id']);
}
$var->setStartDate(DateUtils::getIsoDateForCulture($this->taintedValues['start_date']));
$var->setEndDate(DateUtils::getIsoDateForCulture($this->taintedValues['end_date']));
$var->setIcpm($this->taintedValues['icpm']);
$var->save($con);
}
So once the validation is valid, it will perform the save function and set the right date format before actually save it into the database.
Hope that this is helpful for other people who had this problem.