/** * @param string $valueSet * @param mixed $data * @param bool|false $null * @return StringS */ public static function StringS($valueSet = null, $data = null, $null = false) { $string = new StringS(); $string->setValueSet($valueSet); $string->setData($data); $string->setNull($null); return $string; }
/** * Returns an array of closures that can check and format * to the $string type * * @param $string * @return array * @throws \Exception */ function compileString($string) { /** * Examples: * numeric[-10, 30) * integer(0, inf) * float[0,1] */ $numeric = '/^(numeric|float|integer|int)((\\(|\\[).+,[^\\]\\)]+(\\)|\\]))$/'; /** * Examples: * string{pendent, payed, ready, cancelled} * integer{10, 100, 1000} * scalar{0, false} * {0, false} //same as the previous one */ $valueSetScalar = '/^(scalar|string|float|integer|int|str|boolean|bool|numeric)?(\\{[^}]*\\})$/'; /** * Examples: * string(5..10) * string(5..) * string(..10) * string(5..5) // strict length * string(..) // pointless, but valid */ $lengthString = '/^string(\\(\\d*\\.\\.\\d*\\))$/'; /** * Examples: * (string|integer)[] * (string|integer{0,1})[] * (bool{true}|integer[1,inf))[] */ $quickArray = "/^(\\(.+(\\|.+)+\\)|[^\\|]*)\\[(\\d+|\\d*\\+|\\*|\\d*\\.\\.\\d*)?\\]\$/"; $identityStructure = array("check" => function ($data, $null, &$failed) { return true; }, "format" => function ($data) { return $data; }); // allow "type1|type2|..." $types = explode("|", $string); if (preg_match($quickArray, $string)) { $structure = new ArrayS(); $structure->setFormat($string); $structure->setCountStrict($this->countStrict); $arrayStructure = true; $objects = array($structure); $i = count($types) + 1; } else { /** @var Structure[] $objects */ $objects = array(); // Use a do-while to check always $type[0] $i = 0; } while (count($types) > $i) { $type = $types[$i]; if (preg_match($numeric, $type, $matches)) { switch ($type[0]) { case "n": $structure = new NumericS(); break; case "f": $structure = new FloatS(); break; case "i": $structure = new IntegerS(); break; } /** @var NumericS $structure */ $structure->setRange($matches[2]); } else { if (preg_match($valueSetScalar, $type, $matches)) { switch ($type[0] . $type[1]) { default: //fall through to _scalar_ //fall through to _scalar_ case "sc": $structure = new ScalarS(); break; case "st": $structure = new StringS(); break; case "nu": $structure = new NumericS(); break; case "fl": $structure = new FloatS(); break; case "in": $structure = new IntegerS(); break; case "bo": $structure = new BooleanS(); break; } /** @var ScalarS $structure */ $structure->setValueSet($matches[2]); } else { if (preg_match($lengthString, $type, $matches)) { $structure = new StringS(); $structure->setLength($matches[1]); } else { if (preg_match($quickArray, $type, $matches)) { $structure = new ArrayS(); $structure->setFormat($type); $structure->setCountStrict($this->countStrict); $arrayStructure = true; } else { switch ($type) { case "scalar": $structure = new ScalarS(); break; case "string": // fall through to _str_ // fall through to _str_ case "str": $structure = new StringS(); break; case "numeric": $structure = new NumericS(); break; case "integer": // fall through to _int_ // fall through to _int_ case "int": $structure = new IntegerS(); break; case "float": $structure = new FloatS(); break; case "boolean": // fall through to _bool_ // fall through to _bool_ case "bool": $structure = new BooleanS(); break; case "array": $structure = new ArrayS(); $structure->setFormat("array"); $structure->setCountStrict($this->countStrict); break; case "*": case "any": // set structure:identity $structure = $identityStructure; break; case "null": case null: // set structure:null $structure = array("check" => function ($data, $null, &$failed) { $valid = is_null($data); if (!$valid) { $failed = Structure::typeof($data); } return $valid; }, "format" => function () { return null; }); break; default: if (class_exists($string)) { // todo: create ObjectS class $structure = array("check" => function ($data, $null, &$failed) use($string) { if (is_null($data)) { $valid = $null; } else { $valid = $data instanceof $string; } if (!$valid) { $failed = Structure::typeof($data); } return $valid; }, "format" => $identityStructure["format"]); } else { // maybe $format is a simple array (type[] or type[int]) $structure = new ArrayS(); $structure->setFormat($type); $structure->setCountStrict($this->countStrict); $arrayStructure = true; } break; } //prevent errors if (!isset($structure)) { $structure = $identityStructure; } } } } } // Add the Structure to use it after the loop $objects[] = $structure; $i++; } /** * Define return functions, depending on the number of $objects * (1 or more) */ $ret = array(); if ($i == 1) { if ($objects[0] instanceof Structure) { $check = function ($data, $null, &$failed) use($objects) { $objects[0]->setNull($null); return $objects[0]->check($data, $failed); }; $format = function ($data, $null) use($objects) { $objects[0]->setNull($null); return $objects[0]->format($data); }; } else { $check = $objects[0]["check"]; $format = function ($data) use($objects) { return call_user_func($objects[0]["format"], $data); }; } } else { $check = function ($data, $null, &$failed) use($objects) { foreach ($objects as $obj) { if ($obj instanceof Structure) { $obj->setNull($null); if ($obj->check($data, $failed)) { return true; } } else { if (is_array($obj) && isset($obj["check"])) { $check = $obj["check"]; if ($check($data, $null, $failed)) { return true; } } } } return false; }; $format = function ($data, $null) use($objects) { foreach ($objects as $obj) { try { if ($obj instanceof Structure) { $obj->setNull($null); return $obj->format($data); } else { return call_user_func($obj["format"], $data); } } catch (\Exception $e) { } } throw new \Exception("Unable to format \$data"); }; } $ret["check"] = $check; $ret["format"] = $format; if (isset($arrayStructure) && $arrayStructure) { $ret["meta"] = "array"; } return $ret; }