How can I restrict certain entities from my queryBuilder? - doctrine

I'm trying to use a queryBuilder to get some users who did NOT have an appointment with subject 'PC' ("Prise de Contact").
and fit certain criteria of appointment dates ina related entity, "Amont".
I'm reusing a queryBuilder using "clone" so I can perform my search on the result of the queryBuilder that was made for displaying the page.
I'm trying to use the notIn() method from the expressions of queryBuilder
$nots
->leftJoin('u.rendezVouses', 'rdv')
->andWhere("rdv.objetRDV = 'PC'");
$qb
->select('u.id')
->leftJoin('u.amonts', 'a')
->andWhere($qb->expr()->notIn('u.id', $nots))
->andWhere('a.datePremierRDV <= :dateNj')
->andWhere('a.datePremierRDV >= :dateMini')
->andWhere($qb->expr()->isNotNull('a.datePremierRDV'))
->setParameter('dateNj', $dateNj)
->setParameter('dateMini', $dateMini);
$array = $qb->getQuery()->getResult();
here's the error message I get in symfony profiler:
Error: Method Doctrine\Common\Collections\ArrayCollection::__toString() must not throw an exception, caught ErrorException: Catchable Fatal Error: Object of class Doctrine\ORM\EntityManager could not be converted to string

Related

Undefined relationship error in sorting of existence and non existence relationship using Eager Load in Laravel eloquent model

I have a Student model and a corresponding one to one mapping relationship to Result model.
I have an eligibleList array containing a list of student id whose marks are to be displayed. Some student have results while some does not have but i need to display all of them from the list.
I am able to retrieve and display students using the following:
$students = Student::with('result:student_id,marks')->whereIn('students.id', $eligibleList)->get();
foreach($students as student) {
if ($student->result != null)
Log::debug($student->result->marks)
else
Log::debug("-1") //-1 indicate no results
}
The above has no issue until i need to sort the list (ascending or descending) by the marks. I tried the following:
$students = Student::with(['result:student_id,marks' => function ($query) {
$query->orderBy('marks','DESC');
}])->whereIn('student.id', $eligibleList)->get();
It throws me a "Call to undefined relationship" error. Is there anyway to sort from the query ? I avoid sorting the collection as it can get very slow for thousands of records. Somehow eloquent early loading encounter some error when sorting with non existence relationship.
you should use 'Subquery Ordering', ordering inside 'with' will not sort the overall result.
$students = Student::with(['result:student_id,marks'])->whereIn('student.id', $eligibleList)
->orderByDesc(Result::select('marks')->whereColumn('student_id','students.id'))
->get();
https://laravel.com/docs/7.x/eloquent#advanced-subqueries
if you use laravel 5 you have to use 'join':
Student::with(['result:student_id,marks'])->whereIn('student.id', $eligibleList)
->join('result','result.student_id','student.id')
->select('user.*,result.marks')->orderBy('result.marks')->get();
'join' use table name not the relation name, so please be careful about table name in previous 'join' and 'select' statements

Laravel queryScope

I created a queryScope
public function scopeCtmpActive($query)
{
return $query->where('ctmp_active', 'y');
}
Then I replace following line
$customtemplates_collection = Auth::user()->customtemplates->where('ctmp_active', 'y')->sortByDesc('ctmp_id');
with
$customtemplates_collection = Auth::user()->customtemplates->ctmpActive()->sortByDesc('ctmp_id');
And I am getting following FatalErrorException
Call to undefined method Illuminate\Database\Eloquent\Collection::ctmpActive()
How am I suppose to use a query exception with a relationship?
As the name implies, "query" scopes are for reusable, common "query" constraints.
$customtemplates_collection = Auth::user()->customtemplates;
This returns a collection. You are getting all "customtemplates" that belong to the authenticated user. Then, Laravel is nice in that the Collection class allows for a nice way to filter out results, which is why the next part works:
$customtemplates_collection = Auth::user()->customtemplates->where('ctmp_active', 'y');
You are using PHP. Not MySQL. To emphasize, you are getting every single "customtemplates" that belongs to the user, and then using (PHP) Laravel Collection's where method to go through each one and filter out the results. You are not adding a where clause to the query. That's why the above works.
However, query scopes are for query constraints so they need to happen during the query, not after. What you probably want is something like this:
$customtemplates_collection = Auth::user()->customtemplates()->ctmpActive()->orderBy('ctmp_id', 'desc')->get();
When you add the paranthesis after customtemplates(), you are invoking the customtemplates method. In this case, I'm assuming it's a HasMany relationship so it'll return a HasMany instance. Then basically, it uses PHP's magic method (__call) to build the query builder so each method after that is essentially prepping the database query. Then, when you're finished building the query, you call get to fetch the results.

Error when retrieving and updating data from database in Codeigniter

In my application controller, I have a method transaction_reimburse() that receives ids as POST string values. The method's function is to get all transactions that match the ids from the database, and update them accordingly.
Controller method:
public function transaction_reimburse() {
$reimburse = array('reimburse' => 1);
$transactions = $this->Transaction_model->get_these_ids($this->input->post('ids'));
$this->Transaction_model->reimburse_these($transactions, $reimburse);
}
Model method:
function get_these_ids($ids) {
$this->db->select('tbl_user.name as uname, tbl_transactions.participant_id as pid, tbl_transactions.card_number as card_no, tbl_transactions.group as ugroup, tbl_toilet.name as utoilet, tbl_transactions.amount_paid as u_amount, tbl_transactions.toilet_price as t_price, tbl_transactions.reimburse_amount as r_amount, tbl_transactions.details as u_details');
$this->db->from('tbl_transactions');
$this->db->join('tbl_user', 'tbl_user.participant_id = tbl_transactions.participant_id', 'left');
$this->db->join('tbl_toilet', 'tbl_toilet.toilet_code = tbl_transactions.toilet_code', 'left');
$this->db->where("tbl_transactions.id IN (". $ids .")");
return $this->db->get();
}
Model method:
function reimburse_these($transactions, $reimburse) {
$this->db->select('tbl_user.name as uname, tbl_transactions.participant_id as pid, tbl_transactions.card_number as card_no, tbl_transactions.group as ugroup, tbl_toilet.name as utoilet, tbl_transactions.amount_paid as u_amount, tbl_transactions.toilet_price as t_price, tbl_transactions.reimburse_amount as r_amount, tbl_transactions.details as u_details');
$this->db->from('tbl_transactions');
$this->db->join('tbl_user', 'tbl_user.participant_id = tbl_transactions.participant_id', 'left');
$this->db->join('tbl_toilet', 'tbl_toilet.toilet_code = tbl_transactions.toilet_code', 'left');
$this->db->where("tbl_transactions.id IN (". $transactions .")");
$this->db->update($this->tbl_transaction, $reimburse);
}
However, I am getting the following error:
A PHP Error was encountered
Severity: 4096
Message: Object of class CI_DB_mysql_result could not be converted to string
Filename: models/transaction_model.php
Line Number: 450
A Database Error Occurred
Error Number: 1064
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1
UPDATE `tbl_transactions` SET `reimburse` = 1 WHERE `tbl_transactions`.`id` IN ()
Filename: C:\xampp\htdocs\ipa\system\database\DB_driver.php
Line Number: 330
What I need to know is why do I get these errors?
The errors mean that your $ids variable is not in a string format (meaning: 1,2,3,4. Its probably an array). To fix it, first find out what format it is on by using print_r($ids) or var_dump($ids). Once you know the format, use PHP functions(such as implode()) to transform it into strings.
IN is looking for a set in the format e.g. (1,2,3,4).
Either make your post values adopt the format 1,2,3,4 so that when the value is included into the query it's valid or if you're sending an array use a method in PHP such as implode(',',$array) to create the desired format for binding into the query..
I have reviewed your both function and found that in both function you put tbl_transactions.id in where clause and ids is passed from post and hence there is no need to call get_these_ids to get ids, you already have ids in post array and hence instead of transactions variable, just use $this->input->post('ids') for reimburse_these functions.
if you surely want to get tbl_transactions from get_these_ids function then you need to use group_concat with group by in query of get_these_ids function and just return that concated id in get_these_ids function then it will work.

ActiveRecord search returns 'Syntax error or access violation' error

In my Yii application, I have a model that represents siteconfig table and have four columns:
integer config_id,
string key,
string value,
string update_time.
I created a model using Gii (to ensure that I will not make any mistakes). I don't publish entire code here, cause this is 100% unmodified by me, standard model code generated by Gii. Since my problem is related to search, I only publish important part of generated code (the search() method):
public function search()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('config_id',$this->config_id);
$criteria->compare('key',$this->key,true);
$criteria->compare('value',$this->value,true);
$criteria->compare('update_time',$this->update_time,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
I'm trying to use generated model in normal Yii ActiveRecord search like that:
$etona = new SiteConfigurationRecord();
$crit = new CDbCriteria();
$crit->select = "value";
$crit->condition = "key=:key";
$crit->params = array(":key"=>"sitename");
$etona = $etona->find($crit);
But, instead of getting expected search results, a strange (for me) error occurs:
CDbCommand failed to execute the SQL statement: SQLSTATE[42000]:
Syntax error or access violation: 1064 You have an error in your SQL
syntax; check the manual that corresponds to your MySQL server version
for the right syntax to use near 'key='sitename' LIMIT 1' at line 1.
The SQL statement executed was: SELECT value FROM siteconfig t
WHERE key=:key LIMIT 1
Where did I go wrong?
You used key for column name, which is a reserved word in MySQL. Yii uses table alias in queries, but does not take any special care in case of reserverd word used as columns names. So, you have to take care of this by yourself.
For example:
$etona = new SiteConfigurationRecord();
$crit = new CDbCriteria();
$crit->select = "value";
$crit->condition = "t.key=:key"; // 't' is default alias
$crit->params = array(":key"=>"sitename");
$etona = $etona->find($crit);
This should solve your problem.
As #Dmitry explained, SQL doesn't allow you to use the column name key. The Yii call in the code in your answer works because Yii performs parameter binding automatically, using names other than reserved words for the parameters. And it also uses fully-qualified column names (prefixes all column name references with <tablename>., regardless of what invalid column name (reserved words) you pass the findByAttributes method.
now it works.. ^^
i just use this code...
$etona = SiteConfigurationRecord::model()->findByAttributes(array('key'=>'sitename'));
maybe i need to study activerecord more somehow...
but still i don't know why the code above doesn't work

Aggregate query with Castle ActiveRecord

I'm trying to perform a simple aggregate query that returns the aggregate's result plus an extra column. This post -> Custom query with Castle ActiveRecord had a good example about how to achieve this, but I can't seem to get it to work. It seems that ActiveRecordMediator.ExecuteQuery returns an ArrayList of objects (instead of ArrayList of object[] which is what I would expect). Also if I try to cast it to ICollection I get a run-time error complaining of invalid cast. Code below, any help appreciated (don't want to use hand-written sql).
HqlBasedQuery query = new HqlBasedQuery(typeof(Something), #"select count(1),
p.Name from Something p
where p.SomeDate > :date
order by p.Name
group by p.Name");
query.SetParameter("date", new DateTime(2009, 1, 1));
var results = from summary in
(ICollection<object[]>)ActiveRecordMediator.ExecuteQuery(query)
select new {
Count = (int)summary[0], Name= (string)summary[1]
};
The line after "from summary in" is the one that throws the invalid cast exception.
(Forgot to mention: using VS2008, .NET 3.5SP1, ActiveRecord 1.0RC3, NHibernate 1.2)
I think you meant count(*) instead of count(1) (this is why you're getting only 1-col rows)
ActiveRecordMediator.ExecuteQuery (at least in RC3) returns an ArrayList (not a generic ICollection) of object[]
Be careful casting count results as int. Some databases return counts as long (e.g. SQL Server)

Resources