Two types of likes with Cookie - laravel

I need any user to be able to like it every 24 hours
I wrote a function for this
const LIKE_HEART = 'like_heart';
const LIKE_FINGER = 'like_finger';
public static $types = [self::LIKE_HEART, self::LIKE_FINGER];
public function setLikes() {
$likes = Cookie::get($types);
$hours = 24;
if ($likes) {
self::where('id', $article->id)
->where('updated_at', '<', Carbon::now()->subHours($hours))
->increment($types);
}
}
But I have two fields in my database, like_heart and like_finger, these should be two types of likes. How can I rewrite my function into a method so that I can only choose one type of like out of two?
An array of the following type must be serialized in cookies:
$r = [
'1' => [
'like_heart' => '2021-09-28 22:02:01',
'like_finger' => '2021-11-28 11:12:34',
],
'2' => [
'like_finger' => '2021-11-28 11:12:34',
],
];
where 1, 2 is the article ID. Date - the date the like was added by current users
The current date is compared with the date in this cookie for a specific article, and if it is less than 24 hours old or missing, add +1 to the corresponding like in the article and add / change information in the like.
article.blade
<div class="blog-wrapper">
<div class="container">
<div class="article">
<p><b>{!! $article->title !!}</b></p>
<p><b>{!! $article->subtitle !!}</b></p>
<picture>
<source srcset="{{ $article->image_list_mobile }}" media="(max-width: 576px)" alt="{{ $article->image_mobile_alt }}" title="{{ $article->image_mobile_title }}">
<source srcset="{{ $article->image_list }}" alt="{{ $article->image_alt }}" title="{{ $article->image_title }}">
<img srcset="{{ $article->image_list }}" alt="{{ $article->image_alt }}" title="{{ $article->image_title }}">
</picture>
<p><b>{{ date('d F Y', strtotime($article->published_at)) }}</b></p>
<p><b>{{ $article->getTotalViews() }} Views</b></p>
<p><b>{{ $allArticleCommentsCount }} Comments</b></p>
</div>
Like Heart
Like Finger
<div class="comments">
<div class="recommend-title"><p><b>Comments ({{ $allArticleCommentsCount }})</b></p></div>
#foreach($article_comments as $article_comment)
<p><b>{!! $article_comment->name !!}</b></p>
<p><b>{!! $article_comment->text !!}</b></p>
<p><b>{{ date('d F Y', strtotime($article_comment->date)) }}</b></p>
#endforeach
</div>
</div>
</div>
controller
public function index(Request $request, $slug)
{
$article = Article::where('slug', $slug)->first();
if(!$article){
return abort(404);
}
$viewed = Session::get('viewed_article', []);
if (!in_array($article->id, $viewed)) {
$article->increment('views');
Session::push('viewed_article', $article->id);
}
$allArticleCommentsCount = ArticleComment::where('article_id', $article->id)->count();
$article_comments = ArticleComment::where('article_id', $article->id)->get();
return view('article', compact('article', 'article_comments', 'allArticleCommentsCount'));
}
public function postLike() {
if ($like = request('like')) {
$articleId = request('article_id');
if (User::hasLikedToday($articleId, $like)) {
return response()
->json([
'message' => 'You have already liked the Article #'.$articleId.' with '.$like.'.',
]);
}
$cookie = User::setLikeCookie($articleId, $like);
return response()
->json([
'message' => 'Liked the Article #'.$articleId.' with '.$like.'.',
'cookie_json' => $cookie->getValue(),
])
->withCookie($cookie);
}
}
Article model
class User extends Authenticatable
{
// ...
public static function hasLikedToday($articleId, string $type)
{
$articleLikesJson = \Cookie::get('article_likes', '{}');
$articleLikes = json_decode($articleLikesJson, true);
// Check if there are any likes for this article
if (! array_key_exists($articleId, $articleLikes)) {
return false;
}
// Check if there are any likes with the given type
if (! array_key_exists($type, $articleLikes[$articleId])) {
return false;
}
$likeDatetime = Carbon::createFromFormat('Y-m-d H:i:s', $articleLikes[$articleId][$type]);
return ! $likeDatetime->addDay()->lt(now());
}
public static function setLikeCookie($articleId, string $type)
{
// Initialize the cookie default
$articleLikesJson = \Cookie::get('article_likes', '[]');
$articleLikes = json_decode($articleLikesJson, true);
// Update the selected articles type
$articleLikes[$articleId][$type] = today()->format('Y-m-d H:i:s');
$articleLikesJson = json_encode($articleLikes);
return cookie()->forever('article_likes', $articleLikesJson);
}
}
route
Route::get('/article', function () {
$articleLikesJson = \Cookie::get('article_likes', '{}');
return view('article')->with([
'articleLikesJson' => $articleLikesJson,
]);
});
Route::get('article/{id}/like', 'App\Http\Controllers\ArticleController#postLike');

First of all, you should never store any logic in the client side. A great alternative for this kind of feature would be using the Laravel Aquantances package.
https://laravel-news.com/manage-friendships-likes-and-more-with-the-acquaintances-laravel-package
Anyway, since you want to do it with cookies;
We can actually do this a lot easier than thought.
Articles.php
class User extends Authenticatable
{
// ...
public static function hasLikedToday($articleId, string $type)
{
$articleLikesJson = \Cookie::get('article_likes', '{}');
$articleLikes = json_decode($articleLikesJson, true);
// Check if there are any likes for this article
if (! array_key_exists($articleId, $articleLikes)) {
return false;
}
// Check if there are any likes with the given type
if (! array_key_exists($type, $articleLikes[$articleId])) {
return false;
}
$likeDatetime = Carbon::createFromFormat('Y-m-d H:i:s', $articleLikes[$articleId][$type]);
return ! $likeDatetime->addDay()->lt(now());
}
public static function setLikeCookie($articleId, string $type)
{
// Initialize the cookie default
$articleLikesJson = \Cookie::get('article_likes', '[]');
$articleLikes = json_decode($articleLikesJson, true);
// Update the selected articles type
$articleLikes[$articleId][$type] = today()->format('Y-m-d H:i:s');
$articleLikesJson = json_encode($articleLikes);
return cookie()->forever('article_likes', $articleLikesJson);
}
}
The code above will allow us to is a user has liked an article and generate the cookie we want to set.
There are a couple important things you need to care about.
Not forgetting to send the cookie with the response.
Redirecting back to a page so that the cookies take effect.
I've made a very small example:
routes/web.php
Route::get('/test', function () {
$articleLikesJson = \Cookie::get('article_likes', '{}');
if ($like = request('like')) {
$articleId = request('article_id');
if (User::hasLikedToday($articleId, $like)) {
return redirect()->back()
->with([
'success' => 'You have already liked the Article #'.$articleId.' with '.$like.'.',
]);
}
$cookie = User::setLikeCookie($articleId, $like);
return redirect()->back()
->withCookie($cookie)
->with([
'success' => 'Liked the Article #'.$articleId.' with '.$like.'.',
]);
}
return view('test')->with([
'articleLikesJson' => $articleLikesJson,
]);
});
resources/views/test.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.6.0/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
</head>
<body>
<div class="container">
#if (session('success'))
<div class="alert alert-success" role="alert">
{{ session('success') }}
</div>
#endif
<pre>{{ $articleLikesJson }}</pre>
<div class="row">
#foreach (range(1, 4) as $i)
<div class="col-3">
<div class="card">
<div class="card-header">
Article #{{ $i }}
</div>
<div class="card-body">
<h5 class="card-title">Special title treatment</h5>
<p class="card-text">With supporting text below as a natural lead-in to additional content.</p>
<a href="/test?like=heart&article_id={{ $i }}" class="btn btn-primary">
Like Heart
</a>
<a href="/test?like=finger&article_id={{ $i }}" class="btn btn-primary">
Like Finger
</a>
</div>
<div class="card-footer text-muted">
2 days ago
</div>
</div>
</div>
#endforeach
</div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#4.6.0/dist/js/bootstrap.min.js" integrity="sha384-+YQ4JLhjyBLPDQt//I+STsc9iw4uQqACwlvpslubQzn4u2UU2UFM80nGisd026JF" crossorigin="anonymous"></script>
</body>
</html>
Post Update:
1- Remove the range()
2- Update the route of these links (to where you put the logic for liking)
3- Below I've added an example for route Route::post('article/{id}/like', [SomeController::class, 'postLike'])
Like Heart
Like Finger

Related

Vue, Laravel Pagination doesn't work well

This is my post page:
<template>
<br/>
<pagination
#pageClicked="getPage($event)"
v-if="this.getdArray.data != null"
:links="this.getdArray.links"
/>
<a
:href="route('create',{region1:this.region})"
class="list-group-item list-group-item-action w-25 float-right text-gray-200 align-text-bottom"
style="background-color: rgb(00, 00, 00)"
>
글작성
<!-- {{ this.getdArray }} -->
</a>
<div v-for="post in this.getdArray.data" :key="post.id">
<a
:href="route('show',{'id': post.id},{region1:this.region})"
class="list-group-item list-group-item-action w-100 float-right text-gray-200 "
style="background-color: rgb(50, 60, 60)"
>
{{post.title}}
</a>
</div>
</template>
<script>
import {InertiaLink} from "#inertiajs/inertia-vue3";
import Pagination from "./Pagination.vue";
export default {
data(){
return{
postdata: []
}
},
methods: {
check(){
console.log(this.postRegion);
},
getPage(url) {
axios
.get(url)
.then((res) => {
this.getdArray = res.data;
console.log(res.data);
})
.catch((err) => {
console.log(err);
});
},
},
props: [
'regionN', 'posts','dArray'
],
data() {
return {region: "", getposts: [],getdArray:[]}
},
beforeMount() {
this.region = this.regionN;
this.getposts = this.posts;
this.getdArray=this.dArray;
// console.log(this.getposts);
console.log(this.region);
console.log(this.getposts);
console.log(this.getdArray);
},
components: {
InertiaLink,
Pagination
},
computed: {
postRegion: function () {
return this
.getposts
.filter((post) => {
if (post.region == this.region) {
return post
}
});
}
//computed 로 필요한 데이터만 반환
//.filter 함수는 배열에 적용가능하며 배열내 각 원소에 적용
}
}
</script>
And this is my pagination page:
<template>
<div v-if="links.length > 3">
<div class="flex flex-wrap -mb-1">
<template v-for="(link, key) in links">
<div
v-if="link.url === null"
:key="key"
class="px-4 py-3 mb-1 mr-1 text-sm leading-4 text-gray-400 border rounded"
v-html="link.label"
/>
<div
v-else
#click="pageClicked(link.url)"
:key="link.url"
class="px-4 py-3 mb-1 mr-1 text-sm leading-4 border rounded hover:bg-white focus:border-indigo-500 focus:text-indigo-500"
:class="{ 'bg-white': link.active }"
:href="link.url"
v-html="link.label"
></div>
</template>
</div>
</div>
</template>
<script>
export default {
props: {
links: Array,
},
methods: {
pageClicked(url) {
this.$emit("pageClicked", url);
},
},
};
</script>
When I push list button,
something like
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title inertia>Laravel</title>
This kind of thing send by res.data
How can I fix it? On other people's code, res.data has data and link,
but on my res.data, HTML code send back.
this is my controller
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Storage;
use Inertia\Inertia;
use Symfony\Component\Console\Input\Input;
class PostController extends Controller
{
// public function index()
// {
// //
// }
public function create(Request $request)
{
$region1 = $request->region1;
return Inertia::render('Create', ["region1" => $region1]);
}
public function store(Request $request)
{
$request->validate([
'title' => 'required|min:3',
'content' => 'required|min:3',
'image' => 'image',
// 'region1' => 'required'
]);
// $user_id = Auth::user()->id;
// $region =
// $request->region1;
$post = new Post();
$post->user_id = Auth::user()->id;
$post->title = $request->title;
$post->content = $request->content;
//inertia 에서의 post요청
//function storePost() {
//form.post('/post/store')
//}
//와 같이.
$path = $request->file('image')->store('image', 'public');
$imgpath = "/storage/" . $path;
$post->image = $imgpath;
$post->region = $request->region;
$post->save();
// $validated = array_merge($validated, ['image' => $imgpath]);
// $validated = array_merge($validated, ['user_id' => $user_id]);
// $validated = array_merge($validated, ['region' => $region]);
// Post::create($validated);
// if ($request->hasFile('image')) {
// $image_path = $request->file('image')->store('image', 'public');
// }
// $post = new Post();
// $post->title = $request->title;
// $post->content = $request->content;
// $post->user_id = Auth::user()->id;
// $post->region = $request->region;
// $post->image = "/storage/" . $image_path;
// $posts = Post::all();
// $b2018 = DB::table('crimes')->get();
// $t2018 = json_decode(json_encode($b2018), true);
// $region1 = $request->region1;
// $posts = Post::find($post->id);
return Redirect::route('main');
}
public function show($id)
{
$posts = Post::find($id);
return Inertia::render('Show', ["posts" => $posts]);
}
public function edit($id)
{
$post = Post::find($id);
return Inertia::render('Edit', ["post" => $post]);
}
public function update(Request $request, $id)
{
$post = Post::find($id);
$post->title = $request->title;
$post->content = $request->content;
$post->user_id = Auth::user()->id;
if ($request->hasFile('image')) {
$fileName = time() . '_' . $request->file('image')->getClientOriginalName();
$request->file('image')->storeAs('public/images', $fileName);
if ($fileName) {
$input = array_merge($input, ['image' => $fileName]);
}
}
$post->save();
$posts = Post::find($id);
return Inertia::render('Show', ["posts" => $posts]);
}
public function destroy($id)
{
$post = Post::find($id);
$post->delete();
if ($post->image) {
Storage::delete('public/images/' . $post->image);
}
return Inertia::render('question');
}
}
i added my controller, and i tried to fix it but it still sent request twice...
I think problem is in your Laravel back-end or bad request in front-end side, sometime laravel return error in HTML format, if you not defined accept application/json in your request headers.
Try to resolve that problem first, and edit your question.

Refresh same livewire component after form wire:submit.prevent

Please I'd like to refresh same component after form submit. There is an if statement that allows the the form to display in the component. I'd like to refresh the whole component so as not to show the form again after submit.
I already tried emit but I don't think it works for same component.
Livewire component
<?php
namespace App\Http\Livewire;
use App\Lesson;
use App\Question;
use App\QuestionsOption;
use App\TestsResult;
use Livewire\Component;
class LessonTest extends Component
{
public $test_result;
public $lesson;
public $test_exists;
public array $question = [];
//protected $listeners = ['testDone' => 'render'];
public function mount($test_exists, $lesson, $test_result)
{
$this->lesson = $lesson;
$this->test_exists = $test_exists;
$this->test_result = $test_result;
}
public function lessonTest()
{
$lesson = Lesson::where('slug', $this->lesson->slug)->firstOrFail();
$answers = [];
$test_score = 0;
foreach ($this->question as $question_id => $answer_id) {
$question = Question::find($question_id);
$correct = QuestionsOption::where('question_id', $question_id)
->where('id', $answer_id)
->where('correct', 1)->count() > 0;
$answers[] = [
'question_id' => $question_id,
'option_id' => $answer_id,
'correct' => $correct,
];
if ($correct) {
$test_score += $question->score;
}
/*
* Save the answer
* Check if it is correct and then add points
* Save all test result and show the points
*/
}
$test_result = TestsResult::create([
'test_id' => $this->lesson->test->id,
'user_id' => \Auth::id(),
'test_result' => $test_score,
]);
$test_result->answers()->createMany($answers);
$this->reset(['question']);
$this->emit('testDone');
}
public function render()
{
return view('livewire.lesson-test');
}
}
Livewire Blade View
<div>
#if ($test_exists)
<hr />
<h3>Test: {{ $lesson->test->title }}</h3>
#if (!is_null($test_result))
<div class="alert alert-info">Your test score: {{ $test_result->test_result }} /
{{ $lesson->test->questions->count() }}</div>
#else
<form wire:submit.prevent='lessonTest' action="{{ route('lessons.test', [$lesson->slug]) }}"
method="post">
{{ csrf_field() }}
#foreach ($lesson->test->questions as $question)
<b>{{ $loop->iteration }}. {{ $question->question }}</b>
<br />
#foreach ($question->options as $option)
<input type="radio" wire:model='question.{{ $question->id }}'
name="questions[{{ $question->id }}]" value="{{ $option->id }}" />
{{ $option->option_text }}<br />
#endforeach
<br />
#endforeach
<button class="btn btn-success btn-lg refresh" type="submit">Submit</button>
</form>
#endif
<hr />
#endif
</div>
Thank You. I got it solved, I forget that I passed the test result from the controller before, so I had to recall the test_result and also the test_exist inside the lessonTest action.
$this->test_result = TestsResult::where('test_id', $this->lesson->test->id)
->where('user_id', \Auth::id())
->first();
$this->test_exists = true;

Undefined variable when trying to use two loops

I have two functions
whatsnew()
and
perfume()
both has its own #foreach in different sub folders which i show them in one page.
problem is if one #foreach works the other show an error undefined variable
ps- this is my first time posting a question in SO .. sorry if its sloppy..
ProductController.php
//to show last 5 latest items
public function whatsnew(){
$cat_new = products::orderBy('id', 'desc')->take(5)->get();
return view('/home', compact('cat_new'));
}
//to show category
public function perfume(){
$perfume = products::where('category','LIKE','perfume')->get();
return view('/home', compact('perfume'));
}
Web.blade.php
Route::get('/', [
'uses' => 'ProductController#whatsnew',
'as' => 'db.whatsnew']);
Route::get('/', [
'uses' => 'ProductController#perfume',
'as' => 'db.perfume']);
perfume.blade.php
#foreach($perfume as $perfume_cat)
whatnew.blade.php
#foreach($cat_new as $row)
It looks like you are passing only 1 collection back to the view each time, which is probably why one or the other works.
If you change this:
public function whatsnew(){
$cat_new = products::orderBy('id', 'desc')->take(5)->get();
return view('/home', compact('cat_new'));
}
public function perfume(){
$perfume = products::where('category','LIKE','perfume')->get();
return view('/home', compact('perfume'));
}
to this:
public function whatsNew(){
$cat_new = products::orderBy('id', 'desc')->take(5)->get();
return $cat_new; // return the collection
}
public function perfume(){
$perfume = products::where('category','LIKE','perfume')->get();
return $perfume; // return the collection
}
// Create a new index function and pass both collections to your view
public function index() {
return view('index', [
'cat_new' => $this->whatsNew(),
'perfume' => $this->perfume(),
]);
}
Your web routes file can be:
Route::get('/', 'ProductController#index')->name('product.index');
Your index.blade.php
<div class="container">
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<ol>
#foreach( $cat_new as $new )
<li>{{ $new->foo }}</li>
#endforeach
</ol>
</div>
</div>
<div class="card">
<div class="card-body">
<ol>
#foreach( $perfume as $p )
<li>{{ $p->bar }}</li>
#endforeach
</ol>
</div>
</div>
</div>
</div>
</div>
where foo and bar are whatever columns you are after.
//merge become one
public function perfume(){
$perfume = products::where('category','LIKE','perfume')->get();
$cat_new = products::orderBy('id', 'desc')->take(5)->get();
return view('/home', compact('perfume', 'cat_new'));
}

Display tests for lessons who belong to Courses

I have Courses which has lessons, and each lesson has a test. I'm trying to display the test when a lesson is clicked.
I've created the models, controller and view and it doesn't seem to work.
Here is the model for the Lesson
public function course()
{
return $this->belongsTo(Course::class, 'course_id')->withTrashed();
}
public function test() {
return $this->hasOne('App\Test');
}
Here is the controller
public function show($id)
{
$course = Course::with( 'lessons')->with('activeLessons')->findOrFail($id);
$created_bies = \App\User::get()->pluck('name', 'id')->prepend(trans('global.app_please_select'), '');
$trainers = \App\User::get()->pluck('name', 'id');
// $test = \App\Test::where('course_id', $id)->get();
$lesson = \App\Lesson::where('course_id', $id)->get();
// $course_test = Course::with('tests')->findOrFail($id);
$user = User::find(1);
$user->name;
return view('admin.courses.showCourse', compact('course', 'test', 'lesson','course_test', 'previous_lesson', 'next_lesson','date', 'user'));
}
function view_tests($id)
{
$lessons = Lesson::findOrFail($id);
$lessons->test;
return view('admin.courses.test', compact('lessons'));
Here is the Route
Route::get('/test/{id}', 'EmployeeCoursesController#view_tests')->name('test.show');
And here is the Blade with the link to display the test
#foreach($course->activeLessons as $lesson)
<article class="lesson" >
<p></p>
<p></p>
{!! $loop->iteration!!}.
<div class="body" id="title"> {!!$loop->iteration!!}. <h4>{{ $lesson->title }}</div>
<p> {!! $lesson->short_description !!}</p>
<iframe width="420" height="315" src="{{ $lesson->video_link}}" frameborder="0" allowfullscreen></iframe>
</article>
#endforeach
The issue was on the test blade. The code works well.

Flash data in Laravel 5

I'm trying to display flash data but it's not showing properly. It's showing:
{{ Session::get('flash_message') }}
but it should be the message
"Your article has been created"
What's wrong with my code? Thanks!
In my controller I have:
public function store(ArticleRequest $request)
{
Auth::user()->articles()->create($request->all());
\Session::flash('flash_message', 'Your article has been created');
return redirect('articles');
}
My app.blade.php is:
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>App Name - #yield('title')</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ elixir('css/all.css') }}">
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="js/app.js"></script>
</head>
<body>
<div class="container">
#if(Session::has('flash_message'))
<div class="alert alert-success">{{ Session::get('flash_message') }}</div>
#endif
#yield('content')
</div>
#yield('footer')
</body>
</html>
In my route.php I have the following: Curly braces display content as string not variables.
<?php
Blade::setContentTags('<%', '%>'); // for variables and all things Blade
Blade::setEscapedContentTags('<%%', '%%>'); // for escaped data
Route::get('/', function() {
return 'Home Page';
});
Route::get('blade', function () {
return view('about');
});
Route::get('about', 'HelloWorld#about');
Route::get('foo', ['middleware' => 'manager', function() {
return 'this page may only be viewed by managers';
}]);
Route:resource('articles', 'ArticlesController');
Route::controllers([
'auth' => 'Auth\AuthController',
'password' => 'Auth\PasswordController'
]);
If you have this in your route.php:
Blade::setContentTags('<%', '%>');
then that means you cannot use curly brackets for blade content. Try this instead:
#if(Session::has('flash_message'))
<div class="alert alert-success">
<% Session::get('flash_message') %>
</div>
#endif
or simply remove the setContentTags() call from your route.php.
You can make a multiple messages and with different types.
Follow these steps below:
Create a file: "app/Components/FlashMessages.php"
namespace App\Components;
trait FlashMessages
{
protected static function message($level = 'info', $message = null)
{
if (session()->has('messages')) {
$messages = session()->pull('messages');
}
$messages[] = $message = ['level' => $level, 'message' => $message];
session()->flash('messages', $messages);
return $message;
}
protected static function messages()
{
return self::hasMessages() ? session()->pull('messages') : [];
}
protected static function hasMessages()
{
return session()->has('messages');
}
protected static function success($message)
{
return self::message('success', $message);
}
protected static function info($message)
{
return self::message('info', $message);
}
protected static function warning($message)
{
return self::message('warning', $message);
}
protected static function danger($message)
{
return self::message('danger', $message);
}
}
On your base controller "app/Http/Controllers/Controller.php".
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesResources;
use App\Components\FlashMessages;
class Controller extends BaseController
{
use AuthorizesRequests, AuthorizesResources, DispatchesJobs, ValidatesRequests;
use FlashMessages;
}
This will make the FlashMessages trait available to all controllers that extending this class.
Create a blade template for our messages: "views/partials/messages.blade.php"
#if (count($messages))
<div class="row">
<div class="col-md-12">
#foreach ($messages as $message)
<div class="alert alert-{{ $message['level'] }}">{!! $message['message'] !!}</div>
#endforeach
</div>
</div>
#endif
On "boot()" method of "app/Providers/AppServiceProvider.php":
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Components\FlashMessages;
class AppServiceProvider extends ServiceProvider
{
use FlashMessages;
public function boot()
{
view()->composer('partials.messages', function ($view) {
$messages = self::messages();
return $view->with('messages', $messages);
});
}
...
}
This will make the $messages variable available to "views/partials/message.blade.php" template whenever it is called.
On your template, include our messages template - "views/partials/messages.blade.php"
<div class="row">
<p>Page title goes here</p>
</div>
#include ('partials.messages')
<div class="row">
<div class="col-md-12">
Page content goes here
</div>
</div>
You only need to include the messages template wherever you want to display the messages on your page.
On your controller, you can simply do this to push flash messages:
use App\Components\FlashMessages;
class ProductsController {
use FlashMessages;
public function store(Request $request)
{
self::message('info', 'Just a plain message.');
self::message('success', 'Item has been added.');
self::message('warning', 'Service is currently under maintenance.');
self::message('danger', 'An unknown error occured.');
//or
self::info('Just a plain message.');
self::success('Item has been added.');
self::warning('Service is currently under maintenance.');
self::danger('An unknown error occured.');
}
...
Hope it'l help you.

Resources