This function returns a unique sequence
864 | * It ensures a collision free number only if we don't do more than one operation
865 | * per 0.0001 second However,it also adds a pseudo random number (0-4095)
866 | * so the chances of collision is 1/4095 (per two operations executed every 0.0001 second).
867 | * It is based on Twitter's Snowflake number.
868 | *
869 | * @return string (it returns a 64bit integer).
870 | * @throws Exception
871 | */
872 | public function getSequencePHP(): string
873 | {
874 | $ms = microtime(true); // we use this number as a random number generator (we use the decimals)
875 | //$ms=1000;
876 | $timestamp = round($ms * 1000);
877 | $rand = (int)(fmod($ms, 1) * 1000000) % 4096; // 4096= 2^12 It is the millionth of seconds
878 | if ($this->nodeId === -1) {
879 | $number = random_int(0, 1023); // a 10bit number.
880 | $calc = (($timestamp - 1459440000000) << 22) + ($number << 12) + $rand;
881 | } else {
882 | $calc = (($timestamp - 1459440000000) << 22) + ($this->nodeId << 12) + $rand;
883 | }
884 | usleep(1);
885 | return '' . $calc;
886 | }
887 |
888 | /**
889 | * It gets the next sequence. If the sequence doesn't exist, it generates a new one with 1.
890 | * You could peek a sequence with get('genseq_*name*')
891 | * If the sequence is corrupt then it's resetted.
892 | *
893 | * @param string $name Name of the sequence.
894 | * @param int $tries number of tries. It uses the default value defined in $defaultNumRetry (-1)
895 | * @param int $init The initial value of the sequence (if it's created)
896 | * @param int $interval The interval between each sequence. It could be negative.
897 | * @param int $reserveAdditional Reserve an additional number of sequence. It's useful when you want to
898 | * generates many sequences at once.
899 | *
900 | * @return bool|int It returns false if it fails to lock the sequence or if it's unable to read thr sequence.
901 | * Otherwise, it returns the sequence
902 | */
903 | public function getNextSequence(string $name = "seq", int $tries = -1, int $init = 1, int $interval = 1, int $reserveAdditional = 0)
904 | {
905 | $id = "genseq_" . $name;
906 | $file = $this->filename($id) . ".seq";
907 | if ($this->lock($file, $tries)) {
908 | if (file_exists($file)) {
909 | $read = @file_get_contents($file);
910 | if ($read === false) {
911 | $this->unlock($file);
912 | $this->throwError(error_get_last());
913 | return false; // file exists but I am unable to read it.
914 | }
915 | $read = (is_numeric($read)) ? ($read + $interval)
916 | : $init; // if the value stored is numeric, then we add one, otherwise, it starts with 1
917 | } else {
918 | $read = $init;
919 | }
920 | $write = @file_put_contents($file, $read + $reserveAdditional, LOCK_EX);
921 | $this->unlock($file);
922 | if ($write === false) {
923 | $this->throwError(error_get_last());
924 | }
925 | $this->resetChain();
926 | return ($write === false) ? false : $read;
927 | }
928 | $this->resetChain();
929 | return false; // unable to lock
930 | }
931 |
932 | /**
933 | * Add or update a whole document.
934 | *
935 | * @param string $id "ID" of the document.
936 | * @param string|array $document The document
937 | * @param int $tries number of tries. The default value is -1, it uses the default value
938 | * $defaultNumRetry.
939 | *
940 | * @return bool True if the information was added, otherwise false
941 | */
942 | public function insertOrUpdate(string $id, $document, int $tries = -1): bool
943 | {
944 | $file = $this->filename($id);
945 | $this->currentId = $id;
946 | if ($this->lock($file, $tries)) {
947 | if ($this->autoSerialize) {
948 | $this->srvSerialize->insert($id, $document, $tries);
949 | $write = @file_put_contents($file, $this->serialize($document), LOCK_EX);
950 | } else {
951 | $write = @file_put_contents($file, $document, LOCK_EX);
952 | }
953 | $this->unlock($file);
954 | if ($write === false) {
955 | $this->throwError(error_get_last());
956 | }
957 | $this->resetChain();
958 | return ($write !== false);
959 | }
960 | $this->throwError("Unable to lock file [$this->currentId]");
961 | return false;
962 | }
963 |
964 | /**
965 | * Update a whole document
966 | *
967 | * @param string $id "ID" of the document.
968 | * @param string|array $document The document
969 | * @param int $tries number of tries. The default value is -1 (it uses the default value
970 | * $defaultNumRetry)
971 | *
972 | * @return bool True if the information was added, otherwise false
973 | */
974 | public function update(string $id, $document, int $tries = -1): bool
975 | {
976 | $file = $this->filename($id);
977 | $this->currentId = $id;
978 | if ($this->lock($file, $tries)) {
979 | if (file_exists($file)) {
980 | if ($this->autoSerialize) {
981 | $write = @file_put_contents($file, $this->serialize($document), LOCK_EX);
982 | } else {
983 | $write = @file_put_contents($file, $document, LOCK_EX);
984 | }
985 | } else {
986 | $write = false;
987 | }
988 | $this->unlock($file, $tries);
989 | if ($write === false) {
990 | $this->throwError(error_get_last());
991 | }
992 | $this->resetChain();
993 | return ($write !== false);
994 | }
995 | $this->throwError("Unable to lock file [$this->currentId]");
996 | return false;
997 | }
998 |
999 | /**
1000 | * Set the current collection. It also could create the collection.
1001 | *
1002 | * @param string $collection
1003 | * @param bool $createIfNotExist if true then it checks if the collection (folder) exists, if not then it's
1004 | * created
1005 | *
1006 | * @return DocumentStoreOne
1007 | */
1008 | public function collection(string $collection, bool $createIfNotExist = false): DocumentStoreOne
1009 | {
1010 | $this->collection = $collection;
1011 | if ($createIfNotExist && !$this->isCollection($collection)) {
1012 | $this->createCollection($collection);
1013 | }
1014 | return $this;
1015 | }
1016 |
1017 | /**
1018 | * Check a collection
1019 | *
1020 | * @param string $collection
1021 | *
1022 | * @return bool It returns false if it's not a collection (a valid folder)
1023 | */
1024 | public function isCollection(string $collection): bool
1025 | {
1026 | $this->collection = $collection;
1027 | return is_dir($this->getPath());
1028 | }
1029 |
1030 | /**
1031 | * Creates a collection
1032 | *
1033 | * @param string $collection
1034 | * @param bool $throwifFail
1035 | * @return bool true if the operation is right, false if it fails.
1036 | */
1037 | public function createCollection(string $collection, bool $throwifFail = true): bool
1038 | {
1039 | $oldCollection = $this->collection;
1040 | $this->collection = $collection;
1041 | $r = @mkdir($this->getPath(), 0755);
1042 | if ($r === false && $throwifFail) {
1043 | $this->throwError('error create collection :' . @error_get_last());
1044 | }
1045 | $this->collection = $oldCollection;
1046 | $this->resetChain();
1047 | return $r;
1048 | }
1049 |
1050 | /**
1051 | * It deletes a collection inside a database,including its content.
1052 | *
1053 | * @param string $collection
1054 | * @param boolean $throwOnError
1055 | * @param bool $includeContent if true (default), then it deletes the content.
1056 | * @return void
1057 | */
1058 | public function deleteCollection(string $collection, bool $throwOnError = false, bool $includeContent = true): void
1059 | {
1060 | $oldCollection = $this->collection;
1061 | $this->collection = $collection;
1062 | try {
1063 | $r = false;
1064 | if ($includeContent) {
1065 | array_map('unlink', glob($this->getPath() . "/*.*"));
1066 | }
1067 | $r = rmdir($this->getPath());
1068 | } catch (Exception $ex) {
1069 | if ($throwOnError) {
1070 | $this->throwError($ex->getMessage());
1071 | }
1072 | }
1073 | if ($r === false && $throwOnError) {
1074 | $this->throwError('error create collection :' . @error_get_last());
1075 | }
1076 | $this->collection = $oldCollection;
1077 | $this->resetChain();
1078 | }
1079 |
1080 | /**
1081 | * It sets if we want to auto serialize the information, and we set how it is serialized
1082 | * php = it serializes using serialize() function
1083 | * php_array = it serializes using include()/var_export() function. The result could be cached using OpCache
1084 | * json_object = it is serialized using json (as object)
1085 | * json_array = it is serialized using json (as array)
1086 | * none = it is not serialized. Information must be serialized/de-serialized manually
1087 | * php_array = it is serialized as a php_array
1088 | *
1089 | * @param bool $value
1090 | * @param string $strategy =['auto','php','php_array','json_object','json_array','csv','igbinary','msgpack','none'][$i]
1091 | * @param bool|null $tabular indicates if the value is tabular (it has rows and columns) or not.
1092 | * Note: if null then it takes the default value (csv is tabular, while others
1093 | * don't
1094 | */
1095 | public function autoSerialize(bool $value = true, string $strategy = 'auto', ?bool $tabular = null): void
1096 | {
1097 | $this->autoSerialize = $value;
1098 | if ($value === false) {
1099 | $strategy = 'none';
1100 | }
1101 | $this->serializeStrategy = $strategy;
1102 | if ($this->serializeStrategy === 'auto') {
1103 | if (function_exists('igbinary_serialize')) {
1104 | $this->serializeStrategy = 'igbinary';
1105 | } elseif (function_exists('msgpack_pack')) {
1106 | $this->serializeStrategy = 'msgpack';
1107 | } else {
1108 | $this->serializeStrategy = 'php';
1109 | }
1110 | }
1111 | switch ($this->serializeStrategy) {
1112 | case 'csv':
1113 | $this->srvSerialize = new DocumentStoreOneCsv($this);
1114 | break;
1115 | case 'igbinary':
1116 | $this->srvSerialize = new DocumentStoreOneIgBinary($this);
1117 | break;
1118 | case 'msgpack':
1119 | $this->srvSerialize = new DocumentStoreOneMsgPack($this);
1120 | break;
1121 | case 'php':
1122 | $this->srvSerialize = new DocumentStoreOnePHP($this);
1123 | break;
1124 | case 'php_array':
1125 | $this->srvSerialize = new DocumentStoreOnePHPArray($this);
1126 | break;
1127 | case 'json_object':
1128 | $this->srvSerialize = new DocumentStoreOneJsonObj($this);
1129 | break;
1130 | case 'json_array':
1131 | $this->srvSerialize = new DocumentStoreOneJsonArray($this);
1132 | break;
1133 | default:
1134 | $this->srvSerialize = new DocumentStoreOneNone($this);
1135 | break;
1136 | }
1137 | if ($tabular === null) {
1138 | $this->tabular = $this->srvSerialize->defaultTabular();
1139 | }
1140 | }
1141 |
1142 | /**
1143 | * It sets the style of the csv.
1144 | *
1145 | * @param string $separator For example ",", "\t", etc.
1146 | * @param string $enclosure The enclosure of a string value.
1147 | * @param string $lineEnd
1148 | * @param bool $header If the csv contains or not a header
1149 | * @param string $prefixColumn If the csv or the data does not contain name, then it uses this value to create a
1150 | * column name
1151 | * **Example:**
1152 | * 'col': columns 'col0','col1',etc.
1153 | * '': columns 0,1
1154 | *
1155 | * @return void
1156 | */
1157 | public function csvStyle(string $separator = ',', string $enclosure = '"', string $lineEnd = "\n"
1158 | , bool $header = true, string $prefixColumn = ''): void
1159 | {
1160 | if ($this->srvSerialize instanceof DocumentStoreOneCsv) {
1161 | $this->srvSerialize->csvSeparator = $separator;
1162 | $this->srvSerialize->csvText = $enclosure;
1163 | $this->srvSerialize->csvLineEnd = $lineEnd;
1164 | $this->srvSerialize->csvHeader = $header;
1165 | $this->srvSerialize->csvPrefixColumn = $prefixColumn;
1166 | }
1167 | }
1168 |
1169 | /**
1170 | * It sets the regional style
1171 | *
1172 | * @param string $regionalDecimal
1173 | * @param string $regionalDate
1174 | * @param string $regionalDateTime
1175 | * @return void
1176 | */
1177 | public function regionalStyle(string $regionalDecimal = '.', string $regionalDate = 'Y-m-d'
1178 | , string $regionalDateTime = 'Y-m-d H:i:s'): void
1179 | {
1180 | $this->regionDecimal = $regionalDecimal;
1181 | $this->regionDate = $regionalDate;
1182 | $this->regionDateTime = $regionalDateTime;
1183 | }
1184 |
1185 | /**
1186 | * List all the Ids in a collection (or returns the documents if $returnOnlyIndex is false)
1187 | *
1188 | * @param string $mask see http://php.net/manual/en/function.glob.php
1189 | *
1190 | * @param bool $returnOnlyIndex
1191 | * If false then it returns each document.
1192 | * If returns (default) then it returns indexes.
1193 | *
1194 | * @return array
1195 | * @throws RedisException
1196 | */
1197 | public function select(string $mask = "*", bool $returnOnlyIndex = true): array
1198 | {
1199 | $list = glob($this->database . "/" . $this->collection . "/" . $mask . $this->docExt);
1200 | foreach ($list as $key => $fileId) {
1201 | $list[$key] = basename($fileId, $this->docExt);
1202 | }
1203 | if ($returnOnlyIndex) {
1204 | return $list;
1205 | }
1206 | $listDoc = [];
1207 | foreach ($list as $fileId) {
1208 | $listDoc[] = $this->get($fileId);
1209 | }
1210 | return $listDoc;
1211 | }
1212 |
1213 | /**
1214 | * Get a document from the datastore
1215 | * **Example:**
1216 | * ```
1217 | * $data=$this->get('rows',-1,false); // it returns a value or false
1218 | * $data=$this->get('rows',-1,"not null"); // it returns a value or "not null" if not found
1219 | * ```
1220 | *
1221 | * @param string $id "ID" of the document.
1222 | * @param int $tries number of tries.
1223 | * The default value is -1 (it uses the default value $defaultNumRetry)
1224 | * 0 means it will not try to lock
1225 | * @param mixed $default Default value (if the value is not found)
1226 | *
1227 | * @return mixed The object if the information was read, otherwise false (or default value).
1228 | * @throws RedisException
1229 | * @throws RedisException
1230 | */
1231 | public function get(string $id, int $tries = -1, $default = false)
1232 | {
1233 | $file = $this->filename($id);
1234 | $this->currentId = $id;
1235 | if ($this->lock($file, $tries)) {
1236 | if ($this->serializeStrategy === 'php_array') {
1237 | $json = @include $file;
1238 | $this->unlock($file);
1239 | } else {
1240 | $json = @file_get_contents($file);
1241 | $this->unlock($file, $tries);
1242 | if ($json !== false) {
1243 | if (strpos($json, $this->separatorAppend) === false) {
1244 | if ($this->autoSerialize) {
1245 | $json = $this->deserialize($json);
1246 | }
1247 | } else {
1248 | $arr = explode($this->separatorAppend, $json);
1249 | if (count($arr) > 0 && $arr[0] === '') {
1250 | unset($arr[0]);
1251 | }
1252 | $json = [];
1253 | foreach ($arr as $item) {
1254 | $json[] = $this->deserialize($item);
1255 | }
1256 | }
1257 | }
1258 | }
1259 | if ($json === false) {
1260 | $this->throwError(error_get_last());
1261 | }
1262 | $this->resetChain();
1263 | return ($json === false) ? $default : $json;
1264 | }
1265 | $this->resetChain();
1266 | return $default;
1267 | }
1268 |
1269 | /**
1270 | * Set if you don't want to throw an exception when error.
1271 | * This value is reset every time the value is read or an exception is throw.
1272 | * However, the error message lastError() is still stored.
1273 | * **Example:**
1274 | * ```
1275 | * $this->noThrowOnError()->get('id'); // it will not throw an exception if "ID" document does not exist.
1276 | * ```
1277 | * @param bool $throw if false (default), then it doesn't throw an exception on error.
1278 | * @return $this
1279 | */
1280 | public function noThrowOnError(bool $throw = false): DocumentStoreOne
1281 | {
1282 | $this->throwable = $throw;
1283 | return $this;
1284 | }
1285 |
1286 | protected function deserialize($document)
1287 | {
1288 | return $this->srvSerialize->deserialize($document);
1289 | }
1290 |
1291 | /**
1292 | * It gets the timestamp of a document or false in case of error.
1293 | * **Example**
1294 | * ```
1295 | * $timeStamp=$this->getTimeStamp("doc20");
1296 | * ```
1297 | *
1298 | * @param string $id "ID" of the document.
1299 | * @param bool $returnAsAbsoluteTime if true then it returns the age (how many seconds are elapsed)
1300 | * if false then it returns the regular timestamp of the time.
1301 | *
1302 | * @return false|int
1303 | */
1304 | public function getTimeStamp(string $id, bool $returnAsAbsoluteTime = false)
1305 | {
1306 | $this->currentId = $id;
1307 | $file = $this->filename($id);
1308 | try {
1309 | $rt = @filemtime($file);
1310 | } catch (Exception $ex) {
1311 | $rt = false;
1312 | }
1313 | if ($returnAsAbsoluteTime) {
1314 | if ($rt === false) {
1315 | return false;
1316 | }
1317 | return time() - $rt;
1318 | }
1319 | return $rt;
1320 | }
1321 |
1322 | /**
1323 | * It sets the modification time of a document
1324 | * **Example**
1325 | * ```
1326 | * $timeStamp=$this->setTimeStamp("doc20",12323232); // set the absolute timestemp
1327 | * $timeStamp=$this->setTimeStamp("doc20",100,false); // set the relative timestamp (relative current time)
1328 | * ```
1329 | * @param string $id "ID" of the document
1330 | * @param int $ttl the interval (in seconds).
1331 | * @param bool $setTTLAsAbsoluteTime if true then it sets the age ($ttl+time())
1332 | * if false then it sets the regular timestamp of the time.
1333 | * @return bool
1334 | */
1335 | public function setTimeStamp(string $id, int $ttl, bool $setTTLAsAbsoluteTime = true): bool
1336 | {
1337 | $time = $setTTLAsAbsoluteTime ? $ttl : time() + $ttl;
1338 | try {
1339 | return @touch($this->filename($id), $time);
1340 | } catch (Exception $ex) {
1341 | return false;
1342 | }
1343 | }
1344 |
1345 | /**
1346 | * It gets a values from the datastore filtered by a condition
1347 | * **Example:**
1348 | * ```
1349 | * $data=$this->getFiltered('rows',-1,false,['type'=>'busy']); // it returns values [0=>...,1=>...]
1350 | * $data=$this->getFiltered('rows',-1,false,['type'=>'busy'],false); // it returns values [2=>...,4=>..]
1351 | * ```
1352 | *
1353 | * @param string $id "ID" of the document.
1354 | * @param int $tries number of tries. The default value is -1 (it uses the default value $defaultNumRetry)
1355 | * @param mixed $default default value (if the value is not found)
1356 | * @param array $condition An associative array with the conditions.
1357 | * @param bool $reindex If true then the result is reindexed (starting from zero).
1358 | *
1359 | * @return array
1360 | * @noinspection TypeUnsafeComparisonInspection
1361 | * @throws RedisException
1362 | */
1363 | public function getFiltered(string $id, int $tries = -1, $default = false, array $condition = [], bool $reindex = true): array
1364 | {
1365 | $rows = $this->get($id, $tries, $default);
1366 | $result = [];
1367 | foreach ($rows as $k => $v) {
1368 | $fail = false;
1369 | foreach ($condition as $k2 => $v2) {
1370 | if (is_object($v)) {
1371 | if (!isset($v->{$k2}) || $v->{$k2} != $v2) {
1372 | $fail = true;
1373 | break;
1374 | }
1375 | } elseif (!isset($v[$k2]) || $v[$k2] != $v2) {
1376 | $fail = true;
1377 | break;
1378 | }
1379 | }
1380 | if (!$fail) {
1381 | if ($reindex) {
1382 | $result[] = $v;
1383 | } else {
1384 | $result[$k] = $v;
1385 | }
1386 | }
1387 | }
1388 | return $result;
1389 | }
1390 |
1391 | /**
1392 | * Delete a document.
1393 | * **Example:**
1394 | * ```
1395 | * $isDeleted=$this->delete('doc20');
1396 | * ```
1397 | *
1398 | * @param string $id "ID" of the document
1399 | * @param int $tries number of tries. The default value is -1 (it uses the default value $defaultNumRetry)
1400 | *
1401 | * @return bool if it's unable to unlock or the document doesn't exist.
1402 | */
1403 | public function delete(string $id, int $tries = -1, $throwOnError = false): bool
1404 | {
1405 | $file = $this->filename($id);
1406 | if ($this->lock($file, $tries)) {
1407 | $r = @unlink($file);
1408 | $this->unlock($file);
1409 | if ($r === false && $throwOnError) {
1410 | $this->throwError(error_get_last());
1411 | }
1412 | $this->resetChain();
1413 | return $r;
1414 | }
1415 | $this->resetChain();
1416 | return false;
1417 | }
1418 |
1419 | /**
1420 | * Copy a document. If the destination exists then it's replaced.
1421 | * **Example:**
1422 | * ```
1423 | * $isCopied=$this->copy('doc20','doc20copy');
1424 | * ```
1425 | * @param string $idOrigin
1426 | * @param string $idDestination
1427 | * @param int $tries number of tries. The default value is -1 (it uses the default value $defaultNumRetry)
1428 | *
1429 | * @return bool true if the operation is correct, otherwise it returns false (unable to lock / unable to copy)
1430 | */
1431 | public function copy(string $idOrigin, string $idDestination, int $tries = -1): bool
1432 | {
1433 | $fileOrigin = $this->filename($idOrigin);
1434 | $fileDestination = $this->filename($idDestination);
1435 | if ($this->lock($fileOrigin, $tries)) {
1436 | if ($this->lock($fileDestination, $tries)) {
1437 | $r = @copy($fileOrigin, $fileDestination);
1438 | $this->unlock($fileOrigin);
1439 | $this->unlock($fileDestination);
1440 | if ($r === false) {
1441 | $this->throwError(error_get_last());
1442 | }
1443 | $this->resetChain();
1444 | return $r;
1445 | }
1446 | $this->unlock($fileOrigin);
1447 | $this->throwError("Unable to lock file [$idDestination]");
1448 | return false;
1449 | }
1450 | $this->throwError("Unable to lock file [$idOrigin]");
1451 | return false;
1452 | }
1453 |
1454 | /**
1455 | * Rename a document. If the destination exists then it's not renamed
1456 | * **Example:**
1457 | * ```
1458 | * $isRenamed=$this->rename('doc20','doc20newName');
1459 | * ```
1460 | *
1461 | * @param string $idOrigin
1462 | * @param string $idDestination
1463 | * @param int $tries number of tries. The default value is -1 (it uses the default value $defaultNumRetry)
1464 | *
1465 | * @return bool true if the operation is correct, otherwise it returns false
1466 | * (unable to lock / unable to rename)
1467 | */
1468 | public function rename(string $idOrigin, string $idDestination, int $tries = -1): bool
1469 | {
1470 | $fileOrigin = $this->filename($idOrigin);
1471 | $fileDestination = $this->filename($idDestination);
1472 | if ($this->lock($fileOrigin, $tries)) {
1473 | if ($this->lock($fileDestination, $tries)) {
1474 | $r = @rename($fileOrigin, $fileDestination);
1475 | $this->unlock($fileOrigin);
1476 | $this->unlock($fileDestination);
1477 | if ($r === false) {
1478 | $this->throwError(error_get_last());
1479 | }
1480 | $this->resetChain();
1481 | return $r;
1482 | }
1483 | $this->unlock($fileOrigin);
1484 | $this->resetChain();
1485 | return false;
1486 | }
1487 | $this->resetChain();
1488 | return false;
1489 | }
1490 | }
1491 |
1492 |
--------------------------------------------------------------------------------
/lib/services/DocumentStoreOneCsv.php:
--------------------------------------------------------------------------------
1 | parent = $parent;
37 | }
38 | public function defaultTabular():bool {
39 | return true;
40 | }
41 | public function appendValue($filePath, $id, $addValue, $tries = -1)
42 | {
43 | $fp=$this->parent->appendValueDecorator($filePath,$id,$addValue,$tries);
44 | if(!is_resource($fp)) {
45 | return $fp;
46 | }
47 | fseek($fp, 0, SEEK_END);
48 | $addValue = $this->parent->serialize($addValue, true); // true no add header
49 | $r = @fwrite($fp, $addValue);
50 | @fclose($fp);
51 | $this->parent->unlock($filePath);
52 | if($r===false) {
53 | $this->parent->throwError(error_get_last());
54 | }
55 | return ($r !== false);
56 | }
57 | public function insert($id, $document, $tries = -1) {
58 | $this->getHeaderCSV($document);
59 | $this->determineTypes($document[0]);
60 | }
61 | public function serialize($document, $special = false) {
62 | return $this->serializeCSV($document, $special);
63 | }
64 |
65 | public function serializeCSV($table, $noheader = false)
66 | {
67 | $result = '';
68 | if (!$noheader && $this->csvHeader) {
69 | // had header
70 | $line = [];
71 | foreach ($this->parent->schemas[$this->parent->currentId] as $colname => $type) {
72 | $line[] = $this->parent->convertTypeBack($colname, 'string');
73 | }
74 | $result = implode($this->csvSeparator, $line) . $this->csvLineEnd;
75 | }
76 | $line = [];
77 | if (!$this->parent->isTable($table)) {
78 | // it just a row, so we convert into a row.
79 | $table = [$table];
80 | }
81 | foreach ($table as $kr => $row) {
82 | foreach ($row as $kcol => $v) {
83 | $line[$kr][$kcol] = $this->parent->convertTypeBack($v, $this->parent->schemas[$this->parent->currentId][$kcol]);
84 | }
85 | $result .= implode($this->csvSeparator, $line[$kr]) . $this->csvLineEnd;
86 | }
87 | return $result;
88 | }
89 |
90 |
91 | /**
92 | * @param array $row is an associative array with the values to determine
93 | * @return void
94 | * @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection
95 | */
96 | public function determineTypes(&$row)
97 | {
98 | $cols = isset($this->parent->schemas[$this->parent->currentId]) ? $this->parent->schemas[$this->parent->currentId] : null;
99 | // $this->parent->schemas[$this->parent->currentId] = [];
100 | if ($cols === null) {
101 | // there is no columns defined, so we define columns using this row
102 | foreach ($row as $kcol => $item) {
103 | if (is_numeric($kcol)) {
104 | $kcol = $this->csvPrefixColumn . $kcol;
105 | }
106 | $this->parent->schemas[$this->parent->currentId][$kcol] = $this->parent->getType($item);
107 | }
108 | } else {
109 | $c = -1;
110 | foreach ($cols as $kcol => $v) {
111 | if (isset($row[0])) {
112 | $c++;
113 | $this->parent->schemas[$this->parent->currentId][$kcol]
114 | = $this->parent->getType($row[$c]);
115 | } else {
116 | $this->parent->schemas[$this->parent->currentId][$kcol]
117 | = $this->parent->getType($row[$kcol]);
118 | }
119 | }
120 | }
121 | }
122 |
123 |
124 | public function convertTypeBack($input, $type) {
125 | switch ($type) {
126 | case 'int':
127 | return $input;
128 | case 'decimal':
129 | if ($this->parent->regionDecimal !== '.') {
130 | $inputD = str_replace('.', $this->parent->regionDecimal, $input);
131 | } else {
132 | $inputD = $input;
133 | }
134 | return $inputD;
135 | case 'date':
136 | return $this->csvText . $input->format($this->parent->regionDate) . $this->csvText;
137 | case 'string':
138 | if($this->csvText && strpos($input,$this->csvText)) {
139 | return $this->csvText .str_replace($this->csvText,$this->csvEscape.$this->csvText,$input) . $this->csvText;
140 | }
141 | return $this->csvText .$input . $this->csvText;
142 | case 'datetime':
143 | return $this->csvText . $input->format($this->parent->regionDateTime) . $this->csvText;
144 | }
145 | return $input;
146 | }
147 |
148 | public function convertType($input, $type)
149 | {
150 | switch ($type) {
151 | case 'int':
152 | return (int)$input;
153 | case 'decimal':
154 | if ($this->parent->regionDecimal !== '.') {
155 | $inputD = str_replace($this->parent->regionDecimal, '.', $input);
156 | } else {
157 | $inputD = $input;
158 | }
159 | return (float)$inputD;
160 | case 'string':
161 | if(!$this->csvEscape || strpos($input,$this->csvEscape)===false) {
162 | return (string)$input;
163 | }
164 | return (string)str_replace($this->csvEscape,'',$input);
165 | case 'date':
166 | return DateTime::createFromFormat($this->parent->regionDate, $input);
167 | case 'datetime':
168 | return DateTime::createFromFormat($this->parent->regionDateTime, $input);
169 | }
170 | return $input;
171 | }
172 |
173 |
174 | public function insertOrUpdate($id, $document, $tries = -1)
175 | {
176 |
177 | }
178 | public function deserialize($document)
179 | {
180 | return $this->unserializeCSV($document);
181 | }
182 |
183 | /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
184 | public function unserializeCSV(&$document)
185 | {
186 | $lines = explode($this->csvLineEnd, $document);
187 | $result = [];
188 | $numLines = count($lines);
189 | if ($numLines > 0) {
190 | if ($this->csvHeader) {
191 | // it has header
192 | $header = $this->splitLine($lines[0], false);
193 | foreach ($header as $namecol) {
194 | $this->parent->schemas[$this->parent->currentId][$namecol] = 'string';
195 | }
196 | $first = 1;
197 | } else {
198 | // no header
199 | $this->parent->schemas[$this->parent->currentId] = null;
200 | $first = 0;
201 | }
202 | if (isset($lines[$first])) {
203 | // asume types
204 | $firstLine = $this->splitLine($lines[$first], true);
205 | //$numcols=count($firstLine);
206 | $this->determineTypes($firstLine);
207 | for ($i = $first; $i < $numLines; $i++) {
208 | $tmp = $this->splitLine($lines[$i], true);
209 | foreach ($tmp as $namecol => $item) {
210 | if (!isset($this->parent->schemas[$this->parent->currentId][$namecol])) {
211 | $this->parent->throwError('incorrect column found in csv line ' . $i);
212 | return null;
213 | }
214 | $tmp[$namecol] = $this->parent->convertType($item, $this->parent->schemas[$this->parent->currentId][$namecol]);
215 | }
216 | if (count($tmp) > 0) {
217 | // we avoid inserting an empty line
218 | $result[] = $tmp;
219 | }
220 | }
221 | }
222 | }
223 | return $result;
224 | }
225 | private function splitLine($lineTxt, $useColumn)
226 | {
227 | if ($lineTxt === null || $lineTxt === '') {
228 | return [];
229 | }
230 | $arr = str_getcsv($lineTxt, $this->csvSeparator, $this->csvText,$this->csvEscape);
231 | $result = [];
232 | if ($useColumn === true) {
233 | $colnames = isset($this->parent->schemas[$this->parent->currentId]) ? array_keys($this->parent->schemas[$this->parent->currentId]) : [];
234 | foreach ($arr as $numCol => $v) {
235 | if (!isset($colnames[$numCol])) {
236 | $colnames[$numCol] = $this->csvPrefixColumn . $numCol;
237 | $this->parent->schemas[$this->parent->currentId][$colnames[$numCol]] = $this->parent->getType($v); // column is missing so we create a column name
238 | }
239 | $result[$colnames[$numCol]] = trim($v);
240 |
241 | }
242 | } else {
243 | foreach ($arr as $k => $v) {
244 | $result[$k] = trim($v);
245 | }
246 | }
247 | return $result;
248 | }
249 | /**
250 | * It gets the header of a csv only if the id of the document doesn't have it.
251 | *
252 | * @param array $table
253 | * @return void
254 | */
255 | public function getHeaderCSV($table)
256 | {
257 | if (!isset($this->parent->schemas[$this->parent->currentId])) {
258 | if (!$this->parent->isTable($table)) {
259 | // it just a row, so we convert into a row.
260 | $table = [$table];
261 | }
262 | $this->parent->schemas[$this->parent->currentId] = [];
263 | foreach ($table[0] as $kcol => $v) {
264 | if (is_numeric($kcol)) {
265 | $kcol = $this->csvPrefixColumn . $kcol;
266 | }
267 | $this->parent->schemas[$this->parent->currentId][$kcol] = 'string'; // default value is string
268 | }
269 | }
270 | }
271 |
272 |
273 |
274 |
275 | }
276 |
--------------------------------------------------------------------------------
/lib/services/DocumentStoreOneIgBinary.php:
--------------------------------------------------------------------------------
1 | parent = $parent;
25 | }
26 | public function defaultTabular():bool {
27 | return false;
28 | }
29 |
30 | public function appendValue($filePath, $id, $addValue, $tries = -1)
31 | {
32 | return $this->parent->appendValueRaw2($id,$addValue,$tries);
33 | }
34 | public function insert($id, $document, $tries = -1) {
35 | }
36 | public function serialize($document, $special = false) {
37 | return igbinary_serialize($document);
38 | }
39 | public function convertTypeBack($input, $type) {
40 | switch ($type) {
41 | case 'decimal':
42 | case 'string':
43 | case 'int':
44 | return $input;
45 | case 'date':
46 | return $input->format($this->parent->regionDate);
47 | case 'datetime':
48 | return $input->format($this->parent->regionDateTime);
49 | }
50 | return $input;
51 | }
52 | public function convertType($input, $type) {
53 | return $input;
54 | }
55 | public function insertOrUpdate($id, $document, $tries = -1)
56 | {
57 |
58 | }
59 | public function deserialize($document)
60 | {
61 | return igbinary_unserialize($document);
62 | }
63 |
64 |
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/lib/services/DocumentStoreOneJsonArray.php:
--------------------------------------------------------------------------------
1 | parent = $parent;
25 | }
26 | public function defaultTabular():bool {
27 | return false;
28 | }
29 |
30 | public function appendValue($filePath, $id, $addValue, $tries = -1)
31 | {
32 | $fp=$this->parent->appendValueDecorator($filePath,$id,$addValue,$tries);
33 | if(!is_resource($fp)) {
34 | return $fp;
35 | }
36 | fseek($fp, -1, SEEK_END);
37 | $addValue = $this->parent->serialize($addValue, true);
38 | $r = @fwrite($fp, ',' . $addValue . ']');
39 | @fclose($fp);
40 | $this->parent->unlock($filePath);
41 | if($r===false) {
42 | $this->parent->throwError(error_get_last());
43 | }
44 | return ($r !== false);
45 | }
46 | public function insert($id, $document, $tries = -1) {
47 | }
48 | public function serialize($document, $special = false) {
49 | return json_encode($document);
50 | }
51 | public function convertTypeBack($input, $type) {
52 | switch ($type) {
53 | case 'decimal':
54 | case 'string':
55 | case 'int':
56 | return $input;
57 | case 'date':
58 | return $input->format($this->parent->regionDate);
59 | case 'datetime':
60 | return $input->format($this->parent->regionDateTime);
61 | }
62 | return $input;
63 | }
64 | public function convertType($input, $type) {
65 | return $input;
66 | }
67 | public function insertOrUpdate($id, $document, $tries = -1)
68 | {
69 |
70 | }
71 | public function deserialize($document)
72 | {
73 | return json_decode($document, true);
74 | }
75 |
76 |
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/lib/services/DocumentStoreOneJsonObj.php:
--------------------------------------------------------------------------------
1 | parent = $parent;
26 | }
27 | public function defaultTabular():bool {
28 | return false;
29 | }
30 |
31 | public function appendValue($filePath, $id, $addValue, $tries = -1)
32 | {
33 | $fp=$this->parent->appendValueDecorator($filePath,$id,$addValue,$tries);
34 | if(!is_resource($fp)) {
35 | return $fp;
36 | }
37 |
38 | fseek($fp, -1, SEEK_END);
39 | $addValue = $this->parent->serialize($addValue, true);
40 | $r = @fwrite($fp, ',' . $addValue . ']');
41 |
42 | @fclose($fp);
43 | $this->parent->unlock($filePath);
44 | if($r===false) {
45 | $this->parent->throwError(error_get_last());
46 | }
47 | return ($r !== false);
48 | }
49 | public function insert($id, $document, $tries = -1) {
50 | }
51 | public function serialize($document, $special = false) {
52 | return json_encode($document);
53 | }
54 | public function convertTypeBack($input, $type) {
55 | switch ($type) {
56 | case 'decimal':
57 | case 'string':
58 | case 'int':
59 | return $input;
60 | case 'date':
61 | return $input->format($this->parent->regionDate);
62 | case 'datetime':
63 | return $input->format($this->parent->regionDateTime);
64 | }
65 | return $input;
66 | }
67 | public function convertType($input, $type) {
68 | return $input;
69 | }
70 |
71 | public function insertOrUpdate($id, $document, $tries = -1)
72 | {
73 |
74 | }
75 | public function deserialize($document)
76 | {
77 | return json_decode($document, false);
78 | }
79 |
80 |
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/lib/services/DocumentStoreOneMsgPack.php:
--------------------------------------------------------------------------------
1 | parent = $parent;
25 | }
26 | public function defaultTabular():bool {
27 | return false;
28 | }
29 |
30 | public function appendValue($filePath, $id, $addValue, $tries = -1)
31 | {
32 | return $this->parent->appendValueRaw2($id,$addValue,$tries);
33 | }
34 | public function insert($id, $document, $tries = -1) {
35 | }
36 | public function serialize($document, $special = false) {
37 | return msgpack_pack($document);
38 | }
39 | public function convertTypeBack($input, $type) {
40 | switch ($type) {
41 | case 'decimal':
42 | case 'string':
43 | case 'int':
44 | return $input;
45 | case 'date':
46 | return $input->format($this->parent->regionDate);
47 | case 'datetime':
48 | return $input->format($this->parent->regionDateTime);
49 | }
50 | return $input;
51 | }
52 | public function convertType($input, $type) {
53 | return $input;
54 | }
55 | public function insertOrUpdate($id, $document, $tries = -1)
56 | {
57 |
58 | }
59 | public function deserialize($document)
60 | {
61 | return msgpack_unpack($document);
62 | }
63 |
64 |
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/lib/services/DocumentStoreOneNone.php:
--------------------------------------------------------------------------------
1 | parent = $parent;
26 | }
27 | public function defaultTabular():bool {
28 | return false;
29 | }
30 |
31 | public function appendValue($filePath, $id, $addValue, $tries = -1)
32 | {
33 | return $this->parent->appendValueRaw($filePath, $addValue);
34 | }
35 | public function insert($id, $document, $tries = -1) {
36 | }
37 | public function serialize($document, $special = false) {
38 | return $document;
39 | }
40 | public function convertTypeBack($input, $type) {
41 | return $input;
42 | }
43 | public function convertType($input, $type) {
44 | return $input;
45 | }
46 |
47 | public function insertOrUpdate($id, $document, $tries = -1)
48 | {
49 |
50 | }
51 | public function deserialize($document)
52 | {
53 | return $document;
54 | }
55 |
56 |
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/lib/services/DocumentStoreOnePHP.php:
--------------------------------------------------------------------------------
1 | parent = $parent;
26 | }
27 | public function defaultTabular():bool {
28 | return false;
29 | }
30 |
31 | public function appendValue($filePath, $id, $addValue, $tries = -1)
32 | {
33 | return $this->parent->appendValueRaw($filePath, $addValue);
34 | }
35 | public function insert($id, $document, $tries = -1) {
36 | }
37 | public function serialize($document, $special = false) {
38 | return serialize($document);
39 | }
40 | public function convertTypeBack($input, $type) {
41 | switch ($type) {
42 | case 'decimal':
43 | case 'string':
44 | case 'int':
45 | return $input;
46 | case 'date':
47 | return $input->format($this->parent->regionDate);
48 | case 'datetime':
49 | return $input->format($this->parent->regionDateTime);
50 | }
51 | return $input;
52 | }
53 | public function convertType($input, $type) {
54 | return $input;
55 | }
56 |
57 | public function insertOrUpdate($id, $document, $tries = -1)
58 | {
59 |
60 | }
61 | public function deserialize($document)
62 | {
63 |
64 | return unserialize($document);
65 | }
66 |
67 |
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/lib/services/DocumentStoreOnePHPArray.php:
--------------------------------------------------------------------------------
1 | parent = $parent;
26 | }
27 | public function defaultTabular():bool {
28 | return false;
29 | }
30 |
31 | public function appendValue($filePath, $id, $addValue, $tries = -1)
32 | {
33 | $fp=$this->parent->appendValueDecorator($filePath,$id,$addValue,$tries);
34 | if(!is_resource($fp)) {
35 | return $fp;
36 | }
37 |
38 | fseek($fp, -4, SEEK_END);
39 | $addValue = $this->parent->serialize($addValue, true);
40 | $r = @fwrite($fp, ',' . $addValue . ");\n "); //note: ");\n " it must be exactly 4 characters.
41 |
42 | @fclose($fp);
43 | $this->parent->unlock($filePath);
44 | if($r===false) {
45 | $this->parent->throwError(error_get_last());
46 | }
47 | return ($r !== false);
48 | }
49 | public function insert($id, $document, $tries = -1) {
50 | }
51 | public function serialize($document, $special = false) {
52 | return DocumentStoreOne::serialize_php_array($document, $special);
53 | }
54 | public function convertTypeBack($input, $type) {
55 | switch ($type) {
56 | case 'decimal':
57 | case 'string':
58 | case 'int':
59 | return $input;
60 | case 'date':
61 | return $input->format($this->parent->regionDate);
62 | case 'datetime':
63 | return $input->format($this->parent->regionDateTime);
64 | }
65 | return $input;
66 | }
67 | public function convertType($input, $type) {
68 | return $input;
69 | }
70 |
71 | public function insertOrUpdate($id, $document, $tries = -1)
72 | {
73 |
74 | }
75 | public function deserialize($document)
76 | {
77 | //php_array should be included.
78 | return $document;
79 | }
80 |
81 |
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/lib/services/IDocumentStoreOneSrv.php:
--------------------------------------------------------------------------------
1 |