I try to show two flash messages in Laravel using with:
return redirect('cabinet/result')->with('user', $client->unique_code)->with('fio', $client->name.' '.$client->secondname. ' '.$client->patronymic);
Then I display this as:
{{ session('fio') }} {{ session('unique_code') }}
It shows me nothing
Firstly, when you pass data with the method 'with' to a view, it does not get stored in the session, it is just made available as a variable with the same name to the view that gets loaded after the redirect takes place.
You have two options:
Passing an array of key value pairs to the view
You may pass an array of data to views:
return view('greetings', ['name' => 'Victoria', 'last_name' => 'Queen']);
As you can see by the way the method is implemented in {root}/vendor/laravel/framework/src/Illuminate/View/View.php
/**
* Add a piece of data to the view.
*
* #param string|array $key
* #param mixed $value
* #return $this
*/
public function with($key, $value = null)
{
if (is_array($key)) {
$this->data = array_merge($this->data, $key);
} else {
$this->data[$key] = $value;
}
return $this;
}
the method accepts either a key value pair, or an array. All the keys of this array will be available in the view that is loaded next as php variables with the same name (of course you need to append the dollar sign to the calls in the view). So in the 'greetings' view you would retrieve them as such:
$variable1 = {{ $name }}
$variable2 = {{ $last_name }}
Flashing an array of key value pairs to the next session
You can do pretty much the same using the flashInput method that is found in {root}/vendor/laravel/framework/src/Illuminate/Session/Store.php:
/**
* Flash a key / value pair to the session.
*
* #param string $key
* #param mixed $value
* #return void
*/
public function flash($key, $value)
{
$this->put($key, $value);
$this->push('_flash.new', $key);
$this->removeFromOldFlashData([$key]);
}
You would do that as such:
$request->session()->flashInput('flashData' => ['key1' => value1, 'key2' => value2]);
The difference here is that the data would not be available as variables to your loaded view. Instead they would be stored in an associative array in the session and you would retrieve the stored values this way:
$variable1 = {{ session('flashData['key1']) }}
$variable2 = {{ session('flashData['key2']) }}
Resources
https://laravel.com/docs/5.3/views
https://laravel.com/docs/5.3/session
If you feel that this solved your problem please mark the answer as accepted :)
First make sure your queries return data.
In my projects, I use simple way for doing it.
$user = $client->unique_code; //now user has the code
$fio = $client->name.' '.$client->secondname. ' '.$client->patronymic;
//please make sure this returns your indented result.
return redirect('cabinet/result')->with('user', $user)->with('fio',$fio );
I hope this will work,
Try this code:
$user = 'user';
$fio = 'fio';
return redirect('cabinet/result')
->with('user', $user)
->with('fio', $fio);
For View:
{{ Session::get('user') }} {{ Session::get('fio') }}
Related
I want to validate the array inputs value to already selected or not. In my case, I am using Laravel Livewire and I have dynamic inputs such as I can add new options like Size, Color. But I do not want to select the same value in two inputs like the select size in two inputs. Basically, If select the same value in the second input, I want to show it already selected.
Below code livewire controller,
public $i = -1;
public $inputs = [];
public $options = ['Size', 'Color', 'Material', 'Style'];
public $option_name;
function rules()
{
$rules = [];
if ($this->inputs) {
foreach ($this->inputs as $key => $val) {
$rules['option_name.' . $val] = ['required'];
}
return $rules;
}
}
public function addLine($i)
{
$i = $i + 1;
$this->i = $i;
array_push($this->inputs, $i);
}
public function updated($propertyName)
{
if ($this->inputs) {
$this->validateOnly($propertyName);
}
}
Below code livewire view code,
#forelse ($inputs as $key => $value)
<x-native-select label="Option name" :options="$options" wire:model="option_name.{{ $value }}"/> // I am using livewire-wireui
#empty
#endforelse
<a wire:click="addLine({{ $i }})" class="mt-4 text-sm cursor-pointer">
+ Add another option
</a>
Any idea how to validate this?
Try this and let me see how it goes.
public function updatedOptionName($selectedOption) {
//You can use laravel collection filter as well depending on how commplicated you want it
$this->options = array_filter($this->options, function ($value) {
return $value != $selectedOption;
}, ARRAY_FILTER_USE_BOTH));
}
The above function would filter out the selected option so that the option is not available when it is already selected. It might be overkill and subject to improvement from the community. All reviews are welcome. One thing to note is that you might want a sort of reset method in case the user decides to start all over again. Something along the lines of public $originalOptions that you would want to set on mount and then a reset function that assigns this->options to it. Let me know if it works.
More info on those functions Lifecycle hooks
What's the basic difference between Laravel's foreach and forelse? How does forelse work?
I know that foreach duplicates your given array and works on it while in forelse it checks whether it exists and loops on it if it exists but if not it uses your provided else condition.
I believe the answer to your question is that, essentially, ForElse is a ForEach loop, but with extra handling for empty array.
From the Laravel 5 docs on Blade Templates, an example illustrating both loops with the same list of Users as Input:
#foreach ($users as $user)
<p>This is user {{ $user->id }}</p>
#endforeach
#forelse ($users as $user)
<li>{{ $user->name }}</li>
#empty
<p>No users</p>
#endforelse
Now if we compare this to the source code for the Laravel Framework to see how the loops are compiled (all Blades constructs are compiled into HTML when being rendered by PHP on the web page):
/**
* Compile the for-each statements into valid PHP.
*
* #param string $expression
* #return string
*/
protected function compileForeach($expression)
{
preg_match('/\( *(.*) +as *(.*)\)$/is', $expression, $matches);
$iteratee = trim($matches[1]);
$iteration = trim($matches[2]);
$initLoop = "\$__currentLoopData = {$iteratee}; \$__env->addLoop(\$__currentLoopData);";
$iterateLoop = '$__env->incrementLoopIndices(); $loop = $__env->getLastLoop();';
return "<?php {$initLoop} foreach(\$__currentLoopData as {$iteration}): {$iterateLoop} ?>";
}
/**
* Compile the for-else statements into valid PHP.
*
* #param string $expression
* #return string
*/
protected function compileForelse($expression)
{
$empty = '$__empty_'.++$this->forElseCounter;
preg_match('/\( *(.*) +as *(.*)\)$/is', $expression, $matches);
$iteratee = trim($matches[1]);
$iteration = trim($matches[2]);
$initLoop = "\$__currentLoopData = {$iteratee}; \$__env->addLoop(\$__currentLoopData);";
$iterateLoop = '$__env->incrementLoopIndices(); $loop = $__env->getLastLoop();';
return "<?php {$empty} = true; {$initLoop} foreach(\$__currentLoopData as {$iteration}): {$iterateLoop} {$empty} = false; ?>";
}
Essentially, the ForElse loop has a built-in code and compile check for an empty input, in which case it optionally outputs an alternate display template for the empty input.
I would imagine you can use a ForEach loop in every case that you might use a ForElse loop, adding that you include and empty checks that ForElse might catch for you.
Links for reference:
Blade Templates
Blade View Compile Functions
The foreach loop as you described loops over each element in an array, the foresee loop in essence is exactly the same with one extra element as you already noticed, the else statement. The primary use for this to use when you have an empty array.
Thus looping over all elements and for example rendering a row of a table but putting an empty notice when you do not have any data.
See the basic difference is in case of no data found
foreach loop you have to check count condition and then print as per output. This will increase little bit of effort but in forelse it auto check and using #empty you have to echo no data found..
On my project i made a contact form. It was store details on databse and shows admin panel and sends it to via mail so i cant pass array variables to mailable view.
My controller;
$iletisim = new Contact();
$iletisim->ad = $request->input('ad');
$iletisim->soyad =$request->input('soyad');
$iletisim->email = $request->input('email');
$iletisim->mesaj = $request->input('mesaj');
$iletisim->save();
$gonder = array( 'gonderen'=>$request->input('ad'),
'email'=>$request->input('email'),
'mesaj'=>$request->input('mesaj')
);
Mail::send(new ContactMail($gonder));
Session::flash('success', 'Mesajınız Gönderilmiştir. En kısa sürede dönüş sağlanacaktır.');
return back();
}
My Contact.php
public $bilgiler;
public function __construct($gonder)
{
$this->bilgiler = $gonder;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view('homepage.emails.contact')->with(['bilgiler'=>$this->bilgiler]);
}
and my blade file
#component('mail::message')
# New Contact Form
{{$bilgiler->ad}}
Thanks,<br>
{{ config('app.name') }}
#endcomponent
Where is my mistake can you help.
Thanks
First of all, you don't need to add ->with(['bilgiler'=>$this->bilgiler]); since $bilgiger is public property. All public properties of Mailable are available in Blade
Also, since it's an array, you need to access it with:
$bilgiger['gonderen']
The $bilgiler->gonderen syntax is for objects, not for arrays. Also, you don't have id in the array.
And the last thing is you're using markdown email, so use the markdown() method:
return $this->markdown('homepage.emails.contact');
I'm using Form Model Binding as such and updating my DB using the fill() and save() methods.
{{ Form::model($account) }}
{{ Form::text('name', null, array('class'=>'class')) }}
{{ Form::text('email', null, array('class'=>'class')) }}
{{ Form::password('password', array('class'=>'class')) }}
{{ Form::password('password_confirmation', array('class'=>'class')) }}
{{ Form::close() }}
Which fires my editAccount controller method:
$rules = array(
'name' => array('required'),
'email' => array('required'),
'password' => array('confirmed')
);
$validator = Validator::make(Input::all(), $rules);
if ($validator->fails())
{
// Redirect
}
// Save to DB
$account->fill(Input::all());
$account->save();
Which works fine, but if no password was supplied (because the user doesn't want to update/modify it) then the password field is set to null in the db. So, I only want the password field to update if a new password value is supplied via the form.
I know I can do the following:
// Set the fields manually
$account->name = Input::get('name');
$account->email = Input::get('email');
// Only update the password field if a value is supplied
if (Input::get('password')) {
$account->password = Input::get('password');
}
$account->save();
However I'm wondering if there is a more cleaner way to handle this? Like an UpdateOnlyIfValueExists() method within Laravel/Eloquent.
Using Input::only('foo', 'bar') will grab only the values needed to complete the request - instead of using Input::all().
However, if 'foo' or 'bar' doesn't exist within the input, the key will exist with the value of null:
$input = Input::only('foo', 'bar');
var_dump($input);
// Outputs
array (size=2)
'foo' => null
'bar' => null
To filter in a clean way, any values with a null value:
$input = array_filter($input, 'strlen');
In your example, this would replace: $account->fill(Input::all());
Create Base model and override update function like
/**
* #param array $attributes
* #return mixed
*/
public function update(Array $attributes = array()){
foreach($attributes as $key => $value){
if(!is_null($value)) $this->{$key} = $value;
}
return $this->save();
}
After use:
$model = Model::find($id);
$model->update(Input::only('param1', 'param2', 'param3'));
Check this, you can validate if password is present in input, and exclude it from mass assignment. You can use Input::except and Input::only for this purpose
public function update ($id) {
$user = User::findOrFail ($id);
if (Input::get ('password') == '') {
$user->update (Input::except ('password'));
}
else {
$user->update (Input::all ());
}
//return something
}
$data = $request->password ? $request->all():$request->except('password');
$user->update($data);
This will only update the password if it's not null
I would stick with your latter example. Another option would be to use a mutator which checks the value there, and doesn't update if the value is empty. But in my opinion, Eloquent should not be responsible for doing that.
I'd also avoid using ALL input with fill(). Choose only what you want.
This is a pretty shitty and common issue with Laravel (and other frameworks). My solution resembles some of the previous...
I always have the form data Input::all() stored in a variable at the beginning of the update/store methods. Since you usually need it at least twice (validate and create/update) it seems like a good practice. Then with that and before doing anything else I check in update() for the presence of the password, something like this:
$aFormData = Input::all();
if ( !$aFormData['password'] )
unset( $aFormData['password'] );
... the rest of your code here using $aFormData ;) ...
And that's it, hope it helps!
A much cleaner approach would be to use Eloquent Mutators
Under no circumstances would you allow a null or an empty string as password so you can safely define the following mutator in your Account model.
// Only accept a valid password and
// hash a password before saving
public function setPasswordAttribute($password)
{
if ( $password !== null & $password === '' )
{
$this->attributes['password'] = bcrypt($password);
}
}
The above mutator will only set a password attribute if it is not null and an empty string. It also hashes the password before saving so you do not need to do it in your controller action or application elsewhere.
Best approche is to use mutators as Noman Ur Rehman said above, but he had mistake in his code. Right one will be:
public function setPasswordAttribute($password){
if ( $password !== null && $password !== '' )
$this->attributes['password'] = Hash::make($password);
}
How can we validate form fields that are arrays? Take a look at the following code
UserPhone Model:
public static $rules= array(
'phonenumber'=>'required|numeric',
'isPrimary'=>'in:0,1'
)
...........
UserController:
$validation = UserPhone::validate(Input::only('phonenumber')));
if($validation->passes())
{
$allInputs = Input::only('phonenumber','tid');
$loopSize = sizeOf($allInputs);
for($i=0;$i<$loopSize;$i++)
{
$phone = UserPhone::find($allInputs['tid'][$i]);
$phone->phonenumber = $allInputs['phonenumber'][$i];
$phone->save();
}
return Redirect::to('myprofile')->with('message','Update OK');
}
else
{
return Redirect::to('editPhone')->withErrors($validation);
}
}
the $validation comes from a BaseModel which extends Eloquent.
In my view:
<?php $counter=1; ?>
#foreach($phones as $thephone)
<section class="col col-12">
<label class="label">Phone Number {{$counter++}}</label>
<label class="input">
<i class="icon-append icon-phone"></i>
{{Form::text('phonenumber[]',$thephone->phonenumber)}}
{{Form::hidden('tid[]',$thephone->id)}}
</label>
</section>
#endforeach
Everything is working fine and I get all the phone numbers I want in the Update Form, but I cannot update the model because the validation fails with the message "Phonenumber must be a number".
I know that there is not a simple solution for validating array form fields and I tried to extend the validator class but with no success.
How can I validate this kind of fields?
Here's the solution I use:
Usage
Simply transform your usual rules by prefixing each. For example:
'names' => 'required|array|each:exists,users,name'
Note that the each rule assumes your field is an array, so don't forget to use the array rule before as shown here.
Error Messages
Error messages will be automatically calculated by the singular form (using Laravel's str_singular() helper) of your field. In the previous example, the attribute is name.
Nested Arrays
This method works out of the box with nested arrays of any depth in dot notation. For example, this works:
'members.names' => 'required|array|each:exists,users,name'
Again, the attribute used for error messages here will be name.
Custom Rules
This method supports any of your custom rules out of the box.
Implementation
1. Extend the validator class
class ExtendedValidator extends Illuminate\Validation\Validator {
public function validateEach($attribute, $value, $parameters)
{
// Transform the each rule
// For example, `each:exists,users,name` becomes `exists:users,name`
$ruleName = array_shift($parameters);
$rule = $ruleName.(count($parameters) > 0 ? ':'.implode(',', $parameters) : '');
foreach ($value as $arrayKey => $arrayValue)
{
$this->validate($attribute.'.'.$arrayKey, $rule);
}
// Always return true, since the errors occur for individual elements.
return true;
}
protected function getAttribute($attribute)
{
// Get the second to last segment in singular form for arrays.
// For example, `group.names.0` becomes `name`.
if (str_contains($attribute, '.'))
{
$segments = explode('.', $attribute);
$attribute = str_singular($segments[count($segments) - 2]);
}
return parent::getAttribute($attribute);
}
}
2. Register your validator extension
Anywhere in your usual bootstrap locations, add the following code:
Validator::resolver(function($translator, $data, $rules, $messages)
{
return new ExtendedValidator($translator, $data, $rules, $messages);
});
And that's it! Enjoy!
Bonus: Size rules with arrays
As a comment pointed out, there's seems to be no easy way to validate array sizes. However, the Laravel documentation is lacking for size rules: it doesn't mention that it can count array elements. This means you're actually allowed to use size, min, max and between rules to count array elements.
It works best to extend the Validator class and re-use the existing Validator functions:
Validator::resolver(function($translator, $data, $rules, $messages)
{
return new Validation($translator, $data, $rules, $messages);
});
class Validation extends Illuminate\Validation\Validator {
/**
* Magically adds validation methods. Normally the Laravel Validation methods
* only support single values to be validated like 'numeric', 'alpha', etc.
* Here we copy those methods to work also for arrays, so we can validate
* if a value is OR an array contains only 'numeric', 'alpha', etc. values.
*
* $rules = array(
* 'row_id' => 'required|integerOrArray', // "row_id" must be an integer OR an array containing only integer values
* 'type' => 'inOrArray:foo,bar' // "type" must be 'foo' or 'bar' OR an array containing nothing but those values
* );
*
* #param string $method Name of the validation to perform e.g. 'numeric', 'alpha', etc.
* #param array $parameters Contains the value to be validated, as well as additional validation information e.g. min:?, max:?, etc.
*/
public function __call($method, $parameters)
{
// Convert method name to its non-array counterpart (e.g. validateNumericArray converts to validateNumeric)
if (substr($method, -7) === 'OrArray')
$method = substr($method, 0, -7);
// Call original method when we are dealing with a single value only, instead of an array
if (! is_array($parameters[1]))
return call_user_func_array(array($this, $method), $parameters);
$success = true;
foreach ($parameters[1] as $value) {
$parameters[1] = $value;
$success &= call_user_func_array(array($this, $method), $parameters);
}
return $success;
}
/**
* All ...OrArray validation functions can use their non-array error message counterparts
*
* #param mixed $attribute The value under validation
* #param string $rule Validation rule
*/
protected function getMessage($attribute, $rule)
{
if (substr($rule, -7) === 'OrArray')
$rule = substr($rule, 0, -7);
return parent::getMessage($attribute, $rule);
}
}
each()
It's not in the docs, but the 4.2 branch may have a simple solution around line 220.
Just like the sometimes($attribute, $rules, callable $callback) function, there is now an each($attribute, $rules) function.
To use it, the code would be something simpler than a sometimes() call:
$v->each('array_attribute',array('rule','anotherRule')); //$v is your validator
Caveats
sometimes() and each() don't seem to be easily chainable with each other so if you want to do specifically conditioned rules on array values, you're better off with the magic solutions in other answers for now.
each() only goes one level deep which isn't that different from other solutions. The nice thing about the magic solutions is that they will go 0 or 1 level deep as needed by calling the base rules as appropriate so I suppose if you wanted to go 1 to 2 levels deep, you could simply merge the two approaches by calling each() and passing it a magic rule from the other answers.
each() only takes one attribute, not an array of attributes as sometimes() does, but adding this feature to each() wouldn't be a massive change to the each() function - just loop through the $attribute and array_merge() $data and the array_get() result. Someone can make it a pull request on master if they see it as desirable and it hasn't already been done and we can see if it makes it into a future build.
Here's an update to the code of Ronald, because my custom rules wouldn't work with the array extension. Tested with Laravel 4.1, default rules, extended rules, …
public function __call($method, $parameters) {
$isArrayRule = FALSE;
if(substr($method, -5) === 'Array') {
$method = substr($method, 0, -5);
$isArrayRule = TRUE;
}
//
$rule = snake_case(substr($method, 8));
// Default or custom rule
if(!$isArrayRule) {
// And we have a default value (not an array)
if(!is_array($parameters[1])) {
// Try getting the custom validation rule
if(isset($this->extensions[$rule])) {
return $this->callExtension($rule, $parameters);
}
// None found
throw new \BadMethodCallException("Method [$method] does not exist.");
} // Array given for default rule; cannot be!
else return FALSE;
}
// Array rules
$success = TRUE;
foreach($parameters[1] as $value) {
$parameters[1] = $value;
// Default rule exists, use it
if(is_callable("parent::$method")) {
$success &= call_user_func_array(array($this, $method), $parameters);
} else {
// Try a custom rule
if(isset($this->extensions[$rule])) {
$success &= $this->callExtension($rule, $parameters);
}
// No custom rule found
throw new \BadMethodCallException("Method [$method] does not exist.");
}
}
// Did any of them (array rules) fail?
return $success;
}
There are now array validation rules in case this helps anybody. It doesn't appear that these have been written up in the docs yet.
https://github.com/laravel/laravel/commit/6a2ad475cfb21d12936cbbb544d8a136fc73be97