1 <?php 2 /* Copyright (c) 2012, Geert Bergman (geert@scrivo.nl) 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. Neither the name of "Scrivo" nor the names of its contributors may be 14 * used to endorse or promote products derived from this software without 15 * specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 * 29 * $Id: SequenceNo.php 866 2013-08-25 16:22:35Z geert $ 30 */ 31 32 /** 33 * Implementation of the \Scrivo\SequenceNo class. 34 */ 35 36 namespace Scrivo; 37 38 /** 39 * Class to manage the sequence (or order) numbers of various Scrivo entities. 40 * Most Scrivo entitites like pages and lists items can be ordered manually. 41 * This is done by setting a sequence number field in the database for say 42 * all pages with a common parent. 43 * 44 * Note that this ordering has nothing to do with database sequence generation 45 * used for generating ids. 46 */ 47 class SequenceNo { 48 49 /** 50 * Constant to indicate that we want the entity to move one position up. 51 */ 52 const MOVE_UP = -1; 53 54 /** 55 * Constant to indicate that we want the entity to move one position down. 56 */ 57 const MOVE_DOWN = -2; 58 59 /** 60 * Constant to indicate that we want to move the entity to the beginning. 61 */ 62 const MOVE_FIRST = -3; 63 64 /** 65 * Constant to indicate that we want to move the entity to the end. 66 */ 67 const MOVE_LAST = -4; 68 69 /** 70 * Regenerate all sequence numbers for a set of entities determined by 71 * the parent of the entity with the given $id. The new sequence numbers 72 * will start with and will have an offset of 2. Sequence numbers with 73 * a value of zero or less will not be updated. 74 * 75 * @param \Scrivo\Context $context A Scrivo context. 76 * @param string $tableName The table name for the entity to resequence. 77 * @param string $parentField The parent id field in the table for the 78 * entity to resequence. 79 * @param int $id The id of the entity to resequence. 80 */ 81 private static function resequence( 82 $context, $tableName, $parentField, $id) { 83 84 $pJoin = ""; 85 if (!is_array($parentField)) { 86 $parentField = array($parentField); 87 } 88 foreach ($parentField as $pf) { 89 $pJoin .= str_replace("[P]", $pf, " AND D1.[P] = D2.[P]"); 90 } 91 92 $sth = $context->connection->prepare( 93 str_replace("[T]", $tableName, 94 "UPDATE [T] T, ( 95 SELECT @n:=@n+2 NEW_SEQ, D1.instance_id, D1.[T]_id FROM 96 (SELECT @n:=0) x, [T] D1, [T] D2 WHERE 97 D1.instance_id = :instId AND D2.instance_id = :instId 98 {$pJoin} AND D2.[T]_id = :id AND 99 D1.sequence_no > 0 ORDER BY D1.sequence_no) R 100 SET T.sequence_no = R.NEW_SEQ 101 WHERE (T.instance_id = R.instance_id AND T.[T]_id = R.[T]_id)")); 102 103 $context->connection->bindInstance($sth); 104 $sth->bindValue(":id", $id, \PDO::PARAM_INT); 105 106 $sth->execute(); 107 } 108 109 /** 110 * Move an entity to a given position. Note that this is a postion number 111 * starting at 1, not a zero based index. Instead of an actual position 112 * number also one of \Scrivo\SequenceNo::MOVE_* constants can be used. 113 * 114 * @param \Scrivo\Context $context A Scrivo context. 115 * @param string $tableName The table name for the entity to resequence. 116 * @param string $parentField The parent id field in the table for the 117 * entity to resequence. 118 * @param int $id The id of the entity to resequence. 119 * @param int $pos The new position of the entity to resequence, note that 120 * this is a postion number starting at 1, not a zero based index. 121 */ 122 public static function position( 123 \Scrivo\Context$context, $tableName, $parentField, $id, $pos) { 124 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array( 125 null, null, null, 126 array(\Scrivo\ArgumentCheck::TYPE_INTEGER), 127 array(\Scrivo\ArgumentCheck::TYPE_INTEGER) 128 )); 129 try { 130 131 self::resequence($context, $tableName, $parentField, $id); 132 133 $sth = $context->connection->prepare( 134 str_replace("[T]", $tableName, 135 "SELECT sequence_no FROM [T] WHERE 136 instance_id = :instId AND [T]_id = :id")); 137 138 $context->connection->bindInstance($sth); 139 $sth->bindValue(":id", $id, \PDO::PARAM_INT); 140 141 $sth->execute(); 142 143 $seqNo = $sth->fetchColumn(0); 144 145 switch ($pos) { 146 case self::MOVE_UP: 147 if ($seqNo > 2) { 148 $seqNo -= 3; 149 } 150 break; 151 case self::MOVE_DOWN: 152 $seqNo += 3; 153 break; 154 case self::MOVE_FIRST: 155 $seqNo = 1; 156 break; 157 case self::MOVE_LAST: 158 $seqNo = 10000000; 159 break; 160 default: 161 if ($pos * 2 < $seqNo) { 162 $seqNo = ($pos-1) * 2 + 1; 163 } else if ($pos * 2 > $seqNo) { 164 $seqNo = $pos * 2 + 1; 165 } 166 break; 167 } 168 169 $sth = $context->connection->prepare( 170 str_replace("[T]", $tableName, 171 "UPDATE [T] SET sequence_no = :seqNo WHERE 172 instance_id = :instId AND [T]_id = :id")); 173 174 $context->connection->bindInstance($sth); 175 $sth->bindValue(":seqNo", $seqNo, \PDO::PARAM_INT); 176 $sth->bindValue(":id", $id, \PDO::PARAM_INT); 177 178 $sth->execute(); 179 180 } catch(\PDOException $e) { 181 throw new \Scrivo\ResourceException($e); 182 } 183 184 } 185 186 } 187 188 ?>
Documentation generated by phpDocumentor 2.0.0a12 and ScrivoDocumentor on August 29, 2013