Bootstrap button with a badge counter not working - mysql

I have a Bootstrap button with a badge counter (a numerical indicator of how many items are associated with the link).
Events <span class="badge badge-light">{{ $events = Event::where(['status' => 0])->count() }}</span>
The link works OK, but the badge counter isn't working. It should check how many events are in the database and show that number on the badge counter. So, something is wrong with this line:
{{ $events = Event::where(['status' => 0])->count() }}
I tried adding to my Events controller
public function events()
{
return view('groups.index', [
'count' => Event::where(['status' => 0])->count(),
]);
}
and calling {{ $count }}
but I get this error
Call to a member function count() on null (View: C:\laragon\www\version2\resources\views\groups\index.blade.php)
Note: The button needs to count the number of event, but the button itself shows on the groups.index page (mentioned for clarity)!

Extract logic in controller.
use \App\Event; // use your model
public function someMethod()
{
// other code
return view('some.view', [
'count' => Event::where(['status' => 0])->count(),
]);
}
view:
Events <span class="badge badge-light">{{ $count }}</span>

Related

Can't get input value with Twig

Hello I was trying to pass some arguments but I don't know how to get value of input using twig here is my code :
okey first of all im displaying the blog details using this detailsaction which also rendering a form to add comments to the blog ;
public function detailsAction(Request $request,Blog $blog){
$user=$this->getUser();
if($user==null)
return $this->redirectToRoute('fos_user_security_login');
$add_comment = new CommentaireBlog();
$em = $this->getDoctrine()->getManager();
$comments = $em->getRepository(CommentaireBlog::class)->findByBlog($blog);
$add_comment->setBlog($blog);
$add_comment->setUser($user);
$add_comment->setDate( new \DateTime());
$form = $this->createFormBuilder($add_comment)
->add('contenu', TextareaType::class)
->getForm();
if ($request->getMethod() == 'POST') {
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$add_comment = $form->getData();
$em = $this->getDoctrine()->getEntityManager();
$em->persist($add_comment);
$em->flush();
return $this->redirectToRoute('blog_details', array('id' => $blog->getId()));
}
}
return $this->render('blog/details.html.twig', array(
'form' => $form->createView(),
'comment' => $add_comment,
'blog' => $blog,
'comments'=>$comments,
));
}
twig page:
{{ form_start(form) }}
<div class="row form-group">
<div class="col col-md-3"><label class=" form-control-label">Votre Commentaire </label></div>
<div class="col-12 col-md-9"> {{ form_widget(form.contenu, { 'attr': {'class': 'form-control'} }) }}<small class="form-text text-muted"></small></div>
<button type="submit" class="btn btn-default">Envoyer</button>
<div class="col-12 col-md-9">
</div>
</div>
{{ form_end(form) }}
now what i want to do is that after someone add a comment and its(racist/verbual abuse..) an other user can report the comment and a mail will be sent so i used reportAction which take three arguments the reason the message and comment id
public function reportAction($msg,$type,$id)
{
}
i still didnt write inside it cause first of all i need to the value of inputs so i went to the twig page and i made this little form to get inputs but idk how to get the value
here is the form :
<div class="modal-body">
<form id="lala" method="GET">
<label for="cars">Reason:</label>
<select id="reportreason">
<option value="Inappropriate Content">Inappropriate Content</option>
<option value="Spam">Spam</option>
<option value="Racism">Racism</option>
<option value="Nudity">Nudity</option>
<option value="Other">Other</option>
</select>
<div class="form-group">
<label for="message-text" class="col-form-label">Message:</label>
<textarea id="reportmessage" class="form-control" id="message-text"></textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<a id="reportlink" href="{{ path('comment_report', { 'msg': form.vars.data.reportmessage ,'type': form.vars.data.reportreason, 'id': comment.id }) }}" type="button" class="btn btn-primary">Send message</a>
</div>
this is yml file :
blog_details:
path: /{id}/details
defaults: { _controller: "BlogBundle:Blog:details" }
methods: [GET, POST]
comment_report:
path: /{msg}/{type}/{id}/report
defaults: { _controller: "BlogBundle:Blog:report" }
methods: [GET, POST]
but im getting this error now :
Neither the property "reportmessage" nor one of the methods "reportmessage()", "getreportmessage()"/"isreportmessage()" or "__call()" exist and have public access in class "BlogBundle\Entity\CommentaireBlog".
so how can i get get the value of the inputs using twig ?
Twig Object Syntax https://twigfiddle.com/01iobj
Effectively the twig error message is saying that in your path() arguments, you are passing an object without an associated key as {value} The correct syntax would be {key: value} or [value], resembling a JSON syntax.
{
"key1": { "key1a": "value1a" },
"key2": ["value2"],
"key3": "value3"
}
Result
$_GET = array(
'key1' => array('key1a' => 'value1a'),
'key2' => array('value2'),
'key3' => 'value3'
);
A different approach
Looking at what you want to do, you need to refactor your approach.
First change your controller pathing for ONLY the comment.
blog_details:
path: /{id}/details
defaults: { _controller: "BlogBundle:Blog:details" }
methods: [GET, POST]
comment_report:
path: /{comment}/report
defaults: { _controller: "BlogBundle:Blog:report" }
methods: [POST]
Next create a form instance for your modal, this will allow you use the FormInstance for rendering and validating the submitted form elsewhere. Ensuring that all of the validation occurs and you're not having to update different scripts for the same form.
/* /src/Form/CommentReportForm.php */
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type as Form;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints as Assert;
class CommentReportForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('reason', Form\ChoiceType::class [
'choices' => [
'Inappropriate Content' => 'Inappropriate Content',
'Spam' => 'Spam',
'Racism' => 'Racism',
'Nudity' => 'Nudity',
'Other' => 'Other'
]
])
->add('message', Form\TextType::class, [
'constraints' => [
new Assert\Length(['min' => 10]),
new Assert\NotBlank(),
],
]);
}
public function getBlockPrefix()
{
return 'report_comment_form';
}
}
Next, update your Controller actions accordingly.
public function detailsAction(Request $request, Blog $blog)
{
if (!$user = $this->getUser()) {
//this should be handled in your firewall configuration!!!!
return $this->redirectToRoute('fos_user_security_login');
}
$em = $this->getDoctrine()->getManager();
$add_comment = new CommentaireBlog();
$add_comment->setBlog($blog);
$add_comment->setUser($user);
$add_comment->setDate(new \DateTime());
$form = $this->createFormBuilder($add_comment)
->add('contenu', TextareaType::class)
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
//Symfony form sets values for the model by_reference
$em->persist($add_comment);
$em->flush();
return $this->redirectToRoute('blog_details', array('id' => $blog->getId()));
}
/*
* create the report form
*/
$reportForm = $this->createForm(\App\Form\CommentReportForm::class);
$reportForm->handleRequest($request);
return $this->render('blog/details.html.twig', array(
'form' => $form->createView(),
'comment' => $add_comment,
'blog' => $blog,
'comments'=> $em->getRepository(CommentaireBlog::class)->findByBlog($blog),
/*
* give the report form a different name in twig
*/
'report_form' => $reportForm->createView(),
));
}
public function reportAction(Request $request, CommentaireBlog $comment)
{
$reportForm = $this->createForm(\App\Form\CommentReportForm::class);
$reportForm->handleRequest($request);
/** #var array|string[message, reason] */
$reportData = $reportForm->getData();
/*
array( 'reason' => 'value', 'message' => 'value' )
*/
dump($reportData);
if ($reportForm->isSubmitted() && $reportForm->isValid()) {
//send email
//redirect to success message
}
//display an error message
}
Lastly update your view to support the new form in your modal.
<div class="modal-body">
{{ form_start(report_form, { action: path('comment_report', { comment: comment.id }) })
{{ form_label(report_form.reason) }}
{{ form_widget(report_form.reason) }}
<div class="form-group">
{{ form_label(report_form.message) }}
{{ form_widget(report_form.message) }}
</div>
{{ form_end(report_form) }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Send message</button>
</div>
As a recommendation, I strongly urge you to record the report submissions in the database, to function as a case log and status of the reports. My approach will get you most of the way there, you would just need to create your App\Entity\CommentReport entity, with an optional association to the CommentaireBlog entity. Which would be passed to the form and adding the data_class to the form options resolver, mimicking what you have done in your other database forms.
I don't know why you wrote your path call like that, but there should not be any round brackets about the variables you want to use in your route. The following code should work:
<a
href="{{ path('comment_report', { 'msg': form.reportmessage.value ,'type': form.reportreason.value, 'id': comment.id }) }}"
type="button"
class="btn btn-primary">
Send message
</a>

How to pass parameter from controller to another view (a form) inside a view

This is my actionIndex() in my controller.
public function actionIndex()
{
$featured= new ActiveDataProvider([
'query'=>News::find()
->where(['not', ['featuredOrder' => null]])
->orderBy('featuredOrder'),
]);
$checkList=Featured::find()
->joinWith('news')
->where(['news.featuredOrder'=>null])
->orderBy('featuredOrder')
->all();
return $this->render('index', [
'dataProvider' => $featured,
'checkList'=>$checkList,
]);
I have a listview in my index view which is rendered by this controller. If an item of the listview is clicked, it will display the detailView of each item, along with the update button to update the item's data which will generate a form to update. I need to pass the $checklist to this form. Later I'll use this $checklist to populate a drop-down list. I wonder how to pass the parameter. I could just move this part to the form view, but I think it's not a good practice to have this inside a view.
$checkList=Featured::find()
->joinWith('news')
->where(['news.featuredOrder'=>null])
->orderBy('featuredOrder')
->all();
This is my index :
<?php echo \yii\widgets\ListView::widget([
'dataProvider' => $featured,
'itemView'=>'_post',
'options'=>['class'=>'row'],
'itemOptions'=>['class'=>'col-md-4'],
'summary'=>'',
'viewParams'=>['cekList'=>'cekList'],
'pager' => [
'options'=>['class'=>'pagination justify-content-center'],
'linkContainerOptions'=>['class'=>'page-item'],
'linkOptions'=>['class'=>'page-link'],
_post view
div class = "panel panel-default">
<div class = "panel-body">
<h2 class="truncate text-center"><?=Html::a($model->title, ['view', 'id' => $model->id] ) ?> </h2>
<hr>
</div>
<!-- another block of code, but unrelated, so I won't include it -->
This is the view.php file,being rendered if an item's title in the _post above is clicked.
<div class="row justify-content-between">
<div class="col-xs-6">
<?= Html::a('Update', ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?>
<?= Html::a('Delete', ['delete', 'id' => $model->id], [
'class' => 'btn btn-danger',
'data' => [
'confirm' => 'Do you want to delete this post?',
'method' => 'post',
],
]) ?>
If an update button is clicked, it will render a form. I want to pass the param to this form.
My Answer is Based On this Query :
$checkList=Featured::find()
->joinWith('news')
->where(['news.featuredOrder'=>null])
->orderBy('featuredOrder')
->all();
If you want to use only above query for drop down there is a two way to do that :
1. Create A method in controller and use array helper method for drop down list add select statement in query
public function checklistDropdown(){
$items = Featured::find()
->joinWith('news')
->where(['news.featuredOrder'=>null])
->orderBy('featuredOrder')
->all();
$items = ArrayHelper::map($items, 'id', 'name');
}
In your index action call this method pass just like you passed model and dataprovider
2. second option is more feasible i think
Create a component helper for generic drop down list add above method in that component and use that component to call the method in you view , you can define that method as STATIC . It will be reusable.

Laravel nested select and conditional statement in view blade

So I've succeeded to make a calendar display for the current month. This time, I want to show event details for a specific date. I'm not sure how to get the $event data where $event == $date.
This is the controller. I have event and dates to be used in the view:
$event = Event::where("started_at", '>=', Carbon::now()->subDays(30)->toDateTimeString())
->orderBy("started_at", "asc")
->first();
$data["event"] = $event;
$data["month"] = Carbon::now()->month;
$data["dates"] = range('1', date('t'));
return view('event.all', $data);
This is the event.all view:
#foreach($dates as $date)
<div class="seven-cols">
<div class="titlehead">
<h6>{{$date}}</h6>
<h6 style="color: lightgrey;">{{date("D", mktime(0, 0, 0, $month, $date))}}</h6>
<div style=" ">{{$eventdate = date('d',strtotime(#$event->started_at))}}</div>
#if($event->started_at == $date)
<div>Test</div>
#endif
</div>
</div>
#endforeach
What I got for this code:
As this other answer suggests I would use CarbonPeriod (or create a range with a loop if CarbonPeriod not available for you) and then collect the events for each date at the same time.
As a good practice, we should avoid keeping too much logic inside the templates and therefore build as much as we can of the content before actually building the template itself.
Using your example, and assuming that you only want to show one event for each day we could have something like this:
(Not tested code though)
$startDate = Carbon::now()->subDays(30)->toDateTimeString();
$endDate = Carbon::now()->toDateTimeString();
// Narrow down the list from the database
$events = Event::whereBetween("started_at", [$startDate, $endDate])
->orderBy("started_at")
->get();
$data = CarbonPeriod::create(
$startDate,
$endDate
)
->map(function(Carbon $date) {
$event = $events
->where("started_at", $date->toDateTimeString())
->first();
return [
"date" => $date,
"event" => $event,
];
});
return view('event.all', $data);
And in the template:
#foreach($data as $day)
<div class="seven-cols">
<div class="titlehead">
<h6>{{$day["date"]->day}}</h6>
<h6 style="color: lightgrey;">{{$day["date"]->format("D")}}</h6>
<div style=" ">{{$day["date"]->format("d")}}</div>
#if(!is_null($day["event"]))
<div>{{$day["event"]->someTextField}}</div>
#endif
</div>
</div>
</div>
#endforeach
I hope it helps!

How to pass a value from controller in a button to the next blade?

I want to pass the value from this controller:
public function show($id)
{
$data_show = DB::select("SELECT * FROM staffs WHERE id = ?", [$id]);
$data_profil = DB::select("SELECT id FROM staffs WHERE id = ?", [$id]);
return view('keluarga.index', compact('data_show', 'data_profil'));
}
Passing the value to this blade:
<div class="row">
<div class="form-group">
<!--add new button -->
<div class="col-lg-2">
{!! Form::open(['route' => 'addkeluarga_form', $data_profil->id]) !!}
{{ Form::submit('Add New', ['class' => 'btn btn-primary']) }}
{!! Form::close() !!}
</div>
<!-- show all button -->
<div class="col-lg-1">
{{ Form::submit('Delete', ['class' => 'btn btn-danger']) }}
</div>
<div class="col-lg-1">
{{ Form::submit('Cancel', ['class' => 'btn btn-warning']) }}
</div>
</div>
</div>
This is add new button which bring the staff id to the add new blade. But it fail to read the value of id in the blade.
How to fix this?
It would be easier to write
$data_profil = DB::table("staffs")->select("id")->whereId($id)->first();
BUT it doesn't make any sense, as you already have $id in your controller. There is no point on retrieving it again from the DB.
Pass $id to the template and use it instead
return view( 'keluarga.index', compact('data_show', 'id') );
check if the data_profil variable is containing your expectation using the print_r() method. i.e
$data_profil = DB::select("SELECT id FROM staffs WHERE id = ?", [$id]);
print_r($data_profil);//you will comment this out latter
check on the top of your page the content of your variable, I you see a nested array output like Array ( [0] => stdClass Object ( [id] => 1 , ...)) , then you may want to refer your variable as an array in your template. i.e.
$data_profil[0]->id
For the first query get all column,
and for secound query I don't think that you need to get id, as you already have id.
$data_show = DB::table("staffs")->where('id',$id)->first();
$data_profil = $data_show->id;
OR
$id = $id; // As the same id it will return
return view('keluarga.index', compact('data_show', 'data_profil','id'));

Yii2 DynamicForm: Demo 3: Nested Dynamic Form with types of rooms

Is it possible to have differents types of rooms in the "demo 3: Nested Dynamic Form" and get the rooms separated by their type? For example, if I wanna create the same as the demo 3 shows and adding a type for each room. I want to have rooms type A, rooms type B and rooms type C. Is it possible? (types are preloaded in the database, the user doesn't have to insert a new type nor select one type. If I want to insert a "room type A", I just add it where it belongs)
I've changed the html but the room's array in the controller didn't has all the rooms (because the first ones are overwritten). So, what do I have to do to make it work fine?
In the picture you can see the approach, I want to make it work because by just editing the html didn't work.
Ok, here is my solution:
Create 2 more clases extended of "Model". So I have 3 clases: Room (ActiveRecord), RoomB (Model), RoomC (Model). So I can representate the 3 types of room.
The attributes of the two "Model" clases, are the "id" and the "description" of the "ActiveRecord" class (remember, we are talking about Room).
In the "_form.php", I've put two "render('_form-rooms')" more, inside divs with class "col-md-4" to get the separation.
<td>
<div class="row">
<div class="col-md-4">
<?= $this->render('_form-rooms', [
'form' => $form,
'indexHouse' => $indexHouse,
'modelsRoom' => $modelsRoom[$indexHouse],
]) ?>
<button type="button" class="remove-house btn btn-danger btn-xs"><span class="fa fa-minus"></span></button>
</div>
<div class="col-md-4">
<?= $this->render('_form-rooms', [
'form' => $form,
'indexHouse' => $indexHouse,
'modelsRoom' => $modelsRoomB[$indexHouse],
]) ?>
<button type="button" class="remove-house btn btn-danger btn-xs"><span class="fa fa-minus"></span></button>
</div>
<div class="col-md-4">
<?= $this->render('_form-rooms', [
'form' => $form,
'indexHouse' => $indexHouse,
'modelsRoom' => $modelsRoomC[$indexHouse],
]) ?>
<button type="button" class="remove-house btn btn-danger btn-xs"><span class="fa fa-minus"></span></button>
</div>
</div>
</td>
In the "actionCreate", I've made 2 extra arrays representing the 2 "Model" clases, so I have those 3 arrays: $modelsRoom = [[new Room]]; $modelsRoomB = [[new RoomB]]; $modelsRoomC = [[new RoomC]];
I've changed all the logic of the code inside "actionCreate" ad hoc with the two extra arrays, so, for example, in the "isset($_POST['Room'][0][0])", I've asking for "isset($_POST['RoomB'][0][0])" and "isset($_POST['RoomC'][0][0])" as well:
// validate person and houses models
$valid = $modelPerson->validate();
$valid = Model::validateMultiple($modelsHouse) && $valid;
$valid2 = $valid3 = $valid;
if (isset($_POST['Room'][0][0])) {
foreach ($_POST['Room'] as $indexHouse => $rooms) {
foreach ($rooms as $indexRoom => $room) {
$data['Room'] = $room;
$modelRoom = new Room;
$modelRoom->load($data);
$modelsRoom[$indexHouse][$indexRoom] = $modelRoom;
$valid = $modelRoom->validate();
}
}
}
if (isset($_POST['RoomB'][0][0])) {
foreach ($_POST['RoomB'] as $indexHouse => $rooms) {
foreach ($rooms as $indexRoom => $room) {
$data['Room'] = $room;
$modelRoom = new Room;
$modelRoom->load($data);
$modelsRoomB[$indexHouse][$indexRoom] = $modelRoom;
$valid2 = $modelRoom->validate();
}
}
}
if (isset($_POST['RoomC'][0][0])) {
foreach ($_POST['RoomC'] as $indexHouse => $rooms) {
foreach ($rooms as $indexRoom => $room) {
$data['Room'] = $room;
$modelRoom = new Room;
$modelRoom->load($data);
$modelsRoomC[$indexHouse][$indexRoom] = $modelRoom;
$valid3 = $modelRoom->validate();
}
}
}
so I ask if the 2 extra "valid" variables are true to continue
if ($valid && $valid2 && $valid3) {
$transaction = Yii::$app->db->beginTransaction();
try {
if ($flag = $modelPerson->save(false)) {
foreach ($modelsHouse as $indexHouse => $modelHouse) {
if ($flag === false) {
break;
}
... (continue with the same code)
and, in the render of the form, I've pass as a parameter the extra arrays created:
return $this->render('create', [
'modelPerson' => $modelPerson,
'modelsHouse' => (empty($modelsHouse)) ? [new House] : $modelsHouse,
'modelsRoom' => (empty($modelsRoom)) ? [[new Room]] : $modelsRoom,
'modelsRoomB' => (empty($modelsRoomB)) ? [[new RoomB]] : $modelsRoomB,
'modelsRoomC' => (empty($modelsRoomC)) ? [[new RoomC]] : $modelsRoomC,
]);
In the "_form.php" view, you can see the code above, I've used the two extra arrays in the render of the two extra "_form-rooms".
In the "_form-rooms", I've removed the code representing the model's id, because in the "actionUpdate", I've remove all the "Houses", so, all their "rooms" will be deleted too. After this, I've just do the same as in the "actionCreate" (after the post).
I hope you can understand my solution. It maybe not the best solution, but it works for me. There are more details that I've omited to not to extend too much this reply, but you can always contact me ;)
If you need more details, email me.