joinWith multiple tables yii 2 - php

Hi is possible to join multiple table based on a column in yii 2? Right now I am using the concept of joinWith
Take a look at my code:
ActiveCurriculum.php
This is where I am joining the tables
public static function Addblock($group, $clientid){
$subjects = ActiveCurriculum::find()
->select(['scstock.*', 'schead.*', 'glhead.*', 'glfees.*'])
->joinWith('schead')
->joinWith('glhead')
->joinWith('glfees')
->where([
'scstock.sectiongroup' => $group
])
->asArray()
->all();
}
And these are the relations that I set:
Scstock
<?php
namespace app\models;
use Yii;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
class Scstock extends ActiveRecord{
public static function tableName()
{
return '{{%scstock}}';
}
public function getSchead(){
return $this->hasOne(Schead::className(), ['TrNo' => 'TrNo']);
}
public function getGlhead(){
return $this->hasOne(Glhead::className(), ['TrNo' => 'TrNo']);
}
public function getGlfees(){
return $this->hasOne(Glfees::className(), ['TrNo' => 'TrNo']);
}
}?>
Schead
<?php
namespace app\models;
use Yii;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
class Schead extends ActiveRecord{
public static function tableName()
{
return '{{%schead}}';
}
public function getScstock(){
return $this->hasOne(ActiveCurriculum::className(), ['TrNo' => 'TrNo']);
}
public function getGlhead(){
return $this->hasOne(Glhead::className(), ['TrNo' => 'TrNo']);
}
public function getGlfees(){
return $this->hasOne(Glfees::className(), ['TrNo' => 'TrNo']);
}
}?>
Glhead
<?php
namespace app\models;
use Yii;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
class Glhead extends ActiveRecord{
public static function tableName()
{
return '{{%glhead}}';
}
public function getScstock(){
return $this->hasOne(ActiveCurriculum::className(), ['TrNo' => 'TrNo']);
}
public function getSchead(){
return $this->hasOne(Schead::className(), ['TrNo' => 'TrNo']);
}
public function getGlfees(){
return $this->hasOne(Glfees::className(), ['TrNo' => 'TrNo']);
}
}?>
Glfees
<?php
namespace app\models;
use Yii;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
class Glfees extends ActiveRecord{
public static function tableName()
{
return '{{%glfees}}';
}
public function getGlhead(){
return $this->hasOne(Glhead::className(), ['TrNo' => 'TrNo']);
}
public function getSchead(){
return $this->hasOne(Schead::className(), ['TrNo' => 'TrNo']);
}
public function getScstock(){
return $this->hasOne(ActiveCurriculum::className(), ['TrNo' => 'TrNo']);
}
}?>
But I am getting this error when the query executes
Invalid Parameter – yii\base\InvalidParamException
app\models\ActiveCurriculum has no relation named "glhead".
↵
Caused by: Unknown Method – yii\base\UnknownMethodException
Calling unknown method: app\models\ActiveCurriculum::getglhead()
in C:\xampp\htdocs\enrollment\vendor\yiisoft\yii2\base\Component.php at line 285
Am I doing something wrong with the relations or is it something else? Help would be greatly appreaciated. Thank you.

All these relations:
->joinWith('schead')
->joinWith('glhead')
->joinWith('glfees')
must be declared in ActiveCurriculum class. Consult relations in Yii2 documentation.

Related

How to decode in laravel join

I have json resource collection like this
<?php
namespace App\Http\Resources;
use App\Models\Curriculum;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\DB;
class CurriculumDisplayResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'title_section' => json_decode($this->title_section),
'learning_objective'=> json_decode($this->learning_objective),
'content_detail' =>
DB::table('curriculums')
->join('content_texts','curriculums.id','=','content_texts.curriculum_id')
->join('content_files','curriculums.id','=','content_files.curriculum_id')
->join('content_videos','curriculums.id','=','content_videos.curriculum_id')
->join('quizzes','curriculums.id','=','quizzes.curriculum_id')
->select('content_texts.title_text','content_texts.text_course',
'content_files.title_file','content_files.file_course','content_videos.title_video',
'content_videos.video_course','quizzes.title_quiz','quizzes.question','quizzes.answer','quizzes.right_answer')
->get(),
'parent_id' => $this->id,
];
}
}
Can I json decode the result of join quiz?, I just want to json decode the quizzes result. when I'm try display this json resource the result like this
this is the controller
<?php
namespace App\Http\Controllers\Course;
use App\Http\Controllers\Controller;
use App\Http\Resources\CurriculumResource;
use App\Models\Curriculum;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class CurriculumController extends Controller
{
public function index()
{
return Curriculum::all();
}
public function store (Request $request)
{
$c = new Curriculum();
$c->title_section = json_encode($request->get('title_section'));
$c->learning_objective = json_encode($request->get('learning_objective'));
$c->user_id = Auth::id();
$c->course_id = $request->get('course_id');
$c->save();
return response(new CurriculumResource($c));
}
}
What's wrong with my code?, I've also made cast for title_quiz, question, answer and right_answer.
Hope this help your problem. It seems like you have double quotation mark
On your Model which has title_quiz, question, answer, and right_answer, add this line of code (depend on your Model):
Model.php
public function getTitleQuizAttribute($value){
return str_replace('\"','', $value);
}
public function getQuestionAttribute($value){
return str_replace('\"','', $value);
}
public function getRightAnswerAttribute($value){
return str_replace('\"','', $value);
}
public function title_quiz($value){
return str_replace('\"','', $value);
}
public function getAnswerAttribute($value){
return json_decode($value);
}
They will modify your string first then pass it to your response
Docs

How can I get a pivot on my relationship in Laravel?

I have a relationship in my app. A candidate can have several "candidate_trainings" and each "candidate_training" is associated with a training. I wanted to avoid making "candidate_trainings" the piviot since it's hard to delete the right values when detaching, etc. So, how can I, on my hasMany relationship get the CandidateTraining model with the data from the Training model.
Here are my relationships:
<?php
namespace App;
use App\Traits\SanitizeIds;
use App\Salary;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;
class Candidate extends Model
{
public function saveTraining($data) {
$this->candidateTrainings()->delete();
foreach(json_decode($data['training']) as $training) {
if(Training::find($training->training)->first()) {
$candidateTraining = new CandidateTraining;
$candidateTraining->description = $training->value;
$candidateTraining->training_id = $training->training;
$this->candidateTrainings()->save($candidateTraining);
}
}
}
public function candidateTrainings() {
return $this->hasMany('\App\CandidateTraining');
}
public function trainings() {
return $this->belongsToMany('\App\Training');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Training extends Model
{
protected $fillable = ['name_french', 'name_english'];
public function candidates() {
return $this->belongsToMany('\App\Candidate');
}
public function candidateTrainings() {
return $this->hasMany('\App\CandidateTraining');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class CandidateTraining extends Pivot
{
public function candidate() {
return $this->belongsTo('\App\Candidate');
}
public function training() {
return $this->belongsTo('\App\Training');
}
}
Thank you!
For you to be able to update the data directly on the CandidateTraining model, you need to add the $fillable fields to it.
protected $fillable = ['training_id', 'description'];
Your code should work! But if you don't mind, I did a little refactoring. You can accomplish this in another way:
<?php
namespace App;
use App\Traits\SanitizeIds;
use App\Salary;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;
class Candidate extends Model
{
public function saveTraining($data)
{
// remove all relationships
$this->trainings()->detach();
// add new ones
foreach(json_decode($data['training']) as $training)
{
if(Training::find($training->training)->first())
{
$this->trainings()->attach($training->training, [
'description' => $training->value,
]);
}
}
}
public function candidateTrainings()
{
return $this->hasMany(App\CandidateTraining::class);
}
public function trainings()
{
return $this->belongsToMany(App\Training::class)
->withTimestamps()
->using(App\CandidateTraining::class)
->withPivot([
'id',
'training_id',
'description',
]);
}
}
That $training->training stuff is not readable, change it to something like $training->id if you are able to.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Training extends Model
{
protected $fillable = ['name_french', 'name_english'];
public function candidates()
{
return $this->belongsToMany(App\Candidate::class)
->withTimestamps()
->using(App\CandidateTraining::class)
->withPivot([
'id',
'training_id',
'description',
]);;
}
public function candidateTrainings()
{
return $this->hasMany(App\CandidateTraining::class);
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class CandidateTraining extends Pivot
{
protected $fillable = ['training_id', 'description'];
public function candidate()
{
return $this->belongsTo(App\Candidate::class);
}
public function training()
{
return $this->belongsTo(App\Training::class);
}
}
If you want to access the pivot object from a controller:
$candidates = Candidate::with(['trainings'])->get();
foreach ($candidates as $candidate)
{
dd($candidate->pivot);
}

Laravel Tables Join

I have three tables:
notes: id, business_id, note
businesses: id, title, description
businessimages : id, business_id, image
I get my customers notes with this:
$customer = Auth::guard('customer-api')->user();
$notes = Note::where('customer_id', $customer->id)->with('business:id')-
>orderBy('id', 'desc')->get();
Now I want to get notes.id, businesses.id, businesses.title, businesses.description, businessimages.image for each notes and show all of them in one json array
How could I do?
Note::where('customer_id',$customer->id)
->join('businesses', 'businesses.id', '=', 'notes.buisness_id')
->join('businessimages', 'businesses.id', '=', 'businessimages.buisness_id')
->select(notes.id, businesses.id, businesses.title, businesses.description,businessimages.image)
->get();
Note model;
public function business() {
return $this->hasOne('App\Business', 'business_id', 'id');
}
Business mode;
public function businessImage()
{
return $this->hasOne('App\BusinessImage', 'business_id', 'id');
}
Your controller;
$notes = Note::where('customer_id', $customer->id)->with('business.businessImage')->orderBy('id', 'desc')->get();
You should consider using API Resources
This is a great way to organize a model(or a collection of models as well).
App\Note
use Illuminate\Database\Eloquent\Model;
class Note extends Model
{
public function business()
{
return $this->belongsTo('App\Business');
}
}
App\Business
namespace App;
use Illuminate\Database\Eloquent\Model;
class Business extends Model
{
public function note()
{
return $this->hasOne('App\Note');
}
public function businessImage()
{
return $this->hasOne('App\BusinessImage');
}
}
App\BusinessImage
namespace App;
use Illuminate\Database\Eloquent\Model;
class BusinessImage extends Model
{
protected $table = 'businessimages';
public function business()
{
return $this->belongsTo('App\Business');
}
}
App\Http\Resources\Note
namespace App\Http\Resources;
class Note
{
public function toArray($request)
{
return [
'noteId' => $this->resource->id,
'businessId' => $this->resource->business->id,
'businessTitle' => $this->resource->business->title,
'businessDescription' => $this->resource->business->description,
'businessImage' => $this->resource->business->businessImage->image
];
}
}
Somewhere in a controller
use App\Http\Resources\Note as NoteResource;
public function foo()
{
$customer = Auth::guard('customer-api')->user();
$notes = Note::where('customer_id', $customer->id)->with(['business','business.businessImage'])->orderBy('id', 'desc')->get();
return NoteResource::collection($notes);
}

laravel 5.7 data not passed to the view

I'm trying to pass my article data to the single page article named article.blade.php although all the data are recorded into the database but when I tried to return them in my view, nothing showed and the [ ] was empty. Nothing returned.
this is my articleController.php
<?php
namespace App\Http\Controllers;
use App\Article;
use Illuminate\Http\Request;
class ArticleController extends Controller
{
public function single(Article $article)
{
return $article;
}
}
this is my model:
<?php
namespace App;
use Cviebrock\EloquentSluggable\Sluggable;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
use Sluggable;
protected $guarded = [];
protected $casts = [
'images' => 'array'
];
public function sluggable()
{
return [
'slug' => [
'source' => 'title'
]
];
}
public function path()
{
return "/articles/$this->slug";
}
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
}
and this is my Route
Route::get('/articles/{articleSlug}' , 'ArticleController#single');
Change your code to
class ArticleController extends Controller
{
public function single(Article $article)
{
return view('article', compact('article'));
}
}
change route to
Route::get('/articles/{article}' , 'ArticleController#single');
And model
public function getRouteKeyName()
{
return 'slug';
}
See docs https://laravel.com/docs/5.7/routing#route-model-binding
You might not be getting any data because you have not specified that you're using title_slug as the route key for model binding in your model.
Add this to your model class and it should give you the data
public function getRouteKeyName()
{
return 'slug';
}
Then you can return the data in json, view or other format.
Depending on what you try to archive, you need to either ...
return $article->toJson(); // or ->toArray();
.. for json response or ..
return view(..., ['article' => $article])
for passing a the article to a certain view

How can you include column headers when exporting Eloquent to Excel in Laravel?

I am trying to allow users to download Excel, using Laravel Excel files with product information. My current web route looks like this:
Route::get('/excel/release', 'ExcelController#create')->name('Create Excel');
My current Export looks like this:
class ProductExport implements FromQuery
{
use Exportable;
public function __construct(int $id)
{
$this->id = $id;
}
public function query()
{
return ProductList::query()->where('id', $this->id);
}
}
My current controller looks like this:
public function create(Request $request) {
# Only alowed tables
$alias = [
'product_list' => ProductExport::class
];
# Ensure request has properties
if(!$request->has('alias') || !$request->has('id'))
return Redirect::back()->withErrors(['Please fill in the required fields.'])->withInput();
# Ensure they can use this
if(!in_array($request->alias, array_keys($alias)))
return Redirect::back()->withErrors(['Alias ' . $request->alias . ' is not supported'])->withInput();
# Download
return (new ProductExport((int) $request->id))->download('iezon_solutions_' . $request->alias . '_' . $request->id . '.xlsx');
}
When I head over to https://example.com/excel/release?alias=product_list&id=1 this executes correctly and returns an excel file. However, there is no column headers for the rows. The data comes out like so:
1 150 1 3 2019-01-16 16:37:25 2019-01-16 16:37:25 10
However, this should contain column headers like ID, cost etc... How can I include the column headers in this output?
According to documentation you can change your class to use the WithHeadings interface, and then define the headings function to return an array of column headers:
<?php
namespace App;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
class ProductExport implements FromQuery, WithHeadings
{
use Exportable;
public function __construct(int $id)
{
$this->id = $id;
}
public function query()
{
return ProductList::query()->where('id', $this->id);
}
public function headings(): array
{
return ["your", "headings", "here"];
}
}
This works with all export types (FromQuery, FromCollection, etc.)
<?php
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use DB;
class LocationTypeExport implements FromCollection,WithHeadings
{
public function collection()
{
$type = DB::table('location_type')->select('id','name')->get();
return $type ;
}
public function headings(): array
{
return [
'id',
'name',
];
}
}
You can combine this with array_keys to dynamically get your column headers:
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
class ProductExport implements FromQuery, WithHeadings
{
use Exportable;
public function __construct(int $id)
{
$this->id = $id;
}
public function query()
{
return ProductList::query()->where('id', $this->id);
}
public function headings(): array
{
return array_keys($this->query()->first()->toArray());
}
}
If you're using it with a collection, you can do so like the following:
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
class ProductExport implements FromCollection, WithHeadings
{
/**
* #return \Illuminate\Support\Collection
*/
public function collection()
{
// for selecting specific fields
//return ProductList::select('id', 'product_name', 'product_price')->get();
// for selecting all fields
return ProductList::all();
}
public function headings(): array
{
return $this->collection()->first()->keys()->toArray();
}
}
<?php
namespace App\Exports;
use App\Models\UserDetails;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
class CustomerExport implements FromCollection, WithHeadings
{
public function collection()
{
return UserDetails::whereNull('business_name')
->select('first_name','last_name','mobile_number','dob','gender')
->get();
}
public function headings() :array
{
return ["First Name", "Last Name", "Mobile","DOB", "Gender"];
}
}
<?php
namespace App\Exports;
use App\Models\StudentRegister;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
class StudentExport implements FromCollection, WithHeadings
{
/**
* #return \Illuminate\Support\Collection
*/
public function collection()
{
return StudentRegister::select('name','fname','mname','gender','language','address')->get();
}
public function headings(): array
{
//Put Here Header Name That you want in your excel sheet
return [
'Name',
'Father Name',
'Mother Name',
'Gender',
'Opted Language',
'Corresponding Address'
];
}
}
I am exporting from Collections and I wanted to generate headings automatically from the column names. The following code worked for me!
public function headings(): array
{
return array_keys($this->collection()->first()->toArray());
}
If you want to manually write the column names return an array with the column names.
And don't forget to impliment WithHeadings Interface
Thanks #Ric's comment.
This code works for me
use App\Newsletter;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
class NewsletterExport implements FromCollection, WithHeadings
{
public function headings(): array
{
return [
'Subscriber Id',
'Name',
'Email',
'Created_at',
];
}
public function collection()
{
return Newsletter::where('isSubscribed', true)->get(['id','name','email','created_at']);
}
}

Categories