Laravel Nova Custom Fields get model value - laravel

I created a custom field for Nova.
On this field I need to get some extra model data like $model->country to show on the form.
How can I pass this data to the Vue component?
I try to use:
return $this->withMeta
But I don't know how to pass the data from the model.

Add the custom field like a normal field to the resource fields() and chain a custom method with the data from the model:
CountryField::make('Country')->country('Germany'),
Define this custom method in your Nova component (see src folder):
public function country($value)
{
return $this->withMeta([
'country' => $value,
]);
}
You can access the returned data from this method in FormField.vue like this:
{{ field.country }}

Related

Resolving a model using multiple columns in a Laravel route

I'm trying to register a route to fetch a single model automatically based on multiple columns. For example:
Route:get( 'sample/{myModel:status}/{myModel:slug}', [ SomeController:class, 'show' );
Let's access this URI:
www.example.com/sample/publish/this-is-a-slug
Now what I expect to get in my controller is a single myModel instance, which has a status column equal to publish and a slug column equal to this-is-a-slug. Is this possible?
Trying to register the above route will result in a reference error:
Route pattern "/sample/{myModel}/{myModel}" cannot reference variable name "myModel" more than once.
Now I can just drop the model name and do the query in my controller, but I wonder if it's possible to inject a model into a controller using more than 1 column. The slug column is not unique, but the combination of slug and status is.
You may define the route like this,
Route::get('sample/{model_by_status}/{slug}', [ SomeController:class, 'show'] );
Then you can add route binding in the boot() method of RouteServiceProvider.php like this,
Route::bind('model_by_status', function($value){
$slug = request()->route('slug');
return myModel::where([
'status' => $value,
'slug' => $slug,
])->firstOrFail();
});
And in your controller method you need to declare the show method like this
public function show(myModel $model_by_status){
}
Note that the naming is important here. model_by_status (whatever in your case) must be same in all those three places

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()

My form requires additional data, where should I put my routes and controller methods to get it?

I'm learning how to create web application with laravel and I don't know correct way to create struct for this example form:
I have simple controller named i.e. PostController with methods:
index(), create(), store(), show(), edit(), update(), destroy()
created via make:controller --resource.
And I have routes for it in my web.php file created via Route::resource() method.
Now, my create() method in PostController display a form for create new post, but this form required select an option from list.
I can't display whole list because it's thousands of options do I want create search field which use ajax to get available options from my database. Then user just select an option and can send form.
It's ofcourse just example but in that situation where should I put my method controller and route for search options?
Should I crate additional method in my PostController ( i.e. searchOption( $string ) ) or should it be new controller?
If it should be new controller then do you have any suggestion for folder/name structure for it?
And where should I put my routes for it? Still in web.php? or api.php?
And again, how should I name this route?
Sinse you have another entity you can make another controller. Let's say you want filtered City in your Post's create view.
// Controllers/Api/CityController.php
public function index(Request $request)
{
$query = City::query();
if ($request->has('search')) {
$query->where('name', 'LIKE', $request->input('search') . '%');
}
$cities = $query->paginate();
return response()->json(['cities' => $cities]);
}

Passing Multiple Parameters to Laravel Resource Collection

I am creating an API via apiResource with following code being passed to the resource collection
$coupons=Coupons:paginate(15);
$brand='brand1';
$brand_id='123';
return CouponResource::collection($coupons);
I am passing $coupons variable to the Resource Collection. But i want to pass $brand and $brand_id too.
How can I do that?
if you have created a relationship for brand you can use that
$coupons=Coupons::with('brand')->paginate(15);
or you can use appended parameters in your Coupons model
$appends =['brand_id','brand'];
and then
public function getBrandIdAttribute(){
return $this->brand()->id;
}
public function getBrandAttribute(){
return $this->brand()->name;
}

How to create slugs in Laravel?

I'm trying to develop an e-com website in Laravel 5 (Since it required lot of customization, I decided not to use Magento or OpenCart).
The problem I'm facing is to creating category and product URLs from slugs.
For example, one URL can be:
http://somewebsite.com/products/lenovo-yoga-500
But I want to make URL like:
http://somewebsite.com/lenovo-yoga-500
I tried to create a route like:
Route::get('{slug}', 'BaseController#route');
and in the route() method, I tried:
function route($route){
$product = Product::where(array('slug' => $slug))->first();
if(isset($product))
.....
else
.....
but first of all, the value is not getting passed to variable '$slug' and secondly I want to redirect the request to another route after checking the condition.
You might want to go with the first URL (product/{slug}) because the way you have it setup with the slug as the first parameter, every route you make for any page will be interpreted as the slug.
Either way, fix your controller method as such
function route($slug){
$product = Product::where(array('slug' => $slug))->first();
if(isset($product))
.....
else
.....
The documentation covers everything you are asking for here, so please read through about redirecting to routes.
To achieve it like Magento does, you need to add a new product-routes.php file that will be rebuilt.
First instruct app/Providers/RouteServiceProvider.php to load your dynamic route file thus:
protected function mapWebRoutes(Router $router)
{
$router->group([
'namespace' => $this->namespace,
], function ($router) {
require app_path('Http/routes.php');
require base_path('resources/routes/product-routes.php');
});
}
Next: Rebuild product-routes.php automatically on save or when the user requests it in the backend to include all product slug routes and to load the product by slug.
Hope that helps.
in Product-model:
public function getRouteKeyName() {
return 'slug';
}
in routes:
Route::get('{product}', 'ProductController#product');
in ProductController:
public function product(Product $product) {
$product->doSomething();
}
Note that the route should be last in the routes-file so any other route has chance to match before that.
You must use this Route
Route::get('/sample/show/{sample : slug}',[SampleController::class]);
Enter the model of the controller and set the value of getRouteKeyName equal to slug such as:
public function getRouteKeyName(){return 'slug';}
Custom Keys & Scoping
When implicitly binding multiple Eloquent models in a single route definition, you may wish to scope the second Eloquent model such that it must be a child of the previous Eloquent model. For example, consider this route definition that retrieves a blog post by slug for a specific user:
use App\Models\Post;
use App\Models\User;
Route::get('/users/{user}/posts/{post:slug}', function (User $user, Post $post) { return $post;});

Resources