diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..0f45882 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,231 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space +insert_final_newline = false +max_line_length = 140 +tab_width = 2 +ij_continuation_indent_size = 2 +ij_formatter_off_tag = @formatter:off +ij_formatter_on_tag = @formatter:on +ij_formatter_tags_enabled = false +ij_smart_tabs = false +ij_wrap_on_typing = false + +[{*.ctp,*.hphp,*.inc,*.module,*.php,*.php4,*.php5,*.phtml}] +max_line_length = 999 +ij_continuation_indent_size = 4 +indent_size = 4 +tab_width = 4 +ij_php_align_assignments = true +ij_php_align_class_constants = true +ij_php_align_group_field_declarations = true +ij_php_align_inline_comments = true +ij_php_align_key_value_pairs = true +ij_php_align_multiline_array_initializer_expression = true +ij_php_align_multiline_binary_operation = false +ij_php_align_multiline_chained_methods = false +ij_php_align_multiline_extends_list = false +ij_php_align_multiline_for = true +ij_php_align_multiline_parameters = false +ij_php_align_multiline_parameters_in_calls = false +ij_php_align_multiline_ternary_operation = false +ij_php_align_phpdoc_comments = true +ij_php_align_phpdoc_param_names = true +ij_php_anonymous_brace_style = end_of_line +ij_php_api_weight = 28 +ij_php_array_initializer_new_line_after_left_brace = true +ij_php_array_initializer_right_brace_on_new_line = true +ij_php_array_initializer_wrap = off +ij_php_assignment_wrap = off +ij_php_author_weight = 28 +ij_php_binary_operation_sign_on_next_line = false +ij_php_binary_operation_wrap = off +ij_php_blank_lines_after_class_header = 0 +ij_php_blank_lines_after_function = 1 +ij_php_blank_lines_after_imports = 1 +ij_php_blank_lines_after_opening_tag = 0 +ij_php_blank_lines_after_package = 1 +ij_php_blank_lines_around_class = 1 +ij_php_blank_lines_around_constants = 0 +ij_php_blank_lines_around_field = 0 +ij_php_blank_lines_around_method = 1 +ij_php_blank_lines_before_class_end = 0 +ij_php_blank_lines_before_imports = 1 +ij_php_blank_lines_before_method_body = 0 +ij_php_blank_lines_before_package = 1 +ij_php_blank_lines_before_return_statement = 0 +ij_php_blank_lines_between_imports = 0 +ij_php_block_brace_style = end_of_line +ij_php_call_parameters_new_line_after_left_paren = false +ij_php_call_parameters_right_paren_on_new_line = false +ij_php_call_parameters_wrap = normal +ij_php_catch_on_new_line = false +ij_php_category_weight = 28 +ij_php_class_brace_style = next_line +ij_php_comma_after_last_array_element = false +ij_php_concat_spaces = true +ij_php_copyright_weight = 28 +ij_php_deprecated_weight = 28 +ij_php_do_while_brace_force = always +ij_php_else_if_style = combine +ij_php_else_on_new_line = false +ij_php_example_weight = 28 +ij_php_extends_keyword_wrap = off +ij_php_extends_list_wrap = off +ij_php_fields_default_visibility = private +ij_php_filesource_weight = 28 +ij_php_finally_on_new_line = false +ij_php_for_brace_force = always +ij_php_for_statement_new_line_after_left_paren = false +ij_php_for_statement_right_paren_on_new_line = false +ij_php_for_statement_wrap = off +ij_php_force_short_declaration_array_style = true +ij_php_global_weight = 28 +ij_php_group_use_wrap = on_every_item +ij_php_if_brace_force = always +ij_php_if_lparen_on_next_line = false +ij_php_if_rparen_on_next_line = false +ij_php_ignore_weight = 28 +ij_php_import_sorting = alphabetic +ij_php_indent_break_from_case = true +ij_php_indent_case_from_switch = true +ij_php_indent_code_in_php_tags = false +ij_php_internal_weight = 28 +ij_php_keep_blank_lines_after_lbrace = 2 +ij_php_keep_blank_lines_before_right_brace = 2 +ij_php_keep_blank_lines_in_code = 2 +ij_php_keep_blank_lines_in_declarations = 2 +ij_php_keep_control_statement_in_one_line = true +ij_php_keep_first_column_comment = true +ij_php_keep_indents_on_empty_lines = false +ij_php_keep_line_breaks = true +ij_php_keep_rparen_and_lbrace_on_one_line = true +ij_php_keep_simple_methods_in_one_line = false +ij_php_lambda_brace_style = end_of_line +ij_php_license_weight = 28 +ij_php_line_comment_add_space = false +ij_php_line_comment_at_first_column = true +ij_php_link_weight = 28 +ij_php_lower_case_boolean_const = true +ij_php_lower_case_keywords = true +ij_php_lower_case_null_const = true +ij_php_method_brace_style = next_line +ij_php_method_call_chain_wrap = off +ij_php_method_parameters_new_line_after_left_paren = true +ij_php_method_parameters_right_paren_on_new_line = true +ij_php_method_parameters_wrap = on_every_item +ij_php_method_weight = 28 +ij_php_modifier_list_wrap = false +ij_php_multiline_chained_calls_semicolon_on_new_line = false +ij_php_namespace_brace_style = 1 +ij_php_new_line_after_php_opening_tag = false +ij_php_null_type_position = in_the_end +ij_php_package_weight = 28 +ij_php_param_weight = 0 +ij_php_parentheses_expression_new_line_after_left_paren = false +ij_php_parentheses_expression_right_paren_on_new_line = false +ij_php_phpdoc_blank_line_before_tags = true +ij_php_phpdoc_blank_lines_around_parameters = true +ij_php_phpdoc_keep_blank_lines = true +ij_php_phpdoc_param_spaces_between_name_and_description = 1 +ij_php_phpdoc_param_spaces_between_tag_and_type = 1 +ij_php_phpdoc_param_spaces_between_type_and_name = 1 +ij_php_phpdoc_use_fqcn = true +ij_php_phpdoc_wrap_long_lines = false +ij_php_place_assignment_sign_on_next_line = false +ij_php_place_parens_for_constructor = 0 +ij_php_property_read_weight = 28 +ij_php_property_weight = 28 +ij_php_property_write_weight = 28 +ij_php_return_type_on_new_line = false +ij_php_return_weight = 1 +ij_php_see_weight = 28 +ij_php_since_weight = 28 +ij_php_sort_phpdoc_elements = true +ij_php_space_after_colon = true +ij_php_space_after_colon_in_return_type = true +ij_php_space_after_comma = true +ij_php_space_after_for_semicolon = true +ij_php_space_after_quest = true +ij_php_space_after_type_cast = true +ij_php_space_after_unary_not = false +ij_php_space_before_array_initializer_left_brace = false +ij_php_space_before_catch_keyword = true +ij_php_space_before_catch_left_brace = true +ij_php_space_before_catch_parentheses = true +ij_php_space_before_class_left_brace = true +ij_php_space_before_closure_left_parenthesis = true +ij_php_space_before_colon = true +ij_php_space_before_colon_in_return_type = false +ij_php_space_before_comma = false +ij_php_space_before_do_left_brace = true +ij_php_space_before_else_keyword = true +ij_php_space_before_else_left_brace = true +ij_php_space_before_finally_keyword = true +ij_php_space_before_finally_left_brace = true +ij_php_space_before_for_left_brace = true +ij_php_space_before_for_parentheses = true +ij_php_space_before_for_semicolon = false +ij_php_space_before_if_left_brace = true +ij_php_space_before_if_parentheses = true +ij_php_space_before_method_call_parentheses = false +ij_php_space_before_method_left_brace = true +ij_php_space_before_method_parentheses = false +ij_php_space_before_quest = true +ij_php_space_before_short_closure_left_parenthesis = false +ij_php_space_before_switch_left_brace = true +ij_php_space_before_switch_parentheses = true +ij_php_space_before_try_left_brace = true +ij_php_space_before_unary_not = false +ij_php_space_before_while_keyword = true +ij_php_space_before_while_left_brace = true +ij_php_space_before_while_parentheses = true +ij_php_space_between_ternary_quest_and_colon = false +ij_php_spaces_around_additive_operators = true +ij_php_spaces_around_arrow = false +ij_php_spaces_around_assignment_in_declare = false +ij_php_spaces_around_assignment_operators = true +ij_php_spaces_around_bitwise_operators = true +ij_php_spaces_around_equality_operators = true +ij_php_spaces_around_logical_operators = true +ij_php_spaces_around_multiplicative_operators = true +ij_php_spaces_around_null_coalesce_operator = true +ij_php_spaces_around_relational_operators = true +ij_php_spaces_around_shift_operators = true +ij_php_spaces_around_unary_operator = false +ij_php_spaces_around_var_within_brackets = false +ij_php_spaces_within_array_initializer_braces = false +ij_php_spaces_within_brackets = false +ij_php_spaces_within_catch_parentheses = false +ij_php_spaces_within_for_parentheses = false +ij_php_spaces_within_if_parentheses = false +ij_php_spaces_within_method_call_parentheses = false +ij_php_spaces_within_method_parentheses = false +ij_php_spaces_within_parentheses = false +ij_php_spaces_within_short_echo_tags = true +ij_php_spaces_within_switch_parentheses = false +ij_php_spaces_within_while_parentheses = false +ij_php_special_else_if_treatment = false +ij_php_subpackage_weight = 28 +ij_php_ternary_operation_signs_on_next_line = false +ij_php_ternary_operation_wrap = off +ij_php_throws_weight = 2 +ij_php_todo_weight = 28 +ij_php_unknown_tag_weight = 28 +ij_php_upper_case_boolean_const = false +ij_php_upper_case_null_const = false +ij_php_uses_weight = 28 +ij_php_var_weight = 28 +ij_php_variable_naming_style = mixed +ij_php_version_weight = 28 +ij_php_while_brace_force = always +ij_php_while_on_new_line = false + +[{phpunit.xml.dist,*.jhm,*.rng,*.wsdl,*.fxml,*.xslt,*.jrxml,*.ant,*.xul,*.xsl,*.xsd,*.tld,*.jnlp,*.xml}] +ij_xml_block_comment_at_first_column = true +ij_xml_keep_indents_on_empty_lines = false +ij_xml_line_comment_at_first_column = true diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..54c9e70 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +*.md text eol=lf +*.php text eol=lf +*.ini text eol=lf +*.json text eol=lf +*.yml text eol=lf +*.tcl text eol=lf diff --git a/.gitignore b/.gitignore index 24c6b28..bbea472 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.idea/ /vendor/ /composer.lock +/clover.xml /.phpunit.result.cache diff --git a/.travis.yml b/.travis.yml index 6f0135f..dd98256 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,8 +20,8 @@ before_script: - sudo apt-get install -y expect - docker pull evilfreelancer/docker-routeros:6.42 - docker pull evilfreelancer/docker-routeros:latest -- docker run -d -p 12223:23 -p 18728:8728 -p 18729:8729 -ti evilfreelancer/docker-routeros:6.42 -- docker run -d -p 22223:23 -p 8728:8728 -p 8729:8729 -ti evilfreelancer/docker-routeros:latest +- docker run --device=/dev/net/tun --cap-add NET_ADMIN -d -p 12223:23 -p 18728:8728 -p 18729:8729 -ti evilfreelancer/docker-routeros:6.42 +- docker run --device=/dev/net/tun --cap-add NET_ADMIN -d -p 22223:23 -p 8728:8728 -p 8729:8729 -ti evilfreelancer/docker-routeros:latest - docker ps -a - sleep 60 - ./preconf.tcl 12223 > /dev/null || true diff --git a/composer.json b/composer.json index 57109fc..a85bc9c 100644 --- a/composer.json +++ b/composer.json @@ -47,6 +47,16 @@ "require-dev": { "limedeck/phpunit-detailed-printer": "^5.0", "orchestra/testbench": "^4.0|^5.0", - "phpunit/phpunit": "^8.0" + "phpunit/phpunit": "^8.0", + "roave/security-advisories": "dev-master", + "squizlabs/php_codesniffer": "^3.5" + }, + "scripts": { + "test": "phpunit --coverage-clover clover.xml", + "check": [ + "@cs-check" + ], + "cs-check": "phpcs", + "cs-fix": "phpcbf" } } diff --git a/src/APILengthCoDec.php b/src/APILengthCoDec.php index ad83c9c..19d7a41 100644 --- a/src/APILengthCoDec.php +++ b/src/APILengthCoDec.php @@ -19,42 +19,45 @@ class APILengthCoDec /** * Encode string to length of string * + * <<<<<<< HEAD + * ======= + * Encode the length: + * - if length <= 0x7F (binary : 01111111 => 7 bits set to 1) + * - encode length with one byte + * - set the byte to length value, as length maximal value is 7 bits set to 1, the most significant bit is always 0 + * - end + * - length <= 0x3FFF (binary : 00111111 11111111 => 14 bits set to 1) + * - encode length with two bytes + * - set length value to 0x8000 (=> 10000000 00000000) + * - add length : as length maximumal value is 14 bits to 1, this does not modify the 2 most significance bits (10) + * - end + * => minimal encoded value is 10000000 10000000 + * - length <= 0x1FFFFF (binary : 00011111 11111111 11111111 => 21 bits set to 1) + * - encode length with three bytes + * - set length value to 0xC00000 (binary : 11000000 00000000 00000000) + * - add length : as length maximal value is 21 bits to 1, this does not modify the 3 most significance bits (110) + * - end + * => minimal encoded value is 11000000 01000000 00000000 + * - length <= 0x0FFFFFFF (binary : 00001111 11111111 11111111 11111111 => 28 bits set to 1) + * - encode length with four bytes + * - set length value to 0xE0000000 (binary : 11100000 00000000 00000000 00000000) + * - add length : as length maximal value is 28 bits to 1, this does not modify the 4 most significance bits (1110) + * - end + * => minimal encoded value is 11100000 00100000 00000000 00000000 + * - length <= 0x7FFFFFFFFF (binary : 00000111 11111111 11111111 11111111 11111111 => 35 bits set to 1) + * - encode length with five bytes + * - set length value to 0xF000000000 (binary : 11110000 00000000 00000000 00000000 00000000) + * - add length : as length maximal value is 35 bits to 1, this does not modify the 5 most significance bits (11110) + * - end + * - length > 0x7FFFFFFFFF : not supported + * + * >>>>>>> master * @param int|float $length * * @return string */ public static function encodeLength($length): string { - // Encode the length : - // - if length <= 0x7F (binary : 01111111 => 7 bits set to 1) - // - encode length with one byte - // - set the byte to length value, as length maximal value is 7 bits set to 1, the most significant bit is always 0 - // - end - // - length <= 0x3FFF (binary : 00111111 11111111 => 14 bits set to 1) - // - encode length with two bytes - // - set length value to 0x8000 (=> 10000000 00000000) - // - add length : as length maximumal value is 14 bits to 1, this does not modify the 2 most significance bits (10) - // - end - // => minimal encoded value is 10000000 10000000 - // - length <= 0x1FFFFF (binary : 00011111 11111111 11111111 => 21 bits set to 1) - // - encode length with three bytes - // - set length value to 0xC00000 (binary : 11000000 00000000 00000000) - // - add length : as length maximal vlaue is 21 bits to 1, this does not modify the 3 most significance bits (110) - // - end - // => minimal encoded value is 11000000 01000000 00000000 - // - length <= 0x0FFFFFFF (binary : 00001111 11111111 11111111 11111111 => 28 bits set to 1) - // - encode length with four bytes - // - set length value to 0xE0000000 (binary : 11100000 00000000 00000000 00000000) - // - add length : as length maximal vlaue is 28 bits to 1, this does not modify the 4 most significance bits (1110) - // - end - // => minimal encoded value is 11100000 00100000 00000000 00000000 - // - length <= 0x7FFFFFFFFF (binary : 00000111 11111111 11111111 11111111 11111111 => 35 bits set to 1) - // - encode length with five bytes - // - set length value to 0xF000000000 (binary : 11110000 00000000 00000000 00000000 00000000) - // - add length : as length maximal vlaue is 35 bits to 1, this does not modify the 5 most significance bits (11110) - // - end - // - length > 0x7FFFFFFFFF : not supported - if ($length < 0) { throw new DomainException("Length of word could not to be negative ($length)"); } @@ -80,39 +83,35 @@ class APILengthCoDec return BinaryStringHelper::IntegerToNBOBinaryString(0xF000000000 + $length); } - // Decode length of data when reading : - // The 5 firsts bits of the first byte specify how the length is encoded. - // The position of the first 0 value bit, starting from the most significant postion. - // - 0xxxxxxx => The 7 remaining bits of the first byte is the length : - // => min value of length is 0x00 - // => max value of length is 0x7F (127 bytes) - // - 10xxxxxx => The 6 remaining bits of the first byte plus the next byte represent the lenght - // NOTE : the next byte MUST be at least 0x80 !! - // => min value of length is 0x80 - // => max value of length is 0x3FFF (16,383 bytes, near 16 KB) - // - 110xxxxx => The 5 remaining bits of th first byte and the two next bytes represent the length - // => max value of length is 0x1FFFFF (2,097,151 bytes, near 2 MB) - // - 1110xxxx => The 4 remaining bits of the first byte and the three next bytes represent the length - // => max value of length is 0xFFFFFFF (268,435,455 bytes, near 270 MB) - // - 11110xxx => The 3 remaining bits of the first byte and the four next bytes represent the length - // => max value of length is 0x7FFFFFFF (2,147,483,647 byes, 2GB) - // - 11111xxx => This byte is not a length-encoded word but a control byte. - // => Extracted from Mikrotik API doc : - // it is a reserved control byte. - // After receiving unknown control byte API client cannot proceed, because it cannot know how to interpret following bytes - // Currently control bytes are not used - + /** + * Decode length of data when reading : + * The 5 firsts bits of the first byte specify how the length is encoded. + * The position of the first 0 value bit, starting from the most significant postion. + * - 0xxxxxxx => The 7 remainings bits of the first byte is the length : + * => min value of length is 0x00 + * => max value of length is 0x7F (127 bytes) + * - 10xxxxxx => The 6 remainings bits of the first byte plus the next byte represent the lenght + * NOTE : the next byte MUST be at least 0x80 !! + * => min value of length is 0x80 + * => max value of length is 0x3FFF (16,383 bytes, near 16 KB) + * - 110xxxxx => The 5 remainings bits of th first byte and the two next bytes represent the length + * => max value of length is 0x1FFFFF (2,097,151 bytes, near 2 MB) + * - 1110xxxx => The 4 remainings bits of the first byte and the three next bytes represent the length + * => max value of length is 0xFFFFFFF (268,435,455 bytes, near 270 MB) + * - 11110xxx => The 3 remainings bits of the first byte and the four next bytes represent the length + * => max value of length is 0x7FFFFFFF (2,147,483,647 byes, 2GB) + * - 11111xxx => This byte is not a length-encoded word but a control byte. + * => Extracted from Mikrotik API doc: + * it is a reserved control byte. + * After receiving unknown control byte API client cannot proceed, because it cannot know how to interpret following bytes + * Currently control bytes are not used + * + * @param \RouterOS\Interfaces\StreamInterface $stream + * + * @return int + */ public static function decodeLength(StreamInterface $stream): int { - // if (false === is_resource($stream)) { - // throw new \InvalidArgumentException( - // sprintf( - // 'Argument must be a stream resource type. %s given.', - // gettype($stream) - // ) - // ); - // } - // Read first byte $firstByte = ord($stream->read(1)); @@ -192,7 +191,7 @@ class APILengthCoDec } // Now the only solution is 5 most significance bits are set to 1 (11111xxx) - // This is a control word, not implemented by Mikrotik for the moment + // This is a control word, not implemented by Mikrotik for the moment throw new \UnexpectedValueException('Control Word found'); } } diff --git a/src/Client.php b/src/Client.php index 0a5884c..13cccee 100644 --- a/src/Client.php +++ b/src/Client.php @@ -5,11 +5,19 @@ namespace RouterOS; use RouterOS\Exceptions\ClientException; use RouterOS\Exceptions\ConfigException; use RouterOS\Exceptions\QueryException; +use RouterOS\Interfaces\QueryInterface; use RouterOS\Helpers\ArrayHelper; +use function array_keys; +use function array_shift; use function chr; use function count; use function is_array; use function is_string; +use function md5; +use function pack; +use function preg_match_all; +use function sleep; +use function trim; /** * Class Client for RouterOS management @@ -93,7 +101,6 @@ class Client implements Interfaces\ClientInterface * @return \RouterOS\Client * @throws \RouterOS\Exceptions\QueryException * @deprecated - * @codeCoverageIgnore */ public function write($query): Client { @@ -115,10 +122,10 @@ class Client implements Interfaces\ClientInterface /** * Send write query to RouterOS (modern version of write) * - * @param string|Query $endpoint Path of API query or Query object - * @param array|null $where List of where filters - * @param string|null $operations Some operations which need make on response - * @param string|null $tag Mark query with tag + * @param string|\RouterOS\Query $endpoint Path of API query or Query object + * @param array|null $where List of where filters + * @param string|null $operations Some operations which need make on response + * @param string|null $tag Mark query with tag * * @return \RouterOS\Client * @throws \RouterOS\Exceptions\QueryException @@ -138,48 +145,10 @@ class Client implements Interfaces\ClientInterface // If array is multidimensional, then parse each line if (is_array($where[0])) { foreach ($where as $item) { - - // Null by default - $key = null; - $operator = null; - $value = null; - - switch (count($item)) { - case 1: - [$key] = $item; - break; - case 2: - [$key, $operator] = $item; - break; - case 3: - [$key, $operator, $value] = $item; - break; - default: - throw new ClientException('From 1 to 3 parameters of "where" condition is allowed'); - } - $query->where($key, $operator, $value); + $query = $this->preQuery($item, $query); } } else { - // Null by default - $key = null; - $operator = null; - $value = null; - - switch (count($where)) { - case 1: - [$key] = $where; - break; - case 2: - [$key, $operator] = $where; - break; - case 3: - [$key, $operator, $value] = $where; - break; - default: - throw new ClientException('From 1 to 3 parameters of "where" condition is allowed'); - } - - $query->where($key, $operator, $value); + $query = $this->preQuery($where, $query); } } @@ -199,6 +168,40 @@ class Client implements Interfaces\ClientInterface } /** + * Query helper + * + * @param array $item + * @param \RouterOS\Interfaces\QueryInterface $query + * + * @return \RouterOS\Query + * @throws \RouterOS\Exceptions\ClientException + * @throws \RouterOS\Exceptions\QueryException + */ + private function preQuery(array $item, QueryInterface $query): QueryInterface + { + // Null by default + $key = null; + $operator = null; + $value = null; + + switch (count($item)) { + case 1: + [$key] = $item; + break; + case 2: + [$key, $operator] = $item; + break; + case 3: + [$key, $operator, $value] = $item; + break; + default: + throw new ClientException('From 1 to 3 parameters of "where" condition is allowed'); + } + + return $query->where($key, $operator, $value); + } + + /** * Send write query object to RouterOS * * @param \RouterOS\Query $query @@ -367,18 +370,12 @@ class Client implements Interfaces\ClientInterface for ($j = $key + 1; $j <= $lines; $j++) { // If we have lines after current one if (isset($response[$j])) { - $this->pregResponse($response[$j], $matches); - if (isset($matches[1][0], $matches[2][0])) { - $result['after'][$matches[1][0]] = $matches[2][0]; - } + $this->preParseResponse($response[$j], $result, $matches); } } break 2; default: - $this->pregResponse($value, $matches); - if (isset($matches[1][0], $matches[2][0])) { - $result[$i][$matches[1][0]] = $matches[2][0]; - } + $this->preParseResponse($value, $result, $matches, $i); break; } } @@ -386,12 +383,28 @@ class Client implements Interfaces\ClientInterface } /** + * Response helper + * + * @param string $value Value which should be parsed + * @param array $result Array with parsed response + * @param null|array $matches Matched words + * @param string|int $iterator Type of iterations or number of item + */ + private function preParseResponse(string $value, array &$result, ?array &$matches, $iterator = 'after'): void + { + $this->pregResponse($value, $matches); + if (isset($matches[1][0], $matches[2][0])) { + $result[$iterator][$matches[1][0]] = $matches[2][0]; + } + } + + /** * Parse result from RouterOS by regular expression * - * @param string $value - * @param array $matches + * @param string $value + * @param null|array $matches */ - private function pregResponse(string $value, &$matches): void + private function pregResponse(string $value, ?array &$matches): void { preg_match_all('/^[=|.](.*)=(.*)/', $value, $matches); } @@ -458,7 +471,7 @@ class Client implements Interfaces\ClientInterface * @param array $response * * @return bool - * @throws ConfigException + * @throws \RouterOS\Exceptions\ConfigException */ private function isLegacy(array $response): bool { diff --git a/src/Interfaces/QueryInterface.php b/src/Interfaces/QueryInterface.php index ff864a4..cdd334f 100644 --- a/src/Interfaces/QueryInterface.php +++ b/src/Interfaces/QueryInterface.php @@ -2,8 +2,6 @@ namespace RouterOS\Interfaces; -use RouterOS\Query; - /** * Interface QueryInterface * @@ -19,38 +17,54 @@ interface QueryInterface * @param bool|string|int $value Value which need to check (by default true) * @param bool|string|int $operator It may be one from list [-,=,>,<] * - * @return \RouterOS\Query + * @return \RouterOS\Interfaces\QueryInterface * @throws \RouterOS\Exceptions\ClientException * @since 1.0.0 */ - public function where(string $key, $operator = '=', $value = null); + public function where(string $key, $operator = '=', $value = null): QueryInterface; + + /** + * Setter for write/update queries + * + * @param string $key Key which need to find + * @param bool|string|int $value Value which need to check (by default true) + * + * @return \RouterOS\Interfaces\QueryInterface + * @throws \RouterOS\Exceptions\QueryException + * @since 1.1 + */ + public function equal(string $key, $value = null): QueryInterface; /** * Append additional operations * * @param string $operations * + * @return \RouterOS\Interfaces\QueryInterface + * * @since 1.0.0 */ - public function operations(string $operations); + public function operations(string $operations): QueryInterface; /** * Append tag to query (it should be at end) * * @param string $name * + * @return \RouterOS\Interfaces\QueryInterface + * * @since 1.0.0 */ - public function tag(string $name); + public function tag(string $name): QueryInterface; /** * Append to array yet another attribute of query * * @param string $word * - * @return \RouterOS\Query + * @return \RouterOS\Interfaces\QueryInterface */ - public function add(string $word): Query; + public function add(string $word): QueryInterface; /** * Get attributes array of current query @@ -64,27 +78,27 @@ interface QueryInterface * * @param array $attributes * - * @return \RouterOS\Query + * @return \RouterOS\Interfaces\QueryInterface * @since 0.7 */ - public function setAttributes(array $attributes): Query; + public function setAttributes(array $attributes): QueryInterface; /** * Get endpoint of current query * * @return string|null */ - public function getEndpoint(); + public function getEndpoint(): ?string; /** * Set endpoint of query * * @param string $endpoint * - * @return \RouterOS\Query + * @return \RouterOS\Interfaces\QueryInterface * @since 0.7 */ - public function setEndpoint(string $endpoint): Query; + public function setEndpoint(string $endpoint): QueryInterface; /** * Build body of query diff --git a/src/Query.php b/src/Query.php index cfc868b..f436469 100644 --- a/src/Query.php +++ b/src/Query.php @@ -84,11 +84,11 @@ class Query implements QueryInterface * @param bool|string|int $value Value which need to check (by default true) * @param bool|string|int $operator It may be one from list [-,=,>,<] * - * @return \RouterOS\Query + * @return \RouterOS\Interfaces\QueryInterface * @throws \RouterOS\Exceptions\QueryException * @since 1.0.0 */ - public function where(string $key, $operator = null, $value = null): Query + public function where(string $key, $operator = null, $value = null): QueryInterface { return $this->world('?' . $key, $operator, $value); } @@ -99,11 +99,11 @@ class Query implements QueryInterface * @param string $key Key which need to find * @param bool|string|int $value Value which need to check (by default true) * - * @return \RouterOS\Query + * @return \RouterOS\Interfaces\QueryInterface * @throws \RouterOS\Exceptions\QueryException * @since 1.1 */ - public function equal(string $key, $value = null): Query + public function equal(string $key, $value = null): QueryInterface { return $this->world('=' . $key, null, $value); } @@ -115,10 +115,10 @@ class Query implements QueryInterface * @param bool|string|int $value Value which need to check (by default true) * @param bool|string|int $operator It may be one from list [-,=,>,<] * - * @return \RouterOS\Query + * @return \RouterOS\Interfaces\QueryInterface * @throws \RouterOS\Exceptions\QueryException */ - private function world(string $key, $operator = null, $value = null): Query + private function world(string $key, $operator = null, $value = null): QueryInterface { if (null !== $operator && null === $value) { @@ -151,10 +151,10 @@ class Query implements QueryInterface * * @param string $operations * - * @return \RouterOS\Query + * @return \RouterOS\Interfaces\QueryInterface * @since 1.0.0 */ - public function operations(string $operations): Query + public function operations(string $operations): QueryInterface { $this->_operations = '?#' . $operations; return $this; @@ -165,10 +165,10 @@ class Query implements QueryInterface * * @param string $name * - * @return \RouterOS\Query + * @return \RouterOS\Interfaces\QueryInterface * @since 1.0.0 */ - public function tag(string $name): Query + public function tag(string $name): QueryInterface { $this->_tag = '.tag=' . $name; return $this; @@ -179,9 +179,9 @@ class Query implements QueryInterface * * @param string $word * - * @return \RouterOS\Query + * @return \RouterOS\Interfaces\QueryInterface */ - public function add(string $word): Query + public function add(string $word): QueryInterface { $this->_attributes[] = $word; return $this; @@ -202,10 +202,10 @@ class Query implements QueryInterface * * @param array $attributes * - * @return \RouterOS\Query + * @return \RouterOS\Interfaces\QueryInterface * @since 0.7 */ - public function setAttributes(array $attributes): Query + public function setAttributes(array $attributes): QueryInterface { $this->_attributes = $attributes; return $this; @@ -226,10 +226,10 @@ class Query implements QueryInterface * * @param string|null $endpoint * - * @return \RouterOS\Query + * @return \RouterOS\Interfaces\QueryInterface * @since 0.7 */ - public function setEndpoint(string $endpoint = null): Query + public function setEndpoint(string $endpoint = null): QueryInterface { $this->_endpoint = $endpoint; return $this;