staff create/update/delete ready

parent c0263ac7
.phpintel
vendor
\ No newline at end of file
vendor
/nbproject/private/
\ No newline at end of file
This diff is collapsed.
......@@ -14,6 +14,7 @@ return [
['/school', ['school'], ['get']],
['/school/labs', ['school'], ['get']],
['/school/staff', ['school'], ['get', 'post']],
['/school/staff/{id:[1-9][0-9]*}', ['school'], ['delete']],
['/school/assets', ['school'], ['get']],
],
],
......
......@@ -28,7 +28,7 @@ return function (Slim\App $app) {
$container['settings']['db']['user'],
$container['settings']['db']['pass']
);
RedBeanPHP\R::freeze();
// RedBeanPHP\R::freeze();
$container['view'] = function ($c) {
$settings = $c['settings'];
......
......@@ -25,16 +25,22 @@ return function (Slim\App $app) {
);
};
$container[GrEduLabs\Schools\Action\Staff::class] = function ($c) {
return new GrEduLabs\Schools\Action\Staff(
$container[GrEduLabs\Schools\Action\Staff\ListAll::class] = function ($c) {
return new GrEduLabs\Schools\Action\Staff\ListAll(
$c->get('view'),
$c->get('staffservice')
$c->get(GrEduLabs\Schools\Service\StaffService::class)
);
};
$container[GrEduLabs\Schools\Action\StaffCreate::class] = function ($c) {
return new GrEduLabs\Schools\Action\StaffCreate(
$c->get('staffservice')
$container[GrEduLabs\Schools\Action\Staff\PersistTeacher::class] = function ($c) {
return new GrEduLabs\Schools\Action\Staff\PersistTeacher(
$c->get(GrEduLabs\Schools\Service\StaffService::class)
);
};
$container[GrEduLabs\Schools\Action\Staff\DeleteTeacher::class] = function ($c) {
return new GrEduLabs\Schools\Action\Staff\DeleteTeacher(
$c->get(GrEduLabs\Schools\Service\StaffService::class)
);
};
......@@ -58,9 +64,17 @@ return function (Slim\App $app) {
return new GrEduLabs\Schools\Service\SchoolService();
};
$container['staffservice'] = function ($c) {
return new GrEduLabs\Schools\Service\StaffService(
new GrEduLabs\Schools\Filter\Teacher()
$container[GrEduLabs\Schools\InputFilter\Teacher::class] = function ($c) {
return new GrEduLabs\Schools\InputFilter\Teacher();
};
$container[GrEduLabs\Schools\Service\StaffService::class] = function ($c) {
return new GrEduLabs\Schools\Service\StaffService();
};
$container[GrEduLabs\Schools\Middleware\InputFilterTeacher::class] = function ($c) {
return new GrEduLabs\Schools\Middleware\InputFilterTeacher(
$c->get(GrEduLabs\Schools\InputFilter\Teacher::class)
);
};
......@@ -89,8 +103,13 @@ return function (Slim\App $app) {
$app->group('/school', function () {
$this->get('', GrEduLabs\Schools\Action\Index::class)->setName('school');
$this->get('/staff', GrEduLabs\Schools\Action\Staff::class)->setName('school.staff');
$this->post('/staff', GrEduLabs\Schools\Action\StaffCreate::class)->setName('school.staffcreate');
$this->get('/staff', GrEduLabs\Schools\Action\Staff\ListAll::class)->setName('school.staff');
$this->post('/staff', GrEduLabs\Schools\Action\Staff\PersistTeacher::class)
->add(GrEduLabs\Schools\Middleware\InputFilterTeacher::class)
->setName('school.staffcreate');
$this->delete('/staff/{id:[1-9][0-9]*}', GrEduLabs\Schools\Action\Staff\DeleteTeacher::class)
->setName('school.staffdelete');
$this->get('/labs', GrEduLabs\Schools\Action\Labs::class)->setName('school.labs');
$this->post('/labs', GrEduLabs\Schools\Action\LabCreate::class)->setName('school.labcreate');
$this->get('/assets', GrEduLabs\Schools\Action\Assets::class)->setName('school.assets');
......
......@@ -178,6 +178,26 @@ INSERT INTO `schooltype` VALUES (1,'ΝΗΠΙΑΓΩΓΕΙΟ',1),(2,'ΔΗΜΟΤΙ
/*!40000 ALTER TABLE `schooltype` ENABLE KEYS */;
UNLOCK TABLES;
DROP TABLE IF EXISTS `teacher`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `teacher` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`school_id` int(11) unsigned NOT NULL,
`name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`surname` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`telephone` int(11) unsigned NOT NULL,
`email` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`branch_id` int(11) unsigned NOT NULL,
`is_principle` tinyint(1) unsigned DEFAULT '0',
`is_responsible` tinyint(1) unsigned DEFAULT '0',
PRIMARY KEY (`id`),
KEY `index_foreignkey_teacher_school` (`school_id`),
KEY `index_foreignkey_teacher_branch` (`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
......
......@@ -2,100 +2,112 @@
'use strict';
var Staff,
Employee,
EmployeeView,
Teacher,
StaffRow,
StaffView,
ModalView,
employeeTemplate;
TeacherView,
teacherTemplate;
Employee = Backbone.Model.extend({ idAttribute: 'id' });
Teacher = Backbone.Model.extend({ idAttribute: 'id' });
Staff = Backbone.Collection.extend({
model: Employee,
model: Teacher,
comparator: 'surname'
});
EmployeeView = Backbone.View.extend({
StaffRow = Backbone.View.extend({
tagName: 'tr',
template: (function () {
if (typeof employeeTemplate === 'undefined') {
employeeTemplate = _.template($('#employee-row').html());
if (typeof teacherTemplate === 'undefined') {
teacherTemplate = _.template($('#teacher-row').html());
}
return employeeTemplate;
return teacherTemplate;
}()),
initialize: function () {
this.model.on('change', this.render, this);
this.model.on('remove', this.remove, this);
},
render: function () {
this.$el.html(this.template({ employee: this.model.attributes }));
this.$el.html(this.template({ teacher: this.model.attributes }));
this.$el.attr('data-id', this.model.get('id'));
return this;
},
remove: function () {
this.$el.remove();
}
});
StaffView = Backbone.View.extend({
el: '#school',
modal: null,
teacherView: null,
events: {
'click .btn-add-employee': 'addEmployee',
'click .btn-add-teacher': 'addEmployee',
'click tbody tr': 'editEmployee'
},
initialize: function () {
var that = this;
this.modal = new ModalView();
this.teacherView = new TeacherView({model: this.model});
_.each(this.$el.find('tbody tr'), function (tr) {
var data = $(tr).data('employee'),
employee = new Employee(data);
that.model.add(employee);
new EmployeeView({ model: employee, el: tr });
$(tr).attr('data-employee', null);
var data = $(tr).data('teacher'),
teacher = new Teacher(data);
that.model.add(teacher);
new StaffRow({ model: teacher, el: tr });
$(tr).attr('data-teacher', null);
});
this.model.on('add', this.renderEmployee, this);
},
addEmployee: function (evt) {
var that = this;
evt.preventDefault();
this.modal.render(function (data) {
that.model.add(data);
that.$el.find('.no-records').remove();
});
this.teacherView.render();
return this;
},
editEmployee: function (evt) {
var employee = this.model.get($(evt.target).closest('tr').data('id'));
var teacherId;
if ($(evt.target).is('a')) return;
if (!employee) return;
this.modal.render(function (data) {
employee.set(data);
}, employee.attributes);
teacherId = $(evt.target).closest('tr').data('id');
this.teacherView.render(teacherId);
return this;
},
renderEmployee: function (employee) {
this.$el.find('tbody').append(new EmployeeView({
model: employee
renderEmployee: function (teacher) {
this.$el.find('tbody').append(new StaffRow({
model: teacher
}).render().el);
return this;
}
});
ModalView = Backbone.View.extend({
el: '#employee-form-modal',
TeacherView = Backbone.View.extend({
el: '#teacher-form-modal',
form: null,
teacher: null,
url: null,
events: {
'submit form': 'submit',
'submit form': 'persistTeacher',
'click button.remove': 'removeTeacher',
},
initialize: function () {
this.form = this.$el.find('form');
this.url = this.form.data('url');
},
render: function (done, employee) {
this.form.data('done', done);
render: function (teacherId) {
var teacherAttributes;
this.form[0].reset();
this.form.find('input[type="hidden"]').val('');
employee = employee || {};
if (!teacherId) {
this.$el.find('.modal-footer button.remove').addClass('hidden');
} else {
this.$el.find('.modal-footer button.remove').removeClass('hidden');
}
this.teacher = teacherId && this.model.get(teacherId) || null;
teacherAttributes = this.teacher && this.teacher.attributes || {};
_.each(this.form[0].elements, function (element) {
var element = $(element),
name = element.attr('name');
element.val(employee[name] || '');
if ('checkbox' === element.attr('type')) {
element.prop('checked', parseInt(teacherAttributes[name], 10));
} else {
element.val(teacherAttributes[name] || '');
}
});
this.show();
},
......@@ -105,21 +117,40 @@
hide: function () {
this.$el.modal('hide');
},
submit: function (evt) {
persistTeacher: function (evt) {
var data = _.reduce(this.form.serializeArray(), function (hash, pair) {
hash[pair.name] = pair.value;
return hash;
}, {});
var that = this;
evt.preventDefault();
$.post("", data).
$.post(this.url, data).
done(function(response){
that.form.data('done')(response);
that.form.data('done', undefined);
if (that.teacher) {
that.teacher.set(response);
} else{
that.model.add(response);
}
that.hide();
}).fail(function (xhr, err) {
alert(xhr.statusText);
});
},
removeTeacher: function () {
var that = this;
if (!confirm('Να διαγραφεί ο εκπαιδευτικός;')) {
return;
}
$.ajax({
url: this.url + '/' + this.teacher.get('id'),
type: 'delete',
dataType: 'json'
}).done(function () {
that.model.remove(that.teacher.get('id'));
that.hide();
}).fail(function (xhr, err) {
alert(xhr.statusText);
});
}
});
......
<?php
/**
* gredu_labs.
*
* @link https://github.com/eellak/gredu_labs for the canonical source repository
*
* @copyright Copyright (c) 2008-2015 Greek Free/Open Source Software Society (https://gfoss.ellak.gr/)
* @license GNU GPLv3 http://www.gnu.org/licenses/gpl-3.0-standalone.html
*/
namespace GrEduLabs\Schools\Action\Staff;
use Exception;
use GrEduLabs\Schools\Service\StaffServiceInterface;
use Slim\Http\Request;
use Slim\Http\Response;
class DeleteTeacher
{
/**
*
* @var StaffServiceInterface
*/
private $staffService;
public function __construct(StaffServiceInterface $staffService)
{
$this->staffService = $staffService;
}
public function __invoke(Request $req, Response $res, array $args = [])
{
$school = $req->getAttribute('school', false);
if (!$school->id) {
return $res->withStatus(403, 'No school');
}
$id = isset($args['id']) ? $args['id'] : false;
if (!$id) {
$res = $res->withStatus(404);
return $res;
}
$teacher = $this->staffService->getTeacherById($id);
if ($teacher['school_id'] != $school->id) {
$res = $res->withStatus(403, 'Schools not match');
return $res;
}
try {
$this->staffService->removeTeacher($id);
$res = $res->withStatus(204);
} catch (Exception $ex) {
$res = $res->withStatus(500, $ex->getMessage());
}
return $res;
}
}
......@@ -8,31 +8,37 @@
* @license GNU GPLv3 http://www.gnu.org/licenses/gpl-3.0-standalone.html
*/
namespace GrEduLabs\Schools\Action;
namespace GrEduLabs\Schools\Action\Staff;
use GrEduLabs\Schools\Service\StaffServiceInterface;
use Slim\Http\Request;
use Slim\Http\Response;
use Slim\Views\Twig;
class Staff
class ListAll
{
protected $view;
private $view;
private $staffService;
public function __construct(Twig $view, $staffservice)
public function __construct(Twig $view, StaffServiceInterface $staffService)
{
$this->view = $view;
$this->staffservice = $staffservice;
$this->staffService = $staffService;
}
public function __invoke(Request $req, Response $res, array $args = [])
{
$staff = $this->staffservice->getTeachersBySchoolId(1);
$school = $req->getAttribute('school', false);
if (!$school) {
return $res->withStatus(403, 'No school');
}
$staff = $this->staffService->getTeachersBySchoolId($school->id);
return $this->view->render($res, 'schools/staff.twig', [
'staff' => $staff,
'branches' => array_map(function ($branch) {
'branches' => array_map(function ($branch) {
return ['value' => $branch['id'], 'label' => $branch['name']];
}, $this->staffservice->getBranches()),
}, $this->staffService->getBranches()),
]);
}
}
......@@ -8,17 +8,24 @@
* @license GNU GPLv3 http://www.gnu.org/licenses/gpl-3.0-standalone.html
*/
namespace GrEduLabs\Schools\Action;
namespace GrEduLabs\Schools\Action\Staff;
use Exception;
use GrEduLabs\Schools\Service\StaffServiceInterface;
use Slim\Http\Request;
use Slim\Http\Response;
class StaffCreate
class PersistTeacher
{
/**
*
* @var StaffServiceInterface
*/
private $staffService;
public function __construct($staffservice)
public function __construct(StaffServiceInterface $staffService)
{
$this->staffservice = $staffservice;
$this->staffService = $staffService;
}
public function __invoke(Request $req, Response $res, array $args = [])
......@@ -27,26 +34,24 @@ class StaffCreate
if (!$school) {
return $res->withStatus(403, 'No school');
}
$params = $req->getParams();
$id = $params['id'];
unset($params['id']);
$params = $req->getParams();
$params['school_id'] = $school->id;
if ($id > 0) {
$id = $this->staffservice->updateTeacher($params, $id);
$teacher = $this->staffservice->getTeacherById($id);
} else {
$id = $this->staffservice->createTeacher($params);
if ($id > 0) {
$teacher = $this->staffservice->getTeacherById($id);
$id = $params['id'];
unset($params['id']);
try {
if ($id) {
$teacher = $this->staffService->updateTeacher($params, $id);
$res = $res->withStatus(200);
} else {
$teacher = $this->staffService->createTeacher($params);
$res = $res->withStatus(201);
}
$res = $res->withJson($teacher);
} catch (Exception $ex) {
$res = $res->withStatus(500, $ex->getMessage());
}
if (isset($teacher)) {
return $res->withJson(array_merge($teacher->export(), [
'branch' => $teacher->branch->name,
]))->withStatus(201);
} else {
return $res->withStatus(400);
}
return $res;
}
}
<?php
/**
* gredu_labs
*
* @link https://github.com/eellak/gredu_labs for the canonical source repository
* @copyright Copyright (c) 2008-2015 Greek Free/Open Source Software Society (https://gfoss.ellak.gr/)
* @license GNU GPLv3 http://www.gnu.org/licenses/gpl-3.0-standalone.html
*/
namespace GrEduLabs\Schools\Filter;
use InvalidArgumentException;
class Teacher
{
// private static $required = [
// 'school_id',
// 'branch_id',
// 'name',
// 'surname',
// 'email',
// 'telephone',
// ];
// private static $optional = [
// 'is_principle',
// 'is_responsible',
// ];
// private static $messageTemplates = [
// 'school_id' => 'Δεν ορίστηκε το σχολείο',
// 'branch_id' => 'Δεν ορίστηκε η ειδικότητα',
// 'name' => 'Δεν ορίστηκε το όνομα',
// 'surname' => 'Δεν ορίστηκε το επώνυμο',
// 'email'=> 'Δεν ορίστηκε το email',
// 'telephone' => 'Δεν ορίστηκε το τηλέφωνο',
// ];
private static $filter = [
'school_id' => [
'filter' => FILTER_VALIDATE_INT,
'flags' => FILTER_REQUIRE_SCALAR,
],
'branch_id' => [
'filter' => FILTER_VALIDATE_INT,
'flags' => FILTER_REQUIRE_SCALAR,
],
'name' => [
'filter' => FILTER_SANITIZE_STRING,
'flags' => FILTER_REQUIRE_SCALAR,
],
'surname' => [
'filter' => FILTER_SANITIZE_STRING,
'flags' => FILTER_REQUIRE_SCALAR,
],
'email' => FILTER_VALIDATE_EMAIL,
'telephone' => FILTER_SANITIZE_NUMBER_INT,
'is_principle' => [
'filter' => FILTER_VALIDATE_BOOLEAN,
],
'is_responsible' => [
'filter' => FILTER_VALIDATE_BOOLEAN,
],
];
public function __invoke(array $data, $create = true)
{
var_dump(filter_var_array($data, self::$filter, $create));
die();
// $messages = [];
// $fields = array_merge(self::$required, self::$optional);
// $data = array_intersect_key($data, array_flip($fields));
// $filtered = array_map('trim', $data);
// foreach (self::$required as $required) {
// if (!isset($data[$required])|| empty($data[$required])) {
// $messages[$required][] = self::$messageTemplates[$required];
// }
// }
// if (filter_input_array(type))
// var_dump($messages);
// die();
}
}
\ No newline at end of file
<?php
/**
* gredu_labs
*
* @link https://github.com/eellak/gredu_labs for the canonical source repository
* @copyright Copyright (c) 2008-2015 Greek Free/Open Source Software Society (https://gfoss.ellak.gr/)
* @license GNU GPLv3 http://www.gnu.org/licenses/gpl-3.0-standalone.html
*/
namespace GrEduLabs\Schools\InputFilter;
use Zend\Filter;
use Zend\InputFilter\Input;
use Zend\InputFilter\InputFilter;
use Zend\Validator;
class Teacher
{
private $inputFilter;
public function __construct()
{
$id = new Input('id');
$id->setRequired(false)
->setBreakOnFailure(true)
->getValidatorChain()
->attach(new Validator\Digits());
$name = new Input('name');
$name->setRequired(true)
->setBreakOnFailure(true)
->getFilterChain()
->attach(new Filter\StringTrim());
$name->getValidatorChain()
->attach(new Validator\NotEmpty())
->attach(new Validator\StringLength(['min' => 3]));
$surname = new Input('surname');
$surname->setRequired(true)
->setBreakOnFailure(true)
->getFilterChain()
->attach(new Filter\StringTrim());
$surname->getValidatorChain()
->attach(new Validator\NotEmpty())
->attach(new Validator\StringLength(['min' => 3]));
$email = new Input('email');
$email->setRequired(true)
->setBreakOnFailure(true)
->getValidatorChain()
->attach(new Validator\NotEmpty())
->attach(new Validator\EmailAddress());
$telephone = new Input('telephone');
$telephone->setRequired(true)
->setBreakOnFailure(true)
->getValidatorChain()
->attach(new Validator\NotEmpty())
->attach(new Validator\StringLength(['min' => 10]))
->attach(new Validator\Digits());
$branch_id = new Input('branch_id');
$branch_id->setRequired(true)
->setBreakOnFailure(true)
->getValidatorChain()
->attach(new Validator\NotEmpty())
->attach(new Validator\Digits());
$is_principle = new Input('is_principle');
$is_principle->setRequired(false);
$is_responsible = new Input('is_responsible');
$is_responsible->setRequired(false);
$this->inputFilter = new InputFilter();
$this->inputFilter
->add($id)
->add($name)
->add($surname)
->add($email)
->add($telephone)
->add($branch_id)
->add($is_principle)
->add($is_responsible);
}
public function __invoke(array $data)
{
$this->inputFilter->setData($data);
$isValid = $this->inputFilter->isValid();
return [
'is_valid' => $isValid,
'values' => $isValid ? $this->inputFilter->getValues() : [],
'messages' => $this->inputFilter->getMessages(),
];
}
}