How to change which template is extended based on user authentication - laravel

I am using Laravel 6.20.11, and I have published the Laravel blade error templates. What I need to have happen is that if the user is authenticated, the error message extends the internal-only layout, and if not, it extends the public layout like so:
#auth
#extends ('int-layouts.partials.wrapper')
#section ('error')
<div class="be-content">
<div class="main-content container-fluid">
<div class="container py-5">
<div class="row">
<div class="col-lg-8">
<div class="text-block">
<h1>404 - Not Found</h1>
<p class="text-muted text-uppercase mb-4">Sorry, we couldn't find the page you were looking for.
Please contact the administrator<br/>
Or go back to the <a class="navbar-brand py-1" href="/controlpanel/">Dashboard</a></p>
</div>
</div>
</div>
</div>
</div>
</div>
#endsection
#endauth
#guest
#extends ('ext-layouts.master')
#section('error')
<div class="container py-5">
<div class="row">
<div class="col-lg-8">
<div class="text-block">
<h1>404</h1>
<p class="text-muted text-uppercase mb-4">Sorry,You are trying to reach the page that does not exist.<br>
Please contact the administrator <br/> Or go back to the <a class="navbar-brand py-1" href="/">Home Page</a></p>
</div>
</div>
</div>
</div>
#endsection
#endguest
The problem I am having is that when I test the 404 error using abort(404) or by trying to access a route that doesn't exist, the error message displays twice and the page inherits the int-layouts.partials.wrapper even when the user isn't authenticated.
Is this expected behavior or am I doing something wrong in my blade file?

You can try to use a conditional in one #extends directive:
#extends (auth()->check() ? 'int-layouts.partials.wrapper' : 'ext-layouts.master')
Then you can use a conditional after this inside your section.
#section('error')
#auth
#else
#endif
#endsection
The #extends directive is not actually returning output directly into the compiled result like most directives do. The compiled PHP for this is held in an array to be added later.
Everything inside the ( ) of the directive is being used as a literal to call make on the View Factory:
"<?php echo \$__env->make({$expression}, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?>"
If you found the compiled view for this Blade template you would see this:
<?php echo \$__env->make(auth()->check ? 'int-layouts.partials.wrapper' : 'ext-layouts.master', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?>
The first argument to make ends up being your view name when this compiled view is executed.

In Controller function:
$layouts = Auth::user->admin ? 'view.admin' : 'view.student'; //
view.admin or view.student is the blade file which you want to render
dynamically.
return view('welcome',compact('layouts'));
Write in Blade File:
#extends($layouts)
#section('...')
...
#endsection

Related

why in search-bar using laravel livewire doesn't work

i want to show the user but it doesn't work and i wrote
#livewireScripts and #livewireStyles
i dont know why i found search tutorial at livewire docs
and doing the same but don't work also and not showing up any name of users
here is my code
my test.blade.php
#extends('layouts.master')
#section('css')
#livewireStyles
#section('title')
empty
#stop
#endsection
#section('page-header')
<!-- breadcrumb -->
<div class="page-title">
<div class="row">
<div class="col-sm-6">
<h4 class="mb-0"> </h4>
</div>
<div class="col-sm-6">
<ol class="breadcrumb pt-0 pr-0 float-left float-sm-right ">
<li class="breadcrumb-item">Home</li>
<li class="breadcrumb-item active">Page Title</li>
</ol>
</div>
</div>
</div>
<!-- breadcrumb -->
#endsection
#section('content')
<!-- row -->
<div class="row">
<div class="col-md-12 mb-30">
<div class="card card-statistics h-100">
<div class="card-body">
#livewire('counter')
</div>
</div>
</div>
</div>
<!-- row closed -->
#endsection
#section('js')
#livewireScripts
#endsection
my counter.blade.php
<ul>
#foreach($users as $user)
<li>{{ $user->name }}</li>
#endforeach
</ul>
my route when i show the component
Route::view('test', 'test');
my Counter.php of livewire
<?php
namespace App\Http\Livewire;
use App\User;
use Livewire\Component;
class Counter extends Component
{
public $search = '';
public function render()
{
return view('livewire.counter', [
'users' => User::where('name', $this->search)->get(),
]);
}
}
You have two issues here, one is that you never update your search property, and the other is - because you never update the search-property - you always search for those users who have an empty name (which is not null).
You should be making three changes, one to create an input-element that is bound to the $search proeprty, one to make the search a "like" operator (meaning that if you search for an empty string, all results will be shown, and if you have a user called Foobar and you search for Foo, it will show up in the results) and finally - because your results can change when you change your search criteria - you should be putting a key the list-elements, so Livewire know which row is which. The key should be something that is unique across your page.
First, add a new input-element to your counter view. This will be the search-property in your component. Because Livewire requires you to have only one root element in the view, we wrap it all in a <div>. This is also where we add the key to the different results.
<div>
<input wire:model="search" placeholder="Search users.." />
<ul>
#foreach($users as $user)
<li wire:key="user-{{ $user->id }}">
{{ $user->name }}
</li>
#endforeach
</ul>
</div>
Then, we need to update your retrieval of the results, in order to implement the like functionality. We put SQL wildcards % around the search to make this happen.
return view('livewire.counter', [
'users' => User::where('name', 'like', '%'.$this->search.'%')->get(),
]);
Take a deep look into what you are doing in your Livewire Component. You have initialized $search=''
Next, you are calling Users::where('name', $this->search)->get(). But at this point $this->search is an empty string. So it's either not returning users from your database or retrieving users without a name.
Finally, you are trying to display {{$user->name}} which even if there were users in your database, so either you don't have any users in your database without a name or you won't see anything because those users don't have a name.
You are missing a Search Input whose value is bound to the $search variable.
Add the following to your counter.blade.php
<input type="text" wire:model="search" />
And when you type a name in that field it should begin displaying in your list.

Can't get id from previous page Laravel

I have a button to see detail about user using button in each row datatable, the button will call a route detail.show and open link with user_id with it (ex:http://127.0.0.1:8000/detail/7),
here is the button code
->addColumn('action', function ($post) {
$link = "route('detail.show',$post->user_id)";
$btn = ' <span class="fas fa-eye"></span>';
return $btn;
})
the problem is I cant get any data from it, is there something wrong?
here is my route
Route::resource('detail', DetailController::class);
Here is my controller
public function show($user_id)
{
$post = Post::where('user_id', $user_id)->latest()->get();
return view('detail', compact('post'));
}
and here is my view
#extends('layouts.app')
#section('content')
<div class="row mt-5 mb-5">
<div class="col-lg-12 margin-tb">
<div class="float-left">
<h2> Show Post</h2>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>User ID:</strong>
{{ $post->user_id }}
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Name:</strong>
{{ $post->name }}
</div>
</div>
</div>
#endsection
I cant show anything using code as shown above. Is there something wrong? thanks in advance
Problems like this can often be solved by structuring your logic to be cleaner, more straightforward and use constructs of the framework as intended (documented).
In this case I would treat a user as resource and not the "detail".
I would rather create a specific route for showing the specific details of the user or just use partial resource routes.
Anyway, if you would like to keep your current build:
If I remember correctly, parameter passed to the show function in the controller should match the parameter name in your route.
When you generate routes with
Route::resource('detail', DetailController::class);
it creates something like
/details/{detail}
for the show method.
As described in this part of the docs.
Try replacing
$user_id
with
$detail
in your show method.

Why can't I put <script> tags in my #section?

I have a #section('content') in a file home.blade.php which extends #extends('layouts.app'), for simplicity I'll use the generated Laravel scaffolding as an example.
home.blade.php:
#extends('layouts.app')
#section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Dashboard</div>
<div class="card-body">
#if (session('status'))
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
#endif
You are logged in!
</div>
</div>
</div>
</div>
</div>
#endsection
I try and add a script tag to the section:
#extends('layouts.app')
#section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Dashboard</div>
<div class="card-body">
#if (session('status'))
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
#endif
You are logged in!
</div>
</div>
</div>
</div>
</div>
<script src="js/example.js"></script> <!-- Adding my script here -->
#endsection
But then I get the following error in the console:
app.js:38355 [Vue warn]: Error compiling template:
Templates should only be responsible for mapping the state to the UI. Avoid placing tags with side-effects in your templates, such as <script>, as they will not be parsed.
It says avoid placing script tags in templates? What exactly does this mean? How can I place a script within a #section, I don't want to put the script in my #extends('layouts.app'), I only want my script to work for this #section area.
You can use Blade stacks, they allow you to specifiy JavaScript for child views. In your home.blade.php add the following:
#push('scripts')
<script src="js/example.js"></script>
#endpush
This will push your script to a stack named scripts, you can name your stack to whatever you want. Then in your app.blade.php call the stack within your <head> tag as follows:
#stack('scripts')
Now your example.js file will only load for home.blade.php. Any other views that extend app.blade.php will not load this file.

Laravel allow links on message

I need allow links in messages, when user send message. How I can do this?
#foreach($mess as $message)
<li data-mid="{{ $message->id }}">
<div class="row margin-left-none margin-right-none">
<div class="col-md-2 padding-right-none">
<div class="avatar-user text-center">
<img src="{{ $message->sender->avatar }}" alt="$message->sender->name">
</div>
</div>
<div class="col-md-10 padding-left-none">
<div class="user-name">
<span>{{ $message->sender->name }}
#if(Helper::getOnlineUser($message->sender->id))
<i data-toggle="tooltip" title="Онлайн" class="material-icons online">fiber_manual_record</i>
#else
<i data-toggle="tooltip" title="Оффлайн" class="material-icons offline">fiber_manual_record</i>
#endif
<span class="date float-right">{{ $message->created_at->formatLocalized('%H:%m') }}</span></span>
</div>
<div class="message">
{{ $message->body }}
</div>
</div>
</div>
</li>
#endforeach
This is view of messages.
How I can allow links?
Example: http://example.com in messages =>
http://example.com
I need {!! $message->body !!} ? Or How?
In controller:
$mess = Chat::conversations($conversation)->for($user)->getMessages($limit, $request->page);
I use this package: https://github.com/musonza/chat
There are built in PHP functions to handle this:
<div class="message">
{!! strip_tags($message->body, '<a>') !!}
</div>
Where the second argument is your whitelist.
This has the following advantages:
You're not messing with regex
You're still using blade {!!!!}
You're using well tested code dev'ed by the core team
You can do it by using following php function in your blade,
<?php
function getDataWithURL($text){
// The Regular Expression filter
$reg_exUrl = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/";
// Check if there is a url in the text
if(preg_match($reg_exUrl, $text, $url)) {
// make the urls hyper links
echo preg_replace($reg_exUrl, "".$url[0]." ", $text);
} else {
// if no urls in the text just return the text
echo $text;
}
}
?>
You just need to add this code in your blade file and then you can check and replace the links in your text like this,
<div class="message">
<?php getDataWithURL($message->body);?>
</div>
I hope you will understand.

Laravel 5.0 paginate jump to page section

I'm using Laravel 5.0 and paginate along with the render() function in my view. Rather than go back to the top of the screen after I select the next page I want it to jump to #msgs.
Here is some of my code:
<h1 class="centered" id="msgs">Announcements</h1>
#foreach($messages->getCollection()->all() as $message)
<div class="row">
<div class="row">
<div class="col-sm-9">
<h3>{{$message->title}}</h3>
</div>
<div class="col-sm-3">
<h4>From: {{$message->author_name}}</h4>
</div>
</div>
<div class="row">
<p>{{$message->text}}</p>
</div>
</div>
<hr class="featurette-divider">
#endforeach
<div class="centered">
{!! $messages->render() !!}
</div>
I'm still getting a grasp on the flow of things in laravel so I'm not really sure what to do. I tried to use append->('#msgs') but realized that its appending an array in the parameters, not appending a path to the url. I there a simple way to achieve this without overriding anything?
You might want to use fragment() method:
{!! $messages->fragment('msgs')->render() !!}
Here is the link to the documentation: Pagination - Laravel

Resources