How to fix Grid->addQuickSearch() + Field_Callback error? - atk4

It seems that Grid->addQuickSearch() method does not work will Field_Callback.
I have the following model:
class Country extends \AppAtk4\MyModel {
public $title_field = 'calc_title';
public function init() {
parent::init();
$this->addField('iso_code', ['type' => 'string', 'required' => true]); // ISO 3166-1 alpha-2
$this->addField('name', ['type' => 'string', 'required' => true]);
$this->addExpression('calc_title', ['CONCAT([iso_code], \' - \', [name])', 'type' => 'string', 'read_only' => true, 'ui' => ['visible' => false]]);
}
}
And Grid with search input inicialized by this code:
$crud->setModel($model);
// add quick search
$searchFields = [];
foreach ($model->elements as $name => $element) {
if (!$element instanceof \atk4\data\Field) {
continue;
}
$searchFields[] = $name;
}
$crud->addQuickSearch($searchFields);
$crud->quickSearch->owner->add(new \atk4\ui\FormField\Input(['inputType' => 'Hidden', 'short_name' => 'crud_model', 'content' => get_class($model)]));
Then when I open the Grid, write some search text and press Search, the following Exception is fired:
atk4\dsql\Exception: DSQL got Exception when executing this query
Exception Parameters
error: "SQLSTATE[42S22]: Column not found: 1054 Unknown column 'field_sql' in 'where clause'"
query: "select count(*) from `fromatk4_country` where (`id` like '%s%' or `created_at` like '%s%' or `notes` like '%s%' or `iso_code` like '%s%' or `name` like '%s%' or (CONCAT(`iso_code`, ' - ', `name`)) like '%s%' or `field_sql` like '%s%')"
It seems there is a wrong column name in the SQL query (field_sql). This problem came up one I upgraded to the atk4/data 1.3.5 from some version from last year.
Is this a bug or should/can I inicialize the search fields differently?
I also opened a issue in the project repo: https://github.com/atk4/data/issues/329

My guess is that this extra field is added by something. Perhaps you're using "$grid->addColumn". In the past this used to add a new decorator for existing fields, now it would add a non-existant field.
It does not seem as your code adds it, so perhaps there is something else. Try commenting things out and using foreach without Grid/CRUD to see if that field is still there.

Related

Yii Relational Query with 'through'

Good evening,
In this page (http://www.yiiframework.com/doc/guide/1.1/en/database.arr#relational-query-with-through) it's described how to get all comments for all users of a particular group using 'through':
class Group extends CActiveRecord
{
...
public function relations()
{
return array(
'roles'=>array(self::HAS_MANY,'Role','group_id'),
'users'=>array(
self::HAS_MANY,'User',array('user_id'=>'id'),'through'=>'roles'
),
'comments'=>array(
self::HAS_MANY,'Comment',array('id'=>'user_id'),'through'=>'users'
),
);
}
}
How can I do exactly the opposite? That is, get the group of the user who made a particular comment (Comment Model basically).
So far, I'm not even able to reach 'role' table:
'user' => array(self::BELONGS_TO, 'User', 'user_id'),
'roles'=>array(self::HAS_MANY, 'Role', array('id'=>'user_id'), 'through' => 'user') // shouldn't it join User.id to Role.user_id ?
It's raising the following error: 'Column not found: 1054 Unknown column 'user.user_id' in 'where clause'. And it seems related to the first line, not the second...
Any ideas?
Sincerely,
Apidcloud
As you want to get the group of the user who made a particular comment. You have to add these relation in the comment model.
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'user' => array(self::BELONGS_TO, 'User', 'user_id'),
'roles'=>array(
self::HAS_ONE,'Role',array('id'=>'user_id'),'through'=>'user'
),
'group'=>array(
self::BELONGS_TO,'Group','group_id','through'=>'roles'
)
);
}
And view file you can get group name like this.
<?php echo CHtml::encode($data->group->name); ?>
Hope this will help you.

"Error: SQLSTATE[42S22]: Column not found: 1054" when using a custom primary key in CakePHP 2.x

I'm trying to build a drop-down list in CakePHP 2.x with the following code:
Controller
$Propertytype=$this->Propertytype->find("list",array("fields" => array("Propertytype.propertytype_id,Propertytype.propertytype_name,Propertytype.propertytype_id"),"order" => array("Propertytype.propertytype_id" => "desc"),"conditions" => array("Propertytype.propertytype_status" => "0")));
$this->set("propertytype",$Propertytype);
View
<?php echo $this->Form->input("propertytype",array("class"=>"form-control","data-style"=>"btn-white",
"data-live-search"=>"true","label"=>false,"data-size"=>"5","required"=>"required","options"=>$propertytype));
?>
I am not using Propertytype.id as primary key. I renamed it to Propertytype.Propertytype_id. But when I run the query, it's asking for Propertytype.id.
Database Error
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Propertytype.id' in 'field list'
How can I change it to Propertytype.property_id as option value?
You have to define $primaryKey in class Propertytype:
class Propertytype extends AppModel
{
public $primaryKey = 'property_id';
}
You also have to write your query using the right syntax:
$Propertytype=$this->Propertytype->find("list",array(
"fields" => array(
"Propertytype.propertytype_id",
"Propertytype.propertytype_name"
),
"order" => array("Propertytype.propertytype_id" => "desc"),
"conditions" => array("Propertytype.propertytype_status" => "0")
));
You forgot the quotes.

How do I load associated models and save related data in CakePHP?

I am setting up a user/group system that allows users to send requests to join a group.
I can't seem to load the associated model and add a row. It's really really really difficult to resist the urge to just use $this->query() and be done with it... but I'm trying to learn the Cake conventions and do things the right way.
In my group model's function for handling group join requests:
$this->loadModel('GroupRequest');
$this->data = array('GroupRequest' =>
array('user_id' => $uid, 'group_id' => $gid));
if($this->GroupRequest->save($this->data)){ echo 'save success'; }
else { echo 'save fail'; }
Here are the errors I get when I run this:
Warning (512): SQL Error: 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 'loadModel' at line 1 [CORE/cake/libs/model/datasources/dbo_source.php, line 684]
Query: loadModel
Notice (8): Undefined property: Group::$GroupRequest [APP/models/group.php, line 124]
Fatal error: Call to a member function save() on a non-object in /home/wxworksmat/sspot3/app/models/group.php on line 124
I also tried using App::import:
App::import('Model','GroupRequest');
I don't get any SQL errors importing the Model this way, but it still doesn't work. I get the following error on the save() or create() call:
Fatal error: Call to a member function save() on a non-object in /home/wxworksmat/sspot3/app/models/group.php on line 124
You are confusing controller and model methods
$this->loadModel()
is a controller method and can only be used there.
You should always use
$this->ModelName = ClassRegistry::init('ModelName');
everywhere else
I might be wrong, and please excuse me if I'm wrong, but it looks like you don't understand the concept of the framework very well. It is difficult to answer your question without giving you a complete tutorial.
This said, everything relies on model associations. If it's done correctly, things are getting easy. You should read:
Associations: Linking Models Together
Once you have your models correctly linked, you will be able to save the primary model, as well as the related model, very easily.
Saving Related Model Data (hasOne, hasMany, belongsTo)
As I understand, you are trying to do this from inside a model?
class GroupRequest extends AppModel {
public function associate($user, $group) {
$data["GroupRequest"] = array("user_id" => $user, "group_id" => $group);
$this->save($data);
}
}
Then in your Controller (assuming group_requests_controller)
$this->GroupRequest->associate($user, $group);
If you're calling this from another controller you would loadModel first
$this->loadModel("GroupRequests");
$this->GroupRequest->associate($user, $group);
However, if you're doing all of this from within GroupRequests controller you should be able to save directly, without making a separate method for it
public function add() {
$this->GroupRequest->create();
$this->GroupRequest->save($this->data); #for < 2.0
}
Your view should be something like
<?php
echo $this->Form->create("GroupRequest");
echo $this->Form->input("user_id");
echo $this->Form->input("group_id");
echo $this->Form->end("Submit");
?>
The problem I had was that I didn't have the correct model association declarations at the top of my model.
Now I have:
group.php
var $hasMany = 'GroupRequest';
group_request.php
var $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Group' => array(
'className' => 'Group',
'foreignKey' => 'group_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
public function new_request($user, $group) {
$data["GroupRequest"] = array("user_id" => $user, "group_id" => $group, 'status' => 'pending');
if($this->save($data)){ return true;} else {return false;}
}
Now because everything is set up CORRECTLY... I can do this in my group.php model:
$this->GroupRequest->new_request($uid,$gid)
As an added bonus, because the assocations are populating properly, when I do $this->find in my group or user model, now all the related GroupRequest entries show up. Bonus data FTW.

Search API Solr integration with fivestar (or similar) rating system (fascet and sort)

I'm attempting to sort nodes by ratings using the Search API faceted search with Solr integration. I've already set up fivestar ratings (about 9 per node, its a large multi-axis rating system.) but i'm unable to index these ratings!
Can someone help me understand how to change this so I can use a facet search for ratings?
Otherwise, are there any recommendations on other modules (aside from fivestar) which would allow the votes to be indexed?
Thank you!
Justin
first you need install facetapi module -that's for facets.
second, on hook_update_index, you need to add rating to apachesolr index
<?php function module_apachesolr_update_index(&$document, $node) {
//add additional offers;
if (count($node->field_add_offers)) {
$field = $node->field_add_offers;
foreach ($field as $lang => $values) {
foreach ($values as $value) {
if (isset($value['value'])) {
$document->setMultiValue('sm_offers', $value['value']);
}
}
}
}
} ?>
Please note, it's just an example. I run 2 loops because of multilingual site and problem with this "und" key in field array. Here also you can not add all ratings, but calculate, for instance,one modifier per node, which will be used for sorting (if you don't have that one in ratings)
Third, add facets with using hook_facetapi_facet_info
<?php function module_facetapi_facet_info(array $searcher_info) {
return array(
'sm_games_facet' => array(
'name' => 'sm_games_facet',
'label' => t('games'),
'description' => t('Filter games'),
'field' => 'sm_games',
'field alias' => 'game',
'query type' => 'term',
'default widget' => 'facetapi_links',
'allowed operators' => array(FACETAPI_OPERATOR_OR => TRUE, FACETAPI_OPERATOR_AND => TRUE),
'default sorts' => array(
array('display', SORT_ASC),
),
)
);
} ?>
more about facets you can find at facetapi.api.php file;
Forth - reindex content and enable facet in apachesolr settings.
Regards, Slava

how to create a chain select form in cakephp

My business directory application calls for 3 chained select boxes, and I'm using cakephp to build this application.
The hierarchy and order of choices for the sections is this:
1 - business group
2 - business type
3 - city (included in table customer)
The relationships are:
customer HABTM business types
business groups have many business types
business types have one business group, HABTM customers
I have searched for jquery plugins that help with this, and found one by Remy Sharp, but it doesn't have the more complex relationships I have.
http://remysharp.com/2007/09/18/auto-populate-multiple-select-boxes/
What I imagine happening is the first selection box (business groups) is pre-populated and once a selection is made, an event listener send a message that filters the second selection box, and the same for the third.
What I don't know is how to structure the search action based on the event listener.
Any advice or am I way off base?
As always, I come to the well for help.
Much appreciated.
Paul
Thanks very much Nick, I've read many of your posts I really appreciate your response.
I've followed your instructions but have run into problems. I've tried my best to resolve them but haven't figured it out.
This is what I've done so far:
1) created 'chained' actions in both the business_type and business_directory (renamed customer to business directory, which is more appropriate.)
business type chained action:
function chained($business_group_id) {
$business_types = $this->BusinessType->find('list', array(
'conditions' => array( 'BusinessType.business_group_id' => $business_group_id)
));
$this->set('business_types', $business_types);
}
business directory chained action:
function chained($business_type_id) {
$business_directories = $this->BusinessDirectory->bindModel(array( 'hasOne' => array('business_directories_business_types' )));
$business_directories = $this->BusinessDirectory->find('all', array(
'fields' => array( ' BusinessDirectory.city'),
'conditions' => array( 'business_directories_business_types.business_type_id' => $business_type_id)
));
$this->set('business_directories', $business_directories);
}
I did find that with a HABTM relationship, using find 'list' didn't create the join query, whereas find 'all' did.
2) I then created a search action in the business directory and corresponding view.
For the business groups I created a getList action to populate the option list in the search form:
function getList() {
return $this->BusinessGroup->find('list');
}
In the search view, I've added the javascript for the chain select:
<script type="text/javascript">
<!--
$(function () {
var group = $('#businessGoup');
var type = $('#businessType');
var city = $('#businessDirectoryCity');
type.selectChain({
target: city,
url: '../business_directories/chained/'+$(this).val(),
data: { ajax: true, anotherval: "anotherAction" }
});
group.selectChain({
target: type,
url: '../business_types/chained/'+$(this).val()
}).trigger('change');
});
//-->
</script>
And the form:
create('business_directories', array('action'=>'/search_results')); ?>
input('business_group_id',
array( 'type' => 'select',
'id' => 'businessGoup',
'empty' => '-- Select Business Group --',
'multiple' => true,
'options' => $this->requestAction('/business_groups/getList' ),
'label' => 'Business Group'));
?>
input('business_type.id',
array( 'type' => 'select',
'id' => 'businessType',
'empty' => '-- Select Business Type --',
'multiple' => true,
'options' => 'none selected',
'label' => 'Business Type'));
?>
input('business_directories.id',
array( 'type' => 'select',
'id' => 'businessDirectoryCity',
'empty' => '-- Select City --',
'multiple' => true,
'options' => 'options',
'label' => 'City'));
?>
end('Search'); ?>
When I test the business type chain function, /business_types/chained/1, everything works.
But when I test the search view, I get a javascript alert error. Then when I check firebug, I get the following two errors:
Warning (2): Missing argument 1 for BusinessTypesController::chained() [APP\controllers\business_types_controller.php, line 71]
Notice (8): Undefined variable: business_group_id [APP\controllers\business_types_controller.php, line 73]
Any additional help with this is very much appreciated.
Thanks, Paul
What you need is to have 2 actions in the controllers (business_type and customer).
each action should look like this. In that case for the business type
function chained($parent_id){
$business_types = $this->BusinessType->find('list', array('conditions'=>'BusinessType.business_group_id'=>$parent_id));
$this->set('business_types', $business_types);
}
of course you need also view for that action which will format the values in the proper format for the chained select.
For Business group you need to show all values directly so no ajax is needed.
The Customer controller's action is similar, but you need to select cities of all related customers.
Then with the chained select you need to set the proper elements and set the proper actions which need to be called.
i.e.:
$('#id-of-the-business-group').selectChain({
target: $('#id-of-the-business-type-field'),
url: '/business_types/chained/'+$(this).val()
});

Resources