Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
| 1 | <?php |
||
| 12 | class Field extends \samsonframework\orm\Record |
||
| 13 | { |
||
| 14 | /** Store entity name */ |
||
| 15 | const ENTITY = __CLASS__; |
||
| 16 | |||
| 17 | /** Entity field names constants for using in code */ |
||
| 18 | const F_PRIMARY = 'FieldID'; |
||
| 19 | const F_IDENTIFIER = 'Name'; |
||
| 20 | const F_DESCRIPTION = 'Description'; |
||
| 21 | const F_TYPE = 'Type'; |
||
| 22 | const F_DELETION = 'Active'; |
||
| 23 | const F_DEFAULT = 'Value'; |
||
| 24 | const F_LOCALIZED = 'local'; |
||
| 25 | |||
| 26 | /** Additional field storing text value */ |
||
| 27 | const TYPE_TEXT = 0; |
||
| 28 | /** Additional field storing resource link */ |
||
| 29 | const TYPE_RESOURCE = 1; |
||
| 30 | /** Additional field storing date value */ |
||
| 31 | const TYPE_DATE = 3; |
||
| 32 | /** Additional field storing options value */ |
||
| 33 | const TYPE_OPTIONS = 4; |
||
| 34 | /** Additional field storing other entity identifier */ |
||
| 35 | const TYPE_ENTITYID = 6; |
||
| 36 | /** Additional field storing numeric value */ |
||
| 37 | const TYPE_NUMERIC = 7; |
||
| 38 | /** Additional field storing long text value */ |
||
| 39 | const TYPE_LONGTEXT = 8; |
||
| 40 | /** Additional field storing gallery value */ |
||
| 41 | const TYPE_GALLERY = 9; |
||
| 42 | /** Additional field storing datetime value */ |
||
| 43 | const TYPE_DATETIME = 10; |
||
| 44 | /** Additional field storing boolean value */ |
||
| 45 | const TYPE_BOOL = 11; |
||
| 46 | /** Additional field navigation identifier value */ |
||
| 47 | const TYPE_NAVIGATION = 12; |
||
| 48 | /** Additional field external picture identifier value */ |
||
| 49 | const TYPE_EXTERNALPICTURE = 13; |
||
| 50 | |||
| 51 | /** @var array Collection of field type to php variable type relations */ |
||
| 52 | protected static $phpTYPE = array( |
||
| 53 | self::TYPE_TEXT => 'string', |
||
| 54 | self::TYPE_RESOURCE => 'string', |
||
| 55 | self::TYPE_OPTIONS => 'string', |
||
| 56 | self::TYPE_LONGTEXT => 'string', |
||
| 57 | self::TYPE_BOOL => 'bool', |
||
| 58 | self::TYPE_ENTITYID => 'int', |
||
| 59 | self::TYPE_NUMERIC => 'int', |
||
| 60 | self::TYPE_DATETIME => 'int', |
||
| 61 | self::TYPE_DATE => 'int', |
||
| 62 | self::TYPE_GALLERY => 'int', |
||
| 63 | self::TYPE_NAVIGATION => 'int', |
||
| 64 | self::TYPE_EXTERNALPICTURE => 'string' |
||
| 65 | ); |
||
| 66 | |||
| 67 | /** |
||
| 68 | * Get additional field type in form of Field constant name |
||
| 69 | * by database additional field type identifier. |
||
| 70 | * |
||
| 71 | * @param integer $fieldType Additional field type identifier |
||
| 72 | * |
||
| 73 | * @return string Additional field type constant |
||
| 74 | * @throws AdditionalFieldTypeNotFound |
||
| 75 | */ |
||
| 76 | public static function phpType($fieldType) |
||
| 77 | { |
||
| 78 | $pointer = &static::$phpTYPE[$fieldType]; |
||
| 79 | if (isset($pointer)) { |
||
| 80 | return $pointer; |
||
| 81 | } else { |
||
| 82 | throw new AdditionalFieldTypeNotFound($fieldType); |
||
| 83 | } |
||
| 84 | } |
||
| 85 | |||
| 86 | /** |
||
| 87 | * Get internal field type in form of Field constant name |
||
| 88 | * by php originial type. |
||
| 89 | * |
||
| 90 | * @param string $fieldType PHP type |
||
| 91 | * |
||
| 92 | * @return string Additional field type constant |
||
| 93 | * @throws AdditionalFieldTypeNotFound |
||
| 94 | */ |
||
| 95 | public static function internalType($fieldType) |
||
| 96 | { |
||
| 97 | $types = array_flip(static::$phpTYPE); |
||
| 98 | if (array_key_exists($fieldType, $types)) { |
||
| 99 | return $types[$fieldType]; |
||
| 100 | } else { |
||
| 101 | throw new AdditionalFieldTypeNotFound($fieldType); |
||
| 102 | } |
||
| 103 | } |
||
| 104 | |||
| 105 | /** |
||
| 106 | * Get current entity instances collection by navigation identifier. |
||
| 107 | * |
||
| 108 | * @param QueryInterface $query Database query |
||
| 109 | * @param string $navigationID Navigation identifier |
||
| 110 | * @param self[]|array|null $return Variable where request result would be returned |
||
| 111 | * |
||
| 112 | * @return bool|self[] True if field entities has been found and $return is passed |
||
| 113 | * or self[] if only two parameters is passed. |
||
| 114 | */ |
||
| 115 | public static function byNavigationID(QueryInterface $query, $navigationID, &$return = array()) |
||
| 116 | { |
||
| 117 | /** @var array $fieldIDs Collection of entity identifiers filtered by additional field */ |
||
| 118 | $fieldIDs = null; |
||
| 119 | if (static::idsByNavigationID($query, $navigationID, $fieldIDs)) { |
||
| 120 | static::byIDs($query, $fieldIDs, $return); |
||
| 121 | } |
||
| 122 | |||
| 123 | // If only one argument is passed - return null, otherwise bool |
||
| 124 | return func_num_args() > 2 ? sizeof($return) : $return; |
||
| 125 | } |
||
| 126 | |||
| 127 | /** |
||
| 128 | * Get current entity identifiers collection by navigation identifier. |
||
| 129 | * |
||
| 130 | * @param QueryInterface $query Database query |
||
| 131 | * @param string $navigationID Navigation identifier |
||
| 132 | * @param array $return Variable where request result would be returned |
||
| 133 | * @param array $materialIDs Collection of material identifiers for filtering query |
||
| 134 | * |
||
| 135 | * @return bool|array True if field entities has been found and $return is passed |
||
| 136 | * or collection of identifiers if only two parameters is passed. |
||
| 137 | */ |
||
| 138 | public static function idsByNavigationID( |
||
| 139 | QueryInterface $query, |
||
| 140 | $navigationID, |
||
| 141 | &$return = array(), |
||
| 142 | $materialIDs = null |
||
| 143 | ) |
||
| 144 | { |
||
|
|
|||
| 145 | // Prepare query |
||
| 146 | $query->entity(CMS::FIELD_NAVIGATION_RELATION_ENTITY) |
||
| 147 | ->where('StructureID', $navigationID) |
||
| 148 | ->where('Active', 1); |
||
| 149 | |||
| 150 | // Add material identifier filter if passed |
||
| 151 | if (isset($materialIDs)) { |
||
| 152 | $query->where('MaterialID', $materialIDs); |
||
| 153 | } |
||
| 154 | |||
| 155 | // Perform database query and get only material identifiers collection |
||
| 156 | $return = $query->fields('FieldID'); |
||
| 157 | |||
| 158 | // If only one argument is passed - return null, otherwise bool |
||
| 159 | return func_num_args() > 2 ? sizeof($return) : $return; |
||
| 160 | } |
||
| 161 | |||
| 162 | /** |
||
| 163 | * Get current entity instances collection by their identifiers. |
||
| 164 | * Method can accept different query executors. |
||
| 165 | * |
||
| 166 | * @param QueryInterface $query Database query |
||
| 167 | * @param string|array $fieldIDs Field identifier or their colleciton |
||
| 168 | * @param self[]|array|null $return Variable where request result would be returned |
||
| 169 | * @param string $executor Method name for query execution |
||
| 170 | * |
||
| 171 | * @return bool|self[] True if material entities has been found and $return is passed |
||
| 172 | * or self[] if only two parameters is passed. |
||
| 173 | */ |
||
| 174 | View Code Duplication | public static function byIDs(QueryInterface $query, $fieldIDs, &$return = array(), $executor = 'exec') |
|
| 175 | { |
||
| 176 | $return = $query->entity(get_called_class()) |
||
| 177 | ->where('FieldID', $fieldIDs) |
||
| 178 | ->where('Active', 1) |
||
| 179 | ->orderBy('priority') |
||
| 180 | ->$executor(); |
||
| 181 | |||
| 182 | // If only one argument is passed - return null, otherwise bool |
||
| 183 | return func_num_args() > 2 ? sizeof($return) : $return; |
||
| 184 | } |
||
| 185 | |||
| 186 | /** |
||
| 187 | * Find additional field database record by Name. |
||
| 188 | * This is generic method that should be used in nested classes to find its |
||
| 189 | * records by some its primary key value. |
||
| 190 | * |
||
| 191 | * @param QueryInterface $query Query object instance |
||
| 192 | * @param string $name Additional field name |
||
| 193 | * @param self $return Variable to return found database record |
||
| 194 | * |
||
| 195 | * @return bool|null|self Field instance or null if 3rd parameter not passed |
||
| 196 | */ |
||
| 197 | public static function byName(QueryInterface $query, $name, self & $return = null) |
||
| 198 | { |
||
| 199 | // Get field record by name column |
||
| 200 | $return = static::oneByColumn($query, 'Name', $name); |
||
| 201 | |||
| 202 | // If only one argument is passed - return null, otherwise bool |
||
| 203 | return func_num_args() > 1 ? $return == null : $return; |
||
| 204 | } |
||
| 205 | |||
| 206 | /** |
||
| 207 | * Find additional field database record by Name or ID. |
||
| 208 | * This is generic method that should be used in nested classes to find its |
||
| 209 | * records by some its primary key value. |
||
| 210 | * |
||
| 211 | * @param QueryInterface $query Query object instance |
||
| 212 | * @param string $nameOrID Additional field name or identifier |
||
| 213 | * @param self $return Variable to return found database record |
||
| 214 | * |
||
| 215 | *@return bool|null|self Field instance or null if 3rd parameter not passed |
||
| 216 | */ |
||
| 217 | public static function byNameOrID(QueryInterface $query, $nameOrID, self & $return = null) |
||
| 218 | { |
||
| 219 | // Create id or URL condition |
||
| 220 | $idOrUrl = new Condition('OR'); |
||
| 221 | $idOrUrl->add('FieldID', $nameOrID)->add('Name', $nameOrID); |
||
| 222 | |||
| 223 | // Perform query |
||
| 224 | $return = $query->entity(get_called_class())->whereCondition($idOrUrl)->first(); |
||
| 225 | |||
| 226 | // If only one argument is passed - return null, otherwise bool |
||
| 227 | return func_num_args() > 1 ? $return == null : $return; |
||
| 228 | } |
||
| 229 | |||
| 230 | /** |
||
| 231 | * If this field has defined key=>value set. |
||
| 232 | * |
||
| 233 | * @return array|mixed Grouped collection of field key => value possible values or value for key passed. |
||
| 234 | */ |
||
| 235 | public function options($key = null) |
||
| 249 | |||
| 250 | /** @return string Get additional field value field name depending on its type */ |
||
| 251 | public function valueFieldName() |
||
| 255 | |||
| 256 | /** @return string Get additional field value field name depending on its type */ |
||
| 257 | public static function valueColumn($type) |
||
| 258 | { |
||
| 259 | switch ($type) { |
||
| 260 | case self::TYPE_DATETIME: |
||
| 261 | case self::TYPE_DATE: |
||
| 262 | case self::TYPE_NUMERIC: |
||
| 263 | return MaterialField::F_NUMERIC; |
||
| 264 | case self::TYPE_ENTITYID: |
||
| 265 | case self::TYPE_NAVIGATION: |
||
| 266 | return MaterialField::F_KEY; |
||
| 267 | default: |
||
| 268 | return MaterialField::F_VALUE; |
||
| 269 | } |
||
| 270 | } |
||
| 271 | |||
| 272 | /** @return bool True if field is localized */ |
||
| 273 | public function localized() |
||
| 277 | } |
||
| 278 |