I have these three tables as shown below
courses and instructors tables are linked together in course_instructors
Model: Course
public function attributeLabels()
{
return [
'id' => Yii::t('course', 'Course ID'),
'course_name' => Yii::t('course', 'Course Name'),
'course_code' => Yii::t('course', 'Course Code'),
];
}
public function getCourseInstructors()
{
return $this->hasMany(CourseInstructors::className(), ['course_id' => 'id']);
}
and also
Model:Instructor
public function attributeLabels()
{
return [
'instructor_id' => Yii::t('ins', 'Instructor ID'),
'first_name' => Yii::t('ins', 'First Name'),
'middle_name' => Yii::t('ins', 'Middle Name'),
'last_name' => Yii::t('ins', 'Last Name'),
];
}
function getInstructorFullName()
{
return ($this->first_name." ".$this->middle_name." ".$this->last_name);
}
Then,
Model: CourseInstructors
public function attributeLabels()
{
return [
'id' => 'Course Instructor ID',
'course_id' => 'Course',
'instructor_id' => 'Course Instructor',
'remark' => 'Remark',
];
}
public function getCourses()
{
return $this->hasOne(Courses::className(), ['id' => 'course_id']);
}
public function getInstructors()
{
return $this->hasOne(Instructors::className(), ['instructor_id' => 'instructor_id']);
}
CourseControllers
public function actionView($id)
{
$model = $this->findModel($id);
$courseinstructors = $model->courseInstructors;
return $this->render('view', [
'model' => $model,
'courseinstructors' => $courseinstructors,
]);
}
Detail View: course
<?= DetailView::widget([
'model' => $model,
'options'=>['class'=>'table detail-view'],
'attributes' => [
'course_name',
'course_code',
],
]) ?>
<h2>Details</h2>
<table class="receipt-details table">
<tr>
<th>ID</th>
<th>Instructor Name</th>
<th>Remark</th>
</tr>
<?php foreach($model->courseInstructors as $courseInstructor) :?>
<tr>
<td><?= $courseInstructor->id ?></td>
<td><?= $courseInstructor->instructor_id ?></td>
<td><?= $courseInstructor->remark ?></td>
</tr>
<?php endforeach; ?>
</table>
From my Course Detail view, I want to display the instructor fullname
function getInstructorFullName()
{
return ($this->first_name." ".$this->middle_name." ".$this->last_name);
}
instead of the instructor_id in the Course Detail View
<td><?= $courseInstructor->instructor_id ?></td
This is what am getting
The question is how do I display the instructor full name in the course detail view instead of the instructor_id, since it is many to many.
You should use the framework power and consume the relations for the ActiveRecord models. Change your line from
<td><?= $courseInstructor->instructor_id ?></td>
to the following
<td><?= $courseInstructor->instructors->first_name.' '.$courseInstructor->instructors->last_name ?></td>
a better way would be to add the following method inside the model Instructors
public function getFullName(){
return $this->first_name.' '.$this->middle_name.' '.$this->last_name;
}
and then use it like
<td><?= $courseInstructor->instructors->fullName ?></td>
This should work in the Detail View:
<td><?= $courseInstructor->instructors->first_name ?></td> for first name.
<td><?= $courseInstructor->instructors->last_name ?></td> for last name.
You can join the name string to make a full name.
This comes from
public function getInstructors()
{
return $this->hasOne(Instructors::className(), ['instructor_id' => 'instructor_id']);
}
Let me know if it works for you.
Related
I have a voting form and I would like to validate the minimum and maximum number of candidates that each voter can vote for. These max and min values are stored in the logged user's session. What better way to do it?
MODEL Voto.php
public static function tableName()
{
return 'voto';
}
public function rules()
{
return [
[['eleicao_id', 'candidato_id', 'cargo_id', 'urna_id', 'created'], 'required','message'=> 'Selecione no mÃnimo 1 candidato!'],
[['eleicao_id', 'cargo_id', 'urna_id'], 'integer'],
[['created','candidato_id'], 'safe'],
[['eleitor_hash'], 'string', 'max' => 255],
];
}
FORM _form_votacao.php
<?php $form = ActiveForm::begin(); ?>
<div class="row">
<?php
$candidato = ArrayHelper::map(candidato::find()
->where(['status' => 1])
->Andwhere(['eleicao_id' => Yii::$app->user->identity->eleicao_id])
->orderBy("nome ASC")
->all(), 'id', 'nome'
);
echo $form->field($model, 'candidato_id')->checkboxList($candidato, [
'class' => 'h4',
'data-toggle' => 'button',
'item' => function($index, $label, $name, $checked, $value) {
return "<label class='col-md-5'><input type='checkbox' {$checked} name='{$name}' value='{$value}'> {$label}</label>";
}])->label(false);
?>
</div>
<br>
<div class="row text-center">
<div class="form-group">
<?= Html::submitButton('Confirmar', ['class' => 'btn btn-success']) ?>
</div>
</div>
<?php ActiveForm::end(); ?>
Note: This list of candidates is dynamic, loads the candidates according to the parameters of the user logged in.
Rules Test UPDATE:
public function rules()
{
return [
['candidato_id', 'validateCandidates','message'=> 'teste'],
];
}
public function validateCandidates($attribute, $params, $validator){
if(count($this->candidato_id) >= 4){ // test with value 4
$this->addError($attribute, 'Error message');
}
}
Create custom validation. Something like this:
Model Voto.php
public function rules()
{
return [
....
['candidato_id', 'validateCandidates'],
....
];
}
public function validateCandidates($attribute, $params, $validator){
if(count($this->candidato_id) < {session_min} and count($this->candidato_id) > {session_max}){
$this->addError($attribute, 'Error message');
}
}
I have a form with a CheckboxList generated through a model "Candidates" and I need to make a vote where the voter can select multiple candidates and record.
How do I 'pick up' the selected candidates and write to the votes table / model ??
Form "votos"
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'candidato_id')->checkboxList(ArrayHelper::map(Candidatos::find()->where(['status' => 1])->orderBy("nome ASC")->all(), 'id', 'nome')); ?>
<?= Html::activeHiddenInput($model, 'eleicao_id', ['value' => 1]) ?>
<?= Html::activeHiddenInput($model, 'cargo_id', ['value' => 1]) ?>
<?= Html::activeHiddenInput($model, 'urna_id', ['value' => 1]) ?>
<div class="form-group">
<?= Html::submitButton('Save', ['class' => 'btn btn-success']) ?>
</div>
<?php ActiveForm::end(); ?>
Model "Votos"
namespace app\models;
use Yii;
class Votos extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'votos';
}
public function rules()
{
return [
[['eleicao_id', 'candidato_id', 'cargo_id', 'urna_id', 'data'], 'required'],
[['eleicao_id', 'candidato_id', 'cargo_id', 'urna_id'], 'integer'],
[['data'], 'safe'],
];
}
public function attributeLabels()
{
return [
'id' => 'ID',
'eleicao_id' => 'Eleicao ID',
'candidato_id' => 'Candidato ID',
'cargo_id' => 'Cargo ID',
'urna_id' => 'Urna ID',
'data' => 'Data',
];
}
}
Controller "VotosControllers"
public function actionVotacao()
{
$model = new Votos();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
}
return $this->render('votacao', [
'model' => $model,
]);
}
Slightly unrelated, but if you haven't already I would strongly suggest making sure you have something like xdebug set up so you can quickly see what your code is doing as you make your changes. Being able to set breakpoints and see what your form has submitted can go a long way to helping you solve a problem like this on your own and the framework becomes less mysterious. With that out of the way, something like the following MIGHT help as far as the controller goes. There is other validation you would want to do as well I should add. Maybe the each validator which you can read up on here. For actionUpdate() you would need to look at deleting all the values that relate to the related id and re-populate with the new ones, checkout deleteAll. Hopefully I don't get smashed too hard for providing this solution which is not a drop in solution.
public function actionVotacao()
{
$model = new Votos();
if (Yii::$app->request->isPost) {
$model->load(Yii::$app->request->post());
if ($model->save()) {
// Save the checkbox values.
if (!empty(Yii::$app->request->post()['Votos']['XXXX'])) { // Your form should give you an idea of what the XXXX should be, xdebug is also your friend.
foreach (Yii::$app->request->post()['Votos']['XXXX'] as $candidato_id) {
$candidato = new Candidato();
$candidato->id = $candidato_id;
if (!$candidato->save()) print_r($candidato->errors);
}
}
}
return $this->redirect(['view', 'id' => $model->id]);
}
return $this->render('create', [
'model' => $model,
]);
}
I am working on my collage project in which admin can create Employees(Teachers) and teachers can create students now my problem is that in index and view file any employee can see the total list of students recently added.
i want to put condition on view/index file so that specific teacher can view list of students created by him or her.
i have link between user table and Employee table (Created by & updated by)
Regards,
Yuvraj Verma
<section class="content doc-user-profile">
<div class="col-md-12 text-center">
</div>
</div>
<table class="table table-striped">
<tr>
<th><?= $info->getAttributeLabel('stu_unique_id') ?></th>
<td><?= Html::encode($info->stu_unique_id) ?></td>
</tr>
<tr>
<th><?php echo Yii::t('stu', 'Name'); ?></th>
<td><?= Html::encode($this->title) ?></td>
</tr>
<tr>
<th><?= $info->getAttributeLabel('stu_email_id') ?></th>
<td><?= Html::encode($info->stu_email_id) ?></td>
</tr>
<tr>
<th><?= $info->getAttributeLabel('stu_mobile_no') ?></th>
<td><?= $info->stu_mobile_no ?></td>
</tr>
<tr>
<th><?php echo Yii::t('stu', 'Status'); ?></th>
<td>
<?php if($model->is_status==0) : ?>
<span class="label label-success"><?php echo Yii::t('stu', 'Active'); ?></span>
<?php else : ?>
<span class="label label-danger"><?php echo Yii::t('stu', 'InActive'); ?></span>
<?php endif; ?>
</td>
</tr>
</table>
</div>
<div class="col-lg-9 profile-data">
<ul class="nav nav-tabs responsive" id = "profileTab">
<li class="active" id = "personal-tab"><i class="fa fa-street-view"></i> <?php echo Yii::t('stu', 'Personal'); ?></li>
</ul>
<div id='content' class="tab-content responsive">
<div class="tab-pane active" id="personal">
<?= $this->render('_tab_stu_personal', ['info' => $info, 'model' => $model]) ?>
</div>
</div>
</div>
</div> <!---End Row Div--->
Student Create Controller is as below:
public function actionCreate()
{
$model = new StuMaster();
$info = new StuInfo();
$user =new User();
$auth_assign = new AuthAssignment();
if (Yii::$app->request->isAjax) {
if($info->load(Yii::$app->request->post())) {
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return ActiveForm::validate($info);
}
if($model->load(Yii::$app->request->post())) {
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
}
$stud_uniq_no = \app\modules\student\models\StuInfo::find()->max('stu_unique_id');
$uniq_id = NULL;
if(empty($stud_uniq_no)) {
$uniq_id = $info->stu_unique_id = 1;
}
else {
$chk_id = StuInfo::find()->where(['stu_unique_id' => $stud_uniq_no])->exists();
if($chk_id)
$uniq_id = $stud_uniq_no + 1;
else
$uniq_id = $stud_uniq_no;
}
if ($model->load(Yii::$app->request->post()) && $info->load(Yii::$app->request->post()))
{
if (Yii::$app->request->isAjax) {
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return ActiveForm::validate($info);
}
if (Yii::$app->request->isAjax) {
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
$model->attributes = $_POST['StuMaster'];
$info->attributes = $_POST['StuInfo'];
$info->stu_dob = Yii::$app->dateformatter->getDateFormat($_POST['StuInfo']['stu_dob']);
if(empty($_POST['StuInfo']['stu_email_id']))
$info->stu_email_id = NULL;
else
$info->stu_email_id = strtolower($_POST['StuInfo']['stu_email_id']);
$login_id = \app\models\Organization::find()->one()->org_stu_prefix.$uniq_id;
$user->user_login_id = $login_id;
$user->user_password = md5($user->user_login_id.$user->user_login_id);
$user->user_type = "S";
$user->created_by = Yii::$app->getid->getId();
$user->created_at = new \yii\db\Expression('NOW()');
if($info->save(false))
{
$user->save(false);
}
$model->stu_master_stu_info_id = $info->stu_info_id;
$model->stu_master_user_id = $user->user_id;
$model->created_by = Yii::$app->getid->getId();
$model->created_at = new \yii\db\Expression('NOW()');
$model->save(false);
$s_info = StuInfo::findOne($model->stu_master_stu_info_id);
$s_info->stu_info_stu_master_id = $model->stu_master_id;
$s_info->save(false);
$auth_assign->item_name = 'Student';
$auth_assign->user_id = $user->user_id;
$auth_assign->created_at = date_format(date_create(),'U');
$auth_assign->save(false);
if ($model->save()) {
return $this->redirect(['view', 'id'=>$model->stu_master_id]);
}
else
return $this->render('create', ['model' => $model, 'info' => $info, 'uniq_id'=>$uniq_id]);
} else {
return $this->render('create', [
'model' => $model, 'info' => $info, 'uniq_id'=>$uniq_id
]);
}
}
In your "modelSearch"'s search function add a created_by filter:
public function search($params)
{
$query = StuInfo::find();
...
$query->andFilterWhere(['created_by' => Yii::$app->user->identity->id]);
....
}
For your view(actionView) you could check if the record was created by the logged in user before render.
This would get complex with time so i recommend using authorization - Yii2 Access Control and Authorization
Your create action is ok.
You have to put restriction in index/view action of your controller
Your index action should be like this
public function actionIndex()
{
$searchModel = new StudentSearch();
$query = Student::find()->where(['teacher_id'=>$logged_teacher_id_from_session]);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 20,
],
'sort' => [
'defaultOrder' => [
'student_id' => SORT_ASC,
]
],
]);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
In this case teacher who is logged in can see only his/ student
I have joined 2 table, now I want to show the name of categories in field <th>Categories name</th>. How can I do that with <?php foreach ($posts as $post){ ?> ? Do i render like <?=$post->categories.name?> ? I'm stuck here.
Thank you.
My controller:
public function actionIndex()
{
$query = posts::find()->leftJoin('categories', 'posts.cate_id = categories.id');
$cates = Categories::find()->all();
$posts= $query->orderBy(['create_date' => SORT_DESC])->all();
$images = Images::find()->all();
$searchModel = new PostsSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'posts' => $posts,
'dataProvider' => $dataProvider,
'searchModel' => $searchModel,
'cates' => $cates,
'images' => $images,
]);
}
My view:
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Create Date</th>
</thead>
<tbody>
<?php foreach ($posts as $post){ ?>
<tr>
<td><?= $post->id ?></td>
<th><?= Html::a($post->name, ['post/view', 'id'=>$post->id]) ?></th>
<td><?= $post->create_date ?></td>
</tr>
<?php } ?>
</tbody>
Loop through the categories just as with posts. Its the same principle.
foreach($posts as $post)
foreach($post->categories as $category)
echo $category->name;
This is based on the assumption you have defined the proper relations in the model.
I.e. through foreign key:
public function getCategories()
{
return $this->hasMany(Category::className(), ['post_id' => 'id']);
}
You seem to have it the other way around. You can have category_id in post, but then its limited to one category. Unless, you store the ids in the field seperated by a delimeter. But that option requires a bit more work.
Hey at the moment we have an arrray selecting all from one table (relationship) and we need to put account_name from the Accounts table in that array. How would we do so?
Our Relationship table has (id, receiver_id, sender_id, active, expiry_date). Receiver_id and sender_id both are the foreign keys for account_id.
At the moment it works fine but prints the ids of the receiver and sender, we want the account_name from Account table to be there instead.
Here is our function, view and model:
Function:
//retrieve Account Id of current User
$accountid=$this->Auth->user('account_id');
//Conditions
$conditions=array("OR"=> array(
'Relationship.sender_id' => $accountid,
'Relationship.receiver_id' => $accountid));
//Find all Invoices where receiver_id = accountid
$relationships=$this->Relationship->find('all', array(
'conditions' => $conditions));
debug($relationships);
$this->set('accountid', $accountid);
$this->set('relationship', $relationships);
}
View:
<table>
<tr>
<th>Relationship #</th>
<th>Sender</th>
<th>Receiver</th>
<th>Expiry Date</th>
<th>Status</th>
</tr>
<?php foreach($relationship as $relationships):?>
<?php
if($relationships['Relationship']['active']==1)
{
$status = 'Active';
}
else if($relationships['Relationship']['active']==0)
{
$status = 'Not Active';
}
?>
<tr>
<td align='center'><?php echo $relationships['Relationship']['id']; ?></td>
<td align='center'><?php echo $relationships['Relationship']['sender_id']; ?></td>
<td align='center'><?php echo $relationships['Relationship']['receiver_id']; ?></td>
<td align='center'><?php echo date('d.m.Y', strtotime($relationships['Relationship']['expiry_date'])); ?></td>
<td align='center'><?php echo $status ?></td>
</tr>
<?php endforeach; ?>
</table>
Relationship Model:
class Relationship extends AppModel
{
var $name = 'Relationship';
public $useTable = 'relationships';
public $primaryKey = 'id';
/*
public $hasMany = array(
'Invoice' =>
array(
'className' => 'Invoice',
'joinTable' => 'invoice',
'foreignKey' => 'invoice_id'));*/
//fix this code
public $belongsTo = array(
'User' =>array(
'className' => 'User',
'foreignKey' =>'receiver_id',
'associationForeignKey' => 'accounts_id',
));
var $validate = array(
'date' => array(
'rule' => array(
'datevalidation',
'systemDate'
),
'message' => 'Current Date and System Date is mismatched'
),
'receiver_id' => array(
'userExists' => array(
'rule' => array(
'userExists',
),
'message' => 'That username doesnt exist.'
),
),
);
function datevalidation($field = array(), $compare_field = null)
{
if ($field['date'] > $compare_field)
return TRUE;
else
return FALSE;
}
function accountExists($check)
{
$accountExists = $this->Account->find('count', array('conditions' => array('Account.id'=>$check)));
if ($accountExists == 1) {
return TRUE;
}
else
return FALSE;
}
}
Note it's not another field from another "controller" but rather another model.
There are a number of ways you could do this:
You could use joins on the find() method: http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#joining-tables
Or you could probably also use bindModel(), which I find particularly useful: http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#creating-and-destroying-associations-on-the-fly
Scour the cookbook! Although sometimes tedious, it really is extremely helpful. I had to hack around quite a bit before I got a decent understanding of how Cake works.