Take user input in Yii2 console command - php

I want to create a console command in Yii2 where I can take the input from the user.
I have looked into the Yii2 documentation here-
http://www.yiiframework.com/doc-2.0/guide-tutorial-console.html
But I could not find anything helpful.
I have also searched on Google and StackOverflow with no luck.

CLI command prompt for any user string:
class CronController extends yii\console\Controller
{
public function actionSendTestmail()
{
$emailTo = \yii\helpers\BaseConsole::input("Recipient email: ");
...
}
}
or just ask for confirmation [yes|no]:
class CronController extends yii\console\Controller
{
public function actionSendTestmail()
{
$emailTo = Yii::$app->params["email.to"];
if(!$this->confirm("Send email to {$emailTo}?")){
exit("Sending email interrupted.\n")
}
...
}
}

Check out yii\helpers\BaseConsole helper class method input().
input('Enter your name');
Will prompt you for your name.
Or you can define arguments for the action method to pass values to the action.
static function actionDoSomething (arg1, arg2, ...);

You can use the method prompt() provided in the yii\console\Controller that calls the yii\helpers\BaseConsole::prompt() and gives you additional control to validate the input too after the user enters or just mark it as required so that it is not empty
$code = $this->prompt(
'Enter 4-Chars-Pin',
[
'required' => true,
'validator' => function ($input, &$error) {
if (strlen($input) !== 4) {
$error = 'The Pin must be exactly 4 chars!';
return false;
}
return true;
},
]
);

Related

Symfony 2 Class Constructer Not Getting ContainerInterface?

ok, So I am still a little new to Symfony 2 but I have been all over the web trying to see what I am doing wrong, but going over and over the Symfony docs, I can't see why its not working.
So I have tow points in my app that will need to send two new user emails, one with a password and one with an active path to verify the email. I am using MailGun to send the emails, this works fine. But has I have two controllers that will send these emails, I thought that if I wanted to change/edit them, it would be best if they where in the same place. So I build my own class for them to go in.
This is the problem, as it is not an controller I am trying to 'render' an Standard Email template layout. And for the life of me can not figure out why its not working.
So my Class:
namespace xxxBundle\Classes;
//use Symfony\Component\Templating\EngineInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class NewUserEmails {
//private $templating;
//public function __construct(EngineInterface $templating) {
// $this->templating = $templating;
//}
private $container;
public function __construct(ContainerInterface $container) {
$this->templating = $container->get('templating');
}
public function SendActivePathEmail($GetNewUserID, $Token) {
/* Send Active Path To New User - Before Password */
$Email_Header_ActiveUser = 'Access';
$Email_Content_ActiveUser = 'Please active your account, by clicking the link below.';
$Email_Content_ActiveUser .= '<br/><br/><strong>PLEASE NOTE:</strong> Your account is not active untill you have vifyied your email';
$Email_Content_ActiveUser .= '<br/><br/><p>Active Account Link</p>';
$ActiveUserEmail = $this->templating->render('xxxBundle:Emails:StandardEmail.html.twig',
['EmailContent' => $Email_Header_ActiveUser,
'EmailMessage' => $Email_Content_ActiveUser],
'text/html');
return $ActiveUserEmail;
}
public function SendPswEmail($PlainPwd) {
/* Send Password To New User */
$Email_Header_NewPsw = 'Access';
$Email_Content_NewPsw = 'This is your password <strong>' .$PlainPwd. '</strong> for xxxxx login';
$PasswordEmail = $this->templating->render('xxxBundle:Emails:StandardEmail.html.twig',
['EmailContent' => $Email_Header_NewPsw,
'EmailMessage' => $Email_Content_NewPsw],
'text/html');
return $PasswordEmail;
}
} //Class End
Now this is what I have in my services YML file,
new_user_emails:
class: xxxBundle\Classes\NewUserEmails
arguments: [#service_container]
This is the services file within my bundle, which I know is being loaded has I have a login handler which works without any problems.
And this is how I am calling the class within my Controller,
$GetNewUserEmails = new NewUserEmails();
$ActiveUserEmail = $GetNewUserEmails->SendActivePathEmail($GetNewUserID, $Token);
$PasswordEmail = $GetNewUserEmails->SendPswEmail($PlainPwd);
So has far as I can tell I am doing it right, but when I try to save the user (which does save without any problems) I get the following error,
Catchable Fatal Error: Argument 1 passed to xxxxBundle\Classes\NewUserEmails::__construct() must implement interface Symfony\Component\DependencyInjection\ContainerInterface, none given
P.S. I have tried to insert just the tempting, but that gave me the same error!
All help most welcome,
What am I doing wrong?
Thanks,
You need to retrieve your service from the symfony container.
try this:
$GetNewUserEmails = $this->get('new_user_emails');
$ActiveUserEmail = $GetNewUserEmails->SendActivePathEmail($GetNewUserID, $Token);
$PasswordEmail = $GetNewUserEmails->SendPswEmail($PlainPwd);
Instead of this:
$GetNewUserEmails = new NewUserEmails();
$ActiveUserEmail = $GetNewUserEmails->SendActivePathEmail($GetNewUserID, $Token);
$PasswordEmail = $GetNewUserEmails->SendPswEmail($PlainPwd);
PS: Is not a good practice to pass the whole container to the service, but only the service it really needed.
Hope this help

Custom validation in Laravel 4

To add a new validation to Laravel I have done this:
made a new file called customValidation.php in app/start/
and then included it in app/start/global.php and tested it with an echo() and it worked. So it is loaded into the application now.
Then I wrote the following code to validate checkboxes in Laravel:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
class customValidate extends Illuminate\Validation\Validator
{
public function validateCheckbox($attribute, $value, $parameters)
{
//if(isset($value)) { return true; } else { return true; }
echo "this is the: " . $value;
}
}
/**
* Resolvers for Custom Validations
*/
Validator::resolver(function($translator, $data, $rules, $message){
return new customValidate($translator, $data, $rules, $message);
});
However, in my validation rules, I define :
`array('sex'=>'checkbox')`
But it does not work. Nothing happens. No error is thrown. The application behaves as if it has not executed the function at all. Also when I echo something from within the function,nothing get echoed, another evidence for the function not being called at all.
I would create custom app/validators folder for this then.
1, Create app/validators/CustomValidate.php
<?php
class CustomValidate extends Illuminate\Validation\Validator
{
public function validateCheckbox($attribute, $value, $parameters)
{
echo "this is the: " . $value;
}
}
2, run php artisan optimize or composer dumpautoload
3, Somewhere register your custom validator. Perhaps add app/validators.php into start/global.php
Validator::resolver(function($translator, $data, $rules, $message){
return new CustomValidate($translator, $data, $rules, $message);
});
4, Validate
$rules = ['agreed' => 'checkbox'];
$data = ['agreed' => 0];
$v = Validator::make($data, $rules);
dd($v->passes());
When submitting the form, the radios were not set in their initial states, and this made Laravel not to look for the validator of the item. So, it doesn't have any workaround for that. What I did was I simply added an initial state to the radios and they worked.
Much Like said by Andreyco

How to show Validation message in Controller?

I have tried showing an error message in a Controller and it doesn't work, but when I use dd, it works.
My Code:
if ($validation->fails())
{
/*Doesn't work
foreach ($validation->fails() as $messages) {
$messages // Doesn't work
}
*/
dd($validation->errors); //This works
}
I noticed none of the provided examples here actually work! So here you go. This was my found solution after realizing that validator->messages() returns a protected object which isn't retrievable.
if ($validator->fails())
{
foreach ($validator->messages()->getMessages() as $field_name => $messages)
{
var_dump($messages); // messages are retrieved (publicly)
}
}
I would reference MessageBag, which is what messages() returns. And for additional acknowledgement of the Validator class - reference this.
$validation->fails() returns a boolean of whether or not the input passed validation. You can access the validation messages from $validation->messages() or pass them to the view where they will be bound to the $errors variable.
See the validator docs.
This is what I have just used in an artisan 5.0 console command, to validate the arguments. This is in the fire() method:
// Create the validator.
$validator = Validator::make(
$this->argument(),
['field1' => 'required|other|rules']
);
// Validate the arguments.
if ($validator->fails())
{
// Failed validation.
// Each failed field will have one or more messages.
foreach($validator->messages()->getMessages() as $field_name => $messages) {
// Go through each message for this field.
foreach($messages AS $message) {
$this->error($field_name . ': ' . $message);
}
}
// Indicate the command has failed.
return 1;
}
This is an extension on the answer from #tfont
You may need to change where the message is sent ($this->error()) if this command is not being run as an console command, ie CLI, command-line.

custom validator in symfony

I would like create custom validator for Symfony 1.4, for example check length name. I know that it exist, but i would like own.
I create /myapp/lib/validator/sfValidatorName.class.php
Must be there:
class sfValidatorName extends sfValidatorBase
{
protected function configure($options = array(),
$messages = array()) {
$this->addMessage('invalid', 'Invalid name!');
}
protected function doClean($value) {
}
}
and how can i add for this my function, for example:
if (count($letters) < 3) {
return 'too small';
} else if (count($letters) > 43) {
return 'too long';
}
Open /lib/validator/sfValidatorString.class.php
Model your validator after that one.
Since your example is exactly what sfValidatorString does, why don't you go look at it's source? Basically you just throw a validation error with the relevant error code (eg. invalid, min_length, max_length, ...).
By default any validator has the errors 'invalid' and 'required', but you can add your own with addMessage().
For this specific example, a much smarter choice is to configure or extend sfValidatorString.

Symfony Form: Set default/value on error?

My crazy designer would like the message "Required" displaying (in red) inside a field if the form has been submitted and it is invalid because of an empty field.
The form in question is a login prompt and I'm using a custom class that extends sfGuardFormSignin
I've managed to set the value and add a class with..
$this->widgetSchema['username']->setAttribute('class','red');
$this->widgetSchema['username']->setDefault('Required');
..but how do I do this only when the username field is invalid and because of the Required error?
I assume it's the same for the password field?
Many thanks in advance
EDIT:
Thanks for the advice greg0ire. I've had a play with that but the formatRow method of sfWidgetFormSchemaFormatter doesn't seem to be getting hit. Is this because my form extends sfGuardFormSignin and using the sfGuardAuth plugin?
class FrontendsfGuardFormSignin extends sfGuardFormSignin
{
public function configure()
{
parent::configure();
// This works!
$this->widgetSchema['username']->setLabel('Email');
// I copied this from the link you pasted
$decorator = new myWidgetFormSchemaFormatterCustom($this->getWidgetSchema());
$this->widgetSchema->addFormFormatter('custom', $decorator);
$this->widgetSchema->setFormFormatterName('custom');
}
}
/lib/widget/myWidgetFormSchemaFormatterCustom.class.php
class myWidgetFormSchemaFormatterCustom extends sfWidgetFormSchemaFormatter
{
public function __construct(sfWidgetFormSchema $widgetSchema)
{
parent::__construct($widgetSchema);
}
public function formatRow($label, $field, $errors = array(), $help = '', $hiddenFields = null)
{
// Nothing happens!?
var_dump($errors);
die();
parent::formatRow($label, $field, $errors, $help, $hiddenFields);
}
}
$widget->render(array('value' => $widget->getError()));
Designers have such crazy ideas...
You'll have to write a custom schema formatter to do this. You'll probably have to override the formatRow() method to achieve this.
Analyse the $errors array argument of this method, and if you spot the "Required" error in it, then do your special stuff. You won't need to use the code you posted in your question.

Categories