Laravel Mutator in query builder? - laravel

I've no idea how to define two field as one field using mutator in query builder
here's my code
$model = LoanInformation::select(
'basic_information.first_name', 'basic_information.last_name',
'loan_information.id', 'loan_information.tenor'
)->join(
'basic_information', 'loan_information.user_id', '=', 'basic_information.user_id'
)->where(
'loan_information.status', 'funding'
)->paginate(9);
How can I make first_name and last_name define as name and add statement on it which return strtoupper(first_name) and strtoupper(last_name)

To your LoanInformation model, add the following method:
public function getNameAttribute() {
return strtoupper($this->first_name . ' ' . $this->last_name);
}
This will enable you to write $model->name which will return the firstname and lastname, joined with a space, all in uppercase.

I just figure it out by adding key and value to the array instead of mutator or accessor
here's my own answer
$model = LoanInformation::select(
'loan_information.id', 'loan_information.tenor',
'basic_information.first_name', 'basic_information.last_name'
)->leftjoin(
'basic_information', 'loan_information.user_id', '=',
'basic_information.user_id'
)->where('loan_information.status', 'funding')
->orderBy('loan_information.created_at', 'ASC')
->paginate(9);
foreach($model as $key => $value) {
$tx_funding = TxFunding::whereLoanId($value->id)->get();
$name = substr($value->first_name, 0, 1).substr($value->last_name, 0, 2);
$model[$key]['name'] = strtoupper($name);
$model[$key]['grade'] = 'A+';
$model[$key]['fundraiser'] = $tx_funding->count();
$model[$key]['progress'] = 50;
$model[$key] = array_except($value, ['first_name', 'last_name']);
}
return response()->json($model);

Related

Laravel pagination with problems

i have a simple question as i do not know which line i should add into to get laravel pagination. (->paginate(5).
public function index(Request $request)
{
$codeSearch = $request->get('code');
$descriptionSearch = $request->get('description');
//$tmp = Category::all()->toArray();
$tmp = Category::where('code','like','%' .$codeSearch. '%')->where('description','like','%' .$codeSearch. '%')->get()->toArray();
$category = array();
foreach ($tmp as $key => $row) {
$policy = Category::find($row['parent_id']);
$tmpResult = new Category();
$tmpResult->id = $row['id'];
$tmpResult->code = $row['code'];
$tmpResult->description = $row['description'];
$tmpResult->parent_id = $policy['description'];
$tmpResult->status = $row['status'];
array_push($category, $tmpResult);
}
return view('category.index', compact('category'));
}
Paginate can't be called on the collection, so you have to run it on the query, by simply replace ->get() with ->paginate(5) like this
$tmp = Category::where('code','like','%' .$codeSearch. '%')
->where('description','like','%' .$codeSearch. '%')
->paginate(5)
->toArray();
Try
$tmp = Category::where('code','like','%' .$codeSearch. '%')->where('description','like','%' .$codeSearch. '%')->paginate(5);
In view
#foreach($tmp as $tm)
//whatever operation you like to do
#endforeach
{{$tmp->links()}}
The following ->get(), ->first(), all() get the results from the database and so does ->paginate(5), so I would suggest that you replace ->get() with paginate(5) an you can get rid of toArray() because the result will be a collection with which you can use foreach() or get a value by index.
As you need an array in your condition, then you can simply convert the final array into a collection object and use the pagination concept.
$items = [
'item1',
'item2',
'item3',
'item4',
'item5',
'item6',
'item7',
'item8',
'item9',
'item10'
];
// Get current page form url e.x. &page=1
$currentPage = LengthAwarePaginator::resolveCurrentPage();
// Create a new Laravel collection from the array data
$itemCollection = collect($items);
// Define how many items we want to be visible in each page
$perPage = 1;
// Slice the collection to get the items to display in current page
$currentPageItems = $itemCollection->slice(($currentPage * $perPage) - $perPage, $perPage)->all();
// Create our paginator and pass it to the view
$paginatedItems= new LengthAwarePaginator($currentPageItems , count($itemCollection), $perPage);
// set url path for generted links
$paginatedItems->setPath($request->url());
return view('items_view', ['items' => $paginatedItems]);
It would probably be easier to have a relationship setup for a Category's parent. Then you can load the parent when you retrieve the categories.
class Category extends Model
{
...
public function parent()
{
return $this->belongsTo(self::class);
}
}
I feel like your search is probably trying to do an OR WHERE, search the code field for this value or the description:
$categories = Category::with('parent')
->where('code', 'like', '%' .$codeSearch. '%')
->orWhere('description', 'like', '%' .$codeSearch. '%')
->paginate(5);
Then in your view if you want the parent category's description you can get it through the relationship:
#foreach ($categories as $category)
parent description: {{ $category->parent->description }}
#endforeach

Laravel eloquent whereIn with one query

In laravel, I can use many where rules as an array a run one query to the database using laravel eloquent where method to get needed result.
Code:
$where = [];
$where[] = ['user_id', '!=', null];
$where[] = ['updated_at', '>=', date('Y-m-d H:i:s')];
if($request->searchTerm) {
$where[] = ['title', 'like', '%' . $request->searchTerm . '%'];
}
Model::where($where)->get();
Question part:
Now I need to use Laravel Eloquent method whereIn with array params to get needed result with one query.
I tried by looping method but with many queries to the database.
Code:
$model = new Model;
$whereIn = [];
$whereIn[] = ['date', '>=', Carbon::now()->subDays(10)];
$whereIn[] = ['user_role', 'candidate'];
if (!empty($scope) && is_array($scope)) {
$whereIn[] = ['user_id', $scope];
}
if(is_array($employment) && !empty($employment)) {
$whereIn[] = ['employment', $employment];
}
if(is_array($experience) && !empty($experience)) {
$whereIn[] = ['experience', $experience];
}
foreach ($whereIn as $v) {
$model = $model->whereIn($v[0], $v[1]);
}
dump($model->get());
First I tired $model->whereIn($whereIn)->get() but it's return error. It's possible get results with one query using whereIn without looping?
Note: My $whereIn array will be dynamic array!
whereIn is a query builder function so you can't use it on the model directly. Instead you should create a query builder instance. I also suggest you use when instead of the if statements:
$models = Model::when(!empty($scope) && is_array($scope), function ($query) use ($scope) {
$query->whereIn('user_id', $scope);
})->when(!empty($employment) && is_array($employment), function ($query) use ($employment) {
$query->whereIn('employment', $employment);
})->when(!empty($experience) && is_array($experience), function ($query) use ($experience) {
$query->whereIn('experience', $experience);
})->get();
dump($models);
when essentially runs the function when the first parameter is true. There's more detail in the documentation under conditional clauses.
Since your $whereIn variable is an array of arrays it will work like :
$model->whereIn($whereIn[0][0], $whereIn[0][1])->get();
If it just a simple array then you can use :
$model->whereIn($whereIn[0], $whereIn[1])->get();
Do in Eloquent
$model = Model::whereIn('id', array(1, 2, 3))->get();
Or using Query builder then :
$model = DB::table('table')->whereIn('id', array(1, 2, 3))->get();

Auto inserting table name for subquery/join queries in Laravel (Eloquent)

Here is my query:
PHP
public function find(array $filter = []) : Collection
{
return $this->entity::where($filter)->join('cases_has_services', function ($join) {
$join->on('cases_has_services.cases_id', 'checklists.cases_id');
$join->on('cases_has_services.services_id', 'checklists.item_id');
})->select('checklists.*', 'cases_has_services.quantity')->get();
}
i am receiving the next error:
SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'id' in where
clause is ambiguous (SQL: select `checklists`.*,
`cases_has_services`.`quantity` from `checklists` inner join
`cases_has_services` on `cases_has_services`.`cases_id` =
`checklists`.`cases_id` and `cases_has_services`.`services_id` =
`checklists`.`item_id` where (`id` = 352))
So i fixed my code a little bit:
public function find(array $filter = []) : Collection
{
// TODO fix this
foreach ($filter as $field => $value) {
unset($filter[$field]);
$field = 'checklists.' . $field;
$filter[$field] = $value;
}
return $this->entity::where($filter)->join('cases_has_services', function ($join) {
$join->on('cases_has_services.cases_id', 'checklists.cases_id');
$join->on('cases_has_services.services_id', 'checklists.item_id');
})->select('checklists.*', 'cases_has_services.quantity')->get();
}
But that is not a good practice i think. So, are there any native laravel path to auto insert table name in query with joins?
I mean, how to avoid using that part of code because its a little hacky:
foreach ($filter as $field => $value) {
unset($filter[$field]);
$field = 'checklists.' . $field;
$filter[$field] = $value;
}
Change you $filter variable to:
$filter = ['checklists.id' => 123]

Laravel how to get a Model by two parameters

Hi I'm new to Laravel and got stuck in a Problem.
I have a model Contact
class Contact extends Eloquent {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'contacts';
}
The table have these fields:
user_id (int)
contact_id (int)
...
these two fields represent the primary key.
In the ContactsController I have the function store in wich I create or update the database:
public function store()
{
switch (Input::get('type')){
case 'make_contact_request':
$user = User::where('email', '=', Input::get('login'));
$request_self = new Contact;
$request_contact = new Contact;
$request_self->user_id = Auth::user()->id;
$request_self->contact_id = $user->id;
$request_self->status = 2;
$request_self->message = Input::get('message');
$request_contact->user_id = $user->id;
$request_contact->contact_id = Auth::user()->id;
$request_contact->status = 1;
$request_contact->message = Input::get('message');
$request_self->save();
$request_contact->save();
break;
case 'answer_contact_request':
$request_self = Contact::where('user_id', '=',Input::get('contact_id'))->where('contact_id', '=', Auth::user()->id)->first();
//$request_self = Contact::whereRaw('user_id = '.Input::get('contact_id').' AND contact_id = '.Auth::user()->id.' ');
$request_contact = Contact::whereRaw('user_id = '.Auth::user()->id.' AND contact_id = '.Input::get('contact_id').' ');
$request_self->status = 3;
$request_contact->status = 3;
$request_self->save();
$request_contact->save();
break;
}
}
I tried two different ways to get the Contact Object for the request_self Object and I get the following error:
message: "SQLSTATE[42S22]: Column not found: 1054 Unknown column 'id' in 'where clause' (SQL: update `contacts` set `status` = 3, `updated_at` = 2014-08-02 16:16:56 where `id` is null)"
for the request_contact Object it throws a fatal error (don't get the description) and close the session.
At the end I am at the beginning of laravel so I hope the solution is pretty easy to find :) but I dont even really know for what to search.
Update:
At the end I fixed the Problem with the update function.
case 'answer_contact_request':
$request_self = Contact::where('user_id', '=',Input::get('contact_id'))->where('contact_id', '=', Auth::user()->id)->update(array('status' => 3));
$request_contact = Contact::where('user_id', '=', Auth::user()->id)->where('contact_id', '=', Input::get('contact_id'))->update(array('status' => 3));
break;
I think you can add
public function scopeComposite($query, $user_id, $contact_id)
{
return $query->where('user_id', '=', $user_id)->where('contact_id', '=', $contact_id);
}
and then you can get the contact with:
$request_self = Contact::composite(Input::get('contact_id'), Auth::user()->id)->get();
source: http://laravel.com/docs/eloquent#query-scopes
I'm not sure you can make it like this.
There is a way to make sure it works:
add a column id ( auto increment, primary ) and make the group ( contact_id, user_id ) unique and you can use query scopes and id based

Laravel how do I get the row number of an object using Eloquent?

I'd like to know the position of a user based on its creation date. How do I do that using Eloquent?
I'd like to be able to do something like this:
User::getRowNumber($user_obj);
I suppose you want MySQL solution, so you can do this:
DB::statement(DB::raw('set #row:=0'));
User::selectRaw('*, #row:=#row+1 as row')->get();
// returns all users with ordinal 'row'
So you could implement something like this:
public function scopeWithRowNumber($query, $column = 'created_at', $order = 'asc')
{
DB::statement(DB::raw('set #row=0'));
$sub = static::selectRaw('*, #row:=#row+1 as row')
->orderBy($column, $order)->toSql();
$query->remember(1)->from(DB::raw("({$sub}) as sub"));
}
public function getRowNumber($column = 'created_at', $order = 'asc')
{
$order = ($order == 'asc') ? 'asc' : 'desc';
$key = "userRow.{$this->id}.{$column}.{$order}";
if (Cache::get($key)) return Cache::get($key);
$row = $this->withRowNumber($column, $order)
->where($column, '<=',$this->$column)
->whereId($this->id)->pluck('row');
Cache::put($key, $row);
return $row;
}
This needs to select all the rows from the table till the one you are looking for is found, then selects only that particular row number.
It will let you do this:
$user = User::find(15);
$user->getRowNumber(); // as default ordered by created_at ascending
$user->getRowNumber('username'); // check order for another column
$user->getRowNumber('updated_at', 'desc'); // different combination of column and order
// and utilizing the scope:
User::withRowNumber()->take(20)->get(); // returns collection with additional property 'row' for each user
As this scope requires raw statement setting #row to 0 everytime, we use caching for 1 minute to avoid unnecessary queries.
$query = \DB::table(\DB::raw('Products, (SELECT #row := 0) r'));
$query = $query->select(
\DB::raw('#row := #row + 1 AS SrNo'),
'ProductID',
'ProductName',
'Description',
\DB::raw('IFNULL(ProductImage,"") AS ProductImage')
);
// where clauses
if(...){
$query = $query->where('ProductID', ...));
}
// orderby clauses
// ...
// $query = $query->orderBy('..','DESC');
// count clause
$TotalRecordCount = $query->count();
$results = $query
->take(...)
->skip(...)
->get();
I believe you could use Raw Expresssions to achieve this:
$users = DB::table('users')
->select(DB::raw('ROW_NUMBER() OVER(ORDER BY ID DESC) AS Row, status'))
->where('status', '<>', 1)
->groupBy('status')
->get();
However, looking trough the source code looks like you could achieve the same when using SQLServer and offset. The sources indicates that if you something like the following:
$users = DB::table('users')->skip(10)->take(5)->get();
The generated SQL query will include the row_number over statement.
[For Postgres]
In your model
public function scopeWithRowNumber($query, $column = 'id', $order = 'asc'){
$sub = static::selectRaw('*, row_number() OVER () as row_number')
->orderBy($column, $order)
->toSql();
$query->from(DB::raw("({$sub}) as sub"));
}
In your controller
$user = User::withRowNumber()->get();

Resources