Laravel single blade file used for create and show - laravel

Is it possible and recommended that I have one lets say form.blade.php with html form file used for create new data and show existing data by ID.
I want to create this becouse file for insert and dispaly is the some. I want to avoid DRY.
Example: I have product categories, when I create a new category I need create.blade.php a file containing an html form. Now I want to use that same file to display the details of that category that will populate the fields in the fields by the given ID
Controller
// Create
public function create()
{
return view('admin.category.form');
}
// Show
public function show(Category $category)
{
$category = Category::find($category);
return view('admin.category.form', [
'category' => $category
]);
}
Or is it better to make a separate file for insert and separet file for show?

I read somewhere when you want to use same blade file then you can write in your create method as
public function create()
{
return view('admin.category.form',[
'category' => new Category()
]);
}

Related

How to create data into junction table many to many relationship without create data into the junction point to

It inserts both table inside tags and tagables, what i want is just to insert into tagables ( junction ) table. Cause before it insert into tagables, theres code to check first if tag will insert into tags table already exist or not, if exist just grab the id. To make it simple to my problem. i just don't include code to check if tags is exist or not.
post model
public function tags(){ return $this->morphToMany( Tag::class, 'tagable', 'tagables', null, 'tag_id ); }
post controller
// tags table theres a row id 1 with name greeting
$post = Post::create( ['body' => 'Hello World'] );
$post->tags()->create( ['tag_id' => 1] );
Tables
// posts table
$table->mediumIncrements('post_id');
$table->string('body');
// tags table
$table->mediumIncrements('tag_id');
$table->string('tag_name');
//tagables table
$table->unsignedMediumInteger('tag_id');
$table->unsignedMediumInteger('tagable_id');
$table->string('tagable_type');
I think the simplest way do this to start by creating the tag with the eloquent method 'firstOrCreate', and then when you already have a new tag or existing tag you can add this tag to a new Post. The code may look like something like this:
class Tag extends Model
{
protected $guarded = [];
public function posts()
{
return $this->morphedByMany(Post::class, 'taggable');
}
}
$tag = Tag::firstOrCreate(
['tag_name' => 'traveling'],
);
$post = $tag->posts()->create([
'body' => 'My new interesting post',
]);

Laravel - How to change response format for specific fields

I've "Product" model.
And need to change some value formats for only responses.
For example;
I've "price" on database as decimal (11,2).
I want this as "1.000.000,00" format on response.
Or created_at field to "Carbon::parse($this->created_at)->toDayDatetimeString()"
Or I want to add 3 specific columns with my user attribute, on response. (is_allowed etc.)
How can this be possible on model?
How can I response like that?
You can use Mutator and Accessor to set format :
https://laravel.com/docs/8.x/eloquent-mutators#accessors-and-mutators
public function setDateAttribute($date) {
$this->attributes['date'] = Carbon::createFromFormat('Y-m-d', $date);
}
public function getFirstNameAttribute($value)
{
return ucfirst($value);
}
As a best practice in Laravel you can use Eloquent Resources: Eloquent Resources
It's basically a "transformer" between models data and API/Responses Output.
The only one thing to notice is that in the Resource files yout must specify all fields and relations (if needed) of the Model manually.
In the toArray() function you can modify the type of all data of your model as you prefer.
If not, you can access the new field by $model->my_custom_field (Laravel can resolve the name of the getter function automatically).
public function toArray($request)
{
$editedFieldValue = doSomething();
return [
'my_field' => $editedFieldValue,
'other_field' => '',
];
}
If you want to do that in Model, you can create customs fields:
class MuModel extends Model
{
protected $appends = ['my_custom_field'];
public function getMyCustomFiledAttribute(){
$newData = doSomething($this->existent_field);
return $newData;
}
}
The $appends variable add the new fields to all responses generated from the Model, as a normal database field.
P.S.: You can create a getAttribute() function for existent database attribute and return the value as you want!
For example: getCreatedAtAttribute()

Populating $attributes with values from the previous model?

I've got a Laravel project (actually a Laravel Nova project) that involves entering a lot of data. To save some time I'd like to pre-fill some of the fields in my form, based on the logged in user's last entry.
I can pre-fill fields via the $attributes variable on my model, called Product, like so:
protected $attributes = [
'category' => 'ABC'
];
And I can do this for more dynamic data in the constructor like so:
function __construct() {
$this->attributes['category'] = Str::random();
parent::__construct();
}
But I'm not quite sure how I'd go about this when I want to retrieve what the user entered last time. For example, I'd like to do this:
function __construct() {
$user = auth()->user()->id;
$last = Product::where('created_by', $user)->latest()->first();
$this->attributes['category'] = $last['category'] ?? null;
}
However that ends up in an infinite loop. Same if I call $this->where('created_by' ...
Is there a way I can set $attributes of a new Product based on the last Product created by the user?
Nova fields have resolveUsing method, so in your case if you want to populate Text field:
Text::make('Category')->resolveUsing(function () {
return optional(auth()->user()->products()->latest()->first())->category;
})
I found the solution in the Nova Defaultable package.
Once you add the necessary traits, you can just add ->defaultLast() to a resource field and it'll default to the last set value. This also works for relationships which is perfect for my use case.

how to show authenticated user data from relations

I'm trying to show the data of the authenticated user from his relation with other tables but can't get it to work, and I'm pretty new to laravel.
the user table has a relation with level table thru level_id, and the level table has a morph relation with the languages table, I'm trying to show the language of the level of the current user
here is my user model relation
public function level()
{
return $this->belongsTo(Level::class, 'level_id');
}
and my level model
public function languages()
{
return $this->morphMany(Language::class, 'langable');
}
and in the language table, I need to get back the title of 0 or 1 like
languages['0']title.
here is my controller
public function profile()
{
$user= User::with('level')->with('offers')->get();
return view('pages.user.index',compact('user'));
}
and here is how I got the auth user
{!! auth()->user()->first_name . ' ' . auth()->user()->last_name !!}
I'm trying to get this to work
{{auth()->user()->level()->languages()->title['0']}}
but it shows me this
Try {{ $user->level->languages->title['0'] }} in your index.blade file since you are passing the $user var from your controller to it. Currently you are using the user from session.
i got the answer guys it goes like this
{{Auth::user()->level->languages[0]->title}}
that'd show the level of the current user
Okay, there are a few steps you need to get done
in your controller:
public function profile()
{
$user = Auth::user(); // gets the logged in user
return view('pages.user.profile', compact('user')); // return view with $user variable
}
in your user model add:
// appends the level data to the $user model
// so every time you retrieve a user, the level data is included and accessible
// after that you can use $user->level in your view file
protected $appends = [
'level'
];
in your level model add:
// appends the languages data to the $user model
// so every time you retrieve a level, the languages data is included and accessible
// after that you can use $level->languages in your view file
protected $appends = [
'languages'
];
NOTE: In Step 3 you are retrieving multiple languages for a level. Is that correct ?
usage in view
$user->level->languages[specificLanguage]->title // if level has multiple languages
$user->level->language->title // if level has one language

How to set form data for a Joomla subform?

I'm trying to create a Joomla (3.x) component and struggling with using subforms. There doesn't seem to be much documentation for using subforms besides e.g. https://docs.joomla.org/Subform_form_field_type
For my component I have one parent table and some associated database rows from a child table.
The idea is to display an edit form for that parent table using Joomla's XML syntax for forms and in that edit form also display a subform with multiple items (the associated rows from the child table).
I would like to be able to modify the parent table fields but also in one go the associated child table rows (of course one could just edit each row associated to the parent table individually but I'm guessing that would be a terrible user experience). Or am I approaching this thing the wrong way?
Now, I know how to implement/show a subform and also know how to show the parent table fields and populate those fields with the right data. But how do I populate or refer to the subform using the parent form?
I have this function inside my component model (which inherits from JModelAdmin).
protected function loadFormData()
{
$data = JFactory::getApplication()->getUserState('com_mycomp.edit.parent.data', array());
if (empty($data))
{
$data = $this->getItem();
// how to refer to subform fields inside $data?
}
return $data;
}
I know if a field is called name or title I can just change the $data object after $this->getItem(), e.g. $this->set('name', 'John Doe').
Let's say the field of type subform has a name attribute of books and I wanted to insert one or more rows, how would I refer to it? I've tried dot syntax in various forms, e.g.: $data->set('books.1.childfield') or $data->set('books.pages1.childfield'). But it doesn't seem to refer to the right form.
There is of course getForm function in the same model file, however I do not think a subform should be loaded independently of the containing parent form?
public function getForm($data = array(), $loadData = true)
{
$app = JFactory::getApplication();
$form = $this->loadForm('com_mycomp.parent', 'parent', array('control' => 'jform', 'load_data' => $loadData));
if (empty($form))
{
return false;
}
return $form;
}
EDIT:
Already answered my own question.
Never mind. I figured it out after taking a break for some time and trying again (inspecting the form inputs again and taking a deep breath).
This is the format used:
$data->set('nameofsubformfield',
[
'nameofsubformfield0' => [
'fieldwithinsubform' => 'value-of-field-within-subform'
]
]);
This seems to work! I'm using this within getItem function now. Just have to loop and put loop counter in place of the zero after nameofsubformfield. See code below for some context (function resides in parent model).
public function getItem($pk = null)
{
$data = parent::getItem((int)$pk);
if (empty($data))
{
return false;
}
$childModel = JModelLegacy::getInstance('child', 'MycompModel');
$rowChildren = $childModel->getChildrenByParentID((int)$data->get('id'));
$childArray = [];
for ($i = 0; $i < count($rowChildren); $i++)
{
$childArray['children'. $i] = [
'name' => $rowChildren[$i]['name']
];
}
$data->set('children', $childArray);
return $data;
}

Resources