Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
100.00% |
1 / 1 |
|
100.00% |
2 / 2 |
CRAP | |
100.00% |
60 / 60 |
SequenceNo | |
100.00% |
1 / 1 |
|
100.00% |
2 / 2 |
12 | |
100.00% |
60 / 60 |
resequence( $context, $tableName, $parentField, $id) | |
100.00% |
1 / 1 |
3 | |
100.00% |
15 / 15 |
|||
position( \Scrivo\Context$context, $tableName, $parentField, $id, $pos) | |
100.00% |
1 / 1 |
9 | |
100.00% |
45 / 45 |
<?php | |
/* Copyright (c) 2012, Geert Bergman (geert@scrivo.nl) | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions are met: | |
* | |
* 1. Redistributions of source code must retain the above copyright notice, | |
* this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright notice, | |
* this list of conditions and the following disclaimer in the documentation | |
* and/or other materials provided with the distribution. | |
* 3. Neither the name of "Scrivo" nor the names of its contributors may be | |
* used to endorse or promote products derived from this software without | |
* specific prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
* POSSIBILITY OF SUCH DAMAGE. | |
* | |
* $Id: SequenceNo.php 866 2013-08-25 16:22:35Z geert $ | |
*/ | |
/** | |
* Implementation of the \Scrivo\SequenceNo class. | |
*/ | |
namespace Scrivo; | |
/** | |
* Class to manage the sequence (or order) numbers of various Scrivo entities. | |
* Most Scrivo entitites like pages and lists items can be ordered manually. | |
* This is done by setting a sequence number field in the database for say | |
* all pages with a common parent. | |
* | |
* Note that this ordering has nothing to do with database sequence generation | |
* used for generating ids. | |
*/ | |
class SequenceNo { | |
/** | |
* Constant to indicate that we want the entity to move one position up. | |
*/ | |
const MOVE_UP = -1; | |
/** | |
* Constant to indicate that we want the entity to move one position down. | |
*/ | |
const MOVE_DOWN = -2; | |
/** | |
* Constant to indicate that we want to move the entity to the beginning. | |
*/ | |
const MOVE_FIRST = -3; | |
/** | |
* Constant to indicate that we want to move the entity to the end. | |
*/ | |
const MOVE_LAST = -4; | |
/** | |
* Regenerate all sequence numbers for a set of entities determined by | |
* the parent of the entity with the given $id. The new sequence numbers | |
* will start with and will have an offset of 2. Sequence numbers with | |
* a value of zero or less will not be updated. | |
* | |
* @param \Scrivo\Context $context A Scrivo context. | |
* @param string $tableName The table name for the entity to resequence. | |
* @param string $parentField The parent id field in the table for the | |
* entity to resequence. | |
* @param int $id The id of the entity to resequence. | |
*/ | |
private static function resequence( | |
$context, $tableName, $parentField, $id) { | |
$pJoin = ""; | |
if (!is_array($parentField)) { | |
$parentField = array($parentField); | |
} | |
foreach ($parentField as $pf) { | |
$pJoin .= str_replace("[P]", $pf, " AND D1.[P] = D2.[P]"); | |
} | |
$sth = $context->connection->prepare( | |
str_replace("[T]", $tableName, | |
"UPDATE [T] T, ( | |
SELECT @n:=@n+2 NEW_SEQ, D1.instance_id, D1.[T]_id FROM | |
(SELECT @n:=0) x, [T] D1, [T] D2 WHERE | |
D1.instance_id = :instId AND D2.instance_id = :instId | |
{$pJoin} AND D2.[T]_id = :id AND | |
D1.sequence_no > 0 ORDER BY D1.sequence_no) R | |
SET T.sequence_no = R.NEW_SEQ | |
WHERE (T.instance_id = R.instance_id AND T.[T]_id = R.[T]_id)")); | |
$context->connection->bindInstance($sth); | |
$sth->bindValue(":id", $id, \PDO::PARAM_INT); | |
$sth->execute(); | |
} | |
/** | |
* Move an entity to a given position. Note that this is a postion number | |
* starting at 1, not a zero based index. Instead of an actual position | |
* number also one of \Scrivo\SequenceNo::MOVE_* constants can be used. | |
* | |
* @param \Scrivo\Context $context A Scrivo context. | |
* @param string $tableName The table name for the entity to resequence. | |
* @param string $parentField The parent id field in the table for the | |
* entity to resequence. | |
* @param int $id The id of the entity to resequence. | |
* @param int $pos The new position of the entity to resequence, note that | |
* this is a postion number starting at 1, not a zero based index. | |
*/ | |
public static function position( | |
\Scrivo\Context$context, $tableName, $parentField, $id, $pos) { | |
\Scrivo\ArgumentCheck::assertArgs(func_get_args(), array( | |
null, null, null, | |
array(\Scrivo\ArgumentCheck::TYPE_INTEGER), | |
array(\Scrivo\ArgumentCheck::TYPE_INTEGER) | |
)); | |
try { | |
self::resequence($context, $tableName, $parentField, $id); | |
$sth = $context->connection->prepare( | |
str_replace("[T]", $tableName, | |
"SELECT sequence_no FROM [T] WHERE | |
instance_id = :instId AND [T]_id = :id")); | |
$context->connection->bindInstance($sth); | |
$sth->bindValue(":id", $id, \PDO::PARAM_INT); | |
$sth->execute(); | |
$seqNo = $sth->fetchColumn(0); | |
switch ($pos) { | |
case self::MOVE_UP: | |
if ($seqNo > 2) { | |
$seqNo -= 3; | |
} | |
break; | |
case self::MOVE_DOWN: | |
$seqNo += 3; | |
break; | |
case self::MOVE_FIRST: | |
$seqNo = 1; | |
break; | |
case self::MOVE_LAST: | |
$seqNo = 10000000; | |
break; | |
default: | |
if ($pos * 2 < $seqNo) { | |
$seqNo = ($pos-1) * 2 + 1; | |
} else if ($pos * 2 > $seqNo) { | |
$seqNo = $pos * 2 + 1; | |
} | |
break; | |
} | |
$sth = $context->connection->prepare( | |
str_replace("[T]", $tableName, | |
"UPDATE [T] SET sequence_no = :seqNo WHERE | |
instance_id = :instId AND [T]_id = :id")); | |
$context->connection->bindInstance($sth); | |
$sth->bindValue(":seqNo", $seqNo, \PDO::PARAM_INT); | |
$sth->bindValue(":id", $id, \PDO::PARAM_INT); | |
$sth->execute(); | |
} catch(\PDOException $e) { | |
throw new \Scrivo\ResourceException($e); | |
} | |
} | |
} | |