Nesting Comments Yii2 - activerecord

I have a comment table, like below:
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | NO | | NULL | |
| parent_id | int(11) | NO | | 0 | |
| post_id | int(11) | NO | | NULL | |
| body | text | NO | | NULL | |
| date | datetime | NO | | NULL | |
| status | tinyint(1) | NO | | 0 | |
+-----------+--------------+------+-----+---------+----------------+
Comment parent_id by defautl is 0, if comment is answered, parent id insert in parent_id column.
And make a relation with User Table with below code:
public function getPosts()
{
return $this->hasMany(Post::className(), ['category_id' => 'id']);
}
How can i show nesting?

First, you need to define the relation inside your Comment model class:
public function getChildComments()
{
return $this->hasMany(self::className(), ['parent_id' => 'id']);
}
That defines the entity relationship to itself. I think it is always good to also keep related logic or handlers into helper/callable methods in the same class in a way that doesn't require having to load them all at once from database. What comes next should answer the question:
How can i show nesting?
CASE01: Inside a RESTFul application
Simply override fields() inside Comment class to always output child comments:
public function fields()
{
$fields = parent::fields();
$fields['childs'] = 'childComments';
return $fields;
}
That's it. yii\rest\Serializer should take care of the recursive representation and you'll get something similar to this when outputting a list of comments:
CASE02: Inside a HTML web view
There is probably many ways to achieve it. The easiest and cleanest way I could think of is to tie on the template engine that Yii is already using to re-render the view holding child comments in a recursive way. As a working example, add something like what follows to your index.php file:
<?php
use yii\helpers\Html;
use yii\widgets\ListView;
use yii\data\ActiveDataProvider;
use app\models\Comment;
?>
<?= ListView::widget([
'dataProvider' => new ActiveDataProvider([
'query' => Comment::find(),
]),
'itemView' => '_comment',
'itemOptions' => ['style' => 'padding: 10px 50px; border: 1px solid red'],
]); ?>
Then create that _comment.php file:
<?php
use yii\helpers\Html;
use yii\widgets\ListView;
use yii\data\ActiveDataProvider;
?>
<div style="background-color: skyblue; padding: 5px 15px">
<h4><?= Html::encode($model->id) ?></h4>
<p><?= Html::encode($model->name) ?></p>
</div>
<?php
if ($model->getChildComments()->count()) {
echo ListView::widget([
'dataProvider' => new ActiveDataProvider([
'query' => $model->getChildComments(),
]),
'itemView' => '_comment',
'itemOptions' => ['style' => 'padding: 10px 0 10px 50px; border: 1px dotted blue'],
]);
}
?>
The template will create a new instance of itself each time it finds childComments linked to the represented one. With that bit of CSS paddings to show the nesting, that code should output this:

Related

validation rule unique in laravel

I want to do a validation of two fields, I have tried but it does not work for me, exactly what I need is for two fields to be validated.
what I want is that the namames of fields "grado" and "fk_nivel_academico" are not repeated
This is the table in my database:
-----------------------------------------------
id | grado | fk_nivel_academico | fk_estado
1 | Primero | 1 | 1
2 | Segundo | 1 | 2
This is the validation rule:
$validatedData = Validator::make(
[
'grado' => $this->grado
],
[
'grado' => [
'required',
Rule::unique('grado')
->where('fk_nivel_academico', '==', $this->fk_nivel_academico)
->where('grado', '==', $this->grado)
]
],
I think the problem it's that you are using the == comparator when in sql it is =.
The other solution I would recommend you to use, is to make a Rule file.
Here's a guide How to create custom validation
And in the passes method you could use something like this
public function passes($attribute, $value)
{
$table = Table::where('fk_nivel_academico', '=', $this->fk_nivel_academico)
->where('grado', '=', $this->grado)->get();
if($table->count() == 0){
return true;
}
}

How use conditional relationship in eloquent laravel

I have a 'conversation_message' table and separate sender role by column 'sender_type' (admin/user). Both of admin & user in a different table. But when I call the model, that showed error Call to a member function addEagerConstraints() on null
Table column and data
| id | id_group | id_reply | id_sender | sender_type | message
| 1 | 1 | null | 3 | admin | Hi, I'm admin
| 2 | 1 | 1 | 3 | admin | I wanna give u promo
| 3 | 1 | 2 | 18 | user | What's promo ?
I've tried if conditional with column value, but it doesn't work.
Conversation_message.php
public function sender(){
switch($this->sender_type){
case "user":
return $this->belongsTo(User::class, 'id_sender', 'id');
case "admin":
return $this->belongsTo(Admin::class, 'id_sender', 'id');
default:
return;
}
}
InboxController.php
public function message_detail_chat($groupId){
$data = [];
$data['messages'] = Conversation_message::with('replies')
->with('sender')
->with('recipients')
->where(['id_group' => $groupId])->get();
}
I expect to use conditional model by column value 'sender_type' but the actual output is wrong.
laravel provide query scope your can read it from here https://laravel.com/docs/5.8/eloquent#local-scopes
function userSender(){
$this->belongsTo(User::class, 'id_sender', 'id');
}
function adminSender(){
return $this->belongsTo(Admin::class, 'id_sender', 'id');
}
public function scopeSender($query)
{
return $query
->when($this->sender_type === 'user',function($q){
return $q->with('userSender');
})
->when($this->sender_type === 'admin',function($q){
return $q->with('adminSender');
});
}
Now you can access your Sender like this
Conversation_message::Sender()->first();
This should give you the right Sender. Hope it helps.

Laravel 5 Eloquent relationship get the data

I have two table.
(Persons)
+------+------+
| id | name |
+------+------+
| 1 | John |
+------+------+
| 2 |Albert|
+------+------+
(Motors)
+------+------+------+
| id | name | age |
+------+------+------+
| 1 | 1 | 20 |
+------+------+------+
| 2 | 2 | 21 |
+------+------+------+
| 3 | 1 | 20 |
+------+------+------+
In "motors.name" i have the ids of people.
I have two models.
(Motors)
class Motors extends Eloquent
{
public function person(){
return $this->hasMany('App\Persons', 'id');
}
}
(Persons)
class Persons extends Eloquent
{
protected $table = 'persons';
public function motors(){
return $this->belongsTo('App\Motors', 'name', 'id');
}
}
1 controller
class PrototypeController extends Controller
{
public function names(Request $request) {
$res = Motors::get()->person->name;
return view('pages.prototype', compact('res'));
}
}
1 view
<ul class="list">
#foreach ($res as $row)
#if (!empty($row->name))
<li class="list-group-item">
{!! $row->name !!}
</li>
#endif
#endforeach
</ul>
I'd like tosee the rerelational dara in view, not the ids. How can it be solved?
This code isn't good:
$res = Motors::get()->person->name;
Thanks in advance for your help.
Let me try to answer this. You should try to follow conventions to make it easier to work with Laravel.
Your motors.name column should be called person_id. Your model for motors table should be called Motor.php (singular of motors). The same for persons table, Person.php.
In your Motor.php file, your relationship will be:
public function person(){
return $this->belongsTo('App\Person');
}
If you follow conventions, you don't need to add the second parameter to the relationship name. Note that I put App\Person, you should have App\Persons if you decide to maintain the file naming you are using.
In your Person.php file, your relationship will be:
public function motors(){
return $this->hasMany('App\Motor');
}
Your foreach will be:
#foreach ($res as $row)
#if (!empty($row->person))
<li class="list-group-item">
{!! $row->person->name !!}
</li>
#endif
#endforeach
Note how I check:
#if (!empty($row->person))
and not:
#if (!empty($row->person->name))
It has to be done like this, because if $row->person is null, it will throw an error when you do $row->person->name

Variable not defined in view in laravel 4

I've just started to learn laravel. These are the steps i'm following:.
Created a route in routes.php
Created two files in view folder and connected them using yield() and extends().
Created a model in models folder
I'm trying to fetch data from a table named as registrations but it's saying variable not defined
(ErrorException:
Undefined variable: userdata (View: /var/www/laravel/app/views/registrations.blade.php)
)
this is the description of table:
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| email | varchar(255) | NO | UNI | NULL | |
+-------+------------------+------+-----+---------+----------------+
This is the routes.php file
<?php
Route::get('registrations', function(){
$userdata = registration::all();
return View::make('registrations')->with('registrations', $userdata);
});
this is registrations.blade.php located in views folder
#extends('layout')
#section('content')
#foreach($userdata as $data)
<p>{{ $data->name }}</p>
#endforeach
#stop
this is layout.blade.php located in views folder
<!DOCTYPE HTML>
<html>
<head>
<title></title>
</head>
<body>
<h1>layout</h1>
#yield('content')
</body>
</html>
this is the registration.php file located in models folder
<?php
class registration extends Eloquent {};
?>
i'm unable to find the exact problem
In your controller you pass the $userdata collection received from your model as 'registrations', so your view will receive this collection as $registrations.
So from what I can see in your question, the following should work:
#extends('layout')
#section('content')
#foreach($registrations as $data)
<p>{{ $data->name }}</p>
#endforeach
#stop

Adding methods to resource routes

I'm trying to add methods to my resource routes that have a parameter. If I create one without a parameter it works find, but when I try to add a parameter it doesn't work.
Here's the code
Route::get('temp_user/activate/{id}', 'TempUserController#activate');
Route::resource('temp_user','TempUserController', array('only' => array('index','create','store')));
The above code doesn't work, but I need to pass a parameter to my method. Please help.
Works fine here. To not create a new controller I just used and old one:
<?php
class StoreController extends Controller {
public function activate($id)
{
return 'activate '.$id;
}
public function index()
{
return 'index';
}
public function create()
{
return 'create';
}
}
Using routes:
Route::get('temp_user/activate/{id}', 'StoreController#activate');
Route::resource('temp_user','StoreController', array('only' => array('index','create','store')));
After executing
php artisan routes
I get
| | GET /temp_user/activate/{id} | | StoreController#activate | | |
| | GET /temp_user | temp_user.index | StoreController#index | | |
| | GET /temp_user/create | temp_user.create | StoreController#create | | |
| | POST /temp_user | temp_user.store | StoreController#store | | |
And browsing:
http://172.17.0.2/temp_user/create
http://172.17.0.2/temp_user/activate/1
http://172.17.0.2/temp_user
Everything works fine.

Resources