I have this relation in my Post model
public function mainItem()
{
return $this->belongsTo('Item', 'item_id');
}
Some of the Posts are connected to Item, some are not.
I can print the binding status with this line:
{{ $post->mainItem->id or 'not yet binded!'}}
I can even print image delivered through relation
<img src="{{ $post->mainItem->pic_filename or ''}}">
...and hide empty IMG with no SRC with the use of CSS3.
But how I can print a link or communique depending of the binding status?
I want to print a button which binds a post to an item - but the button should be visible only when the relation is not yet set.
#if($post->mainItem->count() > 0)
... here comes the button ...
#endif
The code works in case of a hasMany relation, but not in case belongsTo.
The return of a belongTo would be a single model. So to check this would be to check if the object is_null, as if there is no related model it will return null.
So this as you said for a hasMany;
#if($post->mainItem->count() > 0)
... here comes the button ...
#endif
And this for a belongsTo;
#if(is_null($post->mainItem))
.. Button
#endif
To find out more of the return types use the API found here
Related
I am learning how to use vue with laravel. I have basic loops working well to pull direct model relationships, but I can't figure out how to access model methods in a loop. Many of my Larvel models have basic information formulated with a method pulling data from related models. I've tried to research it and think the answer might be some combination of eager loading, preformating the answer as a json response or maybe something with axios, but the snipits I've found aren't clear on what goes where, or what needs to be in place for them to work correctly. I've tried both eager loading and using a json response and neither has worked. I can access methods in simple vue components that are just text, but not in a loop where the variable isn't part of the page.
Example: I want to use Vue to display a list of ingredients on a recipe's page. The ingredient "title" is a method pulling the information from a related model.
RecipeController.php
public function show(Recipe $recipe)
{
$ingredients = $recipe->ingredients;
$view = $this->view('recipes.show');
//(variable in the view, variable defined in current function)
$view->with('recipe', $recipe);
$view->with('ingredients', $ingredients);
return $view;
}
Recipe.php
public function ingredients()
{
return $this->hasMany('App\Models\Ingredient', 'recipe_id', 'recipe_id');
}
Ingredient.php
public function title()
{
$title = $this->item->title();
return $title;
}
public function vueTitle()
{
$title = Ingredient::title()->get();
return response()->json($title );
}
Recipes/show.php
<div>
<ul>
<li
is="test-li"
v-for="ingredient in {{ $ingredients }}"
v-bind:key="ingredient.ingredient_id"
v-bind:title= "ingredient.vueTitle"
v-bind:id="ingredient.ingredient_id"
></li>
</ul>
</div>
I'd prefer to reuse the same methods, but created a new one to try converting to json first but that didn't work (or I'm doing it wrong). I tried eager loading, but it either did nothing, or generated an error (Call to a member function on null) if I tried to eager load the specific method. I've tried various combinations of binding and not binding the title component. I've also tried title= "{{ingredient->title()}}" but that syntax errors.
How can I get the result of the Laravel method in a Vue loop?
After more searching, I found this post which described how to add an accessor to a model. Doing so allowed me to access my custom method as if it were a standard direct relationship. It was a straightforward modification and will reduce complexity in a number of places. I made the following modifications:
Ingredient.php
Added the get..Attribute() function and appended the array
...
protected $table = 'ingredients';
...
protected $appends = array('title');
// Access methods as direct relationships
public function getTitleAttribute()
{
return $this->title();
}
Recipes/show.php
Bound the title prop to the ingredient title as if it were a direct relationship.
<div>
<ul>
<li
is="test-li"
v-for="ingredient in {{ $ingredients }}"
v-bind:key="ingredient.ingredient_id"
v-bind:title= "ingredient.title"
v-bind:id="ingredient.ingredient_id"
></li>
</ul>
</div>
Another example, hope one may find it helpful:
Model.php
/**
* Accessor for Age.
*/
protected $appends = ['age'];
public function getAgeAttribute()
{
return Carbon::parse($this->attributes['dob'])->age;
}
VueFile.vue
<td>
<span v-bind:age="user.age"> {{user.age}} </span>
</td>
I've a parent model which can have n childs
So I want to show delete button ONLY if it has not children (hasMany relationship must return 0 records).
How can I show 'delete' link in each lines of a table (in the list operation), but ONLY if a condition is valid?
The easiest option I see is to use a custom view for the Delete button, instead of the one in the package. Depending on how wide you want this change to be made:
A. If you want to do that across all CRUDs - it's easy, just publish the view by running:
php artisan backpack:publish crud/buttons/delete
This will place the file in your resources/views/vendor/backpack/crud/buttons, for you to change however you like. Inside the delete button view you have the current entry available as $entry so you can do something like $entry->children()->count() if you want. Be mindful that this will be run ONCE PER LINE so if you show 50 lines in the table for example, you'd need to find a way to optimize this.
B. If you want to do that for just one CRUD (eg. do it for Categories but not for Products), then you can do the same thing (publish the button view), but rename the button to something different like delete_if_no_children.blade.php so that it doesn't get used automatically for all CRUDs. Then use it only inside the controllers you want, inside setupListOperation(), by removing the "stock" delete button and adding yours:
// using the Backpack array syntax
$this->crud->removeButton('delete');
$this->crud->addButton('line', 'delete', 'view', 'crud::buttons.delete_if_no_children', 'end');
// using the Backpack fluent syntax
CRUD::button('delete')->view('crud::buttons.delete_if_no_children');
Use
withCount('children')
Docs: withCount
Additionally you can wrap delete buttons with blade directive
#can('destroy', $model) disabled #endcan
Docs: #can
<?php
namespace App\Policies;
use App\Models\Model;
use App\Models\User;
class ModelPolicy
{
public function update(User $user, Model $model)
{
return $model->children_count === 0;
}
}
Docs: policy
A hasMany relationship will return an empty Collection when there are no associated records. You can then proceed to call isEmpty() on the collection to verify there are no child records (children).
Example in PHP:
$parents = Parent::with('children')->get();
And then in your template you can do:
#foreach($parents as $parent)
#if($parent->children->isEmpty())
<button>Delete</button>
#endif
#endforeach
I am trying to retrieve data from database and check if the data is empty or not. What problem I am facing is that html is showing even if the data is empty. I want to ignore the html tag like example ul li. Here how i tried is like
#if(!empty($jobseekers->skill_1))
<li> My Skill is : {{ \App\skill::where('id',$jobseekers->skill_1)->pluck('name')->first() }}</li><br/>
#endif
I want to ignore "My Skill is " if the data is empty. I don't want to show anything.
When using ->get() you can't simply use any of the below:
if (empty($jobseekers->skill_1)) { }
if (!$jobseekers->skill_1) { }
if ($jobseekers->skill_1) { }
But, When you are getting data with first() method, You can simply use all above methods.
Because if you dd($jobseekers->skill_1); you'll notice an instance of Illuminate\Support\Collection is always returned, even when there are no results.
I think you are using !empty() on data with ->get() method which will always return true even data is empty. You need to use other way.
To determine if there are any results you can do any of the following:
if (!$jobseekers->skill_1->isEmpty()) { }
if ($jobseekers->skill_1->count()) { }
if (count($jobseekers->skill_1)) { }
If you get $jobseekers with get() method you can not use empty($jobseekers )
instead of empty you can use other conditions :
#if($jobseekers->skill_1 != '')
in this condition you check skill_1 as empty string
also
#if($jobseekers->skill_1)
and etc
replace your code with below code and check it:
#if($jobseekers->skill_1 != '')
<li> My Skill is : {{ \App\skill::where('id',$jobseekers->skill_1)-pluck('name')->first() }}</li><br/>
#endif
you should use isset()
#if(isset($jobseekers->skill_1))
<li> My Skill is : {{ \App\skill::where('id',$jobseekers->skill_1)->pluck('name')->first() }}</li><br/>
#endif
you can use count method
#if(count($jobseekers->skill_1)>0)
<li> My Skill is : {{ \App\skill::where('id',$jobseekers->skill_1)-pluck('name')->first() }}</li><br/>
#endif
#if(count($data)>0)
//write your code which you want to show if data is available
#endif
I have a form to update an article.in this form I have tow select boxes one for section and another for sub section.An article should have a section but sub section is not necessary.In my update form if a section has subsections it should bring it.My problem is that in my update form if a section does not have any subsection it does not show the continuation of my form because in model it returns false.I tried to return null or an empty array but it could not solve my problem.
Model:
function get_subsection($sec_id,$subsec_name){
$this->db->selec("*");
$this->db->where('sec_id',$sec_id);
$this->db->where('subsec_name !=',$subsec_name);
$query=$this->db->get('sub_section');
if($query->num_rows() > 0)
{
return $query;
}
else
return false;
}
if this function returns false in update form it does not show the continuation of form and the edit submit button.I removed the else condition but it can not solve the problem.
Controller
function edit($id){
$data['rec']=$this->amodel->edit_art($id);//get the record to update
foreach($data['rec'] as $a)
{
$sections['items']=$this->amodel->section('$a->sec_id');//select all sections without that which selected by user
$subsetion['sub']=$this->amodel->subsection($a->sec_id,$a->subsec_name);//select all subsections of a section which selected by user
}
$this->load->view('edit_art',array_merge($data,$sections,$subsection));
}
the problem is with $subsetion which can has no record in database.
please guide me what should I do to show all form element even the subsection be empty.
If i understand ur problem then you can try this
Model:
function get_subsection($sec_id,$subsec_name){
$this->db->selec("*");
$this->db->where('sec_id',$sec_id);
$this->db->where('subsec_name !=',$subsec_name);
$query=$this->db->get('sub_section');
return $query->result();
Controller:
function edit($id){
$data['rec']=$this->amodel->edit_art($id);//get the record to update
foreach($data['rec'] as $a)
{
$data['items']=$this->amodel->section('$a->sec_id');//select all sections without that which selected by user
$data['sub']=$this->amodel->subsection($a->sec_id,$a->subsec_name);//select all subsections of a section which selected by user
}
$this->load->view('edit_art',$data);
}
View :
<?php echo form_dropdown('items',$items,"",'class=""'); ?>
<?php echo form_dropdown('sub',$sub,"",'class=""'); ?>
Let me know is it ok or not. if not ok then post your view code.
Try the following:
function edit($id){
$data['rec']=$this->amodel->edit_art($id);//get the record to update
foreach($data['rec'] as $a){
if($this->amodel->count_sections($a->sec_id) > 0)
$sections['items']=$this->amodel->section('$a->sec_id');//select all sections without that which selected by user
else
$sections['items'] = NULL;
if($this->amodel->count_subsections($a->sec_id,$a->subsec_name) > 0)
$subsetion['sub']=$this->amodel->subsection($a->sec_id,$a->subsec_name);//select all subsections of a section which selected by user
else
$subsetion['sub']= NULL;
}
$this->load->view('edit_art',array_merge($data,$sections,$subsection));
}
Count the number of available sections and subsections and try to read the records if they are avalable!
Write the required functions (count_sections and count_subsections) in the model!
I have laravel project. When I click my view button, I want to see full description of my record. But I don't know how to pass the right id. My database table is called - csstable.
I have model:
<?php
class CssTable extends Eloquent
{
protected $table = 'csstable';
}
View button on each post (I get all of my posts from database, so each of them have id):
<div class="view">
<a href="{{ action('CssController#show') }}" ></a>
</div>
CssController with this show function:
public function show()
{
$csstable = CssTable::all();
return View::make('cssposts/right_post', compact('csstable'));
}
My Route:
Route::get('/css/id_of_right_post', 'CssController#show' );
Right_post, where I want information from description column from row, with id, that i clicked (In this field, I see just last record's description:
<h1 style="color:#fff">{{ $css->description }}</h1>
I have tried to put something like this
public function show($id)
{
$csstable = CssTable::find($id);
return View::make('cssposts/right_post', compact('csstable'));
}
But then there is an error - missing 1 argument in show function. So I want to know, how to pass correct id!
The way to do this involves three steps. First let's go for the route:
Route::get('css/{id}', 'CssController#show');
The {id} there means it's a matching parameter - it'll match a full URI segment (basically anything between slashes) and use that to pass into he method passed. So on to the controller:
class CssController
{
public function show($id)
{
$csstable = CssTable::findOrFail($id);
return View::make('cssposts/view', compact('csstable));
}
}
That controller method accepts a (required) single parameter. You can call it whatever you want, but here I'm going for id as it's an ID for a model. Finally, the last part of the puzzle is how to link to such a route:
// view button for each csstable
<div class="view">
{{ link_to_action('CssController#show', $item->title, array($item->getKey())) }}
</div>
As you can see, I'm using the link_to_action helper, but your method with <a href="{{{ action('CssController#show', array($item->getKey())) }}}"> will work too. After the controller action name, you pass an array that contains all of the parameters in the URI to fill in (in order). In our case we have one parameter, to it's an array with one item. I think in these cases you could also use a string and Laravel will turn it into an array with one element for you. I prefer to be explicit.
Hopefully that's helped you work out how to use the parameter-based routing system in Laravel.