* Verwende stream_context_set_options statt stream_context_set_option master v0.1.4
authorSebastian Brix <sebastian.brix@graph-it.com>
Wed, 14 May 2025 05:35:54 +0000 (07:35 +0200)
committerSebastian Brix <sebastian.brix@graph-it.com>
Wed, 14 May 2025 05:35:54 +0000 (07:35 +0200)
* Psalm-Warnungen bearbeitet

composer.json
composer.lock
src/Connection.php

index e0bbed6d2d5f1c13add26e9d33d8e1bc0abf5780..44acaa385822df738f40dad165e329bc67a53b87 100644 (file)
@@ -1,18 +1,21 @@
 {
-    "name": "graphit/graph-client",
-    "type": "library",
-    "description": "Graph Client",
-    "authors": [
-        {
-            "name": "Graph-IT",
-            "email": "info@graph-it.com"
-        }
-    ],
-    "require": {
-        "php": ">=5.6.0",
-        "graphit/graph-common": "^0.1.1"
-    },
-    "autoload": {
-        "psr-4": { "Graphit\\Graph\\Client\\": "src/" }
+  "name": "graphit/graph-client",
+  "type": "library",
+  "description": "Graph Client",
+  "authors": [
+    {
+      "name": "Graph-IT",
+      "email": "info@graph-it.com"
     }
-}
+  ],
+  "require": {
+    "php": ">=8.3.0",
+    "ext-msgpack": "^2.0.0 | ^3.0.0",
+    "graphit/graph-common": "^0.1.1"
+  },
+  "autoload": {
+    "psr-4": {
+      "Graphit\\Graph\\Client\\": "src/"
+    }
+  }
+}
\ No newline at end of file
index 367fcada802d178df913d8acac52f2033dc29fca..9bd45b883be33b3f049f46c1a2811f340f0237c3 100644 (file)
@@ -4,25 +4,28 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "8819b656c8da858aeee741066f00c123",
+    "content-hash": "3d65b77f5f76008c32a22709c5d58d73",
     "packages": [
         {
             "name": "graphit/graph-common",
-            "version": "v0.1.1",
+            "version": "v0.1.8",
             "source": {
                 "type": "git",
                 "url": "ssh://git@git.graph-it.com:44022/graphit/graph-common",
-                "reference": "fae80afcb63233232c0bf4824e599bc101293225"
+                "reference": "93d05c2c9492c8302d94bf6766db9cb8819467c8"
             },
             "require": {
-                "php": ">=5.6.0",
-                "twig/twig": "^1.26.0"
+                "php": ">=8.3.0",
+                "twig/twig": "^1.44.7 || ^3.4.3"
             },
             "type": "library",
             "autoload": {
                 "psr-4": {
                     "Graphit\\Graph\\Common\\": "src/"
-                }
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
             },
             "authors": [
                 {
                 }
             ],
             "description": "Vom Graphserver und -Client geteilte Sourcen.",
-            "time": "2022-05-04T16:06:22+00:00"
+            "time": "2025-04-09T12:47:01+00:00"
+        },
+        {
+            "name": "symfony/deprecation-contracts",
+            "version": "v3.5.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/deprecation-contracts.git",
+                "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
+                "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.1"
+            },
+            "type": "library",
+            "extra": {
+                "thanks": {
+                    "url": "https://github.com/symfony/contracts",
+                    "name": "symfony/contracts"
+                },
+                "branch-alias": {
+                    "dev-main": "3.5-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "function.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "A generic function and convention to trigger deprecation notices",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2024-09-25T14:20:29+00:00"
         },
         {
             "name": "symfony/polyfill-ctype",
-            "version": "v1.25.0",
+            "version": "v1.32.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-ctype.git",
-                "reference": "30885182c981ab175d4d034db0f6f469898070ab"
+                "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab",
-                "reference": "30885182c981ab175d4d034db0f6f469898070ab",
+                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
+                "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.1"
+                "php": ">=7.2"
             },
             "provide": {
                 "ext-ctype": "*"
             },
             "type": "library",
             "extra": {
-                "branch-alias": {
-                    "dev-main": "1.23-dev"
-                },
                 "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
+                    "url": "https://github.com/symfony/polyfill",
+                    "name": "symfony/polyfill"
                 }
             },
             "autoload": {
                 "portable"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0"
+                "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-10-20T20:35:02+00:00"
+            "time": "2024-09-09T11:45:10+00:00"
         },
         {
-            "name": "twig/twig",
-            "version": "v1.44.6",
+            "name": "symfony/polyfill-mbstring",
+            "version": "v1.32.0",
             "source": {
                 "type": "git",
-                "url": "https://github.com/twigphp/Twig.git",
-                "reference": "ae39480f010ef88adc7938503c9b02d3baf2f3b3"
+                "url": "https://github.com/symfony/polyfill-mbstring.git",
+                "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/twigphp/Twig/zipball/ae39480f010ef88adc7938503c9b02d3baf2f3b3",
-                "reference": "ae39480f010ef88adc7938503c9b02d3baf2f3b3",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
+                "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.2.5",
-                "symfony/polyfill-ctype": "^1.8"
+                "ext-iconv": "*",
+                "php": ">=7.2"
             },
-            "require-dev": {
-                "psr/container": "^1.0",
-                "symfony/phpunit-bridge": "^4.4.9|^5.0.9"
+            "provide": {
+                "ext-mbstring": "*"
+            },
+            "suggest": {
+                "ext-mbstring": "For best performance"
             },
             "type": "library",
             "extra": {
-                "branch-alias": {
-                    "dev-master": "1.44-dev"
+                "thanks": {
+                    "url": "https://github.com/symfony/polyfill",
+                    "name": "symfony/polyfill"
                 }
             },
             "autoload": {
-                "psr-0": {
-                    "Twig_": "lib/"
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Mbstring\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for the Mbstring extension",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "mbstring",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
                 },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2024-12-23T08:48:59+00:00"
+        },
+        {
+            "name": "twig/twig",
+            "version": "v3.21.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/twigphp/Twig.git",
+                "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/twigphp/Twig/zipball/285123877d4dd97dd7c11842ac5fb7e86e60d81d",
+                "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.1.0",
+                "symfony/deprecation-contracts": "^2.5|^3",
+                "symfony/polyfill-ctype": "^1.8",
+                "symfony/polyfill-mbstring": "^1.3"
+            },
+            "require-dev": {
+                "phpstan/phpstan": "^2.0",
+                "psr/container": "^1.0|^2.0",
+                "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/Resources/core.php",
+                    "src/Resources/debug.php",
+                    "src/Resources/escaper.php",
+                    "src/Resources/string_loader.php"
+                ],
                 "psr-4": {
                     "Twig\\": "src/"
                 }
             ],
             "support": {
                 "issues": "https://github.com/twigphp/Twig/issues",
-                "source": "https://github.com/twigphp/Twig/tree/v1.44.6"
+                "source": "https://github.com/twigphp/Twig/tree/v3.21.1"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-11-25T13:31:46+00:00"
+            "time": "2025-05-03T07:21:55+00:00"
         }
     ],
     "packages-dev": [],
     "aliases": [],
     "minimum-stability": "stable",
-    "stability-flags": [],
+    "stability-flags": {},
     "prefer-stable": false,
     "prefer-lowest": false,
     "platform": {
-        "php": ">=5.6.0"
+        "php": ">=8.3.0",
+        "ext-msgpack": "^2.0.0 | ^3.0.0"
     },
-    "platform-dev": [],
-    "plugin-api-version": "2.2.0"
+    "platform-dev": {},
+    "plugin-api-version": "2.6.0"
 }
index 8fd7a908683ece5e80ba1b61373de5a0d08dd33b..0a1c348bdd94560ee8c1a1876296ee1c4e0ab419 100644 (file)
@@ -3,53 +3,24 @@
 namespace Graphit\Graph\Client;
 
 use Graphit\Graph\Common\RemoteConnection;
-use Graphit\Graph\Common\ConnectionInterface;
+use RuntimeException;
+use LogicException;
 
-class Connection extends RemoteConnection implements ConnectionInterface {
+/** @api */
+class Connection extends RemoteConnection {
  
-  const STREAM_SELECT_TIMEOUT = 2;
-
-  /** @var string */
-  private $url;
+  const int STREAM_SELECT_TIMEOUT = 2;
 
   /** @var resource|false */
   private $socket = false;
 
-  /** @var array */
-  private $options;
-
-  /** @var string */
-  private $protocoll;
-
-  /** @var int|false */
-  private $cryptoType;
-
-  /** @var int */
-  private $messageId = 0;
-
-  /**
-   * @param string $url
-   */
-  public function __construct($url, array $options = [])
-  {
-    $this->url = $url;
-    $this->options = $options;
+  private int $messageId = 0;
 
-    $matches = [];
-    $pattern = '/^(?<protocoll>[^:]+):\/\//';
-    if (preg_match($pattern, $this->url, $matches) !== 1) {
-      throw new \Exception('Unable to find Transport in URL '.$this->url.'!');
-    }
-    $this->protocoll = $matches['protocoll'];
-
-    $this->cryptoType = false;
-    $cryptoTypes = [
-      'tls' => STREAM_CRYPTO_METHOD_TLS_CLIENT,
-    ];
-    if (isset($cryptoTypes[$this->protocoll])) {
-      $this->cryptoType = $cryptoTypes[$this->protocoll];
-    }
-  }
+  /** @param array{cafile?: string, lofile?: string } $options */
+  public function __construct(
+    private readonly string $url,
+    private readonly array $options = []
+  ) { }
 
   public function __destruct()
   {
@@ -58,19 +29,18 @@ class Connection extends RemoteConnection implements ConnectionInterface {
     }
   }
 
-  /** @return void */
-  private function _connect()
+  private function _connect(): void 
   {
     $context = stream_context_create();
 
-    if ($this->cryptoType !== false) {
-      stream_context_set_option($context, [
+    if (substr($this->url, 0, 6) === 'tls://') {
+      stream_context_set_options($context, [
         'ssl' => [
           'verify_peer'      => true,
           'verify_peer_name' => false,
           'ciphers'          => 'HIGH',
-          'cafile'           => $this->options['cafile'],
-          'local_cert'       => $this->options['lofile'],
+          'cafile'           => $this->options['cafile'] ?? '',
+          'local_cert'       => $this->options['lofile'] ?? '',
         ],
       ]);
     }
@@ -78,23 +48,19 @@ class Connection extends RemoteConnection implements ConnectionInterface {
     $timeout = (float)ini_get('default_socket_timeout');
     $this->socket = stream_socket_client($this->url, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $context);
     if ($this->socket === false) {
-      throw new \Exception("stream_socket_server() failed: $errstr");
+      throw new RuntimeException("stream_socket_server() failed: $errstr");
     }
     
     if ( !stream_set_blocking($this->socket, false)) {
-      throw new \Exception("stream_set_blocking(false) failed!");
+      throw new RuntimeException("stream_set_blocking(false) failed!");
     }
 
     $this->_readMessage();
   }
 
-  /**
-   * @param int $size
-   * @return string
-   */
-  private function _readBytes($size) {
+  private function _readBytes(int $size): string {
     if ( !$this->socket) {
-      throw new \Exception("Socket not initialized");
+      throw new RuntimeException("Socket not initialized");
     }
 
     $bytes = '';
@@ -103,7 +69,7 @@ class Connection extends RemoteConnection implements ConnectionInterface {
       $rs = [$this->socket]; 
       $ws = NULL; 
       $es = NULL;
-      if (@stream_select($rs, $ws, $es, self::STREAM_SELECT_TIMEOUT)) {
+      if (@stream_select($rs, $ws, $es, self::STREAM_SELECT_TIMEOUT) > 0) {
         if (feof($this->socket)) {
           break;
         }
@@ -117,20 +83,31 @@ class Connection extends RemoteConnection implements ConnectionInterface {
     }
     
     if (strlen($bytes) != $size) {
-      throw new \Exception("Unable to read $size Bytes from the socket");
+      throw new RuntimeException("Unable to read $size Bytes from the socket");
     }
 
     return $bytes;
   }
 
-  /** @return mixed */
-  private function _readMessage() {
+  private function parseUnpackSize(mixed $value): int {
+    if ( !is_array($value))
+      throw new LogicException('array expected');
+      
+    if ( !array_key_exists('size', $value))
+      throw new LogicException('key "size" expected');
+
+    if ( !is_int($value['size']))
+      throw new LogicException('int expected');
+
+    return $value['size'];
+  }
+
+  private function _readMessage(): mixed {
     $size = $this->_readBytes(4);
-    /** @var int $size */
-    $size = unpack('Vsize', $size)['size'];
+    $size = $this->parseUnpackSize(unpack('Vsize', $size));
 
     $message = $this->_readBytes($size);
-    return msgpack_unpack($message);
+    return \msgpack_unpack($message);
   }
 
   /**
@@ -139,7 +116,7 @@ class Connection extends RemoteConnection implements ConnectionInterface {
    */
   private function _writeBytes($bytes) {
     if ( !$this->socket) {
-      throw new \Exception("Socket not initialized");
+      throw new RuntimeException("Socket not initialized");
     }
 
     $size = strlen($bytes);
@@ -161,22 +138,18 @@ class Connection extends RemoteConnection implements ConnectionInterface {
     }
 
     if ($written != $size) {
-      throw new \Exception("Unable to write $size Bytes to socket");
+      throw new RuntimeException("Unable to write $size Bytes to socket");
     }
   }
 
-  /**
-   * @param mixed $message
-   * @return void
-   */
-  private function _writeMessage($message) {
+  private function _writeMessage(mixed $message): void {
     /** @var string $message */
     $message = msgpack_pack($message);
     $message = pack('V', strlen($message)).$message;
     $this->_writeBytes($message);
   }
 
-  /** */
+  #[\Override]
   protected function call($method, array $params)
   {
     if ( !$this->socket) {
@@ -193,14 +166,14 @@ class Connection extends RemoteConnection implements ConnectionInterface {
 
     $response = $this->_readMessage();
     if ( !isset($response['jsonrpc']) || $response['jsonrpc'] != $request['jsonrpc']) {
-      throw new \Exception('Not a JSON-RPC 2.0 response!');
+      throw new RuntimeException('Not a JSON-RPC 2.0 response!');
     }
     if (isset($response['error'])) {
       $error = json_encode($response['error']);
-      throw new \Exception("JSON-RPC: Remote error: {$error}");
+      throw new RuntimeException("JSON-RPC: Remote error: {$error}");
     }
     if ( !isset($response['id']) || $response['id'] != $request['id']) {
-      throw new \Exception('JSON-RPC id missing or invalid');
+      throw new RuntimeException('JSON-RPC id missing or invalid');
     }
 
     return $response['result'];