New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented integration with test_db / employee table. #1

Merged
merged 1 commit into from Feb 2, 2016
Jump to file or symbol
Failed to load files and symbols.
+332 −4
Diff settings

Always

Just for now

View
@@ -15,5 +15,4 @@ VERSION
/index.php
.idea
.composer
addons/
/db/*
View
@@ -5,4 +5,6 @@
'sqlite:../db/sqlite.sqlite3',
//'username',
//'password'
);
);
$config['dsn-employees'] = 'mysql://root:root@127.0.0.1/employees';
View
@@ -14,6 +14,17 @@ function init() {
$this->template->set('css','compact.css');
list($prefix) = explode('_',$this->page);
if($prefix == 'employees'){
$this->initEmployees();
}else{
$this->initBasic();
}
$this->layout->menu->js(true)->find('.active')->removeClass('atk-swatch-ink')->addClass('atk-swatch-blue');
}
function initBasic(){
$sm = $this->api->menu->addMenu('Core Features');
$sm ->addMenuItem('core/hello', 'Hello World');
@@ -41,10 +52,32 @@ function init() {
->link('/db')
->setAttr('title', $e->getText())
->js(true)->tooltip();
}
// unable to connect.
}
function initEmployees(){
$br = $this->menu->addItem('Browse Employee Data','employees/browse');
try {
$this->dbConnect('dsn-employees');
} catch(BaseException $e){
$this->layout->add('Button',null,'User_Menu')
->set(['Set up Employees Database', 'swatch'=>'red', 'icon'=>'attention'])
->link('/employees')
->setAttr('title', $e->getText())
->js(true)->tooltip();
}
}
}
function initTopMenu() {
$m=$this->layout->add('Menu_Horizontal',['highlight_subpages'=>true,'hover_swatch'=>'blue'],'Top_Menu');
$m->addItem('Basic Examples','/');
$m->addItem('Employee DB','/employees');
$m->addItem('AgileToolkit','/sandbox/dashboard');
$m->addItem('Documentation','http://book.agiletoolkit.org/');
$m->js(true)->find('.active')->removeClass('atk-swatch-ink')->addClass('atk-swatch-blue');
}
}
@@ -0,0 +1,111 @@
<?php
class page_employees_browse extends Page {
public $title='Browse Employee Data';
function page_index(){
$this->add('View_Info')->set('A few demos to show you how to access your data on record-by-record basis. If you want to look into the code, see "admin/page/employees/browse.php" file.');
$t = $this->add('Tabs');
$t_dep = $t->addTab('Departments');
$t_dep->add('CRUD')->setModel('emp/Model_Department');
$t->addTabURL('./employees','Employees');
$t->addTabURL('./salaries','Current Salaries');
}
function page_employees(){
$cr = $this->add('CRUD');
$cr->setModel('emp/Model_Employee');
$cr->grid->addPaginator();
$cr->grid->addQuickSearch(['emp_no','first_name','last_name']);
}
/**
* Page will allow us to explore employee salaries at a gieven point in time.
* The interface will offer you to enter a custom date and will also show you
* query used to retrieve data.
*/
function page_salaries(){
// Our page recognizes two get arguments. hiring_date=true will
// use condition on a salary join against a hiring date of an employee
// effectiely showing you their first salary at the time of hire.
// It's important to use stickyGET in here, because we don't
// want those GET arguments got be lost if user changes grid sorting.
if($this->app->stickyGET('hiring_date')){
// Specifying date parameter to a model will disable it's default
// date conditioning and allow us to build condition against
// defined model field
$m = $this->add('emp/Model_Employee_Salary',['date'=>false]);
$m->addCondition('salary_from_date','<=',$m->getElement('hire_date'));
$m->addCondition('salary_to_date','>=',$m->getElement('hire_date'));
}else{
// If date is specified, it will be used in a query. Otherwise
// null will be passed and model will default to today's date.
$m = $this->add('emp/Model_Employee_Salary',['date'=>$this->app->stickyGET('date')]);
}
// This box is used for displaying header with various information
// abone the grid.
$box = $this->add('View_Info');
$col = $box->add('View_Columns');
$info = $col->addColumn(2);
$info->add('H2')->set('Salaries');
$info->add('P')->set('Displaying query for 100 employee with their salary at a selected point in time.');
// Second column of our info header will contain a stacked form, where
// a user will be able to select a custom date for the report.
$form = $col->addColumn(2)->add('Form',null,null,['form/stacked']);
$form->addField('DatePicker','date')->set($_GET['date']);
$form->addSubmit(['Set Date','swatch'=>'blue']);
$b_hiring = $form->addSubmit('Hiring Date');
// When form is submitted we will use AJAX reloading to pass
// an extra parameter for this page.
$form->onSubmit(function($form)use($b_hiring){
if($form->isClicked($b_hiring)){
return $this->js()->reload(['hiring_date'=>true]);
}
return $this->js()->reload(['date'=>$form['date'],'hire_date'=>false]);
});
// The last column will display query that was used to produce the data.
// We do not know the query at this point yet, so we will set the
// contents of this view later.
$v_query = $col->addColumn(8);
$v_query->setStyle('overflow-x','auto');
// Initialize CRUD element, but don't set it up just yet.
$cr = $this->add('CRUD');
// Button to use the current model (with implied conditions) to
// perform a count() query and display list of matched records.
$cr->grid->addButton('Get Record Count')->onClick(function($b)use($m){
return 'There are '.$m->count().' employee records matching';
});
// Button to use the current model (with implied conditions) to
// display average salary
$cr->grid->addButton('Get Average Salary')->onClick(function($b)use($m){
return 'Avearge salary is '.$m->avg('salary');
});
// Limit to 100 records only and only query for relevant fields.
$m->setLimit(100);
$cr->setModel($m,['emp_no','first_name','last_name','hire_date','salary','salary_from_date','salary_to_date']);
// Still allow to do a quick-search on some fields. We will also allow
// user to perform search on the salary.
$cr->grid->addQuickSearch(['emp_no','first_name','last_name','salary']);
// Now that evertyhing is configured, we want to get a query and
// display it in the header. This will not contain conditions for
// quick-search or ordering, since those are added dureng render() stage.
$v_query->add('View')->setElement('code')->setHTML($m->selectQuery()->getDebugQuery());
}
}
View
Binary file not shown.
@@ -0,0 +1,38 @@
<div id="{$_name}" class="page_{$_page} atk-size-mega">
<h2>Employee Database Demos</h2>
<p>
This section of the "Sink" applictaion demonstrates how to access real-life data-base through Agile Toolkit.
<a href="https://github.com/datacharmer/test_db" target="blank">test_db</a> is a public project containing
a prety sizeable data-set for testing applications and data-bases containing about 300,000 employee records
with about 2.8 mil. salary records. With such a data-set we focus on demonstating how to efficiently query
this data.
</p><img src="{public}image/employees-db.png{/}"/>
<p class="atk-effect-danger">
You will need to configure your database and import the data before accessing any of the demos here.
</p>
<h3>1. Install Employee database on your local machine</h3>
<p>Follow the <a href="https://github.com/datacharmer/test_db" target="blank">link to test_db project</a> then
click "Download ZIP" button. Run "mysql &lt; employees_partitioned.sql" in your command-line from this new
folder and if you have any problems, refer to test_db documentation. This will create "employees" database
for you.
</p>
<h3>2. Configure SQL access</h3>
<p>
As per "admin/config-default.php" file your default access string is "mysql://root:root@127.0.0.1/employees".
If you need to use a different MySQL username or password to connect, then create file "admin/config.php"
with the following inside:
</p>
<div class="atk-box"><code>
<pre>&lt;?php
$config['dsn-employees'] = 'mysql://user:secret@127.0.0.1/employees';
</pre></code></div>
<p>
Refresh this page and the warning on the top-rigtht corner should now dissapear.
</p>{$Content}
</div>
@@ -0,0 +1,37 @@
div(id="{$_name}" class="page_{$_page}").atk-size-mega
h2 Employee Database Demos
p.
This section of the "Sink" applictaion demonstrates how to access real-life data-base through Agile Toolkit.
#[a(href="https://github.com/datacharmer/test_db" target="blank") test_db] is a public project containing
a prety sizeable data-set for testing applications and data-bases containing about 300,000 employee records
with about 2.8 mil. salary records. With such a data-set we focus on demonstating how to efficiently query
this data.
img(src="{public}image/employees-db.png{/}")
p.atk-effect-danger.
You will need to configure your database and import the data before accessing any of the demos here.
h3 1. Install Employee database on your local machine
p.
Follow the #[a(href="https://github.com/datacharmer/test_db" target="blank") link to test_db project] then
click "Download ZIP" button. Run "mysql &lt; employees_partitioned.sql" in your command-line from this new
folder and if you have any problems, refer to test_db documentation. This will create "employees" database
for you.
h3 2. Configure SQL access
p.
As per "admin/config-default.php" file your default access string is "mysql://root:root@127.0.0.1/employees".
If you need to use a different MySQL username or password to connect, then create file "admin/config.php"
with the following inside:
.atk-box
code
pre.
&lt;?php
$config['dsn-employees'] = 'mysql://user:secret@127.0.0.1/employees';
p.
Refresh this page and the warning on the top-rigtht corner should now dissapear.
{$Content}
@@ -0,0 +1,15 @@
<?php
namespace emp;
class Model_Department extends \SQL_Model {
public $table='departments';
public $id_field='dept_no';
function init(){
parent::init();
$this->getElement('dept_no')->editable(true)->visible(true);
$this->addField('dept_name');
}
}
@@ -0,0 +1,27 @@
<?php
namespace emp;
/**
* This model defines our access to a model table. A typicall table would have
* an auto-increment ID field, however the sample data uses a custom IDs, so
* we will have to make those editable and viewable. If you will be adding
* new employee, you would need to supply emp_no also.
*/
class Model_Employee extends \SQL_Model {
public $table='employees';
public $id_field='emp_no';
function init(){
parent::init();
$this->getElement('emp_no')->editable(true)->visible(true);
$this->addField('birth_date')->type('date')->sortable(true);
$this->addField('first_name')->sortable(true);
$this->addField('last_name')->sortable(true);
$this->addField('gender')->enum(['M','F'])->sortable(true);
$this->addField('hire_date')->type('date')->sortable(true);
}
}
@@ -0,0 +1,66 @@
<?php
namespace emp;
/**
* This model can dynamically calculate salaries for our employees for a
* desired time.
*
* $m = $this->add('emp/Model_Employee_Salary', ['date'=>$date]);
*
* $date => null -- will use today's date
* $date => '1990-01-01' -- will set a custom date
* $date => false -- will not set date condition leaving it to you
*/
class Model_Employee_Salary extends Model_Employee {
protected $date = null;
function init(){
parent::init();
if($this->date === null){
$this->date = date('Y-m-d');
}
// Creates join with a salaries table and defines necessary fields
$j_salary = $this->join('salaries.emp_no');
$j_salary->addField('salary_from_date','from_date')->type('date');
$j_salary->addField('salary_to_date','to_date')->type('date');
$j_salary->addField('salary')->sortable(true);
// We leave an option to disable automatic inclusion of this condition
// in case we want to manually define conditions
if($this->date)$this->addDateCondition();
}
function addDateCondition(){
$this->addCondition('salary_from_date','<=',$this->date);
$this->addCondition('salary_to_date','>=',$this->date);
}
// This method is missing from ATK, so adding manually (copy-pasted from sum())
function avg($field)
{
// prepare new query
$q = $this->dsql()->del('fields')->del('order');
// put field in array if it's not already
if (!is_array($field)) {
$field = array($field);
}
// add all fields to query
foreach ($field as $f) {
if (!is_object($f)) {
$f = $this->getElement($f);
}
$q->field($q->expr('avg([0])',[$f]), $f->short_name);
}
// return query
return $q;
}
}
ProTip! Use n and p to navigate between commits in a pull request.