I have three tables in mysql database like this picture below :
Now, with gii, I create those model like this :
For table BuktiPenerimaan
class BuktiPenerimaan extends \yii\db\ActiveRecord{
/**
* #return \yii\db\ActiveQuery
*/
public function getInvoiceReports()
{
return $this->hasMany(InvoiceReport::className(), ['bukti_penerimaan_id' => 'id']);
}
}
And InvoiceReports:
class InvoiceReport extends \yii\db\ActiveRecord{
/**
* #return \yii\db\ActiveQuery
*/
public function getInvoiceReportDetails()
{
return $this->hasMany(InvoiceReportDetail::className(), ['invoice_id' => 'id']);
}
My question is, how to access all record in table invoice_report_detail if I created an object that came from BuktiPenerimaan.
I use like this :
$model = $this->findModel($id); // model Bukti Penerimaan.
$dataInvoice = $model->invoiceReports; //exist
$dataInvoiceDetail = $model->invoiceReports->invoiceReportDetails // failed, always null.
Please advixe
$dataInvoice = $model->invoiceReports; is Array of InvoiceReport object.
You need to loop over each InvoiceReport to get related InvoiceReportDetail.
$model = $this->findModel($id); // model Bukti Penerimaan.
$dataInvoice = $model->invoiceReports; //exist , but array of objects
$dataInvoiceDetail = [];
foreach($dataInvoice as $dInvoice):
$dataInvoiceDetail[] = array_merge($dataInvoiceDetail,$dInvoice->invoiceReportDetails );
endforeach;
// $dataInvoiceDetail contains all invoice_report_detail
Related
Hi I am developing an api in laravel for an online course system. In this scheme I have a standard table for users, a table for courses and a pivot table that relates courses and users according to which they sign up for each course.
This last table also carries the events related to the progress of each user in the course, that is, Subscribed, Progress x%, Completed, Approved, so that each user can have multiple entries in the course_users table.
So far everything is clear and everything is fine, the point is that at a certain moment I need to return a json object with the information of the courses and pointed users, this can be clearly achieved using resource collection in the following way:
CourseCollection.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
use App\Http\Resources\CargoResource;
class CourseCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'data' => CourseResource::collection($this->collection),
'links' => [
'self' => 'link-value',
],
];
}
}
CourseResource.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class CourseResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'title'=> $this->title,
'description'=> $this->description,
'price'=> $this->price,
'users' => CourseUserResource::collection($this->whenLoaded('users'))
];
}
}
CourseUserResource.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class CourseUserResource extends JsonResource
{
public function toArray($request)
{
return [
'course_id'=> $this-> course_id,
'user_id'=> $this->user_id,
'event'=> $this->event,
'event_date' => $this->created_at->format('Y-m-d')
];
}
}
The problem to be solved is that with this scheme I obtain a collection of events for each user and course, but what I am needing is only the last event of each user, to know what their status is in relation to the course.
I am analyzing the option to perform the query by sql and then manually build the json object, but I would like to have a "laravel style" solution
Any ideas will be welcome!
Added Models & Controllers for clarification
class Course extends Model
{
protected $fillable = [
'title',
'slug',
'description',
'course_category_id',
'price',
'published'
];
...
public function history()
{
return $this->belongsToMany(CourseUser::class, 'course_id', 'id')->latest();
}
public function scopePublished($query)
{
return $query->where('published', 1);
}
}
class CourseUser extends Model
{
protected $fillable = [
'course_id',
'user_id',
'event'
];
}
class SearchController extends ApiController
{
public function search(Request $request)
{
$results = Course::with('history')
->published
->where('title', 'like', $request->filter['title'])
->where('description', 'like', $request->filter['description'])
->get();
if (! count($results) > 0) {
return $this->sendResponse(
__('No results for your query.'),
[
'code'=>204,
'message'=> __('There are no results for your search criteria.')
],
204
);
}
return new CourseCollection($results);
}
}
I need how to show data in another table like MySQL join or something like that
MySQL example
My Code
Model usuarios
class Usuario extends Model {
protected $table = 'usuarios';
protected $primaryKey = 'idusuarios';
protected $filliable = [
'cedula', 'nombre', 'tele1', 'tele2', 'correo', 'direccion',
'user_name', 'user_pass', 'fecha_ingreso', 'usu_idrol'
];
public function Usuario() {
return $this->hasOne('app\Roles','idrole','usu_idrol','desc_rol');
}
const CREATED_AT = NULL;
const UPDATED_AT = NULL;
}
Model Roles
class Roles extends Model {
protected $table ='roles';
protected $primarykey = 'idrole';
protected $filliable = ['desc_rol'];
public function Roles() {
return $this->belongsTo('app\Usuario', 'usu_idrol', 'idrole');
}
}
Controller usuarios
public function index(Request $request) {
if (!$request->ajax()) return redirect('/');
$usuarios = Usuario::all();
return $usuarios;
}
View usuarios
that's what I need
Try this in the controller that is returning data to your vue instance
//get all the users from the database (in your controller)
//you need to create a new array so as to easily map the role in the returned results
return Usuario::with('Usuario')->get()->map(function($role) {
return [
'field1' => $role->field1,
'field2' => $role->field2,
'field3' => $role->field3,
'field4' => $role->field4,
'field5' => $role->field5,
'rol' => $role->Usuario->desc_role
];
});
i have created an auto complete search box in controller of 'booking' table successfully , but i want the auto complete search box to show data from another table 'patient' that have a one to many relationship with "booking" table according to a specific condition using 'where' condition ,
This is the Booking Controller that i add autocomplete in it:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Booking;
use App\Patient;
use App\User;
use Session;
use DB;
use Auth;
use Input;
class BookingController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$search = \Request::get('search');
$bookings = Booking::whereHas('patient', function ($query) use ($search) {
$query->where('patient_name', 'like', '%' . $search . '%');
})->where('status','=', null)->whereHas('patient', function ($query){
$query->where('company_id','=' ,Auth::user()->company_id);
})->paginate(10);
return view('booking.index')->withBookings($bookings);
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function autoComplete(Request $request) {
$query = $request->get('term','');
$bookings=Booking::whereHas('patient', function ($query){
$query->where('company_id','=' ,Auth::user()->company_id);
})->$data=array();
foreach ($bookings as $booking) {
$data[]=array('value'=>$booking->patient->patient_name,'id'=>$booking->id);
}
if(count($data))
return $data;
else
return ['value'=>'No Result Found','id'=>''];
}
and this is the Booking Model :
class Booking extends Eloquent
{
public function patient()
{
return $this->belongsTo('App\Patient');
}
public function user()
{
return $this->belongsTo('App\User');
}
}
and this is the patient Model:
class Patient extends Eloquent
{
public function booking()
{
return $this->hasMany('App\Booking');
}
public function user()
{
return $this->belongsTo('App\User');
}
}
and i used this code in view :
{!! Form::text('search_text', null, array('placeholder' => 'Search Text','class' => 'form-control','id'=>'search_text')) !!}
i want to show data from "patient" table and there is a one to many relationship between "booking" and "patient" table and i have successfully made a search box to search in patient table as you can see in index function , but i dont know to show data from "patient" table using where condition to show patient_name that his company_id equal Authenticated user company_id
Sorry for my Bad Language .
I have two tables that are related directly in a one-to-one relationship. One is the standard Yii2 user table (abbreviated field list here for clarity) and the other is the employee table that contains user_id. How can I create a globally accessible variable (and the actual code to access the employee id) that I can use anywhere in my application that will give me the logged in user's employee id and how would I call that variable? I wish I could say that I've tried a few things, but unfortunately I am relatively new to Yii2 and have no idea where to start with global variables like this. Thanks for any help.
user table:
id
username
password
etc
employee table:
id
user_id (related in a one-to-one relationship to the user table)
The Employee Model:
<?php
namespace frontend\models\base;
use Yii;
/**
* This is the base model class for table "employee".
*
* #property integer $id
* #property integer $user_id
*
* #property \common\models\User $user
*/
class Employee extends \yii\db\ActiveRecord
{
public function rules()
{
return [
[['user_id', 'required'],
[['user_id'], 'integer'],
[['user_id'], 'unique']
];
}
public static function tableName()
{
return 'employee';
}
public function attributeLabels()
{
return [
'id' => Yii::t('app', 'ID'),
'user_id' => Yii::t('app', 'User ID'),
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getUser()
{
return $this->hasOne(\common\models\User::className(), ['id' => 'user_id']);
}
}
A very simple way is the use of $param array
You can initially config the default value in
your_App\config\param.php
and accessing using
\Yii::$app->params['your_param_key']
Looking to your Employee model (for me ) you don't need a global var you could simply use the getUser
$myUser = Employee::user();
but you need the param you can assign using
\Yii::$app->params['my_user'] = Employee::user();
or in user
\Yii::$app->params['my_user'] = Yii::$app->user->id
or for retrive the model related to actual user from table
$myEmpModel = Employee::find()->where['user_id' => Yii::$app->user->id]->one();
I believe proper way is to use relations in your User model. First method is proper relation with activerecord, second one will get id using relation defined above it. so You will add these methods in your User model:
/**
* #return \yii\db\ActiveQuery
*/
public function getEmployee()
{
return $this->hasOne(Employee::className(), ['user_id' => 'id']);
}
public function getEmployeeId()
{
return $this->employee ? $this->employee->id : NULL; // set to NULL or anything you expect to be if record is not found
}
Then you can call it like this from everywhere in your app:
$employee_id = Yii::$app->user->identity->employeeid;
This will only work for User model because it implements Identity, otherwise you would need to instantiate model class first, lets say like this:
$user_id = 5; // 5 is id of user record in DB
$user = User::findOne($user_id);
$employee_id = $user->employeeid;
// or using first of 2 relations ...
$employee_id = $user->employee->id;
I have an entity called User which has inheritance for Student, Professional and Business.
When a user is registered, is only a User but they must update their profile and choose which kind of user is, I have a form which handles this, a controller which gets the form data, but I can't update the discriminator field type with $userEntity->setType()
This is my mapping stuff
class User
{
const TYPE_BASIC = "Basico";
const TYPE_STUDENT = "Estudiante";
const TYPE_PROFESSIONAL = "Profesional";
const TYPE_BUSINESS = "Empresa";
protected $type = self::TYPE_BASIC;
public function getType()
{
return self::TYPE_BASIC;
}
public function setType($type)
{
$this->type = $type;
}
class Student extends User
{
protected $type = self::TYPE_STUDENT;
And then Professional and Business just like Student (changing const)
<entity name="User" table="user_base" inheritance-type="JOINED">
<discriminator-column name="type" type="string"/>
<discriminator-map>
<discriminator-mapping value="Basico" class="User"/>
<discriminator-mapping value="Estudiante" class="Student"/>
<discriminator-mapping value="Profesional" class="Professional"/>
<discriminator-mapping value="Empresa" class="Business"/>
</discriminator-map>
the child tables are named user_xxx where xxx = Student/Professional/Business
And this is my controller
if($form->isValid())
{
$em = $this->getDoctrine()->getManager();
$data = $form->all();
$type = $data['type']->getData();
$email = $data['email']->getData();
$profile = $data['profile']->all();
$name = $profile['name']->getData();
$lastName = $profile['lastName']->getData();
$birth = $profile['birth']->getData();
$profileEntity = new Profile();
$profileEntity->setBirth($birth);
$profileEntity->setName($name);
$profileEntity->setLastName($lastName);
$profileEntity->setUser($user);
$em->persist($profileEntity);
ladybug_dump($type);
$userEntity = $em->getRepository('User')->find($user);
$userEntity->setProfile($profileEntity);
$userEntity->setType($type);
if($user->getEmail() != $email)
$userEntity->setEmail($email);
$em->persist($userEntity);
$em->flush();
}
Everything is persisted but type field, which remains it's original data. I know when I change discriminator column I need to create a new row inside it's child element, but first I want to know how to change the discriminator column.
it is possible if you use this custom bit of code in the Form of a Trait which you can use inside a Repository.
The Trait:
namespace App\Doctrine\Repository;
use App\Exception\InvalidDiscriminatorClassException;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\ClassMetadata;
/**
* Discriminator Trait
*/
trait DiscriminatorTrait
{
/**
* #return ClassMetadata
*/
abstract public function getClassMetadata();
/**
* #return EntityManager
*/
abstract public function getEntityManager();
/**
* Update Discriminator Column
*
* #param integer $id
* #param string $class
* #return boolean
* #throws InvalidDiscriminatorClassException
*/
private function updateDiscriminatorColumn($id, $class)
{
/* #var ClassMetadata $classMetadata */
$classMetadata = $this->getClassMetadata();
if (!in_array($class, $classMetadata->discriminatorMap)) {
throw new InvalidDiscriminatorClassException($class);
}
$identifier = $classMetadata->fieldMappings[$classMetadata->identifier[0]]["columnName"];
$column = $classMetadata->discriminatorColumn["fieldName"];
$value = array_search($class, $classMetadata->discriminatorMap);
/* #var Connection $connection */
$connection = $this->getEntityManager()->getConnection();
try {
$connection->update(
$classMetadata->table["name"],
[$column => $value],
[$identifier => $id]
);
}
catch (DBALException $e) {
return false;
}
return true;
}
}
According to the Doctrine documentation on Inheritance mapping, it is not possible to either get or set the type. You may wish take advantage of PUGXMultiUserBundle, which readily handles the mapping. This bundle also makes it possible for your users to register with the appropriate profile.