I'm trying to chain two named_scopes in my User model.
The first:
named_scope :commentors, lambda { |*args|
{ :select => 'users.*, count(*) as total_comments',
:joins => :comments,
:conditions => { :comments => { :public_comment => 1, :aasm_state => 'posted', :talkboard_user_id => nil} },
:group => 'users.id',
:having => ['total_comments > ?', args.first || 0],
:order => 'total_comments desc' }
}
The second:
named_scope :not_awarded_badge, lambda { |badge_id|
{ :include => :awards,
:conditions => [ "? not in (select awards.badge_id from awards where awards.user_id = users.id)", badge_id ]
}
}
I am trying to chain the two like this:
User.commentors(25).not_awarded_badge(1)
However, I get the following error:
Mysql::Error: Unknown column 'total_comments' in 'order clause': SELECT `users`.`id`...
How can I resolve this issue?
change
:order => 'total_comments desc'
to
:order => 'count(*) desc'
it should like
named_scope :commentors, lambda { |*args|
{ :select => 'users.*, count(*) as total_comments',
:joins => :comments,
:conditions => { :comments => { :public_comment => 1, :aasm_state => 'posted', :talkboard_user_id => nil} },
:group => 'users.id',
:having => ['total_comments > ?', args.first || 0],
:order => 'count(*) desc' }
}
Related
I have 3 Entities:
Appointment
Doctor (extend fe_users)
Specialization
Dependencies:
Each appointment has exactly one doctor
Each doctor has at least one specialization
Each appointment has at least one specialization - but it can't be
one that its doctor doesn't have
My goal: After a doctor is selected you can choose which specialization of the doctor will be used in order to categorize the appointment - but multiselect should also be possible.
Edit: I came up with this sql to make it clearer what I want in my Select-Field:
SELECT s.name
FROM
tx_appointments_domain_model_specialization s,
fe_users fe,
tx_appointments_doctor_specialization_mm ds,
WHERE fe.username = "###REC_FIELD_doctor###"
AND ds.uid_local = fe.uid
AND s.uid = ds.uid_foreign;
So the part of my TCA of Appointment looks like this now:
It's pretty much all generated by the extension builder except the 'foreign_table_where' in doctor which I found out somehow. But I can't wrap my head around how to set the specialization now.
'doctor' => array(
'exclude' => 1,
'label' => 'doctor',
'config' => array(
'type' => 'select',
'foreign_table' => 'fe_users',
'foreign_table_where' => "AND FIND_IN_SET('1', fe_users.usergroup) ORDER BY fe_users.last_name ASC, fe_users.first_name ASC",
'minitems' => 0,
'maxitems' => 1,
),
),
'specialization' => array(
'exclude' => 1,
'label' => 'specialization',
'config' => array(
'type' => 'select',
'foreign_table' => 'tx_appointments_domain_model_specialization',
'MM' => 'tx_appointments_appointment_specialization_mm',
'size' => 10,
'autoSizeMax' => 30,
'maxitems' => 9999,
'multiple' => 0,
'wizards' => array(
'_PADDING' => 1,
'_VERTICAL' => 1,
'edit' => array(
'module' => array(
'name' => 'wizard_edit',
),
'type' => 'popup',
'title' => 'Edit',
'icon' => 'edit2.gif',
'popup_onlyOpenIfSelected' => 1,
'JSopenParams' => 'height=350,width=580,status=0,menubar=0,scrollbars=1',
),
'add' => Array(
'module' => array(
'name' => 'wizard_add',
),
'type' => 'script',
'title' => 'Create new',
'icon' => 'add.gif',
'params' => array(
'table' => 'tx_appointments_domain_model_appointment',
'pid' => '###CURRENT_PID###',
'setValue' => 'prepend'
),
),
),
),
),
I know I could use something like 'foreign_table_where' => ..."###REC_FIELD_doctor###"... but I have no idea how the whole SQL should look like to get only the doctor's specializations showing.
And I'll probably have to add something like this in ext_tables.php which I got from this answer similar to my problem:
$TCA['tx_appointments_domain_model_appointment']['ctrl']['requestUpdate'] .= ',doctor';
//in my model
public function initialize (array $config)
{
$this->addBehavior('Timestamp');
$this->belongsTo('Users');
}
//in my controller
$query = $this->Articles->find('all')->contain(['users']);
/src/Controller/ArticlesController.php (line 39)
object(Cake\ORM\Query) {
'sql' => 'SELECT Articles.id AS `Articles__id`, Articles.title AS `Articles__title`, Articles.body AS `Articles__body`, Articles.created AS `Articles__created`, Articles.modified AS `Articles__modified`, Articles.is_delete AS `Articles__is_delete`, Articles.user_id AS `Articles__user_id`, Users.id AS `Users__id`, Users.username AS `Users__username`, Users.password AS `Users__password`, Users.role AS `Users__role`, Users.created AS `Users__created`, Users.modified AS `Users__modified` FROM articles Articles LEFT JOIN users Users ON Users.id = (Articles.user_id)',
'params' => [],
'defaultTypes' => [
'Articles.id' => 'integer',
'id' => 'integer',
'Articles.title' => 'string',
'title' => 'string',
'Articles.body' => 'text',
'body' => 'text',
'Articles.created' => 'datetime',
'created' => 'datetime',
'Articles.modified' => 'datetime',
'modified' => 'datetime',
'Articles.is_delete' => 'integer',
'is_delete' => 'integer',
'Articles.user_id' => 'integer',
'user_id' => 'integer'
],
'decorators' => (int) 0,
'executed' => false,
'hydrate' => true,
'buffered' => true,
'formatters' => (int) 0,
'mapReducers' => (int) 0,
'contain' => [
'users' => []
],
'matching' => [],
'extraOptions' => [],
'repository' => object(App\Model\Table\ArticlesTable) {
'table' => 'articles',
'alias' => 'Articles',
'entityClass' => 'App\Model\Entity\Article',
'associations' => [
(int) 0 => 'users'
],
'behaviors' => [
(int) 0 => 'Timestamp'
],
'defaultConnection' => 'default',
'connectionName' => 'default'
}
}
You are debugging the query and not the result. To see the contents you can try:
debug($query->toArray())
I'm trying to save some data using HasAndBelongsToMany relations.
Here are my tables :
commercials:
id (int) AI
name (varchar)
showrooms:
id (int) AI
name (varchar)
commercials_showrooms:
id (int) AI
commercial_id (int)
showroom_id (int)
And my models :
class Showroom extends AppModel
{
public $hasAndBelongsToMany = array(
'Commercial',
);
}
class Commercial extends AppModel
{
public $hasAndBelongsToMany = array(
'Showroom'
);
}
I'm trying to save data (hard coded for now) this way :
$this->loadModel('Showroom');
$this->Showroom->saveAll(array(
'Showroom' => array(
'id' => 1
),
'Commercial' => array(
'name' => 'test'
)
));
saveAll() returns (bool)true, however, nothing is saved in database.
How can I fix this ?
Did you read the section on "Saving Related Model Data (HABTM)" in the CakePHP book?
It suggests a different format than you're using for your data.
to test your table if is working try this in your controller:
$this->loadModel('CommercialsShowroom');
$CommercialsShowroom = array('CommercialsShowroom'=>array(
'commercial_id'=>your_value,
'showroom_id'=>your_value));
$this->CommercialsShowroom->create();
if ($this->CommercialsShowroom->save($CommercialsShowroom, false)){
var_dump('It is saved');
}
and for Model configuration read Dave link for more information
//CommercialsShowroom model:
var $belongsTo = array(
'Commercial' => array(
'className' => 'Commercial',
'foreignKey' => 'commercial_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Showroom' => array(
'className' => 'Showroom',
'foreignKey' => 'showroom_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
//Showroom model:
var $hasAndBelongsToMany = array(
'Commercial' => array(
'className' => 'Commercial',
'joinTable' => 'commercials_showrooms',
'foreignKey' => 'commercial_id',
'associationForeignKey' => 'showroom_id',
'unique' => true,
)
);
//Commercial model:
var $hasAndBelongsToMany = array(
'Showroom' => array(
'className' => 'Showroom',
'joinTable' => 'commercials_showrooms',
'foreignKey' => 'showroom_id',
'associationForeignKey' => 'commercial_id',
'unique' => true,
)
);
I wish to do some optimizations on my SQL queries.
Without doing a performance test for it, what query is the most time-consuming ? I am almost sure they return the same result.
!MyClass.find(:first, :conditions => c).nil?
MyClass.count(:conditions => c) > 0
MyClass.count(:conditions => c, :limit => 1) > 0
Regards
You can test it for your own. Writing a performance test with less then 15 lines of code. For more information:
http://guides.rubyonrails.org/performance_testing.html
I ask the question because I thought the answer was an evidence. It appears not.
So I do some average time for several queries. Here is the result, ordered by time :
.count(:conditions => c, :limit => 1) > 0;
=> 0.042037
.count(:conditions => c) > 0
=> 0.037781
.count(:select => '1', :conditions => c) > 0
=> 0.035976
.count(:select => '1', :conditions => c, :limit => 1) > 0
=> 0.034157
.find(:first, :conditions => c).nil?
=> 0.000377
.find(:first, :select => '1', :conditions => c).nil?
( equivalent to .exists?(c) )
=> 0.000184
The last one is the most efficient. Thanks for the tip of :select => '1' !
I can get my find to work any other way, but I cannot get this working with pagination. What am I doing wrong?
Output in view:
SQL Error: 1054: Unknown column 'fields' in 'where clause'
Warning (2):** Cannot modify header information - headers already sent by (output started at...
Controller Action:
...
$cond = array(
'fields' => array('id', 'name', 'provider_network_url', 'application_url'),
'conditions' => array('PlanDetail.id' => $id),
'contain' => array(
'Company' => array('fields' => array(
'id',
'name',
'company_logo_url',
'plan_detail_by_company_landing')),
'Plan' => array('fields' => array('id', 'monthly_cost'),
'Applicant' => array('fields' => array('id', 'name')),
'Age' => array('fields' => array('id', 'name')),
'State' => array('fields' => array('id', 'name')),
'Zip' => array('fields' => array('id', 'title')),
'PlanDetail' => array('fields' => array('id', 'name')),
)));
$planDetails = $this->paginate('PlanDetail', $cond);
$this->set(compact('planDetails', $planDetails));
...
$this->paginate = array(
'fields' => ....,
'conditions' => ....,
'contain' => array(
'Company' => ...,
'Plan' => ....));
$this->set('planDetails', $this->paginate()));