I am new to yii. I've created a custom in button in CGridView that has a class of CButtonColumn. I'm just wondering how can I pass parameters that I can add to my php function in my model.
This is my custom button in the table
array(
'class'=>'CButtonColumn',
'template'=>'{approve}, {update},{delete}',
'buttons'=>array(
'approve' => array(
'label'=>'Approve',
'options'=>array(),
'click'=>$model->approveRegistrants("$user_id, $category", array("id"=>$data->user_id , "category"=>$data->category),
)
)
)
and this is my function is
public function approveRegistrants($user_id, $category){
$db = new PDO('mysql:host=localhost; dbname=secret; charset=utf8', 'Andy', '*****');
$getCounter = "SELECT registrants FROM counter order by registrants desc limit 1;";
$bool = false;
$show = '0';
do{
$result = $db->query($getCounter);
// $registrants = $db->query($getCounter);
// $result->setFetchMode(PDO::FETCH_ASSOC);
// $registrants = '1';
foreach ($result as $value){
$registrants = $value['registrants'];
echo 'hello'.$registrants.'</br>';
}
// $registrants = $result['registrants'];
// print_r($registrants);
$max_registrants = '3400';
if($max_registrants > $registrants){
// pdo that will use $updateCounterByOne
$updateCounterByOne = "UPDATE counter set registrants = registrants + 1 WHERE registrants = ". $registrants .";";
$updateCounter = $db->prepare($updateCounterByOne);
$updateCounter->execute();
// return affected rows
$returnAffectedRows = $updateCounter->rowCount();
$bool = true;
// break;
}
else{
echo "No more slot Available";
// break;
}
}while($returnAffectedRows == '0');
if($bool = true){
//sql syntax
$selectApprovedUser = "SELECT user_id FROM registrants WHERE user_id = '". $user_id ."';";
//pdo that will use $selectApprovedUser
$updateApprovedUser = "UPDATE registrants set approved = 'YES' where user_id = ". $selectApprovedUser .";";
$updateApproved = $db->prepare($updateApprovedUser);
$updateApproved->execute();
//pdo that will use $insertApprovedUser
$insertApprovedUser = "INSERT INTO approved_registrants (user_id, category, approved_date) VALUES ('".$user_id."', '".$category."', 'curdate()');";
$insertApproved = $db->prepare($insertApprovedUser);
$insertApproved->execute();
//execute trial
$selectSomething = "SELECT registrants from counter where tandem = '0'";
$doSelect = $db->prepare($selectSomething);
$doSelect->execute();
$hello = $doSelect->fetchAll();
echo $hello[0]['registrants'];
}
}
your issue is that you are bypassing the controller fully here.
buttons column is configured with the following parameters
'buttonID' => array(
'label'=>'...', // text label of the button
'url'=>'...', // a PHP expression for generating the URL of the button
'imageUrl'=>'...', // image URL of the button. If not set or false, a text link is used
'options'=>array(...), // HTML options for the button tag
'click'=>'...', // a JS function to be invoked when the button is clicked
'visible'=>'...', // a PHP expression for determining whether the button is visible
)
See CButtonColumn for details.
As you can see click has to be a js function that will be called on clicking the button. You can rewrite your button like this
array(
'class'=>'CButtonColumn',
'template'=>'{approve}, {update},{delete}',
'buttons'=>array(
'approve' => array(
'label'=>'Approve',
'options'=>array(),
// Alternative -1 Url Method -> will cause page to change to approve/id
'url'=>'array("approve","id"=>$data->id)',
// Alternative -2 Js method -> use 1,2 not both
'click'=>'js:approve()',
)
)
)
in your CGridView configuration you add
array(
....
'id'=>'gridViewID', //Unique ID for grid view
'rowHtmlOptionsExpression'=> 'array("id"=>$data->id)',
)
so that each row has the unique ID, ( you can do the same to a button, but it slightly more difficult as $data is not available there)
in your js function you can do this.
<script type="text/javascript">
function approve(){
id = $(this).parent().parent().attr("id");
<?php echo CHtml::ajax(array( // You also can directly write your ajax
'url'=>array('approve'),
'type'=>'GET',
'dataType'=>'json',
'data'=>array('id'=>'js:id'),
'success'=>'js:function(json){
$.fn.yiiGridView.update("gridViewID",{});
// this will refresh the view, you do some other logic here like a confirmation box etc
}'
));?>
}
</script>
Finally your approve action
class YourController extend CController {
......
public function actionApprove(){
id = Yii::app()->request->getQuery('id');
$dataModel = MyModel::model()->findByPk($id); // This is the model has the $user_id, and $category
....
$OtherModel->approve($dataModel->user_id,$dataModel->category) // if approve is in the same model you can self reference the values of category and user_id directly no need to pass as parameters.
// Do some logic based on returned value of $otherModel->approve()
// return the values from the approve() function and echo from here if required back to the view, directly echoing output makes it difficult to debug which function and where values are coming from .
Yii::app()->end();
}
Related
I am trying to work with cakephp virtualFields in cakephp 1.3. My sql query is as follows but I need day_index (my virtual fields) to be 'DAYOFWEEK(start_date)'.
I need to rewrite a query
$data = $this->Calendar->query("SELECT *, DAYOFWEEK(start_date) as day_index, TIME(start_time) as time
FROM calendars WHERE calendar_category_id =$cal ORDER BY day_index, time");
into this format:
$sqlConditions = array("Calendar.calendar_category_id"=>$cal);
$sqlOrderBy = array("Calendar.day_index", "Calendar.time asc");
$sqlParams = array('conditions'=>$sqlConditions,'order'=>$sqlOrderBy);
$data = $this->Calendar->find('all',$sqlParams);
$this->set('data',$data);
So I'm not sure how to/where to put or declare the virtual field.
$fields = $this->Calendar->virtualFields['day_index'].'AS 'DAYOFWEEK(start_date)';
Found 2 ways to do this, not sure if one is better than the other.
controller edit only method
$sqlFields = array("DAYOFWEEK(Calendar.start_date) as day_index",
"TIME(Calendar.start_time) as time",
"Calendar.start_date",
"Calendar.calendar_category_id",
"Calendar.start_time");
$sqlConditions = array("Calendar.calendar_category_id"=>$cal);
$sqlOrderBy = array("Calendar.day_index, Calendar.time asc");
$sqlParams = array('fields'=>$sqlFields,'conditions'=>$sqlConditions,'order'=>$sqlOrderBy);
$data = $this->Calendar->find('all',$sqlParams);
return $data;
exit();
model method with edits to controller based on this method
Model >
var $virtualFields = array(
'day_index' => "DAYOFWEEK(Calendar.start_date)",
'time' => "TIME(Calendar.start_time)"
);
var $displayIndex = 'day_index';
var $displayTime = 'time';
Controller >
$sqlConditions = array("Calendar.calendar_category_id"=>$cal);
$sqlOrderBy = array("Calendar.day_index, Calendar.time asc");
$sqlParams = array('conditions'=>$sqlConditions,'order'=>$sqlOrderBy);
$data = $this->Calendar->find('all',$sqlParams);
return $data;
exit();
I have this code that would create and populate a table in Yii CGridView.
My problem is the function located in the 'approve'=>array('options'=>array('onclick')) is being called for every refresh of the page even if the approve button isn't clicked.
I determined the mistake occurs by printing the value of the counter. The counter should only increment by 1 when approved is clicked not for every refresh of the page.
<?php $this->widget('zii.widgets.grid.CGridView', array(
'id'=>'registrants-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
'user_id',
'first_name',
'middle_name',
'last_name',
'gender',
'shirt_size',
'receipt_number',
'category',
array(
'class'=>'CButtonColumn',
'template'=>'{approve}, {update},{delete}',
'buttons'=>array(
'approve' => array(
'label'=>'Approve',
'options'=>array(
'onclick'=> $model->approveRegistrants($model->user_id, $model->category),
//ending approve-option array
),
//ending approve-button array
),
//ending buttons array
)
//ending table-last-column array
),
//ending table-columns array
),
//ending zii.widgets.grid.CGridview
));
?>
This is my function in my model.
public function approveRegistrants($user_id, $category){
$db = new PDO('mysql:host=localhost; dbname=secret; charset=utf8', 'Andy', '*****');
$getCounter = "SELECT registrants FROM counter order by registrants desc limit 1;";
$bool = false;
$show = '0';
do{
$result = $db->query($getCounter);
// $registrants = $db->query($getCounter);
// $result->setFetchMode(PDO::FETCH_ASSOC);
// $registrants = '1';
foreach ($result as $value){
$registrants = $value['registrants'];
echo 'hello'.$registrants.'</br>';
}
// $registrants = $result['registrants'];
// print_r($registrants);
$max_registrants = '3400';
if($max_registrants > $registrants){
// pdo that will use $updateCounterByOne
$updateCounterByOne = "UPDATE counter set registrants = registrants + 1 WHERE registrants = ". $registrants .";";
$updateCounter = $db->prepare($updateCounterByOne);
$updateCounter->execute();
// return affected rows
$returnAffectedRows = $updateCounter->rowCount();
$bool = true;
// break;
}
else{
echo "No more slot Available";
// break;
}
}while($returnAffectedRows == '0');
if($bool = true){
//sql syntax
$selectApprovedUser = "SELECT user_id FROM registrants WHERE user_id = '". $user_id ."';";
//pdo that will use $selectApprovedUser
$updateApprovedUser = "UPDATE registrants set approved = 'YES' where user_id = ". $selectApprovedUser .";";
$updateApproved = $db->prepare($updateApprovedUser);
$updateApproved->execute();
//pdo that will use $insertApprovedUser
$insertApprovedUser = "INSERT INTO approved_registrants (user_id, category, approved_date) VALUES ('".$user_id."', '".$category."', 'curdate()');";
$insertApproved = $db->prepare($insertApprovedUser);
$insertApproved->execute();
//execute trial
$selectSomething = "SELECT registrants from counter where tandem = '0'";
$doSelect = $db->prepare($selectSomething);
$doSelect->execute();
$hello = $doSelect->fetchAll();
echo $hello[0]['registrants'];
}
}
What I'm trying to achieve is when approve button is clicked it will get the user_id and will do the PDO commands such as the update and insert.
If you see CButtonColumn, it states that 'options' takes in key-value pairs for the HTML tag attributes. Therefore, you should not place PHP code here like what you did here, unless you want them executed immediately. This is wrong:
'options'=>array(
'onclick'=> $model->approveRegistrants($model->user_id, $model->category),
),
What you want is a TbToggleColumn column from YiiBooster extension to approve/unapprove items:
array(
'class' => 'bootstrap.widgets.TbToggleColumn',
'toggleAction' => 'user/toggleApproved',
'name' => 'isApproved',
'header' => 'Approved?'
),
You will also need a corresponding action in the controller. Don't forget to add 'toggleApproved' to the controller filters. In this example, I have simply inverted the value of a single column, but you may do other stuff with this action.
public function actionToggleApproved($id) {
$model = $this->loadModel($id);
if(!is_null($model) && $model->hasAttribute('isApproved')) {
$model->isApproved = $model->isApproved == 0 ? 1 : 0;
$model->update(); // no validation
}
}
I have this php code which I use getdocuments method which connect to a web service, I pass the limit , pageNumber and optional filter array and it returns an array of data in addition to the total count of records and page number
I want to display the result in jqgrid, I want to bring for example 20 records and when user go the next page, bring the next 20 records.
<?php
//ini_set("display_errors","1");
require_once 'grid/jq-config.php';
// include the jqGrid Class
require_once "grid/jqGrid.php";
// include the driver class
require_once "grid/jqGridArray.php";
// include the calendar
require_once "grid/jqCalendar.php";
// include the document class
require_once "lib/document.php";
// include heler.php which contain some helper functions
require_once "lib/helper.php";
// create the array connection
$conn = new jqGridArray();
// Create the jqGrid instance
$grid = new jqGridRender($conn);
// prepare array that contains fileds name which user can filter on
$fields = array("BatchNumber", "SenderCode","ReceiverCode","DocumentNumber","DocumentType","InResponse","SubmitDate");
if(get_magic_quotes_gpc()){
$d = stripslashes($_REQUEST["filters"]);
}else{
$d = $_REQUEST["filters"];
}
$d = json_decode($d);
for($i = 0; $i < count($d->rules); $i++){
foreach ($fields as $value) {
if($d->rules[$i]->field == $value){
$option[$value] == $d->rules[$i]->data;
}
}
}
if(isset($_GET["page"])){
$option["PageNumber"] = $_GET["page"];
}
else{
$option["PageNumber"] = 1;
}
if(isset($_GET["rows"])){
$option["Limit"] = $_GET["rows"];
}
else{
$option["Limit"] = LIMIT_DOCUMENT;
}
$results = Document::getDocuments($option);
$arrResult = _object_to_array($results);
$documents = $arrResult["Documents"]["DocumentDataModel"];
$totalCount = $arrResult["TotalCount"] ;
$totalPages = ceil($totalCount/ $option["Limit"]);
// Always you can use SELECT * FROM data1
$grid->SelectCommand = "SELECT BatchNumber, SenderCode ,ReceiverCode , DocumentNumber, DocumentType, InResponse, SubmitDate,LastModifiedDate FROM documents";
$grid->dataType = 'json';
$grid->setPrimaryKeyId('BatchNumber');
$grid->setColModel();
//enable subgrid
// Set the parameters for the subgrid
$grid->setSubGrid("subgrid_document_attachments.php",
array('File Name'),
array(60),
array('left'));
// Enable toolbar searching
$grid->toolbarfilter = true;
$grid->setFilterOptions(array("stringResult"=>TRUE));
$grid->setUrl('grid_documents.php');
$grid->setGridOptions(array(
"width" => 1124,
"height" => 400,
"rowList"=>array(10,20,30,40,50,100),
"sortname"=>"id",
"caption" => "Documents",
"total" => $arrResult["TotalPages"],
"records" => $arrResult['TotalCount'],
"page" => $arrResult['PageNumber'],
));
$grid->setColProperty("BatchNumber", array("label"=>"Batch Number"));
$grid->setColProperty("SubmitDate", array(
"formatter"=>"date",
"formatoptions"=>array("srcformat"=>"Y-m-d H:i:s","newformat"=>"m/d/Y")
)
);
// format the last modified date
$grid->setColProperty("LastModifiedDate", array(
"formatter"=>"date",
"formatoptions"=>array("srcformat"=>"Y-m-d H:i:s","newformat"=>"m/d/Y")
)
);
// add date picker to submit date
$grid->setDatepicker("SubmitDate",array("buttonOnly"=>FALSE));
$grid->datearray = array('SubmitDate');
// Enable navigator
$grid->navigator = true;
// Enable search
$grid->setNavOptions('navigator', array("excel"=>TRUE,"add"=>false,"edit"=>false,"del"=>false,"view"=>false,"csv"=>FALSE, "pdf"=>false));
// Activate single search
$grid->setNavOptions('search',array("multipleSearch"=>false));
// Enjoy
$grid->renderGrid('#grid','#pager',true, null, null, true,true);
?>
I inspected the http request by firebug, {"records":20,"page":1,"total":1}, and grid just display 20 records with 1 page. I want to it to display 20 records and enable pagination so I can press next and bring the next 20 records. I want these values to be something like {"total":"56","page":"1","records":"560"
jqGrid will pass all the information to your web service you will need to retrieve the correct page of data you need to display. The sort index (sidx), sort order (sord), page (page) and rows (rows).
You controller/web service can get this information and then grab the appropriate data from your dataset.
public ActionResult getGridData(string sidx, string sord, int page, int rows, bool _search, string filters) {
...
var pagedDataset = fullDataset.OrderBy(sidx + " " + sord).Skip((page - 1) * rows).Take(rows);
//then format the pagedDataset for the jqGrid and pass it back.
I am new to SugarCRM. I've created a custom field named 'account name' in the Meetings module so that if we select Contacts from related to field, the 'account name' of that Contact is automatically added to the field.
Here's my code:
$hook_array['after_retrieve'] = Array();
$hook_array['after_retrieve'][] = Array(1, 'Add custom account',
'custom/modules/Meetings/AddAccount.php','AddAccount', 'addAcc');
LogicHook:
class AddAccount
{
public function addAcc(&$bean, $event, $arguments)
{
global $current_user;
global $db;
echo "<pre>";
$meeting_id = $_REQUEST['record'];
$query = "SELECT * FROM `meetings_contacts` WHERE `meeting_id` LIKE '$meeting_id'";
$result = $bean->db->query($query, true, " Error filling in additional detail fields: ");
if ($bean->db->getRowCount($result) > 0) {
while ($row = $bean->db->fetchByAssoc($result)) {
$contact_id = $row['contact_id'];
}
if (isset($contact_id)) {
$query1 = "SELECT * FROM `accounts_contacts` WHERE `contact_id` LIKE '$contact_id'";
$result1 = $bean->db->query($query1, true, " Error filling in additional detail fields: ");
while ($row1 = $bean->db->fetchByAssoc($result1)) {
$account_id = $row1['account_id'];
}
$query2 = "SELECT * FROM `accounts` WHERE `id` LIKE '$account_id'";
$result2 = $bean->db->query($query2, true, " Error filling in additional detail fields: ");
while ($row2 = $bean->db->fetchByAssoc($result2)) {
$account_name = $row2['name'];
}
$update_custom_account = "UPDATE `meetings_cstm` SET `accountname_c` = '$account_name' WHERE `meetings_cstm`.`id_c` = '$meeting_id';";
$Change = $bean->db->query($update_custom_account);
}
}
}
}
The problem is that the field is getting added but the "i" in the ListView has stopped working. Is there a simpler way than this long query?
Thanks in advance.
This is a better way of doing the above.
custom/modules/Meetings/logic_hooks.php
// position, file, function
$hook_array['after_retrieve'] = Array();
$hook_array['after_retrieve'][] = Array(1, 'Add custom account', 'custom/modules/Meetings/AddAccount.php', 'AddAccount', 'getAccountName');
$hook_array['after_save'] = Array();
$hook_array['after_save'][] = Array(1, 'Add custom account', 'custom/modules/Meetings/AddAccount.php', 'AddAccount', 'getAccountName');
custom/modules/Meetings/AddAccount.php
class AddAccount {
public function getAccountName(&$bean, $event, $arguments) {
if ($bean->parent_type == 'Contacts') {
$contact = BeanFactory::getBean('Contacts', $bean->parent_id);
$contact->load_relationship('accounts_contacts');
$account = BeanFactory::getBean('Accounts', $contact->account_id);
$bean->account_name_c = $account->name;
}
}
}
This way, you are using the bean and not SQL.
EDIT:
To add the new field, you can create this fileā¦
custom/Extension/modules/Meetings/Ext/Vardefs/account_name_c.php
<?php
$dictionary['Meeting']['fields']['account_name_c'] =
array (
'name' => 'account_name_c',
'vname' => 'LBL_ACCOUNT_NAME_C',
'type' => 'varchar',
'len' => '255',
'unified_search' => true,
'comment' => 'Account name for meeting',
'studio' => 'true',
);
Then after a Repair/Rebuild, go to Studio > Meetings > Layouts > ListView and drag/drop the new field from 'Hidden' to 'Default.' Select the 'Save & Deploy' button, and after saving the Meeting record, your account name will appear in the list view.
I have an image upload that adds the filename to a table called attachments. If the id already exists then I want it to update and if not then create a new record. At the moment it creates a new record so I have multiple records forthe one id. The id's are from a table called Addon's.
I am not sure how to do this in cakephp.
if (!empty($this->data)) {
$this->layout = null;
//if(empty($this->data['AddOn']['id'])){unset($this->data['AddOn']);}
// restructure data for uploader plugin // NEED TO GET RID OF THIS ? MOVE IT
$tmp_file = $this->data['Attachment'][0]['file'];
$tmp_file['extension'] = array_reverse(explode('.', $tmp_file['name']));
$tmp_file['extension'] = $tmp_file['extension'][0];
$tmp_file['title'] = strtolower(substr($tmp_file['name'],0,(0-strlen('.'.$tmp_file['extension']))));
$this->data['Attachment'][0]['alternative'] = ucwords(str_replace('_',' ', $tmp_file['title']));
$previous = $this->AddOn->Attachment->find('first', array('conditions'=> array('model'=>'AddOn', 'foreign_key'=>$id)));
if( !empty( $previous ) ) {
$this->AddOn->Attachment->id = $previous[ 'Attachment' ][ 'id' ];
}
if ($this->AddOn->save($this->data, array('validate' => 'first'))) {
$id = $this->AddOn->Attachment->getLastInsertID();
$att = $this->AddOn->Attachment->query("SELECT * from attachments WHERE id = ".$id);
$this->set('attachment',$att[0]['attachments']);
} else {
$tmp_file['name'] = 'INVALID FILE TYPE';
}
//debug($this->data);
$this->set('file', $tmp_file);
$this->RequestHandler->renderAs($this, 'ajax');
$this->render('../elements/ajax');
}
save() and saveAll() automatically update an existing row if the id has been set. You can do something like:
$previous = $this->AddOn->Attachment->find( /* whatever conditions you need */ );
if( !empty( $previous ) ) {
$this->AddOn->Attachment->id = $previous[ 'Attachment' ][ 'id' ];
}
Now the old record will be updated if it exists.
As a side note, the code after a successful saveAll() doesn't make much sense: first you're saving data to the database, then immediately retrieving it again. You can just keep using $this->data that already has the same content.
And another side note: you should use query() only as a last resort when you can't use Cake's other methods. query("SELECT * from attachments WHERE id = ".$id) is a trivial case that can be rewritten as $this->Model->id = $id; $this->Model->read(); or using a simple $this->Model->find() query.