Share data with all views, best practises - laravel

I use AppServiceProvider to get all categories on my page.
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register() {}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
view()->creator('layouts.app', function($view) {
//Categories cache
$categories = Cache::rememberForever('categories', function () {
return Category::where("parent_id", "=", null)->with('subcategory.subcategory')->get();
});
view()->share('categories', $categories);
});
}
}
The data is accessible on the master layouts.app view, but not in the view it includes.
So in my layouts/app.blade.php i have this: #yield('content')
sadly the variable $categories isn't present in that content which is included. How can i change it?
The error: Undefined variable: categories <- but only on pages that use that variable, it is accessible on app.blade.php where i display the categories, but not in the view it includes
I tried:
#yield('content', ['categories' => $categories])
but it gives error htmlspecialchars() expects parameter 1 to be string, array given

If you use view()->creator('layouts.app'), every variable you share within that callback, will be shared only with layouts.app view and any views that layouts.app includes.
If you use #extends, for example, a new view called example.blade.php extends the layouts.app using #extends('layouts.app'), the categoriesvariable will not be accessible inextends.blade.phpview, since you said to laravel to share that variable only withlayouts.appviaview()->creator()` method.
The #yield directive is used to display the content of a given section.
Example:
My inc.test view has this content:
<br>
view `test` included.
<br>
#section('post')
Post id: {{ $post->id }} test
#endsection
My welcome.blade.php view, which includes inc.test and yields the post section, has this content:
This is the welcome view.
<br>
It has a `post` variable shared via AppServiceProvider.
<br>
<br>
<br>
Here i'm including 'inc.test' view and yielding the post section from that view:
<br>
<br>
#include('inc.test')
#yield('post')
Since i shared the post variable with the welcome view via service provider, it will be available for all view included by welcome.
view()->creator('welcome', function($view) {
view()->share('post', Post::first());
});
This is the result in my browser:

Related

Use vue to access a Laravel model method in a v-for loop

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>

Laravel 5.8 controller Index function returning blank page

I have created a new resource controller but my index function returns a blank page without any error.
Here is my route:
Route::group(['middleware'=>'admin'], function (){
Route::resource('admin/users', 'AdminUsersController');
Route::resource('admin/posts', 'AdminPostsController');
Route::resource('admin/comments', 'PostCommentsController');
Route::resource('admin/categories', 'AdminCategoriesController');
Route::resource('admin/comment/replies', 'CommentsRepliesController');
Route::resource('admin/products', 'AdminProductsController');
Route::resource('admin/contactus', 'ContactController');
Route::resource('admin', 'AdminController');
Route::get('admin/products/sold',['as'=>'sold', 'uses'=>'AdminProductsController#sold']);
Route::resource('admin/faqs', 'AdminFaqController');
});
My Controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class AdminFaqController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
//
return view('admin.faqs.index');
}
My index.blade file:
#extends('layouts.admin')
#section('title', 'Know and your Brand')
#section('content')
<h2>Faqs</h2>
#endsection
I have not been able to figure out what causes the problem, please help
In your command pro. simply type php artisan route:list you can see all of your routs URL paths.
In your case I think you should use / before admin like-
Route::resource('/admin/faqs', 'AdminController');
As #Harshith said..
The reason behind getting blank pages is because Route::resource will create some route with wildcards. We can explain this using by giving an example /admin/{admin} which will map to show method on the controller. So when you make a get request to /admin/faqs it will be mapped to this show method instead of your /admin/faqs.
The reason for not getting any errors is your show method does not have any code yet. Hence, a blank response.
Try using,
Route::resource('/admin/homepage/faqs', 'AdminFaqController');
i suggest you to use html submit bouton to submit and blank
use this:
<button type="submit" formtarget="_blank">Submit to a new window</button>

Making object accessible throughout application

I am adding user notifications to my system. To access these notifications for a user, I call an API I have created in another system. So, my IndexController looks something like the following
public function index()
{
if ($user = Sentinel::getUser()) {
$notifications = MyAPI::returnNotifications($user->id);
return view('centaur.dashboard', compact('notifications'));
}
}
Now to problem with the above is that notifications is now only available on the dashboard view. Within my header view I have something like this
#if($notifications)
#foreach($notifications as $notification)
<a class="content" href="#">
<div class="notification-item">
<h4 class="item-title">{{ $notification->subject }}</h4>
<p class="item-info">{{ $notification->body }}</p>
</div>
</a>
#endforeach
#endif
But if I now visit another page besides the dashboard page I get a Undefined variable: notifications error. This is because header is on every page, but I am only passing my notification object to the dashboard page.
Is there any way to make this notification object universally available?
Thanks
UPDATE
if($user = Sentinel::getUser()) {
view()->composer('*', function ($view) {
$view->with('notifications', MyAPI::returnNotifications($user->id));
});
}
You can use a view composer. In your App\Providers\AppServiceProvider#boot method add:
view()->composer('*', function ($view) {
$view->with('notifications', MyAPI::returnNotifications($user->id););
});
Now you'll have the variable $notifications in all of your views. If you want it for specific ones just replace the * with the view name.

Laravel - get id from the right database record

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.

Attempting to access View from blade template causes blank body in Laravel4

I have a project which is using laravel4 and its blade view engine. Occasionally I have had the need to call controller methods via a view file to output dynamic data; incidentally this time its a call to a method that generates javascript code for the page. Regardless of whether this is the best way to go about things is a moot point atm as I am simply upgrading from L3 to L4.
My View is similar to:
#extends('en/frontend/layouts/default')
{{-- Page title --}}
#section('title')
Page Title
#parent
#stop
{{-- Page content --}}
#section('pageContent')
...
#stop
{{-- Scripts --}}
#section('scripts')
<?php echo CaseStudy::script(); ?>
#stop
I have set up CaseStudy to load via the laravel facades and the class at current is simply:
class CaseStudy
{
public function display()
{
}
/**
* Returns the javascript needed to produce the case study
* interactivity
*
* #return \Illuminate\View\View|void
*/
public function script()
{
$language = \Config::get('app.locale');
$scriptElementView = $language . '.frontend.elements.casestudy_script';
if ( ! \View::exists($scriptElementView))
{
$scriptElementView = "Training::" . $scriptElementView;
}
return \View::make($scriptElementView, array());
}
}
It would appear that echoing the response of CaseStudy::script is what is causing the blank body; however with no further error message I do not know what is going on. I assume that this is because my static CaseStudy's instance of View is conflicting with the instance being used by the blade engine. How would I go about having CaseStudy::script() returning a string form of the rendered view?
Thank you.
In your view
{{-- Scripts --}}
#section('scripts')
{{ CaseStudy::script() }}
#stop
In your library
class CaseStudy
{
public function script()
{
$string = "your script here";
return $string;
}
}
Note - CaseStudy should really be a "library" or "helper" or something. Not a controller - that does not really conform to MVC approach.

Resources