Zend Form getValue. Need someone to explain? - zend-form

I'm just working with the Zend_Form in Zend Framework and came across something pretty weird.
I have the following inside my loginAction
$form = new Application_Model_FormLogin();
if ($this->getRequest()->isPost()) {
$email = $form->getValue('email');
$pswd = $form->getValue('pswd');
echo "<p>Your e-mail is {$email}, and password is {$pswd}</p>";
}
Which when submitted only outputs
Your e-mail is, and password is
So I checked to see what's going on with print_r ,
print_r($form->getValues());
print_r($_POST);
Which displayed the following,
Array ( [email] => [pswd] => ) Array ( [email] => asd [pswd] => asd [submit] => Login )
So the forms values array has both values as null and the global post array had the correct values. Now I can't work out the problem?
Now I did manage to fix the problem, but I need help understanding why this works? All I did was change the loginAction to this.
$form = new Application_Model_FormLogin();
if ($this->getRequest()->isPost()) {
//Added this in
if ($form->isValid($this->_request->getPost())) {
$email = $form->getValue('email');
$pswd = $form->getValue('pswd');
echo "<p>Your e-mail is {$email}, and password is {$pswd}</p>";
}
}
I don't get how this made it work? Considering there is no validation on the fields?
Any thoughts? All I can think is maybe I have something setup weird in my server configuration?
Thanks

You didnt load the Values in your form object.
Normaly you check if the form is valid and for this load it with the post data, in the next step you can use getValue() to get the (filtered) value from the form.
if($this->getRequest()->isPost()) {
$form = new My_Form();
if($form->isValid($this->getRequest()->getPost())){
echo $form->getValue('fieldname');
}
}

isValid() is what actually populates the fields in your form object, until you do that the values do not exist in your form object yet.
modifying your original code would be as simple as this
if ($this->getRequest()->isPost()) {
//your $form object has none of your POSTed values
$form->isValid($this->getRequest()->getPost())
//now your form object has the POSTed values and you can access them
$email = $form->getValue('email');
$pswd = $form->getValue('pswd');
echo "<p>Your e-mail is {$email}, and password is {$pswd}</p>";
}
This skims over it extremely lightly http://framework.zend.com/manual/1.11/en/zend.form.quickstart.html#zend.form.quickstart.validate
Consider this example also and it might make more sense. Here you just grab the values from the POST.
if ($this->getRequest()->isPost()) {
$email = $this->getRequest()->getPost('email');
$password = $this->getRequest()->getPost('password');
echo "<p> Your email is $email and your password is $password </p>";
}

Related

why using viewSimple renderer in Phalcon corrupts main renderer

First I declare simple view like this:
$di->set('viewSimple', function() {
$view = new \Phalcon\Mvc\View\Simple();
$view->setViewsDir('../app/views/');
$view->registerEngines(array(
".volt" => 'volt'
));
return $view;
});
then to generate html email, I use it as following:
public function renderHTMLEmail($template_name, $template_params) {
$content = $this->viewSimple->render("emails/$template_name", $template_params);
return $this->viewSimple->render("emails/master", array( 'content' => $content) );
}
My emails are being generated just fine, but whenever I call my renderHTMLEmail function actual page rendering is somehow corrupted and page appears totally blank (I have to use redirect as workaround). This is a mystery to me as main view renderer is completely different object. Can I prevent this?
Or does anybody have recommended method of generating arbitrary pieces of html outside of main view rendering process which would not interfere with it? There is couple of similar questions on SO, but none of solutions work. They either don't generate my email or they corrupt main view.
Found a solution, when registering the "\Phalcon\Mvc\View\Simple" component into the DI container make sure to use a new volt instance otherwise it will join up with the application's \Phalcon\Mvc\View volt instance somehow. This is what lot (https://stackoverflow.com/users/1672165/lot) was suggesting in the comments.
Code sample:
public function getTemplate($name, $params)
{
$parameters = array_merge(array(
'publicUrl' => $this->getDI()->getApp()->url->host . $this->getDI()->getApp()->url->baseUri
), $params);
$app = $this->getDI()->getApp();
$this->getDI()->set('simpleView', function() use ($app) {
$view = new \Phalcon\Mvc\View\Simple();
$view->setViewsDir(APP_DIR . $app->application->viewsDir);
$view->registerEngines(array(
".volt" => function ($view, $di) {
$volt = new \Phalcon\Mvc\View\Engine\Volt($view, $di);
$volt->setOptions(array(
'compiledPath' => APP_DIR . '/cache/volt/',
'compiledSeparator' => '_',
'compiledExtension' => '.compiled'
));
$compiler = $volt->getCompiler();
$compiler->addFunction('is_a', 'is_a');
return $volt;
}
));
return $view;
});
/* #var $simpleView \Phalcon\Mvc\View\Simple */
$simpleView = $this->getDI()->get('simpleView');
foreach ($parameters as $key => $value) {
$simpleView->{$key} = $value;
}
$html = $simpleView->render('emails/' . $name, $parameters);
return $html;
}
Sample was pulled straight from our working app so may need some re-working but should help solve the original issue.
This works for me using \View as the application DI registered view component which renders controller action volt views and the above \View\Simple with fresh volt registration successfully emails and allows the original view with volt to carry on.
This was asked a while ago however i've not seen a working solution anywhere else.
For completeness I've registered a github issue with the findings: https://github.com/phalcon/cphalcon/issues/3096
I recently had to deal with a similar problem, I'm not certain where you're falling short, but one important thing was to use a separate view from the one used by the application – you're already doing this. See if the following works.
protected function renderView($view, $template, array $data = null)
{
return $view
->reset()
->pick('emails/' . $template)
->setVars($data)
->start()
->render(null, null)
->finish()
->getContent();
}
public function renderHTMLEmail($template_name, $template_params)
{
$content = $this->render($template_name, $template_params);
return $this->render('master', array('content' => $content));
}

Yii 1.1 - creating a multi step form with validation

I'm basically trying to create a multi-step form using the CActiveForm class in Yii. The idea is I want to use the built-in functionality to achieve this in the simplest way possible. The requirement I have is as follows:
A multi step ONE PAGE form (using DIVs that show/hide with jQuery)
AJAX validation on EACH step (validate step-specific attributes only)
The validation MUST work using the validateOnChange() and validateOnSubmit() methods
This is a half-working solution I have developed so far:
View:
<div class="form">
<?php $form = $this->beginWidget('CActiveForm', array(
'id'=>'listing-form',
'enableClientValidation'=>false,
'enableAjaxValidation'=>true,
'clientOptions'=>array(
'validateOnChange'=>true,
'validateOnSubmit'=>true,
'afterValidate'=>'js:validateListing',
),
)); ?>
<?php echo $form->errorSummary($model); ?>
<div class="step" id="step-1">
// model input fields
<?php echo CHtml::submitButton('Next Step', array('name'=>'step1')); ?>
</div>
<div class="step" id="step-2" style="display: none;">
// model input fields
<?php echo CHtml::submitButton('Next Step', array('name'=>'step2')); ?>
</div>
<div class="step" id="step-3" style="display: none;">
// model input fields
<?php echo CHtml::submitButton('Submit', array('name'=>'step3')); ?>
</div>
<?php $this->endWidget(); ?>
</div>
JavaScript:
function validateListing(form, data, hasError)
{
if(hasError)
{
// display JS flash message
}
else
{
if($('#step-1').css('display') != 'none')
{
$('#step-1').hide();
$('#step-2').show();
}
else if($('#step-2').css('display') != 'none')
{
$('#step-2').hide();
$('#step-3').show();
}
else if($('#step-3').css('display') != 'none')
{
return true; // trigger default form submit
}
}
}
Controller:
public function actionCreate()
{
$model = new Listing;
// step 1 ajax validation
if(isset($_POST['step1']))
{
$attributes = array('name', 'address1', 'etc');
$this->performAjaxValidation($model, $attributes);
}
// step 2 ajax validation
if(isset($_POST['step2']))
{
$attributes = array('category', 'type', 'etc');
$this->performAjaxValidation($model, $attributes);
}
// step 3 ajax validation
if(isset($_POST['step3']))
{
$attributes = array('details', 'source', 'etc');
$this->performAjaxValidation($model, $attributes);
}
// process regular POST
if(isset($_POST['Listing']))
{
$model->attributes = $_POST['Listing'];
if($model->validate()) // validate all attributes again to be sure
{
// perform save actions, redirect, etc
}
}
$this->render('create', array(
'model'=>$model,
));
}
protected function performAjaxValidation($model, $attributes=null)
{
if(isset($_POST['ajax']) && $_POST['ajax']==='listing-form')
{
echo CActiveForm::validate($model, $attributes);
Yii::app()->end();
}
}
To summarise. Basically what I have is a form with 3 submit buttons (one for each step). In my controller I check which submit button was pressed and I run AJAX validation for the attributes specific to that step.
I use a custom afterValidate() function to show/hide the steps upon submit. On step 3, the default form submit is triggered, which posts all the form attributes to the controller.
This works well, except it won't work with validateOnChange() (since the submit button doesn't get posted). Also I was wondering whether this is actually the best way to do this, or if anyone knows of a better way?
Thanks.
I'd suggesting using scenarios to turn on and off the appropriate rules. Adjust the model scenario based on what is sent to your controller.
Note: this may also be a really good place to use a CFormModel instead of a CActiveRecord, depending on what is in your form.
Edit: can you add a hidden field to each div section that contains the info about what step you are on? Seems like that should work instead of your submit buttons.
OPTION 1
When you do not receive a button, why not validate the entire form, why do you need to validate only specific attributes? Yii will validate the entire model, send back all the errors but only that particular error will be shown by the active form because that is how it works already.
OPTION 2
You can have 3 forms (not 1 like you have now), 1 on each step. Also create 3 scenarios 1 for each step.
Each form has a hidden field that gets posted with the form, it can actually be the scenario name just validate it when it comes in. Validate the model using this hidden field to set the scenario you are on.
You can cache parts on the model when the form is submitted successfully and at the end you have the complete model.
you can always have custom validation and it won't break your normal form validation
in your model
private $step1 = false;
private $step2 = false;
private $all_ok = false;
protected function beforeValidate()
{
if(!empty($this->attr1) && $this->attr2) // if the fields you are looking for are filled, let it go to next
{
$this->step1 = true;
}
if($this->step1)
{
... some more validation
$this->step2 = true;
}
if($this->step2)
{
... if all your logic meets
$this->all_ok = true;
}
// if all fields that your looking for are filled, let parent validate them all
// if they don't go with their original rules, parent will notify
if($this->all_ok)
return parent::beforeValidate();
$this->addError($this->tableSchema->primaryKey, 'please fillout the form correctly');
return false;
}
I think better create specific class for each step of validation and use scenarios with rules. Below is small example.
//protected/extensions/validators
class StepOneMyModelValidator extends CValidator
{
/**
* #inheritdoc
*/
protected function validateAttribute($object, $attribute)
{
/* #var $object YourModel */
// validation step 1 here.
if (exist_problems) {
$object->addError($attribute, 'step1 is failed');
}
...
Create other classes(steps) for validation...
// in your model
public function rules()
{
return array(
array('attr', 'ext.validators.StepOneMyModelValidator', 'on' => 'step1'),
...
How to use in controller:
$model = new Listing();
$steps = array('step1', 'step2', /* etc... */);
foreach($_POST as $key => $val) {
if (in_array($key, $steps)) {
$model->setScenario($key);
break;
}
}
$model->validate();
echo '<pre>';
print_r($model->getErrors());
echo '</pre>';
die();
Or we can validate all steps in one validator.

how to send mail in yiimailer extension in view form

how exactly do i use this in view? it works fine in controller but I would like to have it set up like a form. My main question is, how do I submit? how would i make $mail->send() as a button? Not quite understanding the example from it. It looks like the default contact form.
Sorry for the rudimentary question.
$mail = new YiiMailer();
$name = Yii::app()->user->getName();
$email = Yii::app()->user->getEmail();
$mail->setFrom($email, $name);
$mail->setTo('hi#email.com', 'hi');
$mail->setTo(Yii::app()->params['adminWeb']);
$mail->setSubject('Mail subject');
**how to send?**
Add this to trigger the email.
if ($mail->send()) {
Yii::app()->user->setFlash('contact','Thank you for contacting us. We will respond to you as soon as possible.');
} else {
Yii::app()->user->setFlash('error','Error while sending email: '.$mail->getError());
}
Ref : http://www.yiiframework.com/extension/yiimailer/

Inserting new password by overriding old password

In yii i am creating project. After validation of user's entered email, i am displaying password.php file which is having textfield for entering new password.
Password.php=
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'email-form',
'enableClientValidation'=>true,
));
echo CHtml::textField('Enter new password');
echo CHtml::textField('Repeat password');
echo CHtml::submitButton('Submit');
$this->endWidget();
When user will enter new password and click on submit button i want to insert this new password into User table's password field, in such a way that it overright old password.
In controller i had created method as-
public function actionCreate(){
if(isset($_POST['email']))
{
$record=User2::model()->find(array(
'select'=>'userId, securityQuestionId, primaryEmail',
'condition'=>'primaryEmail=:email',
'params'=>array(':email'=>$_POST['email']))
);
if($record===null) {
echo "Email invalid";
}
else {
echo "email exists";
$this->render('Password');
if(isset($_POST['Password']))
{
$command = Yii::app()->db->createCommand();
$command->insert('User', array(
'password'=>$_POST['password'] ,
//'params'=>array(':password'=>$_POST['password'])
}
}
}
else{
$this->render('emailForm'); //show the view with the password field
}
But its not inserting new password. So How can i implement this...Please help me
First of all the way you are handling the form is certainly not Yii-ish which means it's not really the way to go.
The way you should handle this is by creating an object which extends from the CFormModel and put all your logic code in there instead of in the controller.
Now, if you want to continue working with your piece of code, then it would be best to place the following piece of code
$this->render('Password');
BELOW the if isset password stuff.
For your problem, the reason why your password isn't being updated is because the query you created is not being executed. If we take a look here then we can see that the following piece of code should be added:
$command->execute();
Which will execute your piece of sql.
Something like this...
$user = User::find('email = :email', ':email' => $_POST['email']);
if( empty($user) )
return;
$user->password = $_POST['password'];
$user->save();
You can't get password like this $_POST['Password'], because you haven't set this post variable.
You had to use:
echo CHtml::textField('password');
echo CHtml::textField('repeatPassword');
echo CHtml::hiddenField('email', $email);
'password' and 'repeatPassword' are names of POST vars
And in your controller you have too many mistakes, try this (check for typos):
if(isset($_POST['email']))
{
$record=User2::model()->find(array(
'select'=>'userId, securityQuestionId, primaryEmail',
'condition'=>'primaryEmail=:email',
'params'=>array(':email'=>$_POST['email']))
);
if($record===null) {
echo "Email invalid";
}
else {
if(isset($_POST['password']) && isset($_POST['repeatPassword']) && ($_POST['password'] === $_POST['repeatPassword']))
{
$record->password = $_POST['password'];
if ($record->save()) {
$this->render('saved');
}
}
$this->render('Password' array('email'=>$_POST['email']));
}
}
}
else{
$this->render('emailForm'); //show the view with the password field
}
In your code if(isset($_POST['Password'])) won't ever execute, because after sending password you haven't set email variable. So you just $this->render('emailForm');. Thus we set it by CHtml::hiddenField('email', $email);
Upd. I strongly recommend you to read this guide. It will save a lot of time for you.

CGridview filter on page load with pre define value in search field

I am working with the Yii framework.
I have set a value in one of my cgridview filter fields using:
Here is my jQuery to assign a value to the searchfield:
$('#gridviewid').find('input[type=text],textarea,select').filter(':visible:first').val('".$_GET['value']."');
And here my PHP for calling the cgridview:
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'bills-grid',
'dataProvider'=>$dataProvider,
'filter'=>$model,
'cssFile'=>Yii::app()->baseUrl . '/css/gridview.css',
'pager'=>array(
'class'=>'AjaxList',
'maxButtonCount'=>25,
'header'=>''
),
'columns' => $dialog->columns(),
'template'=>"<div class=\"tools\">".$dialog->link()." ".CHtml::link($xcel.' Export to excel', array('ExcelAll'))."</div><br />{items}{summary}<div class=\"pager-fix\">{pager}</div>",));
The value appears in the search field and my cgridview works correctly without any issues, but I am unable to trigger the cgridview to refresh or filter. Does anyone know who to trigger the cgridview to filter after page load with a predefined value?
Any help would be greatly appreciated and please let me know if you need additional information.
Thank you.
You can solve the problem without any clientside code modification. In your controller action just set the default value for the attribute as shown below
public function actionAdmin()
{
$model = new Bills();
$model->unsetAttributes();
$model->attribute_name="default filter value";//where attribute_name is the attribute for which you want the default value in the filter search field
if(isset($_GET['Bills'])){
$model->attributes = $_GET['Bills'];
}
$this->render('admin',array('model'=>$model));
}
Have a look at 'default' index action that gii generates:
public function actionIndex()
{
$model = new Bills();
$model->unsetAttributes();
if(isset($_GET['Bills'])){
$model->attributes = $_GET['Bills'];
}
$this->render('index',array('model'=>$model));
}
So if you add one line like: $model->attribute = 'test';, you're done. 'attribute' is of course the attribute that has to have the default filter value (in this case value is 'test') :). So your code looks like:
public function actionIndex()
{
$model = new Bills();
$model->unsetAttributes();
if(isset($_GET['Bills'])){
$model->attributes = $_GET['Bills'];
}
if(!isset($_GET['Bills']['attribute']) {
$model->attribute = 'test';
}
$this->render('index',array('model'=>$model));
}
Of course youre attribute will have a test value (in filter) set up as long as you wont type anything in its filter field. I hope that that's what you're looking for. Your filter should work as always.
Sorry for my bad english :)
Regards
You can use Yii's update:
$.fn.yiiGridView.update('bills-grid', {
type: 'GET',
url: <?php echo Yii::app()->createUrl('controller/action') ?>"?Class[attribute]=<?php echo $_GET['value'] ?>
success: function() {
$.fn.yiiGridView.update('bills-grid');
}
});
This is how i do it, just change the URL, it should be the same controller action of the gridview and change URL parameters to the structure represented in there, should be like Bills[attribute]=value.