How can I write the on Laravel eloquent? - laravel

The is my DB table screen shot
$query = DB::table('categories');
$query->select('categorsies.*', 'c2.value as name', 'c2.store_id as store_id', 'c2.attribute_id as attribute_id', 'c2.entity_id as entity_id');
if ($this->store_id != 0) {
$query->where('c2.store_id', $this->store_id)->orWhere('store_id', 0);
} else {
$query->where('c2.store_id', $this->store_id);
}
$result_data = $query->get();
I want to get the row, if there is a store_id match get that row from the table otherwise get 0 default row

You're missing the c2 table in your query. Also, you could use when to get the if statement logic in the query.
$query = DB::table('categories')
->when(
$this->store_id != 0,
fn ($query) => $query->where('store_id', $this->store_id)->orWhere('store_id', 0),
fn ($query) => $query->where('store_id', $this->store_id)
)
->get();

Related

OrderBy from relationship, Laravel

I have a table of Questions, where I use:
$query->orderBy($request->sort_by, ($request->sort_direction === 'false') ? 'asc' : 'desc');
//sort_by and sort_direction are from front-end, and this works for my main table
But in that table I have 2 relationships, and I want to sort by a column from the table that has a relationship, also to sort by a count of that.
Ex: a Question has many answer_history, each answer_history has a answer_type column ('none' or 'skipped') I want to sort by count(answer_type = 'none').
$query = Question::select(['id', 'free_text', 'title', 'best_match', 'created_at']);
$query->with('answer_history');
$query->with(['bestMatch']);
$query->orderBy($request->sort_by, ($request->sort_direction === 'false') ? 'asc' : 'desc');
return response()->json($query->paginate($request->per_page));
//this works just for main table
UPDATE:
if($request->sort_by){
if($request->sort_by === 'best_match'){
$query->orderBy(function ($bestMatch, $key) {
return count($bestMatch['name']);
},($request->sort_direction === 'false') ? 'asc' : 'desc');
}else{
$query->orderBy($request->sort_by, ($request->sort_direction === 'false') ? 'asc' : 'desc');
}
}
// I tried to do this for a column from best_match, but is not working
You can apply the check on the relationship when you lazy load it.
->with(['bestMatch' => function ($query) use ($request){
if($request->sort_by && $request->sort_by === 'best_match') {
$query->orderBy('name', 'desc');
}
}
])
You can do same for the 'answer_history'.
Note: Code is not tested.

where clause is ambiguous on a query

I built a search module to get results form different params ! it"s work but when i when to export the result in csv i'm getting problems with my join table. for exemple when i search with a catg_licence_id i get an exception like :
SQLSTATE[23000]: Integrity constraint violation: 1052 Column
'catg_licence_id' in where clause is ambiguous
here my controller to get the result and generate the file with the join tables to get the value from the other tables and not simple ids . hope someone could help me. thanks a lot in advance :)
public function exportLicencesExcelWithParam(Request $request){
$type_licence = Type_licence::pluck('lb_type' , 'id');
$activite = ActiviteLicencie::pluck('lb_activite' , 'id');
$catg_licence = CatgLicence::pluck('lb_catg_lic' , 'id');
$structure = Structure::select('num_structure', 'nom_structure' , 'id')
->get()
->mapWithKeys(function($i) {
return [$i->id => $i->num_structure.' - '.$i->nom_structure];
});
$query = Licencies::query();
$filters = [
'type_licence' => 'type_licence_id',
'activite_licencie' => 'activite_licencie_id',
'assurance' => 'lb_assurance_etat',
'catg_licence' => 'catg_licence_id',
'structure' => 'structure_id',
];
foreach ($filters as $key => $column) {
if ($request->has($key)) {
$query->where($column, $request->{$key});
}
}
$action = Input::get('action', 'none');
if($action =='send'){
//HERE I WANT TO GENERATE THE CSV FILE BUT I NEED TO GET THE JOIN TABLES TO DISPLAY THE RESULT
$licencies = $query->join('activite_licencie', 'activite_licencie.id', '=', 'licencies.activite_licencie_id')
->join('saisons', 'saisons.id', '=', 'licencies.saison_id')
->join('pays', 'pays.id', '=', 'licencies.pays_naissance_id')
->join('type_licence', 'type_licence.id', '=', 'licencies.type_licence_id')
->join('structures', 'structures.id', '=', 'licencies.structure_id')
->join('civilite', 'civilite.id', '=', 'licencies.civilite_id')
->join('catg_licence', 'catg_licence.id', '=', 'licencies.catg_licence_id')
->select('num_licence', 'civilite.lb_civilite', 'lb_nom', 'lb_prenom', 'dt_naissance', 'pays.fr as pays', 'activite_licencie.lb_activite', 'catg_licence.lb_catg_lic', 'type_licence.lb_type', 'saisons.lb_saison', 'lb_surclassement', 'structures.nom_structure', 'structures.num_structure', 'lb_assurance', 'cd_dept_naissance', 'lb_ville_naissance', 'lb_adresse', 'tel_fix_licencie', 'tel_port_licencie', 'adresse_email')
->get();
$licencies->map(function ($licencie) {
$licencie['dt_naissance'] = \Carbon\Carbon::parse($licencie['dt_naissance'])->format('d/m/Y');
$licencie['lb_nom'] = strtoupper($licencie['lb_nom']);
$licencie['lb_prenom'] = ucfirst(strtolower($licencie['lb_prenom']));
if ($licencie['num_structure'] == 662883) {
$licencie['lb_activite'] = 'Super League';
} elseif ($licencie['num_structure'] == 311197) {
$licencie['lb_activite'] = 'ChampionShip';
} else {
//do nothing
}
if ($licencie['lb_activite'] == 'Tricolore LER' or $licencie['lb_activite'] == 'Tricolore - Autres Divisions') {
$licencie['lb_activite'] = 'Tricolore';
}
if ($licencie['lb_type'] == 'Membre') {
$licencie['lb_catg_lic'] = '';
}
return $licencie;
});
$date = Carbon::now('Europe/Paris')->format('d-m-Y h:m:s');
$file = Excel::create('' . $date . '', function ($excel) use ($licencies) {
$excel->sheet('Excel', function ($sheet) use ($licencies) {
$sheet->fromArray($licencies);
});
})->string('csv');
Storage::disk('local')->put('licencies_export_'.$date.'.csv' , $file);
return back()->with('status', "Fichier Exporté");
}else{
}
return view('export/licences' , compact('type_licence' , 'structure' , 'structures' , 'licencies' , 'activite' , 'catg_licence'));
}
here the full exception:
SQLSTATE[23000]: Integrity constraint violation: 1052 Column
'type_licence_id' in where clause is ambiguous (SQL: select
num_licence, civilite.lb_civilite, lb_nom, lb_prenom,
dt_naissance, pays.fr as pays,
activite_licencie.lb_activite, catg_licence.lb_catg_lic,
type_licence.lb_type, saisons.lb_saison, lb_surclassement,
structures.nom_structure, structures.num_structure,
lb_assurance, cd_dept_naissance, lb_ville_naissance,
lb_adresse, tel_fix_licencie, tel_port_licencie, adresse_email
from licencies inner join activite_licencie on
activite_licencie.id = licencies.activite_licencie_id inner
join saisons on saisons.id = licencies.saison_id inner join
pays on pays.id = licencies.pays_naissance_id inner join
type_licence on type_licence.id = licencies.type_licence_id
inner join structures on structures.id =
licencies.structure_id inner join civilite on civilite.id =
licencies.civilite_id inner join catg_licence on
catg_licence.id = licencies.catg_licence_id where
type_licence_id = 4 and catg_licence_id = 1)
When it says it's ambiguous, what it means is that the mysql is joining tables and that specific field (catg_licence_id) is found on another table. So what happens is when you're joining something to this field, he doesn't know what table to join with. A solution would be to place the table name before, something like #user3154557 just said
->join('tablename', 'tablename.field', 'othertablename.field')
You're not joining the 'licencies' table anywhere.
->join('catg_licence', 'catg_licence.id', '=', 'licencies.catg_licence_id')
That line is your problem.
You might also get the same error in your select. It's better to put the table.property in the select rather than the property when you're joining a bunch of tables.

OctoberCMS - Model query with relation manyToMany

Once again i'm asking some help from the community...
Scenario:
I have two tables with one pivot table (something like posts and tags to give some context):
table 1 (Evento):
-id
-....
table 2 (Etiquetas):
-id
-etiqueta
pivot table (Eventos_Etiquetas):
-evento_id (pk)
-etiqueta_id (pk)
The relations are set as:
public $belongsToMany = [
'eventos' => ['JML\Gkb\Models\Evento', 'table' => 'jml_gkb_eventos_etiquetas']
];
and
public $belongsToMany = [
'etiquetas' => ['JML\Gkb\Models\Etiqueta', 'table' => 'jml_gkb_eventos_etiquetas']
];
Now, what i want to achieve:
-get all events that have any individual tag without regarding the order of input (or).
-get all events that have all tags without regarding the order of input (and).
As you can imagine i'm strugling with this as i'm new to October/Laravel query builder (and not so to sql).
What i've done so far:
if (Session::get('tipo') == 'etiqueta'){
$pesquisa = preg_split('/\s+/', $temp, -1, PREG_SPLIT_NO_EMPTY);
if (Session::get('modo') == 0){
$this['records'] = Evento::with('etiquetas')->whereHas('etiquetas', function($query) use ($pesquisa){
foreach ($pesquisa as $palavra){
$query->where('etiqueta', 'like', "%$palavra%");
}
})->orderBy('id', 'DESC')->paginate(25);
}
if (Session::get('modo') == 1){
$this['records'] = Evento::with('etiquetas')->whereHas('etiquetas', function($query) use ($pesquisa){
foreach ($pesquisa as $palavra){
$query->orWhere('etiqueta', 'like', "%$palavra%");
}
})->orderBy('id', 'DESC')->paginate(25);
}
}
The user input is passed by $temp variable and it's splited to words to the $pesquisa array variable. 'modo' defines if the user pretend a search by AND (0) or by OR (1). Based on that choice a query is built to try to get the results using $palavra variable as any word of $pesquisa.
The result of this:
In modo == 0, i only can get the events of one tag of user input, if it have more than one word (any letter that don't exist on first word) don't get any result.
In modo == 1 it gets all events.
In both cases i don't get any event that don't have any tag (etiqueta) - correct behaviour.
I've tried some other ways but with no avail... This one looks to me the most logical of the tries... Can someone point me on the correct direction ?
TIA
JL
After some tries i have half of the problem solved. The part where i want to get any "Evento" that has any of the "Etiqueta" on user input not regarding the order of them is working fine finally.
Resume bellow
if (Session::get('tipo') == 'etiqueta'){
$pesquisa = preg_split('/\s+/', $temp, -1, PREG_SPLIT_NO_EMPTY);
$cadeiapesquisa = implode('|', $pesquisa);
/***** NOT WORKING YET *****/
if (Session::get('modo') == 0){
$this['records'] = Evento::with('etiquetas')->whereHas('etiquetas', function($query) use ($pesquisa){
foreach ($pesquisa as $palavra){
$query->where('etiqueta', 'like', "%$palavra%");
}
})->orderBy('id', 'DESC')->paginate(25);
}
/****** THIS IS WORKING FINE ! *******/
if (Session::get('modo') == 1){
if ( count ($pesquisa) > 0 && !($temp == null)){
$this['records'] = Evento::with('etiquetas')->whereHas('etiquetas', function($query) use ($cadeiapesquisa){
$query->where('etiqueta', 'regexp', "$cadeiapesquisa");
})->orderBy('id', 'DESC')->paginate(25);
} else {
Evento::paginate(25);
}
}
}
The first parte is fighting, but i will get there. :)
TIA
JL
[EDIT]
Problem solved... The resulting snipet of code working so far with the tests i've done is bellow:
if (Session::get('tipo') == 'etiqueta'){
$pesquisa = preg_split('/\s+/', $temp, -1, PREG_SPLIT_NO_EMPTY);
$cadeiapesquisa = implode('|', $pesquisa);
$contagem = count($pesquisa);
if (Session::get('modo') == 0){
if ( strlen($cadeiapesquisa) > 0 ){
$this['records'] = Evento::with('etiquetas')->whereHas('etiquetas', function($query) use ($cadeiapesquisa, $contagem){
$query->where('etiqueta', 'regexp', "$cadeiapesquisa")->groupBy('evento_id')->having(DB::raw("COUNT('etiqueta_id')"), '>=', $contagem );
})->paginate(25);
} else {
$this['records'] = Evento::paginate(25);
}
}
if (Session::get('modo') == 1){
if ( strlen($cadeiapesquisa) > 0 ){
$this['records'] = Evento::with('etiquetas')->whereHas('etiquetas', function($query) use ($cadeiapesquisa){
$query->where('etiqueta', 'regexp', "$cadeiapesquisa");
})->paginate(25);
} else {
$this['records'] = Evento::paginate(25);
}
}
}
JL

Subquery in laravel query builder

How could I do this query in laravel:
SELECT * FROM(
SELECT * FROM `tb_horario` where cod_funcionario="'.$cod.'" and deleted_at is null)
AS temp
where temp.motivo!='' or temp.validado=0
but sometimes I dont have to use cod_funcionario because is a filter in my page
so I've something like:
if ($funcionario)
{
$horariosQuery->where('cod_funcionario', $funcionario);
}
I dont know how to do this query with this subquery in laravel like I did in sql.
thxx!
$horariosQuery = $this->horario->with(array('funcionario', 'item_contabil'))
->whereNull('deleted_at')
->orderby('cod', 'ASC');
if ($funcionario)
{
$horariosQuery->where('cod_funcionario', $funcionario)
->where(function ($query) {
$query->where('validado', 0)
->orWhere('motivo', '!=', '');
})
->orderBy('data');
}
else
{
$horariosQuery->where('validado', 0)
->orWhere('motivo', '<>', '')
->orderBy('cod_funcionario');
}

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