Laravel detect if there is a new item in an array - php

I want to implement a system in my project that "alerts" users when there is a new comment on one of their posts.
I currently query all comments on the posts from the logged in user and put everything in an array and send it to my view.
Now my goal is to make an alert icon or something when there is a new item in this array. It doesn't have to be live with ajax just on page load is already good :)
So I've made a function in my UsersController where I get the comments here's my code
public function getProfileNotifications()
{
$uid = Auth::user()->id;
$projects = User::find($uid)->projects;
//comments
if (!empty($projects)) {
foreach ($projects as $project) {
$comments_collection[] = $project->comments;
}
}
if (!empty($comments_collection)) {
$comments = array_collapse($comments_collection);
foreach($comments as $com)
{
if ($com->from_user != Auth::user()->id) {
$ofdate = $com->created_at;
$commentdate = date("d M", strtotime($ofdate));
$comarr[] = array(
'date' => $ofdate,
$commentdate,User::find($com->from_user)->name,
User::find($com->from_user)->email,
Project::find($com->on_projects)->title,
$com->on_projects,
$com->body,
Project::find($com->on_projects)->file_name,
User::find($com->from_user)->file_name
);
}
}
} else {
$comarr = "";
}
}
Is there a way I can check on page load if there are new items in the array? Like keep a count and then do a new count and subtract the previous count from the new one?
Is this even a good way to apprach this?
Many thanks in advance! Any help is appreciated.
EDIT
so I added a field unread to my table and I try to count the number of unreads in my comments array like this:
$uid = Auth::user()->id;
$projects = User::find($uid)->projects;
//comments
if (!empty($projects)) {
foreach ($projects as $project) {
$comments_collection[] = $project->comments;
}
}
$unreads = $comments_collection->where('unread', 1);
dd($unreads->count());
But i get this error:
Call to a member function where() on array
Anyone any idea how I can fix this?

The "standard" way of doing this is to track whether the comment owner has "read" the comment. You can do that fairly easily by adding a "unread" (or something equivalent) flag.
When you build your models, you should define all their relationships so that stuff like this becomes relatively easy.
If you do not have relationships, you need to define something like the following:
In User
public function projects()
{
return $this->hasMany('App\Models\Project');
}
In Project
public function comments()
{
return $this->hasMany('App\Models\Comment');
}
Once you hav ethose relationshipt, you can do the following. Add filtering as you see fit.
$count = $user->projects()
->comments()
->where('unread', true)
->count();
This is then the number you display to the user. When they perform an action you think means they've acknowledged the comment, you dispatch an asynchronous request to mark the comment as read. A REST-ish way to do this might look something like the following:
Javascript, using JQuery:
jQuery.ajax( '/users/{userId}/projects/{projectId}/comments/{commentId}', {
method: 'patch'
dataType: 'json',
data: {
'unread': false
}
})
PHP, in patch method:
$comment = Comment::find($commentId);
$comment->update($patchData);
Keep in mind you can use Laravel's RESTful Resource Controllers to provide this behavior.

try this
$unreads = $project->comments()->where('unread', 1);
dd($unreads->count());
EDIT
My be Has Many Through relation will fit your needs
User.php
public function comments()
{
return $this->hasManyTrough('App\Project', 'App\Comment');
}
Project.php
public function comments()
{
return $this->hasMany('App\Comment');
}
then you can access comments from user directly
$user->comments()->where('unread', 1)->count();
or I recommend you define hasUnreadComments method in User
public function hasUnreadComments()
{
$return (bool) $this->comments()->where('unread', 1)->count();
}
P.S.
$uid = Auth::user()->id;
$projects = User::find($uid)->projects;
this code is horrible, this way much better
$projects = Auth::user()->projects;

Related

Laravel ORM select query function load() on null

Here's my function to load submissions created by a user.
public function viewSubs()
{
$user = User::find(Input::get('id'));
$submissions = Submission::find($user)->sortByDesc('created_at');
$submissions->load('user')->load('votes')->load('suggestions.votes');
return view('submissions.index' , compact('submissions'));
}
This returns with an error
Call to a member function load() on null
when there are no records on the submission.
How to handle if there are no submission on the DB?
Just check if its null first using an if statement:
public function viewSubs()
{
$user = User::find(Input::get('id'));
if ($submissions = Submission::find($user)->sortByDesc('created_at')) {
$submissions->load('user')->load('votes')->load('suggestions.votes');
}
return view('submissions.index' , compact('submissions'));
}
Also, depending on your DB structure I'm pretty sure you can cut out a lot of the code by utilising your models' relationships by doing something like this:
$user = User::find(Input::get('id'))
->with(['submissions' => function($query) {
$query->orderBy('created_at', 'asc');
}, 'submissions.votes', 'submissions.suggestions.votes']);
Then pass the $user variable to the view, or:
$submissions = Submission::with('user', 'votes', 'suggestions.votes')
->where('user_id', Input::get('id'))
->sortByDesc('created_at')
->first();
Not entirely sure the code will work perfectly, but I'm sure you can tweak it. The point is your code can be a lot shorter and still/or more readable by using relationships you've already set up.

Loop to get user data

I can't put real code here because is very long and will be hard to
explain.
I have users table in database and I have data table in database too.
So, to get the user data I'll pass user_id as parameter. Like this:
public function get_user_data($user_id) {
}
But. I can only get 1 data per "request". (Keep reading)
public function user_data() {
$getUsers = $this->db->get('users');
foreach($getUsers->result_array() as $user)
{
$data = $this->get_user_data($user->ID);
var_dump($data); // Only return 1 data;
}
}
But, I guess that have an way to "bypass" this but I don't know. I'm having trouble thinking.
As I said, I want to "bypass" this, and be able to send multiple user IDs, my real function do not accept that by default and can't be changed.
Thanks in advance!
replace
foreach($getUsers->result_array() as $user)
{
$data = $this->get_user_data($user->ID);
var_dump($data); // Only return 1 data;
}
to this
foreach($getUsers->result_array() as $user)
{
$data[] = $this->get_user_data($user->ID);
}
var_dump($data);
If you are aiming at sending more data to the function, you always need to make signature change of your function as one of the below :
function get_user_data() {
$args = func_get_args();
/** now you can access these as $args[0], $args[1] **/
}
Or
function get_user_data(...$user_ids) {
/** now you can access these as $user_ids[0], $user_ids[1] **/
}
// Only higher version of PHP
But I am not sure how you will handle returning data.
EDIT: Yes, then in the function, you can collect data in array and return an array of data from function.
If you can change in your function from where to where_in I think you will get an easy solution.
public function get_user_data($user_ids)
{
// your db code
$this->db->where_in('ID',$user_ids); //replace where with where_in
}
public function user_data()
{
$getUsers = $this->db->get('users');
foreach($getUsers->result_array() as $user)
{
$user_ids[] = $user->ID;
}
$this->get_user_data($user_ids);
}

Laravel relationship count()

I want to get a total user transaction (specific user) with relationship.
I've done it but i'm curious is my way is good approach.
//User Model
public function Transaction()
{
return $this->hasMany(Transaction::class);
}
//Merchant Model
public function Transaction()
{
return $this->hasMany(Transaction::class);
}
public function countTransaction()
{
return $this->hasOne(Transaction::class)
->where('user_id', Request::get('user_id'))
->groupBy('merchant_id');
}
public function getCountTransactionAttribute()
{
if ($this->relationLoaded('countTransaction'))
$this->load('countTransaction');
$related = $this->getRelation('countTransaction');
return ($related) ? (int)$related->total_transaction : 0;
}
//controller
$merchant = Merchant::with('countTransaction')->get();
What make me curious is part inside countTransaction. I put where where('user_id', Request::get('user_id')) directly inside the model.
is it good approach or any other way to get specific way?
expected result:
"merchant:"{
"name": "example"
"username" : "example"
"transactions": {
"count_transactions: "4" //4 came from a specific user.
}
}
I need to get the merchant data with the transaction count for specific user. This query is based on logged in user. so when a user access merchant page, they can see their transaction count for that merchant.
Thanks.
You really want to keep request data outside of your models (instead opting to pass it in). I'm also a little confused about why you have both a 'hasOne' for transactions, and a 'hasMany' for transactions within the merchant model.
I would probably approach the problem more like the below (untested, but along these lines). Again I'm not fully sure I understand what you need, but along these lines
// Merchant Model
public function transactions()
{
return $this->hasMany(Transaction::class);
}
public function countTransactionsByUser($userId)
{
return $this
->transactions()
->where('user_id', $userId)
->get()
->pluck('total_transaction')
->sum();
}
// Controller
$userId = request()->get('user_id');
// ::all() or however you want to reduce
// down the Merchant collection
//
$merchants = Merchant::all()->map(function($item, $key) {
$_item = $item->getAttributes();
$_item['transactions'] = [
'count_transactions' => $item->countTransactionsByUser($userId);
];
return $_item;
});
// Single total
// Find merchant 2, and then get the total transactions
// for user 2
//
$singleTotal = Merchant::find(2)
->countTransactionsByUser($userId);

Create like/unlike functionality with Laravel

I have a list of properties for a real estate application and im trying to implement a like/unlike functionality based on each property detail. The idea is to add a like or remove it matching the current property and user. This is my code so far, but it only remove likes so it doesnt work as expected. If anyone can suggest for a better approach ill be appreciated.
//Controller
public function storeLike($id)
{
$like = Like::firstOrNew(array('property_id' => $id));
$user = Auth::id();
try{
$liked = Like::get_like_user($id);
}catch(Exception $ex){
$liked = null;
}
if($liked){
$liked->total_likes -= 1;
$liked->status = false;
$liked->save();
}else{
$like->user_id = $user;
$like->total_likes += 1;
$like->status = true;
$like->save();
}
return Redirect::to('/detalle/propiedad/' . $id);
}
// Model
public static function get_like_user($id)
{
return static::with('property', 'user')->where('property_id', $id)
->where('user_id', Auth::id())->first();
}
// Route
Route::get('store/like/{id}', array('as' => 'store.like', 'uses' => 'LikeController#storeLike'));
#Andrés Da Viá Looks like you are returning object from model. In case there is no data in database, it will still return an object - so far my guessing. Can you do something like below in the if($liked){ code?
Try this instead:
if(isset($liked -> user_id)){
Also try to print $liked variable after try and catch blocks. Use var_dump.
If this still does not work for you then let me know. I will try to create code based on your question.
Fix it by adding a where clause in my model to make the status equal to True ->where('status', 1)->first();

How to reroute to another view when a resource doesn't exist in a table (Laravel 4)

I have a resource:
Route::resource('artists', 'ArtistsController');
For a particular url (domain.com/artists/{$id} or domain.com/artists/{$url_tag}), I can look at the individual page for a resource in the table artists. It is controlled by this function:
public function show($id)
{
if(!is_numeric($id)) {
$results = DB::select('select * from artists where url_tag = ?', array($id));
if(isset($results[0]->id) && !empty($results[0]->id)) {
$id = $results[0]->id;
}
}
else {
$artist = Artist::find($id);
}
$artist = Artist::find($id);
return View::make('artists.show', compact('artist'))
->with('fans', Fan::all())
->with('friendlikes', Fanartist::friend_likes())
->with('fan_likes', Fanartist::fan_likes());
}
What I would like to do is have all urls that are visited where the {$id} or the {$url_tag} don't exist int he table, to be rerouted to another page. For instance, if I typed domain.com/artists/jujubeee, and jujubee doesn't exist in the table in the $url_tag column, I want it rerouted to another page.
Any ideas on how to do this?
Thank you.
In your show method you may use something like this:
public function show($id)
{
$artist = Artist::find($id);
if($artist) {
return View::make('artists.show', compact('artist'))->with(...)
}
else {
return View::make('errors.notfound')->withID($id);
}
}
In your views folder create a folder named errors (if not present) and in this folder create a view named notfound.blade.php and in this view file you'll get the $id so you may show something useful with/without the id.
Alternatively, you may register a global NotFoundHttpException exception handler in your app/start/global.php file like this:
App::error(function(Symfony\Component\HttpKernel\Exception\NotFoundHttpException $e) {
// Use $e->getMessage() to get the message from the object
return View::make('errors.notfound')->with('exception', $e);
});
To redirect to another page have a look at the redirect methods available on the responses page of the Laravel docs.
This is how I would go about doing it and note that you can also simplify your database queries using Eloquent:
public function show($id)
{
if( ! is_numeric($id)) {
// Select only the first result.
$artist = Arist::where('url_tag', $id)->first();
}
else {
// Select by primary key
$artist = Artist::find($id);
}
// If no artist was found
if( ! $artist) {
// Redirect to a different page.
return Redirect::to('path/to/user/not/found');
}
return View::make('artists.show', compact('artist'))
->with('fans', Fan::all())
->with('friendlikes', Fanartist::friend_likes())
->with('fan_likes', Fanartist::fan_likes());
}

Categories