Laravel 4 view composers not working - laravel

I saw this question. I have a similar problem, but it ain't working. Laravel 4 public functions.
I have a view composer that includes some codes in base layout. Here's my composer:
View::composer(array('common.menu_addition','common.base_errors','common.view_special'), function($view)
{
if(Auth::check()) {
$roles = Auth::user()->type;
if ($roles == '5') {
$view->with('roles', $roles);
} else {
return Redirect::to('news/index');
}
}
});
When I'm not logged in, it works perfectly. But one of my files of view composer goes like this:
<div class="pull-right">
#if (Auth::check())
#if ($roles == 5)
<ul class="nav">
<li>
<a href="{{ URL::to('admin/dash') }}">
<i class="icon-eye-open">
</i>
<strong>
Admin Dashboard
</strong>
</a>
</li>
</ul>
#endif
#endif
</div>
When I login, it won't display any site. It just says Undefined variable: roles in that view composer file.

I don't think it's possible to return a redirect like that, in your view composer. And even if you could it's a bad place to put that logic. You should create a filter http://four.laravel.com/docs/routing and redirect away if the user doesn't have the proper authentication level.

It looks like you're not defining $roles beforehand and not passing $roles into your views.
When you're making checks against the $roles in views you need to make sure that variable actually exists. Other possibility is to change the check to something like
#if (isset($roles) && $roles == 5)
to ignore the error but that gets really messy in the long run.
So make sure to initialise view variables beforehand in the view composer and everywhere else. Laravel tries to be much more stricter about non-initialised variables than PHP in common.

Related

Laravel 5.6 dynamic pages from a database best practice

I am using/learning Laravel 5.6 and wondered if this is the best approach in trying to accomplish dynamic pages from a database.
The approach I have taken works but I feel it could be improved especially with having to retrieve the pages for the navigation bar with every request.
I have a route in web.php
Route::get('/', 'PageController#index')->name('index');
Route::get('/{page}', 'PageController#show');
I then have my page controller with index and show functions.
public function index()
{
$pages = Page::all();
$posts = Post::latest('created_at')->paginate(2);
return view('index', compact('posts','pages'));
}
public function show($uri)
{
$pages = Page::all();
$page = Page::where('uri', $uri)->first();
return view('templates.page', compact('page','pages'));
}
Now in my header.blade.php I display the list of pages like this:
#foreach($pages as $page)
<li class="nav-item">
<a class="nav-link" href="/{{ $page->uri }}">{{ $page->title }}</a>
</li>
#endforeach
Now my problem is with all the other controllers I have to get the page's information from the database everytime which seems inefficient.
Any advice would be appreciated. Thank you in advance.
You can share your pages data with every view automatically by adding View::share('key', 'value');in the boot method of a service provider. Alternatively you can create a view composer.
one layout blade.
yield title by
<title>#yield('page-title')</title>
then on view,
//process title using php from DB
then display using
#section('page-title')
{{$page_title}}
#endsection

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 Sub-menu Within View

Hi I am very new to Laravel and MVC frameworks in general and am looking to create a list of links (in a view within a template) that links to some content. I am using this to display a list of nine people and to display their profile description when the link is clicked on. I have created a model of what the page looks like at http://i.imgur.com/8XhI2Ba.png. The portion that I am concerned with is in blue. Is there a way to route these links to something like /about/link2 or /about?link2 while maintaining the same exact page structure but modifying the ‘link content’ section (on the right of the link menu) to show the specific link's content? I would greatly appreciate it if someone could point me in the right direction, as I have literally no clue where to go with this!
There are a couple ways you can go about doing this.
Templates
Create your route.
Im assuming a lot about your app here but hopefully you get the picture. If you need help with anything in particular, be sure to update your question with the code youve tried so it will be easier to help you.
Route::get('about/{page}', function($page)
{
$profile = Profile::where('name', $page)->first();
return View::make('about')->with('profile', $profile);
});
Modify Template.blade.php
Put this line where you wish for About.blade.php to appear.
#yield('content')
Create your view which will extend your template
#extends('Template')
#section('content')
<h2>User Profile</h2>
<ul>
<li>Name: {{ $profile->name }}</li>
<li>Last Updated: {{ $profile->updated_at }}</li>
</ul>
#stop
AJAX
This solution will utilize AJAX to grab the data from the server and output it on the page.
Route for initial page view
Route::get('about', function($page)
{
$profiles = Profile::all();
return View::make('about')->with('profiles', $profiles);
});
Feel free to follow the same templating structure as before but this time we need to add some javascript into the template to handle the AJAX. Will also need to id everything which needs to be dynamically set so we can easily set it with jquery.
#extends('Template')
#section('content')
<h2>Links</h2>
#foreach($profiles as $profile)
{{ $profile->name }}
#endforeach
<h2>User Profile</h2>
<ul>
<li>Name: <span id="profile_name">{{ $profile->name }}</span></li>
<li>Last Updated: <span id="profile_updated_at">{{ $profile->updated_at }}</span></li>
</ul>
<script>
function setProfile(a)
{
$.ajax({
method: 'get',
url: 'getProfile',
dataType: 'json',
data: {
profile: $(a).data('id')
},
success: function(profile) {
$('#profile_name').html(profile.name);
$('#profile_updated_at').html(profile.updated_at);
},
error: function() {
alert('Error loading data.');
}
});
}
</script>
#stop
Route to handle the AJAX request
Route::get('getProfile', function()
{
$profile_id = Input::get('profile');
$profile = Profile::find($profile_id);
return $profile->toJson();
});
Now, the page should not have to reload and only the profile information should be updated.
Making some assumptions here as no code posted and assuming you're using the latest version of Laravel, Laravel 5.
Lets say you have a table in your database named users and you have a Model named Users (Laravel 5 comes with the Users model as default, see app/Users.php). The users will be the base of our data for the links.
Firstly, you want to register a route so you can access the page to view some information. You can do this in the routes file. The routes file can be found here: app/Http/routes.php.
To register a route add the following code:
Route::get('users', ['uses' => 'UserController#index']);
Now what this route does is whenever we hit the URL http://your-app-name/public/users (URL might be different depending on how you have your app set up, i.e. you may not have to include public) in our web browser it will respond by running the index method on the UserController.
To respond to that route you can set up your UserController as so:
<?php namespace App\Http\Controllers;
class UserController extends Controller {
public function index()
{
}
}
Controllers should be stored in app/Http/Controllers/.
Now lets flesh out the index method:
public function index()
{
// grab our users
$users = App\Users::all();
// return a view with the users data
return view('users.index')->with('users');
}
This grabs the users from the database and loads up a view passing the users data.
Here's what your view could look like:
<!DOCTYPE html>
<html>
<head>
<title>Users Page</title>
</head>
<body>
#foreach($users as $user)
<a href="{{ URL::route('user', ['id' => $user->id]) }}">
{{ $user->username }}
</a>
#endforeach
</body>
</html>
The view code will loop through each user from the $users data we passed to the view and create a link to their user page which is different for each user based on their id (their unique identifier in the DB)
Due to the way I've named it, this would be found in app/views/users/index.blade.php - if you save files ending in blade.php you can use Laravel's templating language, blade.
Now you need to finally set up another route to respond to a user page, for example http://your-app-name/public/user/22.
Route::get('user/{id}', ['uses' => 'UserController#show']);
Then add the show method to UserController
public function show($id)
{
// this will dump out the user information
return \App\User::find($id);
}
Hope that helps a little! Wrote most of it off the top of my head so let me know if you get any errors via comment.
This question is very bare, and it is difficult to actually help your situation without you showing any code. Just to point you in the right direction though, here is what you would need.
A Model called People, this is how you will access your data.
A controller. In this controller you will do the following
Get the ID of the profile you want from the functions parameters
Find that persons information e.g. People::find($person_id);
return the profile view with that persons data e.g. return view('profile')->with('person', $person);
In your view you can then use that data on that page e.g. {{ $person->name }}
For the page that needs to display the links to the people you would have a method in your controller which..
Get all the people data e.g. People::all();
Return a view with that data return view('all-people')->with('people', $people);
You will then need a route to access an individual person. The route will need to pass the persons ID into a controller method e.g.
Route::get('get-person/{id}',
[ 'as' => 'get-person',
'uses' => 'PeopleController#getPerson' ]);
You can then use this route in your view to get the links to each person
#foreach($people as $person)
{{$person->name}}
#endforeach
This would produce the list of links you want.

Laravel 4 - Update Div Using Ajax

I'm using Laravel 4 and am trying to update a (#articles) div with the new articles that are retrieved from an ajax request. When I inspect the page and view the Network section, I can see the POST requests being fired off and it's not showing any errors (eg, articles appear to be returned). However, unfortunately, the #articles div is not being updated with the new information. Yet, if I do a browser refresh, the new articles are displayed.
Routes.php
Route::any("/dashboard/latest_sa", [
"as" => "dashboard/latest_sa",
"uses" => "DashboardController#latest_sa"
]);
controllers/DashboardController.php
Class DashboardController extends \BaseController
{
...
protected function latest_sa()
{
if( Request::ajax() )
{
// called via ajax
$articles = Articles::orderBy('published_at', 'desc')->paginate(20);
return json_decode($articles);
}
else
{
// fresh page load
$articles = Articles::orderBy('published_at', 'desc')->paginate(20);
return $articles;
}
}
...
}
app/views/dashboard/default.blade.php
...
#section("content")
// defined in /public/js/main.js
<script type="text/javascript">
callServer();
</script>
<div class="col-xs-4 col-sm-4 col-md-4 col-lg-4">
<h4>Latest Articles</h4>
<div class="articles">
<ul>
#foreach ($articles as $article)
<li>
<img src="{{ $article->user_image }}" alt="{{ $article->article_title }}" />
{{ $article->article_title }}
<div class="details">
<span class="author">{{ $article->author_name }}</span>
<span class="created">{{ Helpers::time_ago($article->published_at) }}</span>
<span class="symbol">{{ $article->symbol_title }}</span>
</div>
</li>
#endforeach
</ul>
</div>
{{ $articles->links() }}
</div>
...
/public/js/main.js
function callServer()
{
setInterval(function(){
$.ajax({
type: "POST",
url: "dashboard/latest_sa",
success:function(articles)
{
$(".articles").html(articles);
}
});
},5000);
}
JS is hardly my strong suit, so I'm not sure what I'm doing wrong here.
And, for clarity sake, the reason why I'm trying to update all of the articles in the div is so that the Helpers::time_ago method also gets called, instead of just fetching the new articles. This way, it properly shows how long ago the article was published (eg, less than a minute ago, a minute ago, a hour ago, a day ago, etc) without refreshing the page. Essentially, I'm trying to kill two birds with one stone; update the div with the most recent articles, and update the remaining article's published_at attribute using my Helpers::time_ago method. If there is a more effective / efficient way of doing this, feel free to correct me. This seems rather crude, but since it's only for personal use and will never be used for commercial purposes, it suits my needs (not that that excuses bad code).
Nonetheless, from my fairly basic understanding, the JS should be doing the following steps:
1) Fire a POST request off to the /dashboard/latest_sa route
2) Execute the DashboardController#latest_sa action
3) Return a DB collection of all $articles ordered by the latest published date, and paginated
4) Pass the $articles collection back to the JS success attribute (as articles)
5) Fire the anonymous function, with the articles collection as an argument
6) Update the corresponding inner HTML with the results from the articles collection
The logic sounds right, so I'm pretty sure this is going to be a human error (98% of the time it is, after all. lol). Hopefully, someone here will be able to see the (probably glaring) problem in the logic and point me in the right direction.
In the meantime, I'm going to keep toying around with it.
I look forward to your thoughts, ideas, and suggestions. TIA.
EDIT:
Well, I found one of the problems; the articles div is a class, and in the JS I'm referring to it as an id. I fixed that, and now after the timeInterval, the article's div is "updated" but no results are being displayed (none, zippo, nadda).
Yet, if I directly access the /dashboard/latest_sa URI I get the valid JSON response that I'm expecting. So, albeit I am closer, I am still missing something.
EDIT 2:
Okay, in the controller, I made some changes which can be seen above, where I am now doing a json_decode on the $articles, before returning them to be passed into the view. With that in place, the articles are showing back up again after the timeInterval has elapsed, however, the new articles and the published_at for the existing articles are not being updated. After reviewing Inspect -> Network, it shows that the server is responding with a 500 Internal Server Error from the ajax POST request.
Hrm... Seems like I'm going in circles. Sounds like a good time to take a break and go for a walk. ;)
EDIT 3:
Well, I modified my Helpers class and added in the following method to check if the $article is a json object.
public static function isJson($string)
{
json_decode($string);
return (json_last_error() == JSON_ERROR_NONE);
}
app/views/dashboard/index.blade.php
#foreach ($articles as $article)
<?php
if( Helpers::isJson($article) )
{
$article = json_decode($article);
// dd($article) // when uncommented it returns a valid PHP object
}
?>
<!-- Iterate over the article object and output the data as shown above... -->
#endforeach
As you can see, (for the time being) inside of my view's foreach($articles as $article), I run Helpers::isJson($article) as a test and decode the object if it is json. This has enabled me to get passed the 500 Internal Server Error message, populate the articles div with the results on the initial load, and after the ajax POST request is fired off, I'm getting back a server response of 200 OK according to Inspect -> Network. However, after it updates the div, it doesn't show any articles.
Around, and around I go... I think it's time I take that break I keep murmuring about. ;)
Any thoughts, suggestions and / or ideas are greatly welcomed and appreciated.
At first, you should know that, when you return a collection from the controller/route, the response automatically turns in to a json response so, you don't need to use json_decode() and it won't work, instead, you may try something like this (from your controller for ajax):
$articles = Articles::orderBy('published_at', 'desc')->paginate(20);
return View::make('defaultAjax')->with('articles', $articles);
Since building the HTML in the client side using the json data received from server side would be tough for you so, you may return HTML from the server with the generated view instead of json, so you may try something like this in your success handler:
success:function(articles) {
$(".articles").html(articles);
}
Now create a view for ajax response without extending the template like this:
//defaultAjax.blade.php used in the controller for ajax response
<ul>
#foreach ($articles as $article)
<li>
<img src="{{ $article->user_image }}" alt="{{ $article->article_title }}" />
{{ $article->article_title }}
<div class="details">
<span class="author">{{ $article->author_name }}</span>
<span class="created">{{ Helpers::time_ago($article->published_at) }}</span>
<span class="symbol">{{ $article->symbol_title }}</span>
</div>
</li>
#endforeach
</ul>
{{ $articles->links() }}
Notice, there is no #extendds() or #section(), just plain partial view, so it'll be rendered without the template and you can insert the ul inside the .articles div. That's it.
$("#articles").html(articles); ->> $(".articles").html(articles);

How to Get the Current URL Inside #if Statement (Blade) in Laravel 4?

I am using Laravel 4. I would like to access the current URL inside an #if condition in a view using the Laravel's Blade templating engine but I don't know how to do it.
I know that it can be done using something like <?php echo URL::current(); ?> but It's not possible inside an #if blade statement.
Any suggestions?
You can use: Request::url() to obtain the current URL, here is an example:
#if(Request::url() === 'your url here')
// code
#endif
Laravel offers a method to find out, whether the URL matches a pattern or not
if (Request::is('admin/*'))
{
// code
}
Check the related documentation to obtain different request information: http://laravel.com/docs/requests#request-information
You can also use Route::current()->getName() to check your route name.
Example: routes.php
Route::get('test', ['as'=>'testing', function() {
return View::make('test');
}]);
View:
#if(Route::current()->getName() == 'testing')
Hello This is testing
#endif
Maybe you should try this:
<li class="{{ Request::is('admin/dashboard') ? 'active' : '' }}">Dashboard</li>
To get current url in blade view you can use following,
Current Url
So as you can compare using following code,
#if (url()->current() == 'you url')
//stuff you want to perform
#endif
I'd do it this way:
#if (Request::path() == '/view')
// code
#endif
where '/view' is view name in routes.php.
This is helped to me for bootstrap active nav class in Laravel 5.2:
<li class="{{ Request::path() == '/' ? 'active' : '' }}">Home</li>
<li class="{{ Request::path() == 'about' ? 'active' : '' }}">About</li>
A little old but this works in L5:
<li class="{{ Request::is('mycategory/', '*') ? 'active' : ''}}">
This captures both /mycategory and /mycategory/slug
Laravel 5.4
Global functions
#if (request()->is('/'))
<p>Is homepage</p>
#endif
You can use this code to get current URL:
echo url()->current();
echo url()->full();
I get this from Laravel documents.
I personally wouldn't try grabbing it inside of the view. I'm not amazing at Laravel, but I would imagine you'd need to send your route to a controller, and then within the controller, pass the variable (via an array) into your view, using something like $url = Request::url();.
One way of doing it anyway.
EDIT: Actually look at the method above, probably a better way.
You will get the url by using the below code.
For Example your URL like https//www.example.com/testurl?test
echo url()->current();
Result : https//www.example.com/testurl
echo url()->full();
Result: https//www.example.com/testurl?test
For me this works best:
class="{{url()->current() == route('dashboard') ? 'bg-gray-900 text-white' : 'text-gray-300'}}"
A simple navbar with bootstrap can be done as:
<li class="{{ Request::is('user/profile')? 'active': '' }}">
Profile
</li>
The simplest way is to use: Request::url();
But here is a complex way:
URL::to('/').'/'.Route::getCurrentRoute()->getPath();
There are two ways to do that:
<li{!!(Request::is('your_url')) ? ' class="active"' : '' !!}>
or
<li #if(Request::is('your_url'))class="active"#endif>
You should try this:
<b class="{{ Request::is('admin/login') ? 'active' : '' }}">Login Account Details</b>
The simplest way is
<li class="{{ Request::is('contacts/*') ? 'active' : '' }}">Dashboard</li>
This colud capture the contacts/, contacts/create, contacts/edit...
For named routes, I use:
#if(url()->current() == route('routeName')) class="current" #endif
Set this code to applied automatically for each <li> + you need to using HTMLBuilder library in your Laravel project
<script type="text/javascript">
$(document).ready(function(){
$('.list-group a[href="/{{Request::path()}}"]').addClass('active');
});
</script>
instead of using the URL::path() to check your current path location, you may want to consider the Route::currentRouteName() so just in case you update your path, you don't need to explore all your pages to update the path name again.
In Blade file
#if (Request::is('companies'))
Companies name
#endif
class="nav-link {{ \Route::current()->getName() == 'panel' ? 'active' : ''}}"
Another way to write if and else in Laravel using path
<p class="#if(Request::is('path/anotherPath/*')) className #else anotherClassName #endif" >
</p>
Hope it helps
Try this:
#if(collect(explode('/',\Illuminate\Http\Request::capture()->url()))->last() === 'yourURL')
<li class="pull-right"><a class="intermitente"><i class="glyphicon glyphicon-alert"></i></a></li>
#endif
For Laravel 5.5 +
<a class="{{ Request::segment(1) == 'activities' ? 'is-active' : ''}}" href="#">
<span class="icon">
<i class="fas fa-list-ol"></i>
</span>
Activities
</a>
1. Check if URL = X
Simply - you need to check if URL is exactly like X and then you show something. In Controller:
if (request()->is('companies')) {
// show companies menu or something
}
In Blade file - almost identical:
#if (request()->is('companies'))
Companies menu
#endif
2. Check if URL contains X
A little more complicated example - method Request::is() allows a pattern parameter, like this:
if (request()->is('companies/*')) {
// will match URL /companies/999 or /companies/create
}
3. Check route by its name
As you probably know, every route can be assigned to a name, in routes/web.php file it looks something like this:
Route::get('/companies', function () {
return view('companies');
})->name('comp');
So how can you check if current route is 'comp'? Relatively easy:
if (\Route::current()->getName() == 'comp') {
// We are on a correct route!
}
4. Check by routes names
If you are using routes by names, you can check if request matches routes name.
if (request()->routeIs('companies.*')) {
// will match routes which name starts with companies.
}
Or
request()->route()->named('profile')
Will match route named profile. So these are four ways to check current URL or route.
source
#if(request()->path()=='/path/another_path/*')
#endif
Try This:
<li class="{{ Request::is('Dashboard') ? 'active' : '' }}">
<a href="{{ url('/Dashboard') }}">
<i class="fa fa-dashboard"></i> <span>Dashboard</span>
</a>
</li>
There are many way to achieve, one from them I use always
Request::url()
Try this way :
registration

Resources