Better way for pagination - codeigniter

If I want to do the pagination, I have to fetch data twice, one for get total rows, one for get the rows with limit, for example
<?php
class Admins extends CI_Model
{
public function dataTotal()
{
$total = $this->db->get('admins')->num_rows();
return $total;
}
public function data()
{
return $this->db->limit(10, $this->start)->get('admins')->result();
}
}
Then assign total to pagination and assign the data to view, it's quite make sense, but if there are a lot of conditions, I need to do it twice, for example:
<?php
class Admins extends CI_Model
{
public function dataTotal()
{
$db = $this->db->from('admins')
->where('id >', 1)
->like('name', 'abc', 'both');
return $db->get()->num_rows();
}
public function data()
{
$data = $this->db->from('admins')
->where('id >', 1)
->like('name', 'abc', 'both')
->limit(10, $this->start);
return $data->get()->result();
}
}
More conditions means more duplicated code, any way to make condition filter as one?

You could make a function and use an SQL query as a parameter, that would be the most recommended option. If that's not an option you could do something like this:
public function data($option = "default")
{
if($option == 'default')
{
$data = $this->db->from('admins')
->where('id >', 1)
->like('name', 'abc', 'both')
}
else if($option == 'other')
{
$data = $this->db->from('admins')
->where('id >', 1)
->like('name', 'abc', 'both')
->limit(10, $this->start);
}
return $data->get()->result();
}
And then calling it:
data();
data("other");
That's the most efficient way I can come up with.

Related

How to skip row after headings laravel excel

I just want to make the row of datas will rendered after headings
This's the result that i want
this what i want
But i only get this result
this i get
I already using startRow and set to 7, but nothing change
I have 6 row of heading, so how to render/display the data after headings, and i already return another collection with another model, but the result is same there's nothing change, the data keep displayed from first row
<?php
namespace App\Exports;
Importing Models...
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithColumnWidths;
use Maatwebsite\Excel\Concerns\WithStyles;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use Maatwebsite\Excel\Concerns\RegistersEventListeners;
use Maatwebsite\Excel\Events\AfterSheet;
use Maatwebsite\Excel\Concerns\WithEvents;
class TahapSeleksiExport implements FromCollection, WithHeadings, WithColumnWidths, WithStyles, WithEvents
{
use RegistersEventListeners;
protected $id;
function __construct($id) {
$this->id = $id;
}
/**
* #return \Illuminate\Support\Collection
*/
public function collection()
{
$tahap = Tahap::where('id_tahap', $this->id)->first();
if ($tahap->status == '0') {
if ($tahap->tahap_ke == '1') {
return Pelamar::select('pelamar.id_pelamar', 'alm.nama', 'jur.akronim', 'ang.angkatan', 'pelamar.tanggal_kirim')
->where('lowongankerja_id', $tahap->lowongankerja_id)
->join('alumni_mendaftar_pelamar as almPel', 'almPel.pelamar_id', '=','pelamar.id_pelamar')
->join('alumni as alm', 'almPel.alumni_id', '=','alm.id_alumni')
->join('jurusan as jur', 'alm.jurusan_id', '=','jur.id_jurusan')
->join('angkatan as ang', 'alm.angkatan_id', '=','ang.id_angkatan')
->orderBy('pelamar.tanggal_kirim')
->orderBy('jur.akronim')
->orderBy('ang.angkatan', 'DESC')
->get();
}else{
return SeleksiPelamar::select('pelamar.id_pelamar', 'alm.nama', 'jur.akronim', 'ang.angkatan', 'pelamar.tanggal_kirim')
->where('lowongankerja_id', $tahap->lowongankerja_id)
->join('pelamar', 'pelamar.id_pelamar', '=','seleksi_pelamar.pelamar_id')
->join('alumni_mendaftar_pelamar as almPel', 'almPel.pelamar_id', '=','pelamar.id_pelamar')
->join('alumni as alm', 'almPel.alumni_id', '=','alm.id_alumni')
->join('jurusan as jur', 'alm.jurusan_id', '=','jur.id_jurusan')
->join('angkatan as ang', 'alm.angkatan_id', '=','ang.id_angkatan')
->orderBy('pelamar.tanggal_kirim')
->orderBy('jur.akronim')
->orderBy('ang.angkatan', 'DESC')
->where('keterangan', '1')->whereHas('tahap', function ($tahaps) use ($tahap) {
$tahaps->where('lowongankerja_id', $tahap->lowongankerja_id)->where('tahap_ke', $tahap->tahap_ke - 1);
})->get();
}
}
}
public function columnWidths(): array
{
return [
'A' => 15,
'B' => 40,
'C' => 15,
'D' => 15,
'E' => 25,
'F' => 12,
];
}
public function styles(Worksheet $sheet)
{
$sheet->getStyle(2)->getFont()->setBold(true);
$sheet->mergeCells('A2:G2');
$sheet->mergeCells('A3:G3');
$sheet->mergeCells('A4:G4');
}
public static function afterSheet(AfterSheet $event)
{
$sheet = $event->sheet->getDelegate();
$sheet->getStyle(2)->getFont()->setSize(16);
$sheet->getStyle(3)->getFont()->setSize(14);
$sheet->getStyle(4)->getFont()->setSize(14);
$sheet->getStyle('A6:G6')->getFont()
->setBold(true)
->getColor()->setRGB('ffffff');
$sheet->getStyle('A6:G6')->getFill()
->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
->getStartColor()->setARGB('2041BB');
}
public function headings():array
{
$tahap = Tahap::where('id_tahap', $this->id)->first();
return [ // PER ROW HEADINGNYA
[], [$tahap->nama], ['Seleksi Alumni'], ['BKK SMKN 1 Kota Bekasi'],[],[
'ID Pelamar',
'Nama',
'Jurusan',
'Angkatan',
'Tanggal Submit',
'Nilai',
'Lulus',
]
];
}
}
The easy solution is to add an empty array of data to the collection. The solution is not idle but I think it can works. Try this:
public function collection()
{
$tahap = Tahap::where('id_tahap', $this->id)->first();
$PelamarData = new Collection();
if ($tahap->status == '0') {
if ($tahap->tahap_ke == '1') {
$PelamarData = Pelamar::select('pelamar.id_pelamar', 'alm.nama', 'jur.akronim', 'ang.angkatan', 'pelamar.tanggal_kirim')
->where('lowongankerja_id', $tahap->lowongankerja_id)
->join('alumni_mendaftar_pelamar as almPel', 'almPel.pelamar_id', '=','pelamar.id_pelamar')
->join('alumni as alm', 'almPel.alumni_id', '=','alm.id_alumni')
->join('jurusan as jur', 'alm.jurusan_id', '=','jur.id_jurusan')
->join('angkatan as ang', 'alm.angkatan_id', '=','ang.id_angkatan')
->orderBy('pelamar.tanggal_kirim')
->orderBy('jur.akronim')
->orderBy('ang.angkatan', 'DESC')
->get();
}else{
$PelamarData = SeleksiPelamar::select('pelamar.id_pelamar', 'alm.nama', 'jur.akronim', 'ang.angkatan', 'pelamar.tanggal_kirim')
->where('lowongankerja_id', $tahap->lowongankerja_id)
->join('pelamar', 'pelamar.id_pelamar', '=','seleksi_pelamar.pelamar_id')
->join('alumni_mendaftar_pelamar as almPel', 'almPel.pelamar_id', '=','pelamar.id_pelamar')
->join('alumni as alm', 'almPel.alumni_id', '=','alm.id_alumni')
->join('jurusan as jur', 'alm.jurusan_id', '=','jur.id_jurusan')
->join('angkatan as ang', 'alm.angkatan_id', '=','ang.id_angkatan')
->orderBy('pelamar.tanggal_kirim')
->orderBy('jur.akronim')
->orderBy('ang.angkatan', 'DESC')
->where('keterangan', '1')->whereHas('tahap', function ($tahaps) use ($tahap) {
$tahaps->where('lowongankerja_id', $tahap->lowongankerja_id)->where('tahap_ke', $tahap->tahap_ke - 1);
})->get();
}
//Add empty array data to skip the first 7 rows
foreach (range(1, 7) as $item)
{
$PelamarData->prepend([]);
}
return $PelamarData;
}
}

Cant figure out joins

So I am making a Businesses web app with the filters feature. There are two filters that I have problem with: Order By and Attributes(Has following attributes) features. Which looks like this:
Order By
Highest Rated (radio button)
Most reviews (radio button)
Attributes
Accepts Credit Cards (checkbox)
Accepts Events (checkbox)
Alcohol (checkbox)
Delivery (checkbox)
Smoking (checkbox)
So when Order By option is clicked this function is executed. Where $term is value of order_by get request parameter.
BusinessFilter.php
public function orderby($term)
{
if ($term == 'reviews_count') {
return $this->builder
->leftJoin('reviews', 'businesses.id', '=', 'reviews.business_id')
->groupBy('businesses.id')
->selectRaw('businesses.*, COUNT(reviews.id) as reviews_count')
->orderByDesc('reviews_count');
} else if ($term == 'rating') {
return $this->builder
->leftJoin('reviews', 'businesses.id', '=', 'reviews.business_id')
->groupBy('businesses.id')
->selectRaw('businesses.*, AVG(reviews.rating) AS average')
->orderByDesc('average');
} else {
return $this->builder;
}
}
It works ok and the result is correct.
Now when Attribute have some check boxes this function is executed where $term is an array with set of ids.
BusinessFilter.php
public function attributes($term)
{
$attributes= json_decode($term);
if (count($attributes) == 0) {
return $this->builder;
}
return $this->builder
->select('businesses.*')
->join('business_attribute_value', 'businesses.id', '=', 'business_attribute_value.business_id')
->join('values', 'business_attribute_value.attribute_value_id', '=', 'values.id')
->whereIn('values.id', $attributes)
->groupBy('businesses.id')
->havingRaw('COUNT(*) = ?', [count($attributes)]);
}
the result is correct here too.
Now the problem is when both filters have values it executes both queries together and It doesn't return the correct result. I assume it has something to do with joins. Am I doing something wrong? Please help. And if you need more info or code please let me know. Thank you, you are the best guys!
This is how I execute filters
public function getSearch(BusinessFilter $filters)
{
$businesses = Business::filter($filters)->paginate(30);
return $businesses;
}
This is QueryFilter class. Basically what it does is that it goes through each request parameter and executes its function that was mentioned above.
class QueryFilters{
protected $request;
protected $builder;
public function __construct( Request $request )
{
$this->request = $request;
}
public function apply(Builder $builder)
{
$this->builder = $builder;
foreach( $this->filters() as $name => $value ){
if( !method_exists($this, $name ) ){
continue;
}
if(strlen($value)){
$this->$name($value);
} else {
$this->$name();
}
}
return $this->builder;
}
public function filters()
{
return $this->request->all();
}
}

Laravel query to output json data as select list. How to amend existing code to concatenate two values

I've got a pre-existing function in my controller that will run a simple query and return the model_name and id then return the result as json.
public function getModel($id)
{
$models = DB::table('model')->where('man_id',$id)->pluck('model_name','id');
return json_encode($models);
}
New requirement is that I include an additional column named model_num with the query. Plan is to concatenate the model_name and model_num columns.
Tried the following, but it doesn't return any values and I get a 404 response for the json:
public function getModel($id)
{
$models = DB::table("model")->select("id","CONCAT(model_name, '-', model_num) as model")->where("man_id",$id)->pluck('model','id');
return json_encode($models);
}
Am I missing something obvious?
You are using SQL functions within a select these will probably not work. You can use selectRaw instead:
public function getModel($id)
{
$models = DB::table("model")
->selectRaw("id, CONCAT(model_name, '-', model_num) as model")
->where("man_id",$id)
->pluck('model','id');
return response()->json($models); // response()->json() is preferable
}
alternatively you can do the concatenating in the PHP side:
public function getModel($id)
{
$models = DB::table("model")
->select("id", "model_name" "model_num")
->where("man_id",$id)
->get()
->mapWithKeys(function ($model) {
return [ $model->id => $model->model_name.'-'.$model->model_num ];
})
return response()->json($models);
}
public function getModel($id)
{
$models = DB::table('model')->where('man_id',$id)->first() ;
$models->model = $models->model_name. '-'. $models->model_num;
return json_encode($models->pluck('model', 'id');
}

laravel many to many with chaining where clause

I have a given table :
tools toolparts parts part_details
----- --------- ----- ------------
id* id* id* id*
name tool_id name part_id
part_id total (int)
----- --------- ----- ------------
the relation between Tools and Parts is ManyToMany. and the relation between parts and part_details is one to many.
with Laravel model, how can I get tool with part that has the biggest part_details.total ??
//tool model
public function parts()
{
return $this->belongsToMany('App\Part', 'tool_part');
}
//part model
public function tools()
{
return $this->belongsToMany('App\Tool', 'tool_part')
}
public function details(){
return $this->hasMany('App\Part_detail');
}
//partDetail model
public function part(){
return $this->belongsTo('App\Part');
}
Controller
public function index()
{
$tools = Tool::with('parts', 'parts.details')->has('parts')->get();
return $tools;
}
what I expected is something like :
Controller
public function index()
{
$tool = Tool::with('SinglePartThatHasHigestTotalInPartDetail');
}
Any Idea ??
You can use Laravel aggregates for querying to get the desired result,
In your code use max() function,
public function index()
{
$tool = Tool::with(['parts.part_details' => function ($query) {
$max = $query->max('total');
$query->where('total',$max);
})->first();
}
I haven't tested this but you can do like this.
Comment if you will get any errors.
I Manage my problem with "hacky" ways. if someone have a better and more elegant solution, please tell me.
//tool model
public function partWithHighestTotalDelivery($trans_date = null){
if (is_null($trans_date)) {
$trans_date = date('Y-m-d');
}
$parts = $this->parts;
$highest_total_delivery = 0;
foreach ($parts as $key => $part) {
$part->detail;
$total_delivery = $part->first_value;
if (isset( $part->detail->total_delivery )) {
$total_delivery += $part->detail->total_delivery;
}
if ($highest_total_delivery < $total_delivery ) {
$highest_total_delivery = $total_delivery;
$part->total_delivery = $highest_total_delivery;
$result = $part;
}
}
if (!isset($result)) {
$result = null;
}
$this->part = $result;
}
In controller i have :
public function index(Request $request){
$tools = Tool::has('parts')
->get();
$tools->each(function($tool){
$tool->partWithHighestTotalDelivery();
});
return $tools;
}
with this, I need to run tool->partWithHighestTotalDelivery() tools.count times. which is take noticeable process if the tools is many.
and also, the code I post and the question I ask has a slightly difference.that's for a simplicity sake's
Use the the hasManyThrough Relationship to get the all part details related to tool and then you can check the one by one record and get the highest total of the tool part.
// Tool Model
public function partsdetails()
{
return $this->hasManyThrough('App\PartDetail', 'App\Part','tool_id','part_id');
}
In Your controller
$data = Tool::all();
$array = [];
if(isset($data) && !empty($data)) {
foreach ($data as $key => $value) {
$array[$value->id] = Tool::find($value->id)->partsdetails()->max('total');
}
}
if(is_array($array) && !empty($array)) {
$maxs = array_keys($array, max($array));
print_r($maxs);// This array return the max total of the tool related parts
}
else{
echo "No Data Available";
}
You can start with the part detail and get the tool(s) from there:
$maxPartDetail = Part_detail::orderByDesc('total')->first();
$tools = $maxPartDetail->part->tools;

Adding custom eloquent attribute in Laravel 5

I have a function named siblings which fetches all siblings of a user.
select siblings(id) as `siblings` from users where id = 1
I can access the function in Eloquent as
User::where('id', 1)->first([DB::raw(siblings(id) as `siblings`)]->siblings;
I want to make the siblings available via custom attribute.
I added siblings to $appends array
I also created getSiblingsAttribute method in my User model as
public function getSiblingsAttribute()
{
if (!$this->exists()) {
return [];
}
$siblings = User::where('idd', $this->id)
->first([DB::raw('siblings(id) AS `siblings`')])
->siblings;
return explode(',', $siblings);
}
But this is not working as $this->id returns null
My table schema is users(id, username,...), so clearly id is present.
Is there a way by which I can bind the siblings function while querying db and then returning something like $this->siblings from getSiblingsAttribute. If I can bind siblings(id) as siblings with query select globally as we do for scopes using global scope.
That way my code can be simply
public function getSiblingsAttribute()
{
return $this->siblings;
}
The simplest way is to create a view in your database and use that as a table:
protected $table = 'user_view';
Otherwise I need more information about your id == null problem.
If you can fix this by your own in the next step it is important that you use an other column name by selecting as in your accessor otherwise you run in an infinite loop.
public function getSiblingsAttribute()
{
if (!$this->exists()) {
return [];
}
$siblings = User::where('id', $this->id)
->first([DB::raw('siblings(id) AS `siblings_value`')])
->siblings_value;
return explode(',', $siblings);
}
EDIT
Sadly there is no simple way to archieve this.
But after a little bit tinkering I have found a (not very nice) solution.
Give it a try.
You have to add the following class and trait to your app.
app/Classes/AdditionalColumnsTrait.php (additional column trait)
namespace App\Classes;
trait AdditionalColumnsTrait {
public function newEloquentBuilder($query) {
$builder = new EloquentBuilder($query);
$builder->additionalColumns = $this->getAdditionalColumns();
return $builder;
}
protected function getAdditionalColumns() {
return [];
}
}
app/Classes/EloquentBuilder.php (extended EloquentBuilder)
namespace App\Classes;
use Illuminate\Database\Eloquent\Builder;
class EloquentBuilder extends Builder {
public $additionalColumns = [];
public function getModels($columns = ['*']) {
$oldColumns = is_null($this->query->columns) ? [] : $this->query->columns;
$withTablePrefix = $this->getModel()->getTable() . '.*';
if (in_array('*', $columns) && !in_array($withTablePrefix, $oldColumns)) {
$this->query->addSelect(array_merge($columns, array_values($this->additionalColumns)));
} elseif (in_array($withTablePrefix, $oldColumns)) {
$this->query->addSelect(array_values($this->additionalColumns));
} else {
foreach ($this->additionalColumns as $name => $additionalColumn) {
if (!is_string($name)) {
$name = $additionalColumn;
}
if (in_array($name, $columns)) {
if (($key = array_search($name, $columns)) !== false) {
unset($columns[$key]);
}
$this->query->addSelect($additionalColumn);
}
}
if (is_null($oldColumns)) {
$this->query->addSelect($columns);
}
}
return parent::getModels($columns);
}
}
after that you can edit your model like this:
class User extends Model {
...
use App\Classes\AdditionalColumnsTrait;
protected function getAdditionalColumns() {
return [
'siblings' => DB::raw(siblings(id) as siblings)),
];
}
...
}
now your siblings column will be selected by default.
Also you have the option to select only specific columns.
If you don't want to select the additional columns you can use: User::find(['users.*']).
Perhaps it is a solution for you.

Resources