Im try to create a simple CRUD App in Laravel + Vue.JS (Vuex also)
And I have small problem
What is the problem actually
I have a table 'categories'
Structure of this table u can see on screenshot
And i have created 2 test rows
u can see on screenshot
How can I insert a title instead of a value parent_id
If parent_id has value like someone ids
Im try v-for in Vue Componetn and v-if
But i dont have any results
This is my code:
<tr v-for="(category, $index) in categories" :key="category.id">
<td>{{$index + 1}}</td>
<td>{{category.title}}</td>
<td v-if="category.parent_id === null">Category</td>
<td v-else>SubCategory</td>
<td>{{category.created_at | moment("DD, MMMM, YYYY")}}</td>
<td></td>
</tr>
This is my data what im get from Controller
Anyway thanks for help
This is code of controller
public function index()
{
$result = ['success' => true];
$category = Category::paginate(15);
$result['category'] = $category->items();
$result['pagination']['currentPage'] = $category->currentPage();
$result['pagination']['total'] = $category->total();
$result['pagination']['perPage'] = $category->perPage();
return response()->json($result, 200);
}
And here is how I want it to be
I think render function adn array processing must be at the Vue Component
This is my Category model code
public function products()
{
return $this->hasMany('App/Products');
}
public function parent()
{
return $this->hasOne(Category::class,'id','parent_id');
}
Solution will be to define relation hasOne like
public function parent()
{
return $this->hasOne(Category::class,'id','parent_id');
}
And then you can define resource, where you can claim parent's title using defined relation like below
$this->parent->title
Create you resource using command
php artisan make:resource CategoryResource
Then in your controller you should use resource
use App\Http\Resources\CategoryResource;
and within controller's action provide response like
$categories = Category::paginate(15);
return CategoryResource::collection($results); // instead of response()->json($categories , 200);
And example how your resource should look like
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class CategoryResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'parent_id' => $this->parent_id,
'parent_title' => $this->parent->title,
...
];
}
}
Info about resources you can find https://laravel.com/docs/5.8/eloquent-resources
Related
Good day to all
The situation is as follows
In the controller, in the update method, I try to update the object
There is an image in the fields of this object
Wrote a trait to process this field and load an image
In the model itself, I called the update method, which just determines the event of updating the object
The problem lies in the following image in the specified directory is loaded and the entry itself in the database does not change
Here is my code
Controller
Model
Trait
There is extra code in the model
public function update(Request $request, MainHeader $mainHeader): RedirectResponse
{
$mainHeader->update([
'language_id' => $request->language_id,
'brandLogoImage' => $request->file('brandLogoImage'),
'homeTitle' => $request->homeTitle,
'ourProjectsTitle' => $request->ourProjectsTitle,
'contactTitle' => $request->contactTitle,
'feedbackTitle' => $request->feedbackTitle,
]);
return redirect()->route('admin.header.index')->with('success', 'Данные успешно обновлены');
}
public function setBrandLogoImageAttribute($value): string
{
return $this->uploadImage('brandLogoImage', $value);
}
public function update(array $attributes = [], array $options = [])
{
$this->uploadImage('brandLogoImage', $attributes['brandLogoImage']);
$this->setBrandLogoImageAttribute($attributes['brandLogoImage']);
return parent::update($attributes, $options); // TODO: Change the autogenerated stub
}
protected function uploadImage(string $attr, $value): string
{
$uploadDir = public_path('uploads/');
$imageDir = public_path('uploads/image/');
if (!file_exists($uploadDir)){
mkdir($uploadDir);
}
if (!file_exists($imageDir)){
mkdir($imageDir);
}
if (!file_exists(public_path("uploads/image/$this->table/"))){
mkdir(public_path("uploads/image/$this->table/"));
}
$imageName = Str::random(12) . '.png';
Image::make($value)->save(public_path("uploads/image/$this->table/$imageName") , 100);
return $this->attributes[$attr] = (string) "uploads/image/$this->table/$imageName";
}
if you call the update methode in your model then you are overriding the default update() of the model class , its not listening to the event it simply runs your code before parent:: , so you need to make sure that the changes you are making does not get overwitten by the parent call .
regarding your question on how to detect update , if you want to perform anything before update than i advise you to use eloquent events or use observers , Observers listen to various events regarding your model like updating or updated .. but i think if its only for updating event than you should use event using closure
for example :
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* The "booted" method of the model.
*
* #return void
*/
protected static function booted()
{
static::updating(function ($user) {
// do what you want
});
}
}
If your pupose
I have this simple action:
/**
* Perform the action on the given models.
*
* #param \Laravel\Nova\Fields\ActionFields $fields
* #param \Illuminate\Support\Collection $models
* #return mixed
*/
public function handle(ActionFields $fields, Collection $models)
{
foreach ($models as $model) {
$model->update([
'user_id' => $fields->user
]);
}
}
/**
* Get the fields available on the action.
*
* #return array
*/
public function fields()
{
return [
BelongsTo::make('User', 'user', User::class),
];
}
At first, it seems fine, but when I select User from BelongsTo relation and try to save exception is throwing:
Argument 1 passed to Laravel\Nova\Fields\BelongsTo::getRelationForeignKeyName() must be an instance of Illuminate\Database\Eloquent\Relations\Relation, instance of Illuminate\Support\Fluent given, called in /Users/rd/Sites/bns-crm/vendor/laravel/nova/src/Fields/BelongsTo.php on line 212
Yes i know i'm late but - here's a solution for this:
Use a Select-Field instead of BelongsTo and Pluck your options to build Key-Value pairs:
public function fields()
{
return [
Select::make('debitor')->options(\App\Models\Debitor::pluck('Name', 'id'))
];
}
Then in the handle you should geht the ids in $fields:
public function handle(ActionFields $fields, Collection $models) {
Log::info($fields);
}
Maybe I'm late, but, for the ones like me wanting to use the BelongsTo searchable field because the model they want to search in contains too much records to pack them in a normal Select field here is the solution I found:
Create a class in App\Nova\Fields with this code:
<?php
namespace App\Nova\Fields;
use Laravel\Nova\Fields\BelongsTo;
use Laravel\Nova\Http\Requests\NovaRequest;
class BelongsToForActions extends BelongsTo
{
public function fillForAction(NovaRequest $request, $model)
{
$attribute = $this->attribute;
if ($request->exists($attribute)) {
$value = $request[ $attribute ];
$model->{$attribute} = $this->isNullValue($value) ? null : $value;
}
}
}
Then use it like you would use a normal BelongsTo field. Just remember to fill the 3 arguments on the make, so, for example:
BelongsToForActions::make('User', 'relation', \App\Nova\User::class)->searchable()
Remember that 'relation' must exist.
Check your namespaces. Did you imported right class? User class must be resource class
public function fields()
{
return [
BelongsTo::make('User', 'user', User::class),
];
}
I actually fixed this by mocking the key value pair used in this relationship.
First I build an array with the ID column as key and the name column as value.
$clients = Client::all()
->keyBy('id')
->map(fn($client): string => $client['name'])
->toArray();
Then I use the Select nova field to display it.
Select::make('Klant', 'client')
->searchable()
->options($clients)
->rules('required'),
I have 2 models with a many to many relationship using Laravel and I want to insert into the relationship table upon using the save method.
I have save method creating the new row for the child and I have access to the parent id.
I need to insert a new row into the relationship table using the parent id that I have access to already along with the id created by the create function within the controller
MODELS
class Objective extends Model
{
public function subjects() {
return $this->belongsToMany('App\Models\Subject');
}}
class Subject extends Model
{
public function objectives() {
return $this->belongsToMany('App\Models\Objective');
}}
The function subject receives the id of the parent from the url and the create function should takes in this id too.
CONTROLLER
class ObjectiveController extends Controller
{
public function subject($id)
{
$subjects = Subject::find($id);
$objectives = DB::table('objectives')->get();
return view('admin.objectives.subject',['objectives' => $objectives],['subjects' =>
$subjects],compact('objectives','subjects'));
}
public function create($id)
{
$post = new Objective;
$post->name = 'NEW OBJ';
$post->save();
return redirect('objectives');
}
}
ROUTE
Route::get('objectives/create/{id}', [
'uses' => 'App\Http\Controllers\ObjectiveController#create',
'as' => 'admin.objectives'
]);
VIEW
<a class="card-header-action" href="{{url('objectives/create', ['id' => $subjects->id]) }}"><small class="text-muted">Add New</small></a>
You can use attach to add to the pivot table:
...
$post->save();
$post->subjects()->attach($id);
Like the title says, my Field model and application_fields table have different names. I already set the table name on the Field model to the correct table name. A set the I have another model, Application, and its controller, ApplicationController. In the index method of the ApplicationController, I am trying to retrieve the application and its fields. The Field model has a belongsTo relationship to Application, and the Application model has a hasMany relationship to Field.
The code seems to work, except it pulls the values for the rows from the applications table. So if the applications table has the following rows:
1 'AppOne' 'An App'
2 'AppTwo' 'Another App'
3 'AppThree' 'A third App'
AppOne, AppTwo, and AppThree are returned as the values for the fields.
Can someone give me some advice?
Here is the code for them( I only copied what was related to the issue, not the entire file):
Application model:
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'application_fields';
public function fields()
{
return $this->hasMany('App\Field');
}
Field model:
public function application()
{
return $this->belongsTo('App\Application');
}
ApplicationController:
/**
* Display the dashboard for a single application.
*
* #param String $id
* #return View
*/
public function show( $id )
{
$app = Application::where('id', $id)->first();
$fields = $app::with('application_fields')->get();
return view('applications.show', [
'application' => $app,
'fields' => $fields,
]);
}
View( I stripped out the HTML):
{{ $application->name }}
{{ $application->description }}
#foreach($fields as $field)
{{ $field->name}}
#endforeach
I would appreciate any advice on what I am doing wrong. Thanks
your show method is wrong, eager loading does not work that way :)
public function show( $id ) {
$app = Application::with('fields')->find($id);
$fields = $app->fields;
return view('applications.show', [
'application' => $app,
'fields' => $fields,
]);
}
you can also use model Binding if your route is like that : applications/{app}
public function show(Application $app) {
$fields = $app->fields;
return view('applications.show', [
'application' => $app,
'fields' => $fields,
]);
}
I am using https://github.com/mitulgolakiya/laravel-api-generator
I would like to get data from another model. When inserting a post pick the category data.
PostController.php
class PostController extends AppBaseController
{
/** #var PostRepository */
private $postRepository;
/** #var CategoriesRepository */
private $categoriesRepository;
function __construct(PostRepository $postRepo, CategoriesRepository $categoriesRepo)
{
$this->postRepository = $postRepo;
$this->categoriesRepository = $categoriesRepo;
}
/**
* Display a listing of the Post.
*
* #return Response
*/
public function index()
{
$posts = $this->postRepository->paginate(10);
$categories = $this->categoriesRepository->all('id', 'desc')->get();
return view('posts.index')
->with('posts', $posts)
->with('categories', $categories);
}
fields.blade.php
{!! Form::select('category_id', Categories::lists('name', 'id'), ['class' => 'form-control']) !!}
How can I do this? Thank you!
You should make the list in controller and pass it to the view.
public function index()
{
$posts = $this->postRepository->paginate(10);
$categories = $this->categoriesRepository->all('id', 'desc')->get();
$categoryList = [ '' => '--select--' ] + $categories->lists('name', 'id');
return view('posts.index')
->with('posts', $posts)
->with('categories', $categories)
->with('categoryList', $categoryList);
}
And use this variable to generate the select.
{!! Form::select('category_id', $categoryList, ['class' => 'form-control']) !!}
I think you should use ViewComposers and pass category list array in fields.blade.php. so it will not affect directly your templates or generator.
Whenever you have a requirement where you always have to pass fields of another model in any view, I think you should use view composer.