Events and Full Calendar in CakePHP - cakephp

I set the FullCalendar plugin in CakePHP, i can see it, it's displayed, i'm trying to put the events from my PHP Controller (the view admin feed) to my Full Calendar Plugin . I don't know what's wrong , no events are displayed in my calendar . I will be thankfull if someone can find why my calandar is empty .
Look the screen, this is what i have in my console :
The answer is NULL .
The JS file :
// JavaScript Document
$(document).ready(function() {
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
defaultView: 'agendaWeek',
firstHour: 8,
weekMode: 'variable',
aspectRatio: 2,
editable: true,
events: {
url: FcRoot + '/events/feed',
color: 'yellow', // an option!
textColor: 'black', // an option!
},
eventRender: function(event, element) {
///
}
});
});
EventsController
// The feed action is called from JS to get the list of events (JSON)
public function admin_feed($id=null) {
$this->layout = "ajax";
$vars = $this->params['url'];
$conditions = array('conditions' => array('UNIX_TIMESTAMP(start) >=' => $vars['start'], 'UNIX_TIMESTAMP(start) <=' => $vars['end']));
$events = $this->Event->find('all', $conditions);
foreach($events as $event) {
if($event['Event']['all_day'] == 1) {
$allday = true;
$end = $event['Event']['start'];
} else {
$allday = false;
$end = $event['Event']['end'];
}
$data[] = array(
'id' => $event['Event']['id'],
'title'=>$event['Event']['title'],
'start'=>$event['Event']['start'],
'end' => $end
);
}
$this->set("json", json_encode($data));
}
In View/Events/admin_feed
<?php
echo $json;
?>
The response now :

You should really take advantage of routing and views for this. It allows you to properly organize your code and keep things DRY.
public function admin_feed($id=null) {
$vars = $this->params['url'];
$conditions = array('conditions' => array('UNIX_TIMESTAMP(start) >=' => $vars['start'], 'UNIX_TIMESTAMP(start) <=' => $vars['end']));
$events = $this->Event->find('all', $conditions);
foreach($events as $event) {
if($event['Event']['all_day'] == 1) {
$allday = true;
$end = $event['Event']['start'];
} else {
$allday = false;
$end = $event['Event']['end'];
}
$data[] = array(
'id' => $event['Event']['id'],
'title'=>$event['Event']['title'],
'start'=>$event['Event']['start'],
'end' => $end
);
}
$this->set("events", $data);
}
Now, your admin_feed action is usable as more than just a json feed (even though that may be just want you want). This makes testing easier as well.
Add the following to your routes, to tell Cake that you want to allow the json extension:
Router::parseExtensions('json');
Then, add the RequestHandler to your controller components. This component will automatically switch to your json view and layout when a json extension is found.
Next, add a layout for all json views in /View/Layout/json/default.ctp:
<?php
echo $this->fetch('content');
Then, add your view in /View/Events/json/admin_feed.ctp:
<?php
echo json_encode($events);
That's it. Now, if you want to use admin_feed to view events in HTML, you can by adding a view for it.
Your full calendar url should now be: FcRoot + '/admin/events/feed.json'. Try just visiting it in the browser to see if you see the json.

do not set it, just echo it
echo json_encode($data);
set values are supposed to be used in view, in your case you are just 'returning' as ajax response
for ajax calls, view is not necessary at all, put $this->autoRender = false; in you function: this will prevent 'seeking' for view file.

Related

Drupal: another way to fetch the taxonomy tid (apart from URL)

I am using webforms which have as the topic taxonomy terms saved as hidden fields.
Unfortunate, after attaching files using Upload button this terms are lost ('No category'), as ajax is altering the form #action URL from /tid to /file/ajax/submitted/file4/form-gTwVpNbQRszArGEUS1OfuwA8WgSLJOlcWGOuS6r9D5A
From where to read $tid?
Therefore my $tid fail to load from URL
function MYMODULE_form_alter(&$form, &$form_state, $form_id) {
$tid = arg(1);
$term = taxonomy_term_load($tid);
if (!empty($term)) {
$category = i18n_taxonomy_term_name($term, $language->language);
} else {
$category = 'No category';
}
$form['submitted'][$category_fieldkey] = array(
'#type' => 'hidden',
'#value' => $category,
);
}

CakePHP Pagination: how can I sort by multiple columns to achieve "sticky" functionality?

I see that this paginate can't sort two columns at the same time ticket is still open, which leads me to believe that what I'm trying to do is not possible without a workaround. So I guess what I'm looking for is a workaround.
I'm trying to do what many message boards do: have a "sticky" function. I'd like to make it so that no matter which table header link the user clicks on to sort, my model's "sticky" field is always the first thing sorted, followed by whatever column the user clicked on. I know that you can set $this->paginate['Model']['order'] to whatever you want, so you could hack it to put the "sticky" field first and the user's chosen column second. The problem with this method is that pagination doesn't behave properly after you do it. The table header links don't work right and switching pages doesn't work right either. Is there some other workaround?
User ten1 on the CakePHP IRC channel helped me find the solution. I told him that if he posted the answer here then I would mark it as the correct one, but he said I should do it myself since he doesn't have a Stack Overflow account yet.
The trick is to inject the "sticky" field into the query's "order" setting using the model's "beforeFind" callback method, like this:
public function beforeFind($queryData) {
$sticky = array('Model.sticky' => 'DESC');
if (is_array($queryData['order'][0])) {
$queryData['order'][0] = $sticky + $queryData['order'][0];
}
else {
$queryData['order'][0] = $sticky;
}
return $queryData;
}
What you can do is code it in the action. Just create the query you want when some parameters exist on the URL. (parameters has to be sent by GET)
For example:
public function posts(){
$optional= array();
if(!empty($this->params->query['status'])){
if(strlower($this->params->query['status']=='des')){
$optional= array('Post.status DESC');
}
else if(strlower($this->params->query['status']=='asc')){
$optional= array('Post.status ASC');
}
}
if(!empty($this->params->query['department'])){
//same...
}
//order first by the sticky field and then by the optional parameters.
$order = array('Post.stickyField DESC') + $optional;
$this->paginate = array(
'conditions' => $conditions,
'order' => $order,
'paramType' => 'querystring',
);
$this->set('posts', $this->paginate('Post'));
}
I have used something similar to filter some data using $conditions instead of $order and it works well.
You can use custom field for sorting and update pagination component.
Controller code
$order['Document.DATE'] = 'asc';
$this->paginate = array(
"conditions"=> $conditions ,
"order" => $order ,
"limit" => 10,
**"sortcustom" => array('field' =>'Document.DATE' , 'direction' =>'desc'),**
);
Changes in pagination component.
public function validateSort($object, $options, $whitelist = array()) {
if (isset($options['sort'])) {
$direction = null;
if (isset($options['direction'])) {
$direction = strtolower($options['direction']);
}
if ($direction != 'asc' && $direction != 'desc') {
$direction = 'asc';
}
$options['order'] = array($options['sort'] => $direction);
}
if (!empty($whitelist) && isset($options['order']) && is_array($options['order'])) {
$field = key($options['order']);
if (!in_array($field, $whitelist)) {
$options['order'] = null;
}
}
if (!empty($options['order']) && is_array($options['order'])) {
$order = array();
foreach ($options['order'] as $key => $value) {
$field = $key;
$alias = $object->alias;
if (strpos($key, '.') !== false) {
list($alias, $field) = explode('.', $key);
}
if ($object->hasField($field)) {
$order[$alias . '.' . $field] = $value;
} elseif ($object->hasField($key, true)) {
$order[$field] = $value;
} elseif (isset($object->{$alias}) && $object->{$alias}->hasField($field, true)) {
$order[$alias . '.' . $field] = $value;
}
}
**if(count($options['sortcustom']) > 0 )
{
$order[$options['sortcustom']['field']] = $options['sortcustom']['direction'];
}**
$options['order'] = $order;
}
return $options;
}
Easy insert 'paramType' => 'querystring',
Show Code Example:
$this->paginate = array(
'conditions' => $conditions,
'order' => array(
'Post.name' => 'ASC',
'Post.created' => 'DESC',
),
'paramType' => 'querystring',
);
$this->set('posts', $this->paginate('Post'));

Cakephp to Google Chart

In my controller I create the array to be charted
function chart() {
$results = $this->Visit->query(
"SELECT date(visits.created) as visit_date,
Count(visits.id) AS count_visits
FROM visits
GROUP BY date(visits.created)"
);
foreach($results AS $result) {
$row = array(
$result[0]['visit_date'],
$result[0]['count_visits']
);
$chartData[] = json_encode($row);
}
pr($chartData);
}
pr($chartData) gives following array
Array
(
[0] => ["2012-07-11","5"]
[1] => ["2012-07-13","1"]
[2] => ["2012-07-14","1"]
)
in chart view i have
google.load('visualization', '1.0', {'packages':['corechart']});
google.setOnLoadCallback(drawChart);
function drawChart() {
// Create the data table.
var data = google.visualization.arrayToDataTable($chartData);
var options = {
title: 'Visits by Date',
hAxis: {title: 'Date', titleTextStyle: {color: 'black'}}
};
var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
but this doesn't get me a chart .. no errors ... just no chart ..
if I manually type in an array to test my view, it works fine ... eg if i replace ..
var data = google.visualization.arrayToDataTable($chartData);
with the following format from Google Chart example it generates a nice column chart
var data = google.visualization.arrayToDataTable([
['Date', 'Count'],
['2012-07-11', 5],
['2012-07-13', 1],
['2012-07-14', 1]
]);
couple of questions:
- how do i get the header titles in the var data array?
- do double quotes or single quotes in array make a difference?
- am i passing the array $chartData from php to Google chart javascript correctly?
- the Google example has '[]' around the array, how do i get those around my array too?
(bwt, i know all about cakephp's Find(all) but I just got lost in documentation about how to get what i wanted and sql was much easier )
you are using json_encode in your controller, but in your view you are using -
google.visualization.arrayToDataTable($chartData);
json_encode creates json object, not and javascript array.
using json_encode in your controller function chart() try:
$chartData['cols'] = array(
array('id' => 'visit_date', 'label' => 'Visit date', 'type' => 'date'),
array('id' => 'count_visits', 'label' => 'Count', 'type' => 'number')
);
foreach($results AS $result) {
$time = strtotime($result[0]['visit_date']);
$dateJs = 'Date('.date("Y", $time).', '.(date('n', $time) - 1).', '.date('j', $time).')';
$row = array(
'c' => array(
array('v' => $dateJs),
array('v' => $result[0]['count_visits']),
)
);
$chartData['rows'][] = $row;
}
//make the data available for view
$this->set('chartData', json_encode($chartData);
in your view use :
var data = new google.visualization.DataTable($chartData);

Can I create a Drupal autocomplete textfield in a block?

I want to create an auto-complete form in my custom module that will be loaded in a block. Drupal doesn't seem to be loading the necessary Javascript libraries to work properly. How do I know what needs to be loaded and how/where do I tell Drupal to load these libraries?
hook_block_view:
function my_module_block_view($delta = '') {
//The $delta parameter tells us which block is being reqested.
switch ($delta) {
case 'my_module_my_block':
$block['subject'] = t('Block Subject');
$block['content'] = drupal_get_form('my_module_my_form');
break;
}
return $block;
}
Form code:
function my_module_my_form($form, &$form_state) {
$form = array();
$form['term'] = array(
'#type' => 'textfield',
'#autocomplete_path' => 'my-module-autocomplete'
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Add',
);
return $form;
}
The form loads, the field is there, but auto-complete isn't working :(
If I call the my-module-autocomplete path I do get a valid response back when compared with a Content Type edit form. The ajax spinner in the input field never appears so the ajax isn't being called. Realistically all I want is the autocomplete field...the submit will be handled manually.
It's probably because you're reseting $form to an empty array at the beginning of the function. In Drupal 7 there's a bunch of stuff added to that element before it's passed through to your form function (that's why $form is passed to your function whereas in Drupal 6 it wasn't).
Just remove $form = array(); and it should work, other than that your code looks perfect.
the following should work;
function mymodule_block_info() {
$blocks['mymodule'] = array(
// The name that will appear in the block list.
'info' => t('My Module'),
// Default setting.
'cache' => DRUPAL_NO_CACHE,
);
return $blocks;
}
function mymodule_block_view($delta = ''){
switch($delta){
case 'mymodule':
if(user_access('access content')){ //good idea to check user perms here
$block['subject'] = t('My Module');
$block['content'] = 'Hi :)';
$block['content'] = drupal_get_form('mymodule_form');
return $block;
}
break;
}
}
function mydmodule_menu() {
$items['module/autocomplete'] = array(
'page callback' => 'mymodule_autocomplete',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK
);
return $items;
}
function mymodule_form($form, &$form_state) {
$form['greenentry'] = array(
'#type' => 'textfield',
'#title' => t('Enter'),
'#autocomplete_path' => 'mymodule/autocomplete',
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);
return $form;
}
function mymodule_autocomplete($string) {
$matches = array();
// Some fantasy DB table which holds cities
$query = db_select('cities', 'c');
// Select rows that match the string
$return = $query
->fields('c', array('city'))
->condition('c.city', '%' . db_like($string) . '%', 'LIKE')
->range(0, 10)
->execute();
// add matches to $matches
foreach ($return as $row) {
$matches[$row->url] = check_plain($row->url);
}
// return for JS
drupal_json_output($matches);
}
this code is so pretty to add an auto-complete filed in block. But i just found a tiny notice here. if someone get an error
An ajax error occurred. http result code 200
then just add
exit();
after the line
drupal_json_output($matches);
hence fix the issue.

CakePHP Calendar

I am new to CakePHP, and would like to create a calendar using this framework. I am having a difficult time, and am wondering if there is a tutorial or guide on how to create a simple calendar using CakePHP?
Here are two links: LINK1(calendar helper) and LINK2 to a implementation of FullCalendar.
I did not try both of them...
https://github.com/silasmontgomery/CakePHP-Full-Calendar-Plugin
This is a calendar plugin for cakephp via fullCalendar
Download js or css file
http://fullcalendar.io/download/
Controller code
function feeds(){
$this->layout = 'ajax';
if(isset($this->params->query['start'])){
$start = $this->params->query['start'];
}
if(isset($this->params->query['end'])){
$end = $this->params->query['end'];
}
$events = $this->{$this->modelClass}->find('all',array('conditions' => array('startdate >=' => $start,'enddate $end)));
$data = '';
foreach($events as $res ){
$data[] = array(
'id' => $res[$this->modelClass]['id'],
'title'=> $res[$this->modelClass]['title'],
'start'=> Date('Y-m-d H:m',$res[$this->modelClass]['startdate']),
'end' => Date('Y-m-d H:m',$res[$this->modelClass]['enddate']),
'start_time' => Date('h:ia',$res[$this->modelClass]['startdate']),
'end_time' => Date('h:ia',$res[$this->modelClass]['enddate'])
);
}
echo json_encode($data);
exit;
}
View file
Add this in .ctp file
<div class="" id="calendar_div">
Js code for view file
$('#calendar_div').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'agendaDay,agendaWeek,month'
},
defaultView: 'month',
events: '<?php echo $this->Html->url(array('action' => 'feeds')); ?>',
selectable: true,
selectHelper: true
});

Resources