Bookmark an article in Laravel - php

I am trying to create a functionality for a user to be able to bookmark and article and remove the article from his bookmarks as well. The functionality to bookmark an article works just fine, but when I try to remove the article from the bookmarks then it does not work and instead it inserts the same record but with the article_id being NULL.
Here is my controller:
public function postBookmark() {
$user_id = Auth::user()->id;
$article_id = Input::get('id');
$bookmark = Bookmark::where('user_id', '=', $user_id)->where('article_id', '=', $article_id);
$article = Article::where('id', '=', $article_id);
$article = $article->first();
// I want to check if the article has been already bookmarked by the same user
// but this if statement always returns true
if(!empty($bookmark)) {
$bookmark = Bookmark::create(array(
'user_id' => $user_id,
'article_id' => $article_id,
));
if($bookmark) {
return View::make('article.view')
->with('article', $article)
->with('bookmarked', true);
}
} else {
// Does not work
$bookmark->delete();
return View::make('article.view')
->with('article', $article)
->with('bookmarked', false);
}
return Redirect::route('article-all')
->with('global', 'We were unable to bookmark the article. Please, try again later.');
}
And here is part of my view:
{{ Form::open(array('action' => 'BookmarkController#postBookmark')) }}
<input
type="checkbox"
name="id"
onClick="this.form.submit()"
value="{{ $article->id }}"
id="bookmark"
{{ $bookmarked ? 'checked' : '' }}
/>
<label for="bookmark">Bookmark</label>
{{ Form::close() }}
I do also have a route with a post method for this functionality. I would highly appreciate if anyone could give any idea of why it does not work.

You are not executing your bookmark query.
The $boomark variable in your code example is a Illuminate\Database\Eloquent\Builder object and empty($boomark) will return always false because there is a object stored.
To execute a query you can use get() for example. In your case you want only one result, then you use first() to retrieve the first found bookmark object.
Change:
$bookmark = Bookmark::where('user_id', '=', $user_id)->where('article_id', '=', $article_id);
To this:
$bookmark = Bookmark::where('user_id', '=', $user_id)->where('article_id', '=', $article_id)->first();
Then it should work fine.

If you really want, changing the condition if(!empty($bookmark)) to if ($bookmark->count()) { might do the trick, but it will do another query with COUNT() to the DB and it is not really a good way of doing it.
The problem is with if(!empty($bookmark)), because $bookmark has a QueryBuilder instance, it will never be empty.
The preferred way would be using Eloquent model relations. With relationships you could check by Article::has('bookmark') for instance.

Thanks for the help. I ended up using both of your solutions.
public function postBookmark() {
$user_id = Auth::id();
$article_id = Input::get('id');
$bookmark = User::find($user_id)->bookmarks()->where('article_id', '=', $article_id)->first();
if(empty($bookmark)) {
$bookmark = Bookmark::create(array(
'user_id' => $user_id,
'article_id' => $article_id,
));
if($bookmark) {
return Redirect::route('article-get', array('article_id' => $article_id));
}
} else {
$bookmark->delete();
return Redirect::route('article-get', array('article_id' => $article_id));
}
return Redirect::route('article-all')
->with('global', 'We were unable to bookmark the article. Please, try again later.');
}
Nonetheless, what I really needed to fix was my view. For some reason the id of my input was not being submitted properly, so I ended up creating a hidden field for it as well.
{{ Form::open(array('action' => 'BookmarkController#postBookmark')) }}
<input
type="checkbox"
name="id"
onClick="this.form.submit()"
value="{{ $article->id }}"
id="bookmark"
{{ $bookmarked ? 'checked' : '' }}
/>
<input
type="hidden"
name="id"
value="{{ $article->id }}"
/>
<label for="bookmark">Bookmark</label>
{{ Form::close() }}

Related

laravel fetch dropdown query data value from model

I have a form and there is a dropdown for this. In a view page i want to fetch the data from the model.
model function
public static function allVenueClientList() {
/* Also if possible i want to add ($users = DB::table('clients') join query on this query which is already working for me.
return Client::where('type', static::CLIENT_TYPES['Venue'])
->orWhere('type', static::CLIENT_TYPES['Both'])
->pluck('name', 'id')->all();
*/
$users = DB::table('clients')
->join('users', 'clients.id', '=', 'users.user_id')
->where('users.status', '=', 'Active')
->where('users.id', '!=', '1')
->select('clients.name', 'clients.id')
->get();
return $users;
}
My view page code:
<div class="form-group{{ $errors->has('client_id') ? ' has-error' : '' }}">
{{Form::label('client_id', trans('admin.venue.fields.client_id'),['class' => 'col-md-4 control-label'])}}
<div class="col-md-6">
{{Form::select('client_id',[0 => trans('admin.venue.select.client_id')] + \App\Client::allVenueClientList(), old('client_id', isset($venue) ? $venue->client->id : 0), ['class' => 'form-control select'])}}
#if ($errors->has('client_id'))
<span class="help-block">
<strong>{{ $errors->first('client_id') }}</strong>
</span>
#endif
</div>
How can i get $users data on this dropdown also if it is possible to the first query change as per second query ?
Inside your controller function which defines the above mentioned function of model pass the data by using compact data...
like this $compactdata= your query result.
return view('your view', compact('compactdata'))
and then loop through result in view if it is collection other wise just show result in view withoutloop as you did it above.
Please checkout the syntax error.I am not sure about syntax.
I will admit not entirely understanding the question, but my response is too large for a comment.
It sound like you are going to want to offload some of this into scripts.
script:
function usersearch(client_id)
{
$.post('usersearch', {
_token: $('meta[name=csrf-token]').attr('content'),
client_id: client_id,
}
)
.done(function(data) {
document.getElementById('myotherdropdown').innerHTML = data;
})
.fail(function() {
alert( "I did an oops" );
});
}
Then the current select gets an event
<select name="client_id" onchange=usersearch(this.value)>
in web.php
Route::post('/usersearch', 'JavaController#usersearch');
in JavaController
public function usersearch()
{
$sku = Request::get('client_id');
$options = '';
$result = whatever you need to do here;
foreach($result as $row) {
$options .= "<option value=\"".$row->user_id."\">".$row->user_name."</option>";
}
return $options;
}
Obviously given your setup, things won't be exactly as here, but the idea itself seems to be what you are going for.
If you really want, you can even throw the token around in the script as well for a little extra security.
$.post('usersearch', {
_token: $('meta[name=csrf-token]').attr('content'),
client_id: client_id,
}
Hopefully this is what you were asking for.

Laravel - Method delete does not exist

I'm getting the error:
BadMethodCallException in Macroable.php line 74: Method delete does
not exist.
route:
Route::resource('posts', 'PostController');
my controller:
public function destroy($id)
{
$user_id = Auth::user();
$post= Post::where('id', $id)->where('user_id',$user_id)->get();
$post->delete();
return view('/home', [
'posts' => $post
]);
}
view:
<form action="{{ route('posts.destroy', '$post->id') }}" method="post">
<input type="hidden" name="_method" value="DELETE" />
{{ csrf_field() }}
{{ method_field('DELETE') }}
<input type="submit" class="btn btn-danger" value="delete" />
</form>
I tried changing method="post" to delete: error is gone but nothing gets deleted..
This is your code.
$user_id = Auth::user();
$post= Post::where('id', $id)->where('user_id',$user_id)->get();
$post->delete();
just add ->each() before delete like this,
$post->each->delete();
It work's for me.
Remove get() and it will work
$post= Post::where('id', $id)->where('user_id',$user_id);
$post->delete();
If you want to delete first document you can use :
$post= Post::where('id', $id)->where('user_id',$user_id)->first();
$post->delete();
However, you always need to check if $post is found as a query document or its null so addd :
if($post){
$post->delete();
}
use ->first() instead of ->get()
you can't delete an entire collection with delete()
Change get for first, and check if the post belongs to the user afterwards.
public function destroy($id)
{
$post = Post::where('id', $id)->first();
if($post && $post->user_id == \Auth::user()->id){
$post->delete();
return view('/home');
}else{
abort(404);
}
}
controller:
public function destroy($id)
{
$post = Post::find($id);
$post->delete();
//redirect to
return redirect()->back();
}
view:
{!! Form::open(['method' => 'DELETE','route' => ['posts.destroy', $post->id],'style'=>'display:inline']) !!}
{!! Form::submit('Delete', ['class' => 'btn btn-danger']) !!}
{!! Form::close() !!}
Try this.
hope you created the controller with
--resource
flag.
As post id is primary key of posts table you can directly remove from table,
No need of user_id
To fetch user_id from Auth facade you should use,
$user_id = Auth::id();
Only by passing id should work,
Post::find($id)->delete()
However, if you know the primary key of the model, you may delete the model without retrieving it by calling the destroy method. In addition to a single primary key as its argument, the destroy method will accept multiple primary keys, an array of primary keys, or a collection of primary keys:
Post::destroy($id)
Please Try This:
public function destroy($id)
{
$userId = Auth::user()->id;
$post = Post::where([
'id' => $id,
'user_id' => $userId
])->delete();
Session::flash('success', 'Post was successfully deleted!');
return redirect()->route('posts.index');
}
This is how I am able to delete one (or multiple) associated record(s) in a table:
RFIResponseFile::where('rfi_response_id',$response_id)->delete();
Post::where('id', $id)->where('user_id',$user_id)->delete();
Or
$post= Post::where('id', $id)->where('user_id',$user_id);
if($post->get()->count()){
$post->delete();
}
In your controller
Before change code
public function destroy($id)
{
$user_id = Auth::user();
$post= Post::where('id', $id)->where('user_id',$user_id)->get();
$post->delete();
return view('/home', [
'posts' => $post
]);
}
After change code
public function destroy($id)
{
$user_id = Auth::user();
$post= Post::where(['id'=>$id,'user_id'=>$user_id])->get();
Post::where(['id'=>$id,'user_id'=>$user_id])->delete();
return view('/home', [
'posts' => $post
]);
}
Just add this on top of view, i 've error like you and now solved, sorry for bad english.
{!! Form::model($post, ['route' => ['posts.destroy', $post->id], 'method' => 'DELETE']) !!}
and
{!! Form::close() !!}
on bottom
for controller
$post = Post::find($id);
$post->delete();
Session::flash('success', 'Menu was successfully deleted!');
return redirect()->route('posts.index');

Laravel 5.2 correct way to use variables in blade

So I know about passing variables via the controller for instance if its a query array I will do
public function index()
{
$query = Request::get('q');
if ($query) {
$users = User::where('username', 'LIKE', "%$query%")->get();
}
return view('view', compact('users'));
}
And when on the blade I will do
#if( ! empty($users))
#foreach($users as $user)
{{ $user->username }}
#endforeach
#endif
Now my question is how do I set a variable using a variable from the foreach? at the moment I am using PHP inside of the blade template file but I feel this is messy, here is what I have
#if( ! empty($users))
#foreach($users as $user)
<?php
$lastOnline = \Carbon\Carbon::createFromTimeStamp(strtotime($user->last_online))->diffForHumans();
$fiveMinsAgo = \Carbon\Carbon::now()->subMinute(5);
?>
{{ $user->username }}
#if ($user->last_online <= $fiveMinsAgo)
{{ $lastOnline }}
#else
Online Now
#endif
#endforeach
#endif
found a solution to my issue if anyone else is ever looking for it.
public function getLastOnlineAttribute($value)
{
$fiveMinsAgo = \Carbon\Carbon::now()->subMinute(5);
$thirtMinsAgo = \Carbon\Carbon::now()->subMinute(30);
$lastOnline = \Carbon\Carbon::createFromTimeStamp(strtotime($value))->diffForHumans();
if ($value <= $fiveMinsAgo) {
echo 'Last Active: '.$lastOnline.'';
}
else {
echo 'Online Now';
}
}
Basically add this into your model for the variable (eg, if its a $user->last_online it would go into the user model) , it is called a eloquent mutator if you are ever looking for more info, https://laravel.com/docs/master/eloquent-mutators
It grabs your data for the variable for instance {{ $user->last_online }}
Note that the Underscore is transformed into a CamelCase in the function name, the output is set at $value, you can then set variables inside of the function and mould the output however you wish, then in the blade you can get rid of all the extra crap and just use {{ $user->last_online }}

Laravel update makes new table rule instead of updating

I have a company table and an attributes table with all sorts of value in it.
One company hasMany attributes and an attribute belongsTo a company.
Now I have a value inside the attributes table with a 'account_nr_start' (for example, when a new user is added to a company its account_id starts counting up from 1000).
Controller:
public function __construct(Company $company, User $user)
{
if(Auth::user()->usertype_id == 7)
{
$this->company = $company;
}
else
{
$this->company_id = Auth::user()->company_id;
$this->company = $company->Where(function($query)
{
$query->where('id', '=', $this->company_id )
->orWhere('parent_id','=', $this->company_id);
}) ;
}
$this->user = $user;
$this->middleware('auth');
}
public function edit(Company $company, CompaniesController $companies)
{
$companies = $companies->getCompaniesName(Auth::user()->company_id);
$attributes = $company->attributes('company')
->where('attribute', '=', 'account_nr_start')
->get();
foreach ($attributes as $k => $v) {
$nr_start[] = $v->value;
}
return view('company.edit', ['company' => $company, 'id' => 'edit', 'companies' => $companies, 'nr_start' => $nr_start]);
}
public function update(UpdateCompanyRequest $request, $company, Attribute $attributes)
{
$company->fill($request->input())->save();
$attributes->fill($request->only('company_id', 'attribute_nr', 'value'))->save();
return redirect('company');
}
HTML/Blade:
<div class="form-group {{ $errors->has('_nr_') ? 'has-error' : '' }}">
{!! HTML::decode (Form::label('account_nr_start', trans('common.account_nr_start').'<span class="asterisk"> *</span>', ['class' => 'form-label col-sm-3 control-label text-capitalize'])) !!}
<div class="col-sm-6">
{!! Form::text('value', $nr_start[0], ["class"=>"form-control text-uppercase"]) !!}
{!! $errors->first('account_nr_start', '<span class="help-block">:message</span>') !!}
</div>
</div>
When I update a company now, it will upload like the last input here: :
So it makes a new rule, while it needs to edit the current attribute rule instead of making a new rule with an empty company_id/attribute.
If I understand what you are trying to do, I think this will fix your problem. The issue you have is the Attribute model is a new instance of the model rather than retrieving the model you need.
before running fill() from the attributes method try this
$new_attribute = $attributes->where('company_id', '=', $company->id)->where('attribute', '=', 'account_nr_start')->first();
Then run the fill()
$new_attribute->fill($request->only('company_id', 'attribute_nr', 'value'))->save();

How to gather value(s) from check-boxes, and sync that value to a pivot table?

I want to grab the value from checkboxes, and sync those value into my pivot table.
I have 3 tables :
catalog_downloads
export_frequencies
catalog_download_export_frequency (Pivot Table)
Here is what I've tried
View > My check-boxes
{{ Form::label('export_frequency' , 'Export Frequency', array('class'=> 'required cool-blue'))}} <br>
#foreach (ExportFrequency::all() as $export_frequency)
<input type="checkbox" name="{{$export_frequency->name}}" id="{{$export_frequency->id}}" value="{{$export_frequency->name}}">
{{$export_frequency->name}} <br>
#endforeach
In my Controller (CatalogDownloadController.php)
public function store()
{
$catalog_download = new CatalogDownload;
$catalog_download->title = Input::get('title');
$catalog_download->save();
foreach(ExportFrequency::all() as $export_frequency ){
$export_frequency_id = Input::get($export_frequency->name);
if(is_array($export_frequency_id))
{
$catalog_download->export_frequencies()->sync([$export_frequency_id, $catalog_download_id]);
$catalog_download_id = $catalog_download->id;
}
}
return Redirect::to('catalog_downloads/')
->with('success','The catalog_download was created succesfully!');
}
Goal
Again, I just want to sync : $export_frequency_id, $catalog_download_id
to my catalog_download_export_frequency table.
Question
Can someone tell me what I missed ? The result won't sync.
Feel free to give me suggestions/advice on this.
Thanks for your time.
This should do it mate:
// Your form view
{{ Form::label('export_frequencies' , 'Export Frequencies', array('class'=> 'required cool-blue'))}} <br />
#foreach ($exportFrequencies as $exportFrequency)
<input type="checkbox" name="export_frequencies[]" id="{{ $exportFrequency->id }}" value="{{ $exportFrequency->id }}">
{{ $exportFrequency->name }}<br />
#endforeach
// Your store method
public function store()
{
$input = Input::except('export_frequencies');
$exportFrequencies = Input::get('export_frequencies'); // Use get, not only
$catalogDownload = $this->catalogDownload->create($input); // Using dependency injection here, so don't forget to assign your CatalogDownload model to $this->catalogDownload in your contructor
if (isset($exportFrequencies)
{
$catalogDownload->exportFrequencies()->attach($exportFrequencies);
}
return Redirect::to('catalog-downloads')->with('success', 'The Catalog Download was created successfully!');
}

Categories