Welcome Guest, Not a member yet? Register   Sign In
calendar plugin
#1

[eluser]xwero[/eluser]
New in the list of plugins that replace CI libraries, the calendar plugin
Code:
/*
* generate calendar data
*
* @param string         year,   month,              week,              day
* @param numeric/array  year,   array(year, month), array(year, week), array(year, month, day)
* @param array added to months, days,               days,              hours (24 format)
* @param bool  
* @return array
* */        
function getCalendar($type,$date,$data=array(),$embedded=false)
{
    $output = array();    
    // helper function to reduce to code getting the year
    function temp_year($year)
    {
        if(strlen($year) == 2)
        {
               return array('y',substr(date('Y'),0,-2).$year); // substr to work long after i'm dead
        }
        else
        {
               return array('Y',$year);
        }
    }
    
    switch($type)
    {
        case 'year':
        $output['items'] = range(1,12);
        if(date('Y') == $date OR date('y') == $date){ $output['current'] = $date; }
        if($embedded == false)
        {
            $output['prev'] = (strlen($date) == 2)? str_pad($date-1,2,0,STR_PAD_LEFT) : $date-1 ;
        $output['next'] = (strlen($date) == 2)? str_pad($date+1,2,0,STR_PAD_LEFT) : $date+1 ;
        }
        break;
        case 'month':
        $output['items'] = range(1,date('t',strtotime($date[0].'-'.$date[1].'-1')));
        if(date('Ym') == $date[0].$date[1] OR date('ym') == $date[0].$date[1]){ $output['current'] = date('j'); }
        if($embedded == false)
        {
        list($temp_year_out,$temp_year_date) = temp_year($date[0]);    
        $temp_prev = strtotime('-1 month',strtotime($temp_year_date.'-'.$date[1].'-1'));    
        $output['prev'] = array(date($temp_year_out,$temp_prev),date('n',$temp_prev)) ;
                $temp_next = strtotime('+1 month',strtotime($temp_year_date.'-'.$date[1].'-1'));
            $output['next'] = array(date($temp_year_out,$temp_next),date('n',$temp_next)) ;
        }
        break;
        case 'week':
        $output['items'] = range(1,7);
        if(date('YW') == $date[0].$date[1] OR date('yW') == $date[0].$date[1]){ $output['current'] = date('j'); }
        if($embedded == false)
        {
        list($temp_year_out,$temp_year_date) = temp_year($date[0]);    
        $temp_prev = strtotime('-1 week',strtotime($temp_year_date.'W'.$date[1].'1'));    
        $output['prev'] = array(date($temp_year_out,$temp_prev),date('n',$temp_prev)) ;
                $temp_next = strtotime('+1 week',strtotime($temp_year_date.'W'.$date[1].'1'));
            $output['next'] = array(date($temp_year_out,$temp_next),date('n',$temp_next)) ;
        }
        break;
        case 'day':
        $output['items'] = range(0,23); // zero to 23 values because of the php date function return
        if(date('Ymd') == $date[0].$date[1].$date[2] OR date('ymd') == $date[0].$date[1].$date[2]){ $output['current'] = date('G'); }
        if($embedded == false)
        {
        list($temp_year_out,$temp_year_date) = temp_year($date[0]);    
        $temp_prev = strtotime('-1 day',strtotime($temp_year_date.'-'.$date[1].'-'.$date[2]));    
        $output['prev'] = array(date($temp_year_out,$temp_prev),date('n',$temp_prev),date('j',$temp_prev)) ;
                $temp_next = strtotime('+1 day',strtotime($temp_year_date.'-'.$date[1].'-'.$date[2]));
            $output['next'] = array(date($temp_year_out,$temp_next),date('n',$temp_next),date('j',$temp_prev)) ;
        }
        break;
    default:
        return $output;
        break;
    }

    if(is_array($data) && count($data) > 0)
    {
       foreach($data as $key=>$show)
       {
          $output['items'][$key-1] = array($output['items'][$key-1],$show);
       }
    }

    return $output;
}
I took the approach of the last version of the pagination plugin. the plugin will only return data to make it as flexible as possible.

It's still a little rough around the edges. The main problem is that a month view still requires quite a bit of outside work. An example
Code:
// views/month_calendar.php
<table>
<tr>
<th colspan=2><a href="&lt;?php echo site_url('welcome/index/'.implode('/',$prev)) ?&gt;">Prev</a></th>
<th colspan=3>&lt;?php echo $displayed_month.' '.$displayed_year ?&gt;</th>
<th colspan=2><a href="&lt;?php echo site_url('welcome/index/'.implode('/',$next)) ?&gt;">Next</a></th>
</tr>
<tr>
<td>MO</td>
<td>TU</td>
<td>WE</td>
<td>TH</td>
<td>FR</td>
<td>SA</td>
<td>SU</td>
</tr>&lt;?php foreach($rows as $week): ?&gt;
<tr>&lt;?php foreach($week as $weekday): $day = (is_array($weekday))? $weekday[0]:$weekday;  ?&gt;
<td>
<p>&lt;?php if(is_array($weekday)): ?&gt;<a href="#" title="&lt;?php echo $weekday[1] ?&gt;">&lt;?php echo $day ?&gt;</a>&lt;?php else: echo $day; endif ?&gt;</p>
</td>&lt;?php endforeach ?&gt;
</tr>&lt;?php endforeach ?&gt;
</table>
// controller method
$this->load->plugin('calendar');
$year = 2009;
$month = 4;
$data = getCalendar('month',array($year,$month),array(3=>'hello'));
// pad before the first day of the month isn't monday
$weekday_first = date('N',strtotime($year.'-'.$month.'-1'))-1;
if($weekday_first > 0)
{
   $prev_month_days = date('t',strtotime('-1 month',strtotime($year.'-'.$month.'-1')));    
   $data['items'] = array_merge(range($prev_month_days-$weekday_first,$prev_month_days),$data['items']);
}
// padd after if the array count can't be divided by seven
$mod = count($data['items']) % 7;
if($mod != 0)
{
   for($i=1,$max=ceil(7-$mod);$i<=$max;$i++){ $data['items'][] = $i; }
}
// split days into weeks
$data['rows'] = array_chunk($data['items'],7);
unset($data['items']);
$data['displayed_year'] = $year;
$data['displayed_month'] = $month;
$view['calendar'] = $this->load->view('calendar_month',$data,true);
What is the first impression?
#2

[eluser]sophistry[/eluser]
interesting reading. i like the fact that you are creating alternatives to the CI classes - they need some fresh insight!

first impression? dense code that looks smaller and more concise than the CI class even though it handles year, month, week, and day output. your coding style is quite a bit different than mine so i always learn a lot trying to "translate" it. ;-)

however, as you note in your example about using the month output it puts the onus on the developer to code up a proper table structure and fill it with all the right variables and ternary operators. the CI class has a template that creates a "common ground" for designers and coders to work together. it's annoying to have HTML outside of the view. but, in the case of generating the calendar, it works because it de-clutters the view code and makes the logic explicit (and named with template tags).

also, the month code above "hangs" the data on keys that are determined by the day number of the month. this creates problems if you want to display data in a month but show the data from the end of the previous month or the beginning of the next month.

i've been disappointed with the CI calendar class for a while. it doesn't seem like it is ever going to get fixed, so i began an object oriented version. your contribution spurred me to post it to the wiki. http://codeigniter.com/wiki/OOCalendar/

thanks!
#3

[eluser]xwero[/eluser]
I'm of the idea it's better to have php in the view than markup in the controller because if a designer wants to change the markup he/she has to ask you to change it. If developers mess around with php in the views it's easy to fix. and if you work with a designer that respects your work the fixing will be minimal.

I had not much place with all the code to add all my theories. You are right there is a problem if you want the data for the next and previous month maybe i should have a start and begin date. But what stopped me from adding it from the start is the fact that all of it only is for the month view. The rest of the views have a static set of items; 12 months, 7 days, 24 hours.

I had the idea of adding extra array items to the date but this opens a lot of possible variations. when you add previous and next month cells people will want to set the week start, adding different classes and data.
It can open a can of trouble.

Maybe i should split off the month view because it's too complex?
#4

[eluser]sophistry[/eluser]
markup in the view = good. agreed.

that's why i settled on an OO approach (see wiki page OOCalendar ) so that the object can be packed with data and the view can unpack it as needed. with CI's "template in the controller" approach the markup gets stuck in some ill-defined netherworld.

thanks for stirring the pot - your work is much appreciated.
#5

[eluser]xwero[/eluser]
After a good nights sleep i realised a week view can have days in a previous or next month too. Maybe it's better not to put the item data in a single array but in a two dimensional array which is how the data comes from the database anyway. And just read it out assuming the data is in synch with the period items

But then there is the problem if previous and/or next month days get generated you have to run the function before you can add data. I think there is no other choice than to put in in a library if you want this to be possible. In my framework independent way of creating libraries the database call will look like this
Code:
function pad_period($type,$date,$columns,$get_data=false,$framework='CI')
{
    // recycle the shown controller code here
    // fetch the first and last item to use in the period_data method if needed
    if($get_data)
    {
       $framework_data = 'period_data_'.strtolower($framework);
       $data = $this->$framework_data($first,$last);
    }
    // add data to the items
}

period_data_ci($start,$end)
{
    $CI =& get_instance();
    $CI->load->model($this->model,$this->model_name,true); // to be safe
    return $CI->{$this->model_name}->{$this->method_name}($start,$end);
}
The problem here is the way people store data and how to format the first and last item for the database retrieval. Or you can make it easy and just pass as much data as possible for the first and last item to the model function and the developer has to deal with it in the model method.

But i'm going to stick with the function for now because i think it can work.




Theme © iAndrew 2016 - Forum software by © MyBB