Using laravel presenters inside illuminate/html model forms - php

I use laravel presenters from laracasts video. Basically it doesn't matter that much. What I want is to format output data when I use Form::model. So, for example, I have a phone number input:
<div class="form-group">
{!! Form::label('phone', 'Phone' ) !!}
{!! Form::text('phone', null, ['class' => 'form-control', 'id' => 'phone']) !!}
</div>
In the DB I store phones in e.164 format, but when I output them I want to display them in more readable format. But data-accessors from Laravel won't help me because inside my application I want to use e.164. If I set accessor for phone attribute than I won't be able to get e.164 inside my classes. So, instead of accessors I user presenters, but it doesn't matter that much. Let's say I want to use php number_format function when outputting model attributes inside Form::text. How can I do that?

There's nothing forcing you to have a one to one accessor to field relationship. So you can create a formatted phone attribute to use in the form, and use the phone attribute directly from within your classes.
public function getFormattedPhoneAttribute()
{
return // formatted $this->phone
}
If you already have the presenters set up then you can use them in your form instead of using Form::model.
<div class="form-group">
{!! Form::label('phone', 'Phone' ) !!}
{!! Form::text('phone', $user->present()->phone, ['class' => 'form-control', 'id' => 'phone']) !!}
</div>
Either one of these should work for you, but I would recommend you choose one: Accessors or Presenters, not both.

Related

User Submitted Posts Store function using Laravel

So in addition to my prior topic (thank you guys for helping) routes with compact
I am now facing troubles with my store function, I am getting the error : "Trying to get property of non-object.
This is my store function in my Controller
public function store(Request $request)
{
// validate the data
$this->validate($request, array(
'title' => 'required|max:255',
'body' => 'required'
));
// store in the database
$userpost = new Usp;
$userpost->title = $request->title;
$userpost->body = $request->body;
$userpost->save();
Session::flash('success', 'The blog post was successfully saved!');
return redirect()->route('admin.userposts.show', $userpost->id);
}
This is the view to create userpost(to make it more clear, p.s. the same form with different route ofcourse, works for my simple posts but not for my user submitted posts)
#extends('index')
#section('index-stylesheets')
{!! Html::style('css/parsley.css') !!}
#endsection
#section('content')
<h1>Create New User Post</h1>
<hr>
{!! Form::open(array('route' => 'admin.userposts.store', 'data-parsley-validate' => '')) !!}
{{ Form::label('title', 'Title:') }}
{{ Form::text('title', null, array('class' => 'form-control', 'required' => '', 'maxlength' => '255')) }}
{{ Form::label('body', "Post Body:") }}
{{ Form::textarea('body', null, array('class' => 'form-control', 'required' => '')) }}
{{ Form::submit('Create Post', array('class' => 'btn btn-success btn-lg btn-block', 'style' => 'margin-top: 20px;')) }}
{!! Form::close() !!}
#endsection
#section('index-scripts')
{!! Html::script('js/parsley.min.js') !!}
#endsection
Method of showing the post:
public function show($id)
{
$userpost = Usp::find($id);
return view('admin.userposts.show', compact('userpost'));
}
So the fact is that the problem was not the store method but the routes.
Route::get('/userposts/{id}', 'UserPostsController#show')->name('admin.userposts.show');
Route::get('/userposts/create', 'UserPostsController#create')->name('admin.userposts.create');
Route::post('/userposts/store', 'UserPostsController#store')->name('admin.userposts.store');
When registering the routes in that order, when laravel will iterate over your routes, it will first encounter the show one, and it will therefore take "create" as the id. Therefore, it will go into the show method and it won't find any post that matches, the post being null, you get the error.
So, there are two ways of fixing this.
The first one (the easiest, works in all cases, maybe not the best) is to put the create route before the show route.
The second one, the best in my opinion, is to add a condition to the id (doesn't work in the case of a slug). As the ids are only integers, you get :
Route::get('/userposts/{id}', 'UserPostsController#show')->name('admin.userposts.show')->where('id', '[0-9]+');
Therefore, create won't match the regular expression and it won't go in the show method.
For "resource creations" (storing in database), I wouldn't use a "field-by-field" method.
Instead, I'd do something like this :
$userpost = Usp::create($request->only('title', 'body'));
I feel this is more talkative.
But, it won't work, laravel protects* us against such things. To make it work, you have two options.
(The best option in my opinion)
In your model, add a protected variable called $fillable with all your columns that you allow to mass assign*. In this case you would put :
protected $fillable = ['name'];
(The option if you are sure of what are you doing)
In your model, you can say, hey, I know what I'm doing here, just let me do my stuff without guarding me. In this case you would put :
protected $guarded = [];
Notes :
$request->only('field1', ...) gives you an array of the fields that you want with the fields name as keys, in this case it gives you ['field1' => $request->field1]. In your case it will give you ['title' => $request->title, 'body' => $request->body].
Mass assignment is when you give an array to the model and it puts all attributes to the fields of the array. More informations here https://laravel.com/docs/5.4/eloquent#mass-assignment
When I mean laravel protects us against those things, it does't really protect us because it isn't a bad practice (instead, I find it more readable), but because it does allow you to make mistakes (for exemple, setting fields that don't exist).

Laravel 5 Form Model Binding Checkbox Values

I am using a checkbox in a form, for some reasons I can't store the value of the checkbox status (checked or unchecked).
I am using form model binding.
My form is:
{!! Form::model($profile, ['method' => 'PATCH', 'action' => ['ProfilesController#update', $profile->id]]) !!}
<div class="form-group">
{!! Form::label('wifi', 'Wifi') !!}
{!! Form::checkbox('wifi','yes', $profile->wifi) !!}Wifi
</div>
{!! Form::close() !!}
My Schema:
$table->boolean('wifi')->nullable();
But I also tried it with an integer
I can't figure out what I am doing wrong
Your this piece of code
{!! Form::checkbox('wifi','yes', $profile->wifi) !!}Wifi
is generating this
<input checked="checked" name="wifi" type="checkbox" value="yes">
Which means that you are sending the value yes to the server but your column data type is not varchar/text. You set it to boolean.
update your code to this because you are using form model binding so no need to popluate it, laravel will do this for you.
{!! Form::checkbox('wifi') !!} Wifi
Also, include your wifi key in fillable and casts array. like so
protected $fillable = [ ..., 'wifi' ];
protected $casts = [ 'wifi' => 'boolean' ];
Note: your schema code
$table->boolean('wifi')->nullable;
nullable is not a property, it is a function. so update it as well
$table->boolean('wifi')->nullable();
After that refersh your database migration
php artisan migrate:refresh
It depends on how are you trying to persist this data.
If you're using save() method, do something like this:
$model->wifi = isset($request->wifi);
PS: I guess it should be ->nullable()

Laravel 5 binding value in bootstrap-slider in edit/Patch

I'm implementing bootstrap-slider in my CRUD, I have implemented it successfully in Create, the problem is when I try to edit it,
I want to get the current value from the Model. Idk how to do this.
This is for PATCH.
<div class="form-group">
<h3 class='box-title text-info'>Percentage</h3>
{!! Form::input('text','percentage',null,['id'=>'ex8', 'data-slider-id'=>'ex1Slider', 'data-slider-min'=>'0', 'data-slider-max'=>'100', 'data-slider-step'=>'5', 'data-slider-value'=>'50']) !!}
</div>
In your form instead of creating a new form. You will bind the form to the model.
{!! Form::model('modelname', [options here] !!}
All the fields will math the model's property values.
Edit
Here is an example
You must used something like this to create a EDIT FORM
{{ Form::model($smartphones, ['method' => 'PATCH', 'url' => 'smartphones/'.$smartphones->id]) }}
You get by using $(your_model)['inputID']...You can use in "data-slider-value"... Something like this
{{ Form::input('text','mem_ram', null, ['id' => 'mem_ram', 'data-slider-value'=>$smartphones['mem_ram']]) }}

How to add a default blank option to a select input field using laravelcollective?

I have a form in which the user can optionally select an option and if the user does not choose an option I need the default value of 'null' be submitted to database.
I am using laravel 5.1 so my input field is as follows:
<div class="form-group col-lg-4">
{!! Form::label('cat1', 'CAT Tool 1', ['class' => 'control-label']) !!}
<div class="input-group">
<div class="input-group-addon">
<span class="glyphicon glyphicon-cog"></span>
</div>
{!! Form::select('cat1', $cats , null , ['class' => 'form-control']) !!}
</div>
</div>
Here the $cats array is an array of CAT Tools ($cats=['SDL Trados', 'Deja Vu', 'WordFast', 'OmegaT', 'Fluency'];). I have similar fields in which an array of database attributes are returned (e.g. In the controller create method I have $languages=Language::lists('fa_name', 'id');). How can I accomplish this?
The listsmethod used to return an array but as of Laravel 5.1 it returns a collection so I needed to convert the $languages to an array like this:
$languages=Language::lists('fa_name', 'id')->all();
or
$languages=Language::lists('fa_name', 'id')->toArray();
Next in the view I can use the following:
{!! Form::select('from1', [null => 'Select your language'] + $languages, null , ['class' => 'form-control']) !!}
which will add an empty option to the select field.
I don't know about having it submit as null. If you put a blank one in there, it will just come back as an empty string so you would have to check that it's empty and if it is, set it to null.
To add it to the array, simply add it to the beginning and it should work.
$cats = ['', 'SDL Trados', 'Deja Vu', 'WordFast', 'OmegaT', 'Fluency'];
Or if you already have the $cats variable and you need to modify it...
array_unshift($cats, '');
You may have to key these arrays though because I believe the select is going to set the keys as the text and the values as the value in the option elements.
In that case, you will want to still use array_unshift and pass in an array instead of a string.
array_unshift($languages, ['Optional' => '']);`
That will add an additional option to the select with the test Optional and no value.

laravel populate select box

I have seen similar questions asked before, but was unable to find a solution to my problem. So I have a ClientController and within it this function
public function edit(Client $client)
{
return view('clients.edit', compact('client'));
}
So that passes the client object to my edit view. This view is pretty much the following
{!! Form::model($client, ['method' => 'PATCH', 'route' => ['clients.update', $client->slug]]) !!}
#include('clients/partials/_form', ['submit_text' => 'Edit Client'])
{!! Form::close() !!}
So it is using a partial for the form. At the moment, the partial looks like so
<div class="form-group">
{!! Form::label('clientName', 'Client Name:') !!}
{!! Form::text('clientName') !!}
</div>
<div class="form-group">
{!! Form::label('clientStatus', 'Client Status:') !!}
{!! Form::select('clientStatus') !!}
</div>
When I visit the edit page for a client, I can see the form. The clientName is populated with the clientName value. The clientStatus is populated if I put it as a text input, but I cant get it to populate within a select as shown above. Furthermore, clientStatus can either be New or Existing. I need the select box to be pre-populated with the status of the client that is being edited, but I need the other option available within the select as well. So if the clientStatus is New, New should be pre-selected within the select box and if I open the select, Existing should be the other option.
What would be the best way to achieve this?
Thanks
Modify your select to include an array of the possible values.
Basic Select - Label is value
{!! Form::select('clientStatus',['New','Existing']) !!}
Key Value Select - Key is value
{!! Form::select('clientStatus',[ 1 => 'New', 2 => 'Existing']) !!}
Form model will then set the value in the select to the one in the model.
More information see the docs.

Categories