-
Notifications
You must be signed in to change notification settings - Fork 0
/
README
executable file
·344 lines (249 loc) · 8.14 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
To install simply move htdocs to your public html directory, then set BOILER_LOCATION on line 3 of index to point to the framework folder.
Controllers are the start point of your page.
Testing and Building
====================
Building and testing (optional) is done with a build.xml make file for "ant". You may also consider using the following to help test your code.
The following tools have a config shipped with ant targets, and are fully compatible with Hudson/Jenkins CI
* PHP Mess Detector
pear channel-discover pear.phpmd.org
pear channel-discover pear.pdepend.org
pear install --alldeps phpmd/PHP_PMD
* PHP CodeSniffer
pear install PHP_CodeSniffer
* PHP Copy and Paste detector
pear channel-discover components.ez.no
pear install phpunit/phpcpd
* PHPUnit
pear channel-discover pear.phpunit.de
pear channel-discover pear.symfony-project.com
pear install phpunit/PHPUnit
* PHPUnit skelgen
pear install phpunit/PHPUnit_SkeletonGenerator
CONTROLLERS
===========
-Namespacing follows folder structure to allow PHP lazy loading (please see php.net for Namespacing and __autoload)
-All classes must be namespaced with Controller. This is to allow you to have a controller and model, for example, with the same name.
-Functions being called must be public
-First letter only of class is capitalized
Examples:
http://localhost/class/function/args1/args2/args3
Would execute:
$c = new \Controller\Class();
$c->function(args1, args2, args3);
http://localhost/ns1/ns2/ns3/class/function
Would Execute:
$c = new \Controller\ns1\ns2\ns3\Class();
$c->function();
MODELS
======
-Models should extend DBObject normally for MySQL objects
-Models must be namespaced
-DBObject class (found in application/model/DBObject.php) must have login details entered for PHP
<?php
namespace Model;
class MySQLTable extends DBObject {
public static function getTable($read=true) {
return "mysql_table_name";
}
public static function getPrimaryKey() {
return "mysql_primary_key";
OR
return array("concat", "key");
}
}
//That's it! No SQL! Your MySQL settings are retrieved from a config.php file, built by ant. This stops you committing your MySQL details to git - pretty irritating!
?>
More advanced functions:
N.B. This is a demo which came from when the framework was not namespaced.
<?php
ini_set('display_errors', "On");
include "Linq.php";
include "DBObject.php";
/*
Employee
*/
class Employee extends DBObject {
public static function getPrimaryKey() {
//Use an array for concatinated keys
return "id";
}
public static function getTable($read=true) {
//$read variable gives the class a "heads up" about what is going to be done. Sometimes I have created a
//MySQL view for reading (which of course is read only) and therefore have had to specify a table as well
//for write operations
return "employee";
}
public static function getDB() {
return LinqDB::getDB("mysql.bcslichfield.com", "star241_6", "devpasswd123=", "bcslichfield_dev");
}
//Some nice utility functions
public function getJobs() {
return EmployeeJob::getJobsByEmployee($this);
}
public function giveJob(Job $j) {
EmployeeJob::giveJob($this, $j);
}
}
/*
LINK TABLE to stop many-to-many between Employee and Job
*/
class EmployeeJob extends DBObject {
public static function getPrimaryKey() {
//Use an array for concatinated keys
return array("employee", "job");
}
public static function getTable($read=true) {
//$read variable gives the class a "heads up" about what is going to be done. Sometimes I have created a
//MySQL view for reading (which of course is read only) and therefore have had to specify a table as well
//for write operations
return "employee_job";
}
public static function getDB() {
return LinqDB::getDB("mysql.bcslichfield.com", "star241_6", "devpasswd123=", "bcslichfield_dev");
}
//Some nice function we'll just add in because they are nice to use in a link table
public static function getJobsByEmployee(Employee $e) {
return self::getByAttribute("employee", $e->id);
}
public static function getEmployeesByJob(Job $j) {
return self::getByAttribute("job", $j->id);
}
public static function giveJob(Employee $e, Job $j) {
self::Create(array('employee'=>$e->id, 'job'=>$j->id));
}
}
/*
Jobs table
*/
class Job extends DBObject {
public static function getPrimaryKey() {
//Use an array for concatinated keys
return array("id");
}
public static function getTable($read=true) {
//$read variable gives the class a "heads up" about what is going to be done. Sometimes I have created a
//MySQL view for reading (which of course is read only) and therefore have had to specify a table as well
//for write operations
return "job";
}
public static function getDB() {
return LinqDB::getDB("mysql.bcslichfield.com", "star241_6", "devpasswd123=", "bcslichfield_dev");
}
//A nice little function to aid us
public function getEmployees() {
return EmployeeJob::getEmployeesByJob($this);
}
}
// class LinqDB extends mysqli, so feel free to use it as mysqli too!
//Lets use it to setup some temp tables
$db = LinqDB::getDB("mysql.bcslichfield.com", "star241_6", "devpasswd123=", "bcslichfield_dev");
$db->query("CREATE TEMPORARY TABLE IF NOT EXISTS `employee` (
id INT AUTO_INCREMENT,
name varchar(50) NOT NULL,
male tinyint(1) NOT NULL DEFAULT 1,
dob DATETIME,
PRIMARY KEY (`id`)
) ENGINE=InnoDB");
$db->query("CREATE TEMPORARY TABLE IF NOT EXISTS `job` (
id INT AUTO_INCREMENT,
name varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB");
$db->query("CREATE TEMPORARY TABLE IF NOT EXISTS `employee_job` (
employee INT NOT NULL,
job INT NOT NULL,
PRIMARY KEY (`employee`, `job`)
) ENGINE=InnoDB");
/*
For debug (not applicable on temporary tables):
FOREIGN KEY (`employee`) REFERENCES `employee` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (`job`) REFERENCES `job` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
*/
/*
Once upon a time, in a factory far away there were three workers!
*/
$me = Employee::Create(array("name"=>"Will Tinsdeall"));
$bob = Employee::Create(array("name"=>"Bob Bloggs"));
$joe = Employee::Create(array("name"=>"Joe Bloggs"));
/*
And my AUTO_INCREMENT ID was:
*/
echo "TEST 1: ".$me->id."\r\n";
/*
In the factory there were many jobs
*/
$joba = Job::Create(array('name'=>'A very hard job'));
$jobb = Job::Create(array('name'=>'An average job'));
$jobc = Job::Create(array('name'=>'An easy job'));
/*
And we all had jobs
*/
$me->giveJob($joba);
$me->giveJob($jobb);
$bob->giveJob($joba);
$bob->giveJob($jobc);
$joe->giveJob($jobb);
$joe->giveJob($jobc);
/*
First of all the boss wanted to know all the jobs that were being done
*/
foreach (Job::getAll() as $j) {
echo "Job {$j->id}: {$j->name}"."\r\n";
}
/*
Next, he decided to quickly call me
*/
$me = new Employee("1");
/*
And asked me to check to see who was working well.
*/
$db->Select(Employee);
/*
This consisted of people
EITHER:
*/
$db->getOrFilter();
/*
Those doing a medium job only
*/
$jobs = $db->Select(EmployeeJob);
$jobs->addCount("jobs");
$jobs->addField("employee");
$jobs->addField("job");
$jobs->setGroup("employee");
/* SELECT COUNT(*) as jobs, employee FROM `employee_job` GROUP BY `employee` */
$j = $jobs->Select();
$jFilter = $db->getAndFilter();
$jFilter->eq("job","2")->eq("jobs", "1");
$j->setFilter($jFilter);
//SELECT * FROM (SELECT COUNT(*) as jobs, id FROM `employee_job` GROUP BY `employee`) WHERE `jobs`=1 AND `job`=2
/*
Or those doing an easy job and a very hard job
*/
$jobsB = $db->Select(EmployeeJob);
$jobsB->addField("employee");
$jBFilter = $db->getAndFilter();
$jBFilter->eq('job', 1)->eq("job", 3);
$jobsB->setFilter($jBFilter);
//XXX this would work if the tables weren't temporary!
/*
$u = $db->Union();
$u->addSelect($jobsB)->addSelect($jobs);
echo $u->getSQL();
*/
$out = array();
foreach (array_merge($jobsB->Exec(), $jobs->Exec()) as $a) {
var_dump($a);
$out[$a->employee] = new Employee($a->employee);
}
var_dump($out);
/*
Lastly he wanted a to assess everyone at their jobs (simple JOIN)
*/
$qEmployee = $db->Select(Employee);
$qEmployeeJob = $db->Select(EmployeeJob);
$qJob = $db->Select(Job);
$qEmployeeJob->joinLeft("employee", $qEmployee, "id");
$qEmployeeJob->joinLeft("job", $qJob, "id");
var_dump($qEmployeeJob->Exec());
?>