I am trying to create a Poll (quiz) app, now I am doing a functionality that gets random questions from the database and returns in a poll (test)
I am displaying the answers 1 by 1 and when a user clicks submit answer a request is ran and the next answer is displayed
The problem is that every time a user submits the controller gets called again and the db query as well (when he clicks the next question button
This means that the query will get different random questions now and because of that same questions appears twice sometimes
I want to make sure that the query that gets the questions only gets called once
Model:
private $random_questions;
public function getRandomQuestions($questions_count)
{
if (!$this->random_questions)
{
$this->random_questions = Question::orderByRaw('RAND()')->take($questions_count)->get();
}
return $this->random_questions;
}
public function nextQuestionLink($questions_count, $question_number) {
$nextQuestionLink = [];
if ($questions_count != $question_number && $questions_count > $question_number) {
$nextQuestionLink['url'] = '/polls/random/'.$questions_count.'/'.++$question_number;
$nextQuestionLink['text'] = 'Следващ въпрос';
$nextQuestionLink['class'] = 'btn-default';
} else {
$nextQuestionLink['url'] = '/result';
$nextQuestionLink['text'] = 'Приключи';
$nextQuestionLink['class'] = 'btn-primary';
}
return $nextQuestionLink;
}
Controller:
public function getRandomQuestions($questions_count, $question_number)
{
$question = Question::Instance();
$questions = $question->getRandomQuestions($questions_count);
$nextQuestionLink = $question->nextQuestionLink($questions_count,
$question_number);
return view('polls.random_questions_poll')->with([
'question' => $questions[$questions_count-1],
'next' => $nextQuestionLink,
]);
}
View:
#section('content')
<div id="quiz-wrapper">
<h1>{{ $question->question }}</h1>
{!! Form::open(array( 'id' => 'message')) !!}
{!! csrf_field() !!}
#foreach($question->answers->shuffle() as $answer)
<h3>
<div class="form-group">
<div class="radio">
{{Form::radio('result', "$question->id-$answer->id") }}
{{ Form::label('result', $answer->name) }}
</div>
</div>
</h3>
#endforeach
<a class="next-question-button btn {{ $next['class'] }}" href="{{ $next['url'] }}" style="display: block;" role="button">{{ $next['text'] }}</a>
<p id="validation-error-container"></p>
{!! Form::close() !!}
</div>
#endsection
Since php by default is stateless, you will need to store the initial set of questions in persistent storage and retrieve them from that for all later requests.
You can do this quite succinctly with sessions in your controller:
public function getRandomQuestions($questions_count, $question_number)
{
//attempt to retrieve from session
$questions = session('questions', function(){
//if not found in session, generate from DB,
$questions = Question::Instance()->getRandomQuestions($questions_count);
//and store in session for next request.
session(['questions' => $questions]);
return $questions;
});
$nextQuestionLink = $question->nextQuestionLink($questions_count,
$question_number);
return view('polls.random_questions_poll')->with([
'question' => $questions[$questions_count-1],
'next' => $nextQuestionLink,
]);
}
Related
Thank you for taking the time to read and perhaps reply. I think I may have gotten myself so far down the rabbit hole, I'm overlooking an obvious answer.
Here is what I'm trying to accomplish:
I have a form with numerous text inputs rendered using Laravel Collective. I have a Bootstrap modal which allows a user to input a URL:
<div>
<input wire:model="url" type="text">
<button class="btn btn-primary" wire:click="scrape">Scrape</button>
</div>
Upon submitting the URL, I have a Livewire method which parses specific data from the URL:
`public $url;
public function scrape()
{
$link = GoutteFacade::request('GET', $request->url);
//dd($link->filter('title')->text());
}`
What I'm trying to do is pass $link to my Livewire component (or Blade file if need be) so I can populate an input field like so:
`<div class="form-group">
{!! Form::label('title', 'Title', ['class' => 'control-label']) !!}
{!! Form::text('title', (isset($link) ? $link->filter('title')->text() : null), ['class' => 'form-control', 'placeholder' => 'Your catchy title']) !!}
#error('title')
<x-alert type="danger" :message="$message" />
#enderror
</div>`
I'm trying to avoid doing a complete page reload, hence Livewire to provide a better UX. Just cannot wrap my head around this.
Thank you in advance!
you can do it using events
public function scrape()
{
$link = GoutteFacade::request('GET', $request->url);
$this->emitTo('to-emit-component', 'sendLink',['data' => $link]);
}
in the component to-emit-component listen the event
protected $listeners = [
'sendLink'
];
public function sendLink($data)
{
dd($data);
}
I think my answer will respond to the question but can give to others people hint to proceed otherwise.
Case: I created a mount method in Livewire file for getting query params. As a search issue, I wanted to populate inputs in other page submitting the query.
Query and Local are linked to livewire blade as model.
Livewire file
public String $query = '';
public String $local = '';
public function mount(Request $request)
{
if ($request->input('searchQui') != '' && $request->input('searchOu') != '') {
$this->query = $request->input('searchQui');
$this->local = $request->input('searchOu');
}
}
Livewire Blade
Patient Controller:
public function store(Request $request)
{
$input = request()->all();
Patient::create($input);
dd($input->id);
// return redirect()->route('medical.create',compact('input'));
}
This is my medical.create view
{!! Form::model($input, [
'method' => 'POST',
'action' => ['MedicalController#store', $input->id]
]) !!}
<div class="row">
<div class="col-md-4">
<div class="form-group">
{{Form::label('patient_id','Patient no:')}}
{{Form::text('patient_id', null, array('class' => 'form-control') )}}
</div>
</div>
</div>
{!! Form::close() !!}
I want to get my last inserted id after storing, and display the last id in the next form, but this is the error appear in my screen:
Trying to get property 'id' of non-object
This is my Patient table:
You can do that by saving the Patient object in a variable when creating it:
public function store(Request $request)
{
$input = request()->all();
$patient = Patient::create($input); // Save it in variable
dd($patient->id); //Now you can access patient id here
// return redirect()->route('medical.create',compact('patient')); //Also you can pass it to your view
}
you can use id like Code below with least Changes in your code
$input = request()->all();
$input = Patient::create($input);
dd($input->id);
// return redirect()->route('medical.create',compact('input'));
you can retrive id after saving data by mass assignments :
public function store(Request $request)
{
$input = request()->all();
$patient = new Patient($input); // fill model with mass assignments
$patient->save() // save instant
$id = $patient->id; //retrive id
}
You can't use compact while redirecting. Try this:
Patient Controller:
public function store(Request $request)
{
$input = request()->all();
$patient = Patient::create($input);
$patient = DB::table('patients')->get()->last();
return redirect()->route('medical.create')->with('patient_id', $patient->id);
}
This is my medical.create view
{!! Form::model($input, [
'method' => 'POST',
'action' => ['MedicalController#store', session('patient_id')]
]) !!}
<div class="row">
<div class="col-md-4">
<div class="form-group">
{{Form::label('patient_id','Patient no:')}}
{{Form::text('patient_id', null, array('class' => 'form-control') )}}
</div>
</div>
</div>
{!! Form::close() !!}
I have a few problems.
I can't seem to display the saved data inside my form inputs.
I can't get my urls to validate unique.
My controller code looks very redundant.
Getting the urls to validate unique takes priority though.
Also I created the table for sharing social links with a user one to many relationship. I think thats correct. If not, please correct me.
update Just a thought...I think I'm probably complicating things by only have a single 'type' column. It would be easier if I had a column for each type of link i.e facebook col, twitter col etc. I just didn't want empty columns if user didn't provide info for some services
Heres my code:
UPDATE I gave up and just added individual columns for the different types of urls and changed to a one-to-one relationship.
form
{!! Form::model($user_links,['method' => 'PATCH', 'action'=> ['UserController#update_social']]) !!}
<div class='row form-group'>
<div class='col-md-2'>
{!! Form::label('facebook', 'Facebook Username') !!}
</div>
<div class='col-md-7'>
{!! Form::text('facebook', '',['class'=>'form-control']) !!}
</div>
</div>
<div class='row form-group'>
<div class='col-md-2'>
{!! Form::label('twitter', 'Twitter Username') !!}
</div>
<div class='col-md-7'>
{!! Form::text('twitter', null,['class'=>'form-control']) !!}
</div>
</div>
<div class='row form-group'>
<div class='col-md-2'>
{!! Form::label('reddit', 'Reddit Username') !!}
</div>
<div class='col-md-7'>
{!! Form::text('reddit', null,['class'=>'form-control']) !!}
</div>
</div>
<div class='row form-group'>
<div class='col-md-3'>
{!! Form::submit('Save Changes',['class'=>'btn btn-md btn-success']) !!}
</div>
</div>
{!! Form::close() !!}
controllers
public function show_social(Request $request){
$user_links= $request->user()->links;
return view('user.edit.social_connect',compact('user_links'));
}
public function update_social(SocialRequest $request){
$facebook= Input::get('facebook');
$twitter= Input::get('twitter');
$reddit= Input::get('reddit');
$user = $request->user();
$this->validate($request,['url'=>'unique']);
if(Input::has('facebook')||Input::has('google')||Input::has('reddit')||Input::has('twitter'))
{
if($facebook != ""){
$link = new SocialLinks();
$link->type = 'facebook';
$link->url='https//www.facebook.com/'.$facebook;
$link->user_id=$user->id;
$link->save();
}
if($twitter != ""){
$link = new SocialLinks();
$link->type = 'twitter';
$link->url='https//www.twitter.com/'.$twitter;
$link->user_id=$user->id;
$link->save();
}
if($reddit != ""){
$link = new SocialLinks();
$link->type = 'reddit';
$link->url='https//www.reddit.com/user'.$reddit;
$link->user_id=$user->id;
$link->save();
}
return Redirect::back()->with('message','Your profile has been updated');
}
return Redirect::back();
}
my model file
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Eloquent;
class SocialLinks extends Eloquent{
protected $table= 'social_links';
protected $fillable=[
'type',
'url'
];
public function user()
{
return $this->belongsTo('App\User');
}
}
?>
my request
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
class SocialRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'url'=>'unique|user_id'
];
}
}
Okay, there are a few things wrong here. Your request file is being used incorrectly. You need a model for that, unless ofcourse you're just getting "request file" and "model" mixed up. For the purpose of this comment, I'm going to use Laravel's validation method from within the controller.
Something worth noting, your "url" is not present within the form. The validation looks for a "url" parameter inside of the request, but as you do not appear to be sending that within the form, it is quite redundant. Also, when you use the "unique" validator, you need to supply a database table for it to search and check against the supplied value, in this case; url.
I've added that in, but, really it's not doing anything because the url will always be empty until you supply it in your form, so the request will always pass.
public function show_social(Request $request)
{
$user_links = $request->user()->links;
return view('user.edit.social_connect', compact('user_links'));
}
public function update_social(Request $request)
{
$facebook = $request->facebook;
$twitter = $request->twitter;
$reddit = $request->reddit;
$user = $request->user();
$this->validate($request, [
'url' => 'unique:social_links,column',
]);
if($request->has('facebook') || $request->has('google') || $request->has('reddit') || $request->has('twitter'))
{
if($facebook != ""){
$link = new SocialLinks();
$link->type = 'facebook';
$link->url = 'https//www.facebook.com/'.$facebook;
$link->user_id = $user->id;
$link->save();
}
if($twitter != ""){
$link = new SocialLinks();
$link->type = 'twitter';
$link->url = 'https//www.twitter.com/'.$twitter;
$link->user_id = $user->id;
$link->save();
}
if($reddit != ""){
$link = new SocialLinks();
$link->type = 'reddit';
$link->url = 'https//www.reddit.com/user'.$reddit;
$link->user_id = $user->id;
$link->save();
}
return Redirect::back()->with('message','Your profile has been updated');
}
return Redirect::back();
}
As you can see, I removed the type hinting for your request because what you were actually doing (from what I can tell), was type hinting the model. Your "request file" which you supplied is a model and should be in the App/ directory, and referenced using a namespace.
If you are indeed using that file as a model, then your relationship looks okay, assuming of course you've got the right foreign column setup in your database, referencing the user table.
As for your model binding not working, have you tried dumping the $user_links variable, like so: dd($user_links); - to see if it actually contains anything? As you're using a request there, I cannot tell where you're getting the information.
Hopefully this helps, if you have any more questions, feel free to ask.
I'm creating a project using Laravel. Users are able to like comments. I want to display a "like" button so a user can like a comment and if the user has already liked the comment I want that button to be "unlike" so a user can unlike the liked comment
In my database I have a likes table:
| id | user_id | comment_id |
My Like Model looks like this:
class Like extends \Eloquent {
protected $fillable = ['user_id', 'comment_id'];
protected $table = 'likes';
public function owner()
{
return $this->belongsTo('Acme\Users\User', 'user_id');
}
}
Comment Model looks like this:
class Comment extends \Eloquent {
protected $fillable = ['user_id', 'post_id', 'body'];
protected $table = 'comments';
public function owner()
{
return $this->belongsTo('Acme\Users\User', 'user_id');
}
public function likes()
{
return $this->hasMany('Acme\Likes\Like');
}
}
User model:
class User extends Eloquent {
public function comments()
{
return $this->hasMany('Acme\Comments\Comment');
}
public function likes()
{
return $this->hasMany('Acme\Likes\Like');
}
}
Likes controller :
class LikesController extends \BaseController {
use CommanderTrait;
/**
* Like a comment
* #return Response
*/
public function commentLike()
{
// using a command bus. Basically making a post to the likes table assigning user_id and comment_id then redirect back
extract(Input::only('user_id', 'comment_id'));
$this->execute(new CommentLikeCommand($user_id, $comment_id));
return Redirect::back();
}
public function unlike()
{
$like = new Like;
$user = Auth::user();
$id = Input::only('comment_id');
$like->where('user_id', $user->id)->where('comment_id', $id)->first()->delete();
return Redirect::back();
}
}
In my view I'm able to get the comments via $comment, and I'm able to get likes via $comment->like have:
#foreach($post->comments as $comment)
<div class="user-comment">
<p class="comment">
{{ $comment->owner->first_name }} {{ $comment->owner->last_name }} {{ $comment->body }}
</p>
<div class="com-details">
<!-- how long ago the comment was posted -->
<div class="com-time-container">
{{ $comment->created_at->diffForHumans() }} ·
</div>
<!-- HERE IS WHERE I WANT THE LIKE AND UNLIKE BUTTONS TO DISPLAY -->
#if ($comment->likes->owner->id === $currentUser->id)
{{ Form::open(['route' => 'like']) }}
{{ Form::hidden('user_id', $currentUser->id) }}
{{ Form::hidden('comment_id', $comment->id) }}
<button type="submit" class="com-like">Like</button>
{{ Form::close() }}
#else
{{ Form::open(['route' => 'unlike']) }}
{{ Form::hidden('user_id', $currentUser->id) }}
{{ Form::hidden('comment_id', $comment->id) }}
<button type="submit" class="com-like">Unlike</button>
{{ Form::close() }}
#endif
<!-- how many users like this comment -->
<span class="likes"> · {{ $comment->likes->count() }}</span>
</div>
</div><!--user-comment end-->
#endforeach
Im trying to set up an if statement to see if the current user has liked the status but im not sure how this is done? If the user has not liked the comment yet I want the "like" button to display. If the user has liked the comment I want the "unlike" button to display. I thought I could say #if($comment->likes->owner->id === $currentUser->id) but I get Undefined property. How would I go about doing this?
$comment->likes is a Collection of Like objects. To access the owner property, you would need to iterate the collection.
However, another option is to use the available methods on the Collection to do what you need:
#if (in_array($currentUser->id, $comment->likes->lists('user_id')))
$comment->likes->lists('user_id') will return an array of all the user_id values in the Collection of Likes for the Comment. in_array() will check if the $currentUser->id is in that array.
I haven't worked much with Laravel, so my syntax and terminology might be a bit off, but it should be the right idea.
Basically, $comment->likes is a list of likes on that comment. You need to iterate through those likes and check if one of them is by the current user. If one of them is by the current user, then show the unlike button. Otherwise, show the like button.
Not sure what that'd look like in Blade, but here's some pseudo-code:
$currentUserLiked = false;
// go through all of the comment's likes
foreach ($comment->likes as $like)
{
// check if this like is by the current user
if ($like->owner->id == $currentUser->id)
{
$currentUserLiked = true;
break;
}
}
if ($currentUserLiked)
{
showUnlikeButton();
}
else
{
showLikeButton();
}
I'm developing a Laravel PHP application and one of my forms that I'm using for creating new data contains a checkbox field. When I try to submit the form leaving this checkbox unchecked, I get a 'SQLSTATE: cannot be null' error. I've tried using a couple of solutions to fix this problem but they haven't worked for me yet.
Controller:
public function store()
{
$input = \Input::all();
$validation = new Validators\Video;
if($validation->passes())
{
/* Additional Controller Code for storing file path names */
return \Redirect::route('overview');
}
else
{
return \Redirect::back()
->withInput()
->withErrors($validation->errors)
->with('message', 'Could not create video');
}
}
The name of the field where I'm storing the checkbox data is 'video_active'.
EloquentVideoRepository:
public function create($input, $filename, $thumb_filename)
{
/* Need this structure in order for photos to actually be displayed. */
$newVideo = new Video;
/* Store Data here */
/* Using '\Input::get()' method for accepting unchecked checkboxes */
$newVideo->video_active = \Input::get('video_active');
return $newVideo->save();
}
Form:
#section('content')
{{ Form::open(array('route' => 'store_video', 'method' => 'POST', 'files' => true)) }}
/* Additional Form Code here */
/* Code for accepting checkbox data */
<div class="form-group">
{{ Form::label('video_active', 'Active') }}
{{ Form::checkbox('video_active', 'Active') }}
</div>
<div class="form-group">
{{ Form::submit('Submit', array('class' => 'btn btn-primary')) }}
</div>
{{ Form::close() }}
#stop
I'm not sure why I can't accept an unchecked checkbox when creating new data in my form. Any help is greatly appreciated!
$newVideo->video_active = \Input::get('video_active');
\Input::get('video_active'); will return null if it hasn't been defined.
Use a ternary statement like this
$newVideo->video_active = (\Input::get('video_active') !== null) ? \Input::get('video_active') : "";
this is equivalent to
if(\Input::get('video_active') !== null) {
$newVideo->video_active = \Input::get('video_active');
} else {
$newVideo->video_active = "";
}
What I'd recommend you do is use either 1 or 0 rather than "Active" and ""
set your database column video_active as INT(1) and then do
{{ Form::checkbox('video_active', '1') }}
$newVideo->video_active = (\Input::get('video_active') == 1) ? 1 : 0;
then if you ever need to check if video_active is set
if($myModel->video_active == 1) {
// Video is active
}
While explanation looks good, my suggestion of implementation would be:
$newVideo->video_active = \Input::get('video_active', false);