Fixes for MS SQL server
[bdrem.git] / src / bdrem / Source / Sql.php
1 <?php
2 namespace bdrem;
3
4 /**
5  * Fetch data from an SQL database
6  */
7 class Source_Sql
8 {
9     protected $dsn;
10     protected $user;
11     protected $password;
12     protected $table;
13     protected $fields ;
14
15     public function __construct($config)
16     {
17         $this->dsn      = $config['dsn'];
18         $this->user     = $config['user'];
19         $this->password = $config['password'];
20         $this->table    = $config['table'];
21         $this->fields   = $config['fields'];
22     }
23
24     /**
25      * @param string $strDate Date the events shall be found for, YYYY-MM-DD
26      */
27     public function getEvents($strDate, $nDaysPrevious, $nDaysNext)
28     {
29         $dbh = new \PDO(
30             $this->dsn, $this->user, $this->password,
31             array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION)
32         );
33         $arDays = $this->getDates($strDate, $nDaysPrevious, $nDaysNext);
34         $arEvents = array();
35
36         foreach ($this->fields['date'] as $field => $typeName) {
37             if (substr($this->dsn, 0, 5) == 'dblib') {
38                 //MS SQL Server does of course cook its own sht
39                 $sqlMonth = 'DATEPART(month, ' . $field . ')';
40                 $sqlDay = 'DATEPART(day, ' . $field . ')';
41             } else {
42                 $sqlMonth = 'EXTRACT(MONTH FROM ' . $field . ')';
43                 $sqlDay = 'EXTRACT(DAY FROM ' . $field . ')';
44             }
45
46             $parts = array();
47             foreach ($arDays as $month => $days) {
48                 $parts[] = '('
49                     . $sqlMonth . ' = ' . $dbh->quote($month, \PDO::PARAM_INT)
50                     . ' AND ' . $sqlDay . ' >= '
51                     . $dbh->quote(min($days), \PDO::PARAM_INT)
52                     . ' AND ' . $sqlDay . ' <= '
53                     . $dbh->quote(max($days), \PDO::PARAM_INT)
54                     . ')';
55             }
56             $sql = 'SELECT ' . $field . ' AS e_date'
57                 . ', ' . implode(', ', (array) $this->fields['name'])
58                 . ' FROM ' . $this->table
59                 . ' WHERE '
60                 . implode(' OR ', $parts);
61
62             $res = $dbh->query($sql);
63             while ($row = $res->fetchObject()) {
64                 $arNameData = array();
65                 foreach ((array) $this->fields['name'] as $fieldName) {
66                     $arNameData[] = $row->$fieldName;
67                 }
68                 $name = call_user_func_array(
69                     'sprintf',
70                     array_merge(
71                         array($this->fields['nameFormat']),
72                         $arNameData
73                     )
74                 );
75                 $event = new Event(
76                     $name, $typeName,
77                     str_replace('0000', '????', $row->e_date)
78                 );
79                 if ($event->isWithin($strDate, $nDaysPrevious, $nDaysNext)) {
80                     $arEvents[] = $event;
81                 }
82             }
83         }
84         return $arEvents;
85     }
86
87     /**
88      * @return array Key is the month, value an array of days
89      */
90     protected function getDates($strDate, $nDaysPrevious, $nDaysNext)
91     {
92         $ts = strtotime($strDate) - 86400 * $nDaysPrevious;
93         $numDays = $nDaysPrevious + $nDaysNext;
94
95         $arDays = array();
96         do {
97             $arDays[(int) date('n', $ts)][] = (int) date('j', $ts);
98             $ts += 86400;
99         } while (--$numDays >= 0);
100         return $arDays;
101     }
102 }
103 ?>