438 lines
13 KiB
PHP
438 lines
13 KiB
PHP
<?php
|
|
namespace Model;
|
|
|
|
use SimpleValidator\Validator;
|
|
use SimpleValidator\Validators;
|
|
use PDO;
|
|
|
|
/**
|
|
* Link model
|
|
* A link is made of one bidirectional (<->), or two sided (<- and ->) link labels.
|
|
*
|
|
* @package model
|
|
* @author Olivier Maridat
|
|
*/
|
|
class Link extends Base
|
|
{
|
|
|
|
/**
|
|
* SQL table name
|
|
*
|
|
* @var string
|
|
*/
|
|
const TABLE = 'link';
|
|
|
|
const TABLE_LABEL = 'link_label';
|
|
|
|
/**
|
|
* Direction: left to right ->
|
|
*
|
|
* @var integer
|
|
*/
|
|
const BEHAVIOUR_LEFT2RIGTH = 0;
|
|
|
|
/**
|
|
* Direction: right to left <-
|
|
*
|
|
* @var integer
|
|
*/
|
|
const BEHAVIOUR_RIGHT2LEFT = 1;
|
|
|
|
/**
|
|
* Bidirectional <->
|
|
*
|
|
* @var integer
|
|
*/
|
|
const BEHAVIOUR_BOTH = 2;
|
|
|
|
/**
|
|
* Get a link by the id
|
|
*
|
|
* @access public
|
|
* @param integer $link_id
|
|
* Link id
|
|
* @param integer $project_id
|
|
* Specify a project id. Default: -1 to target all projects
|
|
* @return array
|
|
*/
|
|
public function getById($link_id, $project_id = -1)
|
|
{
|
|
return $this->db->table(self::TABLE)
|
|
->eq(self::TABLE . '.link_id', $link_id)
|
|
->in('project_id', array(
|
|
- 1,
|
|
$project_id
|
|
))
|
|
->join(self::TABLE_LABEL, 'link_id', 'link_id')
|
|
->findAll();
|
|
}
|
|
|
|
/**
|
|
* Get the id of the inverse link label by a link label id
|
|
*
|
|
* @access public
|
|
* @param integer $link_id
|
|
* Link id
|
|
* @param integer $link_label_id
|
|
* Link label id
|
|
* @return integer
|
|
*/
|
|
public function getInverseLinkLabelId($link_label_id)
|
|
{
|
|
$sql = 'SELECT
|
|
la2.id
|
|
FROM ' . self::TABLE_LABEL . ' la1
|
|
JOIN '.self::TABLE_LABEL.' la2 ON la2.link_id = la1.link_id AND (la2.behaviour=2 OR la2.id != la1.id)
|
|
WHERE la1.id = ?
|
|
';
|
|
$rq = $this->db->execute($sql, array(
|
|
$link_label_id
|
|
));
|
|
return $rq->fetchColumn(0);
|
|
}
|
|
|
|
/**
|
|
* Return all link labels for a given project
|
|
*
|
|
* @access public
|
|
* @param integer $project_id
|
|
* Specify a project id. Default: -1 to target all projects
|
|
* @return array
|
|
*/
|
|
public function getLinkLabels($project_id = -1)
|
|
{
|
|
return $this->db->table(self::TABLE_LABEL)
|
|
->in(self::TABLE . '.project_id', array(
|
|
- 1,
|
|
$project_id
|
|
))
|
|
->join(self::TABLE, 'link_id', 'link_id')
|
|
->asc(self::TABLE_LABEL.'.link_id', 'behaviour')
|
|
->columns('id', self::TABLE . '.project_id', self::TABLE_LABEL.'.link_id', 'label', 'behaviour')
|
|
->findAll();
|
|
}
|
|
|
|
/**
|
|
* Return the list of all link labels
|
|
* Used to select a link label
|
|
*
|
|
* @access public
|
|
* @param integer $project_id
|
|
* Specify a project id. Default: -1 to target all projects
|
|
* @return array
|
|
*/
|
|
public function getLinkLabelList($project_id = -1)
|
|
{
|
|
$listing = $this->getLinkLabels($project_id);
|
|
$mergedListing = array();
|
|
foreach ($listing as $link) {
|
|
$suffix = '';
|
|
$prefix = '';
|
|
if (self::BEHAVIOUR_BOTH == $link['behaviour'] || self::BEHAVIOUR_LEFT2RIGTH == $link['behaviour']) {
|
|
$suffix = ' »';
|
|
}
|
|
if (self::BEHAVIOUR_BOTH == $link['behaviour'] || self::BEHAVIOUR_RIGHT2LEFT == $link['behaviour']) {
|
|
$prefix = '« ';
|
|
}
|
|
$mergedListing[$link['id']] = $prefix . t($link['label']) . $suffix;
|
|
}
|
|
$listing = $mergedListing;
|
|
return $listing;
|
|
}
|
|
|
|
/**
|
|
* Return the list of all links (label + inverse label)
|
|
*
|
|
* @access public
|
|
* @param integer $project_id
|
|
* Specify a project id. Default: -1 to target all projects
|
|
* @return array
|
|
*/
|
|
public function getMergedList($project_id = -1)
|
|
{
|
|
$listing = $this->getLinkLabels($project_id);
|
|
$mergedListing = array();
|
|
$current = null;
|
|
foreach ($listing as $link) {
|
|
if (self::BEHAVIOUR_BOTH == $link['behaviour'] || self::BEHAVIOUR_LEFT2RIGTH == $link['behaviour']) {
|
|
$current = $link;
|
|
}
|
|
else {
|
|
$current['label_inverse'] = $link['label'];
|
|
}
|
|
if (self::BEHAVIOUR_BOTH == $link['behaviour'] || self::BEHAVIOUR_RIGHT2LEFT == $link['behaviour']) {
|
|
$mergedListing[] = $current;
|
|
$current = null;
|
|
}
|
|
}
|
|
$listing = $mergedListing;
|
|
return $listing;
|
|
}
|
|
|
|
/**
|
|
* Prepare data before insert/update
|
|
*
|
|
* @access public
|
|
* @param array $values
|
|
* Form values
|
|
*/
|
|
public function prepare(array &$values)
|
|
{
|
|
// Prepare label 1
|
|
$link = array(
|
|
'project_id' => $values['project_id']
|
|
);
|
|
$label1 = array(
|
|
'label' => @$values['label'][0],
|
|
'behaviour' => (isset($values['behaviour'][0]) || !isset($values['label'][1]) || null == $values['label'][1]) ? self::BEHAVIOUR_BOTH : self::BEHAVIOUR_LEFT2RIGTH
|
|
);
|
|
$label2 = array(
|
|
'label' => @$values['label'][1],
|
|
'behaviour' => self::BEHAVIOUR_RIGHT2LEFT
|
|
);
|
|
if (isset($values['link_id'])) {
|
|
$link['link_id'] = $values['link_id'];
|
|
$label1['id'] = $values['id'][0];
|
|
$label2['id'] = @$values['id'][1];
|
|
$label1['link_id'] = $values['link_id'];
|
|
$label2['link_id'] = $values['link_id'];
|
|
}
|
|
|
|
$values = $link;
|
|
$values[] = $label1;
|
|
$values[] = $label2;
|
|
return array(
|
|
$link,
|
|
$label1,
|
|
$label2
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Create a link
|
|
*
|
|
* @access public
|
|
* @param array $values
|
|
* Form values
|
|
* @return bool integer
|
|
*/
|
|
public function create(array $values)
|
|
{
|
|
list ($link, $label1, $label2) = $this->prepare($values);
|
|
// Create link
|
|
$this->db->startTransaction();
|
|
$res = $this->db->table(self::TABLE)->save($link);
|
|
if (! $res) {
|
|
$this->db->cancelTransaction();
|
|
return false;
|
|
}
|
|
|
|
// Create label 1
|
|
$label1['link_id'] = $this->db->getConnection()->lastInsertId(self::TABLE);
|
|
$res = $this->db->table(self::TABLE_LABEL)->save($label1);
|
|
if (! $res) {
|
|
$this->db->cancelTransaction();
|
|
return false;
|
|
}
|
|
|
|
// Create label 2 if any
|
|
if (null != $label2 && self::BEHAVIOUR_BOTH != $label1['behaviour']) {
|
|
$label2['link_id'] = $label1['link_id'];
|
|
$res = $this->db->table(self::TABLE_LABEL)->save($label2);
|
|
if (! $res) {
|
|
$this->db->cancelTransaction();
|
|
return false;
|
|
}
|
|
}
|
|
$this->db->closeTransaction();
|
|
return $res;
|
|
}
|
|
|
|
/**
|
|
* Update a link
|
|
*
|
|
* @access public
|
|
* @param array $values
|
|
* Form values
|
|
* @return bool
|
|
*/
|
|
public function update(array $values)
|
|
{
|
|
list($link, $label1, $label2) = $this->prepare($values);
|
|
// Update link
|
|
$this->db->startTransaction();
|
|
$res = $this->db->table(self::TABLE)
|
|
->eq('link_id', $link['link_id'])
|
|
->save($link);
|
|
if (! $res) {
|
|
$this->db->cancelTransaction();
|
|
return false;
|
|
}
|
|
|
|
// Update label 1
|
|
$this->db->startTransaction();
|
|
$res = $this->db->table(self::TABLE_LABEL)
|
|
->eq('id', $label1['id'])
|
|
->save($label1);
|
|
if (! $res) {
|
|
$this->db->cancelTransaction();
|
|
return false;
|
|
}
|
|
|
|
// Update label 2 (if label 1 not bidirectional)
|
|
if (null != $label2 && self::BEHAVIOUR_BOTH != $label1['behaviour']) {
|
|
// Create
|
|
if (! isset($label2['id']) || null == $label2['id']) {
|
|
unset($label2['id']);
|
|
$res = $this->db->table(self::TABLE_LABEL)->save($label2);
|
|
if (! $res) {
|
|
$this->db->cancelTransaction();
|
|
return false;
|
|
}
|
|
$label2['id'] = $this->db->getConnection()->lastInsertId(self::TABLE_LABEL);
|
|
$this->taskLink->changeLinkLabel($link['link_id'], $label2['id'], true);
|
|
}
|
|
// Update
|
|
else {
|
|
$res = $this->db->table(self::TABLE_LABEL)
|
|
->eq('id', $label2['id'])
|
|
->save($label2);
|
|
if (! $res) {
|
|
$this->db->cancelTransaction();
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
// Remove label 2 (if label 1 bidirectional)
|
|
else {
|
|
$this->taskLink->changeLinkLabel($link['link_id'], $label1['id']);
|
|
$this->db->table(self::TABLE_LABEL)
|
|
->eq('link_id', $link['link_id'])
|
|
->neq('id', $label1['id'])
|
|
->remove();
|
|
}
|
|
$this->db->closeTransaction();
|
|
return $res;
|
|
}
|
|
|
|
/**
|
|
* Remove a link
|
|
*
|
|
* @access public
|
|
* @param integer $link_id
|
|
* Link id
|
|
* @return bool
|
|
*/
|
|
public function remove($link_id)
|
|
{
|
|
$this->db->startTransaction();
|
|
if (! $this->db->table(self::TABLE)
|
|
->eq('link_id', $link_id)
|
|
->remove()) {
|
|
$this->db->cancelTransaction();
|
|
return false;
|
|
}
|
|
$this->db->closeTransaction();
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Duplicate links from a project to another one, must be executed inside a transaction
|
|
*
|
|
* @param integer $src_project_id
|
|
* Source project id
|
|
* @return integer $dst_project_id Destination project id
|
|
* @return boolean
|
|
*/
|
|
public function duplicate($src_project_id, $dst_project_id)
|
|
{
|
|
$labels = $this->db->table(self::TABLE_LABEL)
|
|
->columns(self::TABLE_LABEL.'.link_id', 'label', 'behaviour')
|
|
->eq('project_id', $src_project_id)
|
|
->join(self::TABLE, 'link_id', 'link_id')
|
|
->asc(self::TABLE_LABEL.'.link_id', 'behaviour')
|
|
->findAll();
|
|
|
|
$this->db->startTransaction();
|
|
$link = array('project_id' => $dst_project_id);
|
|
if (! $this->db->table(self::TABLE)->save($link)) {
|
|
$this->db->cancelTransaction();
|
|
return false;
|
|
}
|
|
$link['id'] = $this->db->getConnection()->lastInsertId(self::TABLE);
|
|
|
|
foreach ($labels as $label) {
|
|
$label['link_id'] = $link['id'];
|
|
if (! $this->db->table(self::TABLE_LABEL)->save($label)) {
|
|
$this->db->cancelTransaction();
|
|
return false;
|
|
}
|
|
}
|
|
$this->db->closeTransaction();
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Validate link creation
|
|
*
|
|
* @access public
|
|
* @param array $values
|
|
* Form values
|
|
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
|
*/
|
|
public function validateCreation(array $values)
|
|
{
|
|
$v = new Validator($values, $this->commonValidationRules());
|
|
|
|
return array(
|
|
$v->execute(),
|
|
$v->getErrors()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Validate link modification
|
|
*
|
|
* @access public
|
|
* @param array $values
|
|
* Form values
|
|
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
|
*/
|
|
public function validateModification(array $values)
|
|
{
|
|
$rules = array(
|
|
new Validators\Required('link_id', t('The id is required')),
|
|
// new Validators\Required('id[0]', t('The label id is required'))
|
|
);
|
|
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
|
|
|
|
return array(
|
|
$v->execute(),
|
|
$v->getErrors()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Common validation rules
|
|
*
|
|
* @access private
|
|
* @return array
|
|
*/
|
|
private function commonValidationRules()
|
|
{
|
|
// TODO Update simple-validator to support array in forms
|
|
return array(
|
|
new Validators\Required('project_id', t('The project id required')),
|
|
// new Validators\Required('label[0]', t('The link label is required')),
|
|
new Validators\Integer('project_id', t('The project id must be an integer')),
|
|
new Validators\Integer('link_id', t('The link id must be an integer')),
|
|
// new Validators\Integer('id[0]', t('The link label id must be an integer')),
|
|
// new Validators\Integer('id[1]', t('The link label id must be an integer')),
|
|
// new Validators\Integer('behaviour[0]', t('The link label id must be an integer')),
|
|
// new Validators\Integer('behaviour[1]', t('The link label id must be an integer')),
|
|
// new Validators\MaxLength('label[0]', t('The maximum length is %d characters', 200), 200),
|
|
// new Validators\MaxLength('label[1]', t('The maximum length is %d characters', 200), 200)
|
|
);
|
|
}
|
|
}
|