Friday 18 September 2015

How to build a web calendar in Laravel 5.1

Hi Everybody


Calendar is a very common element in today's web applications. Whether you are building an event booking application, appointment system or even a social network. Calendar is essential.
In this tutorial, we go through steps of building a calendar in Laravel 5.1.

After this tutorial, hopefully you will understand the concepts of building calendar and use the calendar script in your own application.

1. Building the Calendar route


   in routes.php

 Route::get('/calendar', 'CalendarController@getCalendar');

2. Building the calendar controller


  In controller /app/Http/Controllers/CalendarController.php

<?php

namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Input;
use App\Calendar;
use URL;

class CalendarController extends Controller
{

public function getCalendar()
    {
        $month = isset($_GET['month']) && !empty($_GET['month']) ? $_GET['month'] : '';
        $year = isset($_GET['year']) && !empty($_GET['year']) ? $_GET['year'] : '';
        $calendar = new Calendar(URL::to('/') . "/calendar");
        return view('calendar', ['calendar' => $calendar->show()]);
    }
}

3. Building the calendar model


   in model(app/Calendar.php) Calendar.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Calendar extends Model
{
    //
    public function __construct($currentRoute){
-        $this->naviHref = $currentRoute;
    }

    /********************* PROPERTY ********************/
    private $dayLabels = array("Mon","Tue","Wed","Thu","Fri","Sat","Sun");

    private $currentYear=0;

    private $currentMonth=0;

    private $currentDay=0;

    private $currentDate=null;

    private $daysInMonth=0;

    private $naviHref= null;

    /********************* PUBLIC **********************/

    /**
     * print out the calendar
     */
    public function show() {
        $year  = null;

        $month = null;

        if(null==$year&&isset($_GET['year'])){

            $year = $_GET['year'];

        }else if(null==$year){

            $year = date("Y",time());

        }

        if(null==$month&&isset($_GET['month'])){

            $month = $_GET['month'];

        }else if(null==$month){

            $month = date("m",time());

        }

        $this->currentYear=$year;

        $this->currentMonth=$month;

        $this->daysInMonth=$this->_daysInMonth($month,$year);

        $content='<div id="calendar">'.
            '<div class="box">'.
            $this->_createNavi().
            '</div>'.
            '<div class="box-content">'.
            '<ul class="label">'.$this->_createLabels().'</ul>';
        $content.='<div class="clear"></div>';
        $content.='<ul class="dates">';

        $weeksInMonth = $this->_weeksInMonth($month,$year);
        // Create weeks in a month
        for( $i=0; $i<$weeksInMonth; $i++ ){

            //Create days in a week
            for($j=1;$j<=7;$j++){
                $content.=$this->_showDay($i*7+$j);
            }
        }

        $content.='</ul>';

        $content.='<div class="clear"></div>';

        $content.='</div>';

        $content.='</div>';
        return $content;
    }

    /********************* PRIVATE **********************/
    /**
     * create the li element for ul
     */
    private function _showDay($cellNumber){

        if($this->currentDay==0){

            $firstDayOfTheWeek = date('N',strtotime($this->currentYear.'-'.$this->currentMonth.'-01'));

            if(intval($cellNumber) == intval($firstDayOfTheWeek)){

                $this->currentDay=1;

            }
        }

        if( ($this->currentDay!=0)&&($this->currentDay<=$this->daysInMonth) ){

            $this->currentDate = date('Y-m-d',strtotime($this->currentYear.'-'.$this->currentMonth.'-'.($this->currentDay)));

            $cellContent = $this->currentDay;

            $this->currentDay++;

        }else{

            $this->currentDate =null;

            $cellContent=null;
        }


        return '<li id="li-'.$this->currentDate.'" class="'.($cellNumber%7==1?' start ':($cellNumber%7==0?' end ':' ')).
        ($cellContent==null?'mask':'').'">'.$cellContent.'</li>';
    }

    /**
     * create navigation
     */
    private function _createNavi(){

        $nextMonth = $this->currentMonth==12?1:intval($this->currentMonth)+1;

        $nextYear = $this->currentMonth==12?intval($this->currentYear)+1:$this->currentYear;

        $preMonth = $this->currentMonth==1?12:intval($this->currentMonth)-1;

        $preYear = $this->currentMonth==1?intval($this->currentYear)-1:$this->currentYear;

        return
            '<div class="header">'.
            '<a class="prev" href="'.$this->naviHref.'?month='.sprintf('%02d',$preMonth).'&year='.$preYear.'">Prev</a>'.
            '<span class="title">'.date('Y M',strtotime($this->currentYear.'-'.$this->currentMonth.'-1')).'</span>'.
            '<a class="next" href="'.$this->naviHref.'?month='.sprintf("%02d", $nextMonth).'&year='.$nextYear.'">Next</a>'.
            '</div>';
    }

    /**
     * create calendar week labels
     */
    private function _createLabels(){

        $content='';

        foreach($this->dayLabels as $index=>$label){

            $content.='<li class="'.($label==6?'end title':'start title').' title">'.$label.'</li>';

        }

        return $content;
    }



    /**
     * calculate number of weeks in a particular month
     */
    private function _weeksInMonth($month=null,$year=null){

        if( null==($year) ) {
            $year =  date("Y",time());
        }

        if(null==($month)) {
            $month = date("m",time());
        }

        // find number of days in this month
        $daysInMonths = $this->_daysInMonth($month,$year);

        $numOfweeks = ($daysInMonths%7==0?0:1) + intval($daysInMonths/7);

        $monthEndingDay= date('N',strtotime($year.'-'.$month.'-'.$daysInMonths));

        $monthStartDay = date('N',strtotime($year.'-'.$month.'-01'));

        if($monthEndingDay<$monthStartDay){

            $numOfweeks++;

        }

        return $numOfweeks;
    }

    /**
     * calculate number of days in a particular month
     */
    private function _daysInMonth($month=null,$year=null){

        if(null==($year))
            $year =  date("Y",time());

        if(null==($month))
            $month = date("m",time());

        return date('t',strtotime($year.'-'.$month.'-01'));
    }

}

Let us take a look at each function in detail.

3.1. public function show():This is the only public function Calendar has. This function basically calls each private function below to create the HTML calendar interface. 

The basic idea of creating a web calendar is that, firstly it determines how many rows(weeks) to create, and then it loops over the rows and create 7 cells on each row. Meanwhile it puts corresponding day value to the cell according to the day of week (Monday to Sunday). 

Take a closer look at each private function below to understand.

3.2. private function _showDay():This function will determine what value to put to the created cell. It can be empty or numbers.

3.3. private function _createNavi(): This function will create the "Prev" && "Next" navigation buttons on the top of the calendar.

3.4. private function _createLabels(): This function will create labels for the day of week. ( Monday to Sunday). You can update the language string to your own choice. But be cautious. You should not change the order of the labels.

3.5. private function _weeksInMonth(): This is a tricky function. It can tell you how many weeks are there for a given month. This is used in show() function to create number of rows(weeks).

3.6. private function _daysInMonth(); This function tells how many days in a given month.
Functions are working closely to create the PHP calendar. You should follow function show() to understand deeply how exactly they call each. Code is documented. Give yourself some time to read it.

4. Make it prettier


Now the Calendar class is actually ready. 
However it looks messy without some CSS tricks. Let us create a CSS file "public/css/calendar.css" to make the calendar look pretty.

/*******************************Calendar Top Navigation*********************************/
div#calendar{
  margin:0px auto;
  padding:0px;
  width: 602px;
  font-family:Helvetica, "Times New Roman", Times, serif;
}
div#calendar div.box{
    position:relative;
    top:0px;
    left:0px;
    width:100%;
    height:40px;
    background-color:   #787878 ;      
}
div#calendar div.header{
    line-height:40px;  
    vertical-align:middle;
    position:absolute;
    left:11px;
    top:0px;
    width:582px;
    height:40px;   
    text-align:center;
}
div#calendar div.header a.prev,div#calendar div.header a.next{ 
    position:absolute;
    top:0px;   
    height: 17px;
    display:block;
    cursor:pointer;
    text-decoration:none;
    color:#FFF;
}
div#calendar div.header span.title{
    color:#FFF;
    font-size:18px;
}
div#calendar div.header a.prev{
    left:0px;
}
div#calendar div.header a.next{
    right:0px;
}
/*******************************Calendar Content Cells*********************************/
div#calendar div.box-content{
    border:1px solid #787878 ;
    border-top:none;
}
div#calendar ul.label{
    float:left;
    margin: 0px;
    padding: 0px;
    margin-top:5px;
    margin-left: 5px;
}
div#calendar ul.label li{
    margin:0px;
    padding:0px;
    margin-right:5px;  
    float:left;
    list-style-type:none;
    width:80px;
    height:40px;
    line-height:40px;
    vertical-align:middle;
    text-align:center;
    color:#000;
    font-size: 15px;
    background-color: transparent;
}
div#calendar ul.dates{
    float:left;
    margin: 0px;
    padding: 0px;
    margin-left: 5px;
    margin-bottom: 5px;
}
/** overall width = width+padding-right**/
div#calendar ul.dates li{
    margin:0px;
    padding:0px;
    margin-right:5px;
    margin-top: 5px;
    line-height:80px;
    vertical-align:middle;
    float:left;
    list-style-type:none;
    width:80px;
    height:80px;
    font-size:25px;
    background-color: #DDD;
    color:#000;
    text-align:center; 
}
:focus{
    outline:none;
}
div.clear{
    clear:both;
}

5. Now let us show the calendar.

Create a test file "/resources/views/calendar.blade.php".

<html>
<head>   
<link rel="stylesheet" type="text/css" href="{{asset('/css/calendar.css')}}"/>
</head>
<body>
<div class="container-fluid">
<div class="media_box">
<div class="row media_box">
<div class="col-md-6">
<?=$calendar?>
</div>
</div>
</div>
</div>
</body>
</html>



Hopefully this simple tutorial helped you with your development.

If you have questions or find any mistakes in above tutorial, do leave a comment below to let us know.

2 comments:

  1. Thank you for posting this article.I am new to laravel,I want to create a calendar for fixing appointments.How to create that in laravel.
    Any help would be appreciated .

    ReplyDelete