I made a method that writes a view with a calendar table which shows all months of a year using the calendaring class.
Controller:
<?php
class Calendar extends CI_Controller {
public function this_year() {
$data['title'] = 'Calendar: ' . date('Y');
$this->load->library('calendar');
$prefs = array(
'local_time' => 'none',
'start_day' => 'sunday',
'month_type' => 'long',
'day_type' => 'short',
'show_next_prev' => FALSE,
'show_other_days' => TRUE,
'template' => '
{table_open}<table class="table table-condensed">{/table_open}
{heading_row_start}<tr class="info">{/heading_row_start}
{cal_cell_start_today}<td class="today">{/cal_cell_start_today}
{cal_cell_start_other}<td class="other-day">{/cal_cell_start_other}
'
);
$this->load->library('calendar', $prefs);
$data['calendar'] = '<table class="table-calendar"><tr>';
for ($i = 1; $i <= 12; $i++) {
if ($i % 3 == 0) {
$data['calendar'].= "<td>{$this->calendar->generate(date('Y'), $i)}</td>";
$data['calendar'].= '</tr><tr>';
}
else {
$data['calendar'].= "<td>{$this->calendar->generate(date('Y'), $i)}</td>";
}
}
$data['calendar'].= '</tr></table>';
$this->template->load('template/index', __CLASS__ . "/" . __FUNCTION__, $data);
}
}
*On VIEW, just echo '$calendar'
It works as well, and returns this.
But I didn't found a way to highlight only the current month using a template in the calendaring class. I tried to modify the default template but it doesn't work because when I change the class of {heading_title_cell}<th colspan="{colspan}">{heading}</th>{/heading_title_cell}, it modifies all the month's labels like this.
I'm using the default methods (same code) from the basic class tutorial. Any suggestion?
It is possible to extend CI_Calendar to force the method generate() pass his $month variable to the parse_template() method. Then, parse_template($month) will be able to apply an exception while parsing the declared template on {heading_row_start}<tr>{/heading_row_start}:
CI_Calendar::parse_template($month), 483:
if($val == 'heading_row_start'){
if( $month == date('m')){
$this->replacements[$val] = '<tr class="info">';
}
}
else{
$this->replacements[$val] = $match[1];
}
Related
So in my PHP program I'm creating a calendar feature and one of the classes is "CalendarDay". What I want to do is be able to instantiate a new day for each day count, so for example new CalendarDay (22) means a new 22nd of the month date. There is also a show() function used for displaying each day. The class itself functions normally but when I try instantiating new days using recursion it no longer seems to work as everything related to the instantiated object disappears from the webpage.
class CalendarDay{
private $current_month;
private $current_year;
private $current_date;
public $reminderSet;
public $reminders;
public function __construct($current_day_of_month){
$current_year = date("Y");
$current_month = date("m");
$this->days_in_month = cal_days_in_month(CAL_GREGORIAN, $current_month, $current_year);
$this->current_date = date("d");
$this->current_day_of_month = $current_day_of_month;
}
public function show(){
$output = '<div class = "generator>"';
//$output .= $this->current_date;
//$output .= '<h1>' . $this->current_date . '</h1>';
$output .= '</div>';
$output .= $this->current_day_of_month;
echo $output;
}
}
My failed attempt at recursion:
for ($countTo31 == 0; $countTo31 == 31; $countTo31++){
$holder = $countTo31;
$date = new CalendarDay ($holder);
$date->show();
}
For the reference, this original block of code without the recursion works normally:
$holder = $countTo31;
$date = new CalendarDay ($holder);
$date->show();
I'm very confused with what you're trying to accomplish...
You have a "day" class which takes input to initialise a specific day but instead actually works out the current day based on date("Y-m-d");?.. And then outputs the input day anyway?
Honestly, it looks more like you want a "month" object
Initial problems
You use == to define your starting point
== is not an assignment operator, it's a comparison.
It effectively adds an additional iteration of the loop at the start of the loop
for($i == 1; $i < 5; $i++){
echo $i;
}
// Loop 1:
// --> Notice on $i == 1
// --> Notice on $i < 5
// --> Notice on echo $i
// --> Notice on $i++
// Loop 2:
--> $i = 1 BECAUSE of the previous $i++
so the intended loop starts...
Additionaly the loop, in this case, should start with 1 not 0(!)
You use == to define your condition
for loops like yours work effectively as:
for ( A ; B ; C ){
// Do something...
}
// Loop works as:
// Check A against B
// If TRUE then "Do something..."
// and then do C
// IF FALSE then break
However, even if your assignment (A) was correct (i.e. $countTo31 = 1), it still wouldn't work because 1 !== 31 and therfore the loop breaks from the start
It should be $countTo31 <= 31
Looping over object, rewriting the variable
Your code currently rewrites the variable which holds the date object with every loop
Effectively you create an object to output the day, output that data, and instantly remove the object so that it can't be used for anyting else...
Your HTML output has a " in the wrong place:
$output = '<div class = "generator>"';
//Should be...
$output = '<div class = "generator">';
Some of the variables in your class are not assigned or declared properly
$current_month is declared but never assigned
$current_year is declared but never assigned
$current_day_of_month is assigned but not declared
$days_in_month is assigned but not declared
Interim solution
Without further information on what you are intending to do it isn't possible to give good/accurate guidance, so I will leave a working example which should show you what to do:
$days_in_month = cal_days_in_month(
CAL_GREGORIAN,
date("m"),
date("Y")
);
for ($day = 1; $day <= $days_in_month; $day++){
echo "Day {$day}<br>";
}
Proposed changes
It doesn't look as though you really even want a "day" class for the functions you're trying to implement. So, in my mind, it would be better to first create a "month" object with all of the days of the month and then have that generate a "day" object for each day of the month which then can gather the information for each day e.g. reminders.
Doing it this way you can then update each day as you go with, for example, user input or database data.
class Month
{
private $month;
private $year;
private $days = [];
public function __construct($month, $year)
{
$this->month = $month;
$this->year = $year;
$number_of_days = cal_days_in_month(
CAL_GREGORIAN,
$month,
$year
);
for ($i = 1; $i <= $number_of_days; $i++){
$date = "{$this->year}-{$this->month}-{$i}";
// $days[] = new Day($date);
$this->days[$i] = new Day($date);
}
}
public function getDay($day)
{
return $this->days[$day];
}
public function getNumberOfDays()
{
return count($this->days);
}
}
class Day
{
private $date;
private $reminders = [];
public function __construct($date)
{
$this->date = $date;
// Initialise day...
# Get reminders
# Get meetings
# Get bills to pay
}
public function getReminders()
{
return $this->reminders;
}
public function setReminder($content, $time)
{
// Set reminders
$this->reminders[] = [
"content" => $content,
"time" => $time
];
}
public function show()
{
return date("d / m / Y", strtotime($this->date));
}
}
$month = new Month(12, 2020);
for ($i = 1; $i <= $month->getNumberOfDays(); $i++){
echo $month->getDay($i)->show()."<br>";
}
I have calendar whose dates are booked and saved in database. I am trying to pull the bookings from database and show then under corresponding date. Everything is working fine, except the thing, I want the date to be just text instead of link when there are more than 5 events to that date.
I am aware of the calendar template no content cell and content cells. But i want the date to have no link when it has more than 5 events attached to it.
My Model:
public function bookingcalender($year=null,$month=null)
{
if(!$year)
{
$y = date('Y');
}
else
{
$y = $year;
}
if(!$month)
{
$m = date('m');
}
else
{
$m = $month;
}
$this->config = array(
'show_next_prev' => TRUE,
'next_prev_url' => 'http://joshuaflinn.com/CI/booking/show',
'template' => '{table_open}<table class="availability-calendar">{/table_open}
{heading_row_start}<tr class="toolbar">{/heading_row_start}
{heading_title_cell}<th colspan="{colspan}">{heading}</th>{/heading_title_cell}
{heading_previous_cell}<th><</th>{/heading_previous_cell}
{heading_next_cell}<th>></th>{/heading_next_cell}
{heading_row_end}</tr>{/heading_row_end}
{week_row_start}<tr>{/week_row_start}
{week_day_cell}<td>{week_day}</td>{/week_day_cell}
{week_row_end}</tr>{/week_row_end}
{cal_row_start}<tr>{/cal_row_start}
{cal_cell_start}<td>{/cal_cell_start}
{cal_cell_start_today}<td>{/cal_cell_start_today}
{cal_cell_start_other}<td class="other-month">{/cal_cell_start_other}
{cal_cell_content}{day}<span class="date-data">{content}</span>{/cal_cell_content}
{cal_cell_content_today}<div class="highlight">{day}</div>{/cal_cell_content_today}
{cal_cell_no_content}{day}{/cal_cell_no_content}
{cal_cell_no_content_today}<div class="highlight">{day}</div>{/cal_cell_no_content_today}
{cal_cell_blank} {/cal_cell_blank}
{cal_cell_other}{day}{/cal_cel_other}
{cal_cell_end}</td>{/cal_cell_end}
{cal_cell_end_today}</td>{/cal_cell_end_today}
{cal_cell_end_other}</td>{/cal_cell_end_other}
{cal_row_end}</tr>{/cal_row_end}
{table_close}</table>{/table_close}'
);
$this->load->library('calendar',$this->config);
$conf_data = $this->get_booked_dates($year,$month);
return $this->calendar->generate($year,$month,$conf_data);
}
public function get_booked_dates($year,$month)
{
$query = $this->db->select('client_name,booking_date')->from('bookings')->like('booking_date',"$year-$month")->get();
$cal_data = array();
foreach($query->result() as $row)
{
$dt = explode("-", $row->booking_date);
$dt = $dt[2];
$k = ($dt >= 10 ? substr($row->booking_date, 8,2) : substr($row->booking_date, 9,1));
if( #$cal_data[$k] == '' )
{
$cal_data[$k] = $row->client_name;
}
else
{
$cal_data[$k] .= ','.$row->client_name;
}
}
return $cal_data;
}
The options you have are limited since Codeigniters Calendar Library only have the two pseudo variables cal_cell_no_content and cal_cell_contentin the template to play with in terms of what content you want to display.
A quick look behind the door reveals that the library uses isset() to determine which of the two pseudo variables to use.
And it calls str_replace {content} before {day} that opens up for a somewhat hacky solution:
public function bookingcalender($year=null,$month=null)
{
if(!$year)
{
$y = date('Y');
}
else
{
$y = $year;
}
if(!$month)
{
$m = date('m');
}
else
{
$m = $month;
}
$this->config = array(
'show_next_prev' => TRUE,
'next_prev_url' => 'http://joshuaflinn.com/CI/booking/show',
'template' => '{table_open}<table class="availability-calendar">{/table_open}
{heading_row_start}<tr class="toolbar">{/heading_row_start}
{heading_title_cell}<th colspan="{colspan}">{heading}</th>{/heading_title_cell}
{heading_previous_cell}<th><</th>{/heading_previous_cell}
{heading_next_cell}<th>></th>{/heading_next_cell}
{heading_row_end}</tr>{/heading_row_end}
{week_row_start}<tr>{/week_row_start}
{week_day_cell}<td>{week_day}</td>{/week_day_cell}
{week_row_end}</tr>{/week_row_end}
{cal_row_start}<tr>{/cal_row_start}
{cal_cell_start}<td>{/cal_cell_start}
{cal_cell_start_today}<td>{/cal_cell_start_today}
{cal_cell_start_other}<td class="other-month">{/cal_cell_start_other}
{cal_cell_content}{content}{/cal_cell_content}
{cal_cell_content_today}<div class="highlight">{content}</div>{/cal_cell_content_today}
{cal_cell_no_content}{day}{/cal_cell_no_content}
{cal_cell_no_content_today}<div class="highlight">{day}</div>{/cal_cell_no_content_today}
{cal_cell_blank} {/cal_cell_blank}
{cal_cell_other}{day}{/cal_cel_other}
{cal_cell_end}</td>{/cal_cell_end}
{cal_cell_end_today}</td>{/cal_cell_end_today}
{cal_cell_end_other}</td>{/cal_cell_end_other}
{cal_row_end}</tr>{/cal_row_end}
{table_close}</table>{/table_close}'
);
$this->load->library('calendar',$this->config);
$conf_data = $this->get_booked_dates($year,$month);
return $this->calendar->generate($year,$month,$conf_data);
}
public function get_booked_dates($year,$month)
{
$query = $this->db->select('client_name,booking_date')->from('bookings')->like('booking_date',"$year-$month")->get();
$cal_data = array();
foreach($query->result() as $row)
{
$dt = explode("-", $row->booking_date);
$k = intval($dt[2]); // MAKE INTEGER OF DAY NUMBER
if( #$cal_data[$k] == '' )
{
$cal_data[$k] = $row->client_name;
}
else
{
$cal_data[$k] .= ','.$row->client_name;
}
}
// LOOP THROUGH EACH DAY TO FIND THOSE WITH MORE THAN 5 EVENTS
foreach($cal_data as $key=>$val){
// COUNT THE NUMBER OF COMMAS THAT OCCUR IN STRING
$count = strlen($val) - strlen(str_replace(',','',$val));
if($count > 4){ // IF MORE THAN 4 COMMAS (> 5 EVENTS) THEN NO LINK...
$cal_data[$key] = '{day}<span class="date-data">'.$val.'</span>';
} else { // LINKED DAY
$cal_data[$key] = '{day}<span class="date-data">'.$val.'</span>';
}
}
return $cal_data;
}
Note: that I have changed two rows in the template: {cal_cell_content}{content}{/cal_cell_content} and {cal_cell_content_today}<div class="highlight">{content}</div>{/cal_cell_content_today}
You now only need to set {content} since {day} is specified inside the content also containing the html returned from the query.
Update: I have now tested the solution and it seems to work fine!
You have to manipulate or extend the Calendar library if you need a more flexible solution and if you don't want to mix template html in the content returned from your query.
I need to set the pagination order of my register based on field ($results[$key]['Movimento']['status']) created in afterFind callback.
afterFind:
public function afterFind($results, $primary = false) {
foreach ($results as $key => $val) {
if(isset($val['Movimento']['data_vencimento'])) {
$data = $val['Movimento']['data_vencimento'];
$dtVc = strtotime($data);
$dtHj = strtotime(date('Y-m-d'));
$dtVencendo = strtotime("+7 day", $dtHj);
if ($dtVc < $dtHj) {
$results[$key]['Movimento']['status'] = 'vencido';
} elseif ($dtVc <= $dtVencendo) {
$results[$key]['Movimento']['status'] = 'vc15dias';
} else {
$results[$key]['Movimento']['status'] = 'aberto';
}
}
if(isset($val['Movimento']['data_pagamento'])) {
$results[$key]['Movimento']['status'] = 'quitado';
}
}
return $results;
Pagination:
$options = array(
...
'order' => array('Movimento.status' => 'ASC')
);
$this->controller->paginate = $options;
$movimentos = $this->controller->paginate('Movimento');
I know this does not work because the field is created after the paginator call.
Can I make it work?
as I understand, you want to sort by data_pagamento and than by data_vencimento (has it the mysql-type date?)
so you don't need your afterFind-function for ordering, simply use:
'order' => array(
'Movimento.data_pagamento DESC',//first all rows with not-empty data_pagamento
'Movimento.data_vencimento DESC',// first all dates in the furthest future
)
This one's got me stuck!
I have two functions in a controller which can be called from a menu independantly and they work fine.
I want to call them in a month end routine (in the same controller), one after the other; the first function works fine and returns to the calling function, the second function is called but fails because the load of the $model variable fails.
Here is the code for the month end routine,
function month_end_routines()
{
// create stock inventory valuation report in excel format
$export_excel = 1;
$this -> inventory_summary($export_excel);
// create negative stock
$export_excel = 1;
$this -> inventory_negative_stock($export_excel);
echo 'debug 2';
// reset rolling inventory indicator
$this -> load->model('Item');
$this -> load->library('../controllers/items');
$this -> items->reset_rolling();
}
Here is the code for the first function called inventory_summary,
function inventory_summary($export_excel=0, $create_PO=0, $set_NM=0, $set_SM=0)
{
// load appropriate models and libraries
$this -> load->model('reports/Inventory_summary');
$this -> load->library('../controllers/items');
// set variables
$model = $this->Inventory_summary;
$tabular_data = array();
$edit_file = 'items/view/';
$width = $this->items->get_form_width();
$stock_total = 0;
// get all items
$report_data = $model->getData(array());
foreach($report_data as $row)
{
$stock_value = $row['cost_price'] * $row['quantity'];
$stock_total = $stock_total + $stock_value;
// set up the item_number to handle blanks
if ($row['item_number'] == NULL) {$row['item_number'] = $this->lang->line('common_edit');}
$tabular_data[] = array (
$row['category'],
anchor (
$edit_file.$row['item_id'].'/width:'.$width,
$row['item_number'],
array('class'=>'thickbox','title'=>$this->lang->line('items_update'))
),
$row['reorder_policy'],
$row['name'],
$row['cost_price'],
$row['quantity'],
$stock_value,
$stock_total
);
}
$today_date = date('d/m/Y; H:i:s', time());
$data = array (
"title" => $this->lang->line('reports_inventory_summary_report'),
"subtitle" => ' - '.$today_date.' '.$this->lang->line('common_for').' '.$this->db->database.'.',
"headers" => $model->getDataColumns(),
"data" => $tabular_data,
"summary_data" => $model->getSummaryData(array()),
"export_excel" => $export_excel
);
if ($export_excel == 1)
{
$this->load->model('Common_routines');
$this->Common_routines->create_csv($data);
}
else
{
$this->load->view("reports/tabular", $data);
}
return;
.. and here is the code for the second function,
function inventory_negative_stock($export_excel=0, $create_PO=0, $set_NM=0, $set_SM=0)
{
echo 'debug 1.5';
$this -> load->model('reports/Inventory_negative_stock');
$this -> load->library('../controllers/items');
echo 'debug 1.6';
$model = $this->Inventory_negative_stock;
var_dump($model);
$tabular_data = array();
$edit_file = 'items/view/';
$width = $this->items->get_form_width();
echo 'debug 1.7';
$report_data = $model->getData(array());
echo 'debug 1.8';
foreach($report_data as $row)
{
// set up the item_number to handle blanks
if ($row['item_number'] == NULL) {$row['item_number'] = $this->lang->line('common_edit');}
// load each line to the output array
$tabular_data[] = array(
$row['category'],
anchor (
$edit_file.$row['item_id'].'/width:'.$width,
$row['item_number'],
array('class'=>'thickbox','title'=>$this->lang->line('items_update'))
),
$row['name'],
$row['cost_price'],
$row['quantity']
);
}
// load data array for display
$today_date = date('d/m/Y; H:i:s', time());
$data = array (
"title" => $this->lang->line('reports_negative_stock'),
"subtitle" => ' - '.$today_date.' '.$this->lang->line('common_for').' '.$this->db->database.'.',
"headers" => $model->getDataColumns(),
"data" => $tabular_data,
"summary_data" => $model->getSummaryData(array()),
"export_excel" => $export_excel
);
if ($export_excel == 1)
{
$this->load->model('Common_routines');
$this->Common_routines->create_csv($data);
}
else
{
$this->load->view("reports/tabular", $data);
}
return;
}
This line is failing
$model=$this->Inventory_negative_stock;
In the first function $model is loaded correctly. In the second it isn't.
It does not matter in which order these functions are called; $model always fails to load in the second function called.
Any help would be great and thanks in advance. I hope I've given enough code; if you need more information let me know.
As requested, here is the code in Inventory_negative_stock,
<?php
require_once("report.php");
class Inventory_negative_stock extends Report
{
function __construct()
{
parent::__construct();
}
public function getDataColumns()
{
return array (
$this->lang->line('reports_category'),
$this->lang->line('reports_item_number'),
$this->lang->line('reports_item_name'),
$this->lang->line('reports_cost_price'),
$this->lang->line('reports_count')
);
}
public function getData(array $inputs)
{
$this->db->select('category, name, cost_price, quantity, reorder_level, reorder_quantity, item_id, item_number');
$this->db->from('items');
$this->db->where("quantity < 0 and deleted = 0");
$this->db->order_by('category, name');
return $this->db->get()->result_array();
}
public function getSummaryData(array $inputs)
{
return array();
}
}
?>
I'd hate to reinvent the wheel on this one if it's out there somewhere, but has anyone extended or modified the codigniter calendar to handle multi-day events and multiple events per day or is it there a module available somewhere?
Multiple events for one day is actually very easy. It just takes changing the calendar template and here is an example from some of my code.
public function print_calendar($year = 0, $month = 0)
{
$prefs = array (
'show_next_prev' => FALSE,
'next_prev_url' => site_url('events/print_calendar'),
'day_type' => 'long',
'template' => '
{heading_row_start}{/heading_row_start}
{heading_previous_cell}{/heading_previous_cell}
{heading_title_cell}<h1>{heading}</h1>{/heading_title_cell}
{heading_next_cell}{/heading_next_cell}
{heading_row_end}{/heading_row_end}
{table_open}<table border="0" cellpadding="0" cellspacing="0">{/table_open}
{week_row_start}<tr>{/week_row_start}
{week_day_cell}<th bgcolor="#999999">{week_day}</th>{/week_day_cell}
{week_row_end}</tr>{/week_row_end}
{cal_row_start}<tr>{/cal_row_start}
{cal_cell_start}<td background="'.s3_path('images/print_cal_cell.jpg').'">{/cal_cell_start}
{cal_cell_content}<span class="cal_day">{day}</span>{content}{/cal_cell_content}
{cal_cell_content_today}<span class="cal_day">{day}</span>{/cal_cell_content_today}
{cal_cell_no_content}<span class="cal_day">{day}</span>{/cal_cell_no_content}
{cal_cell_no_content_today}<span class="cal_day">{day}</span>{/cal_cell_no_content_today}
{cal_cell_blank} {/cal_cell_blank}
{cal_cell_end}</td>{/cal_cell_end}
{cal_row_end}</tr>{/cal_row_end}
{table_close}</table>{/table_close}
'
);
$this->load->library('calendar', $prefs);
$year = ($year == 0) ? date('Y') : $year;
$month = ($month == 0) ? date('n') : $month;
$start = strtotime('1-'.$month.'-'.$year);
$events = $this->events_model->get_by_date($start, strtotime('+1 month', $start));
$this->template->set_layout('');
if ($events)
{
foreach ($events as $key => $event)
{
$day = date('j', $event['showing_start_time']);
$vars[$day] = $this->template->build('events/calendar/cal_item', $event, TRUE);
}
}
$vars['content'] = $this->calendar->generate($year, $month, $vars);
$this->load->view('calendar/cal_layout', $vars);
}
Hopefully that code is clear and can give you a good starting point. What I normally do if they span multiple days just include the item on each day.
This can be easily modified in the file system/libraries/Calendar.php with the following addition of code. I know that editing any system file is considered taboo, but this helped me out in my application a ton. Take note of the foreach() loop in the commented section that says //If more than one event on the same day. This is the code that needs to be added to the Calendar.php library file. This resource can be futher elaborated on at the following link.
http://codeigniter.com/forums/viewthread/196998/
Calendar.php modified code:
if (isset($data[$day]))
{
// Cells with content
$temp = ($is_current_month == TRUE AND $day == $cur_day) ? $this->temp['cal_cell_content_today'] : $this->temp['cal_cell_content'];
// If more than one event on the same day
if (is_array($data[$day]))
{
$several_events = '';
foreach ($data[$day] as $key => $value)
{
$several_events .= '<li id="'.$key.'">'.$value.'</li>';
}
$out .= str_replace('{day}', $day, str_replace('{content}', $several_events, $temp));
}
// One event per day
else
{
$out .= str_replace('{day}', $day, str_replace('{content}', $data[$day], $temp));
}
}
else
{
// Cells with no content
$temp = ($is_current_month == TRUE AND $day == $cur_day) ? $this->temp['cal_cell_no_content_today'] : $this->temp['cal_cell_no_content'];
$out .= str_replace('{day}', $day, $temp);
}
}
else
{
// Blank cells
$out .= $this->temp['cal_cell_blank'];
}
Keep in mind that I've shown more than just the edited code above to help you locate it within Calendar.php. I hope this helps!