revamp server demo: discuss
authorgggeek <giunta.gaetano@gmail.com>
Sun, 8 Jan 2023 23:52:34 +0000 (23:52 +0000)
committergggeek <giunta.gaetano@gmail.com>
Sun, 8 Jan 2023 23:52:34 +0000 (23:52 +0000)
demo/server/discuss.php

index 3a2e9b7..6ee592c 100644 (file)
 <?php
 /**
  * A basic comment server. Given an ID it will store a list of names and comment texts against it.
- * It uses a Berkeley DB database for storage.
+ * It uses a SQLite DB database for storage.
  */
 
 require_once __DIR__ . "/_prepend.php";
 
+use PhpXmlRpc\Response;
+use PhpXmlRpc\Server;
 use PhpXmlRpc\Value;
 
-$addComment_sig = array(array(Value::$xmlrpcInt, Value::$xmlrpcString, Value::$xmlrpcString, Value::$xmlrpcString));
-
-$addComment_doc = 'Adds a comment to an item. The first parameter
-is the item ID, the second the name of the commenter, and the third
-is the comment itself. Returns the number of comments against that
-ID.';
-
-function addComment($req)
+class CommentManager
 {
-    $err = "";
-    // since validation has already been carried out for us,
-    // we know we got exactly 3 string values
-    $encoder = new PhpXmlRpc\Encoder();
-    $n = $encoder->decode($req);
-    $msgID = $n[0];
-    $name = $n[1];
-    $comment = $n[2];
-
-    $dbh = dba_open("/tmp/comments.db", "c", "db2");
-    if ($dbh) {
-        $countID = "{$msgID}_count";
-        if (dba_exists($countID, $dbh)) {
-            $count = dba_fetch($countID, $dbh);
-        } else {
-            $count = 0;
-        }
-        // add the new comment in
-        dba_insert($msgID . "_comment_{$count}", $comment, $dbh);
-        dba_insert($msgID . "_name_{$count}", $name, $dbh);
-        $count++;
-        dba_replace($countID, $count, $dbh);
-        dba_close($dbh);
-    } else {
-        $err = "Unable to open comments database.";
-    }
-    // if we generated an error, create an error return response
-    if ($err) {
-        return new PhpXmlRpc\Response(0, PhpXmlRpc\PhpXmlRpc::$xmlrpcerruser, $err);
-    } else {
-        // otherwise, we create the right response
-        return new PhpXmlRpc\Response(new PhpXmlRpc\Value($count, "int"));
+    protected $dbFile = "/tmp/comments.db";
+
+    protected function createTable($db)
+    {
+        return $db->exec('CREATE TABLE IF NOT EXISTS comments (msg_id TEXT NOT NULL, name TEXT NOT NULL, comment TEXT NOT NULL)');
     }
-}
 
-$getComments_sig = array(array(Value::$xmlrpcArray, Value::$xmlrpcString));
+    /**
+     * @param string $msgID
+     * @param string $name
+     * @param string $comment
+     * @return int
+     * @throws \Exception
+     */
+    public function addComment($msgID, $name, $comment)
+    {
+        $db = new SQLite3($this->dbFile);
+        $this->createTable($db);
 
-$getComments_doc = 'Returns an array of comments for a given ID, which
-is the sole argument. Each array item is a struct containing name
-and comment text.';
+        $statement = $db->prepare("INSERT INTO comments VALUES(:msg_id, :name, :comment)");
+        $statement->bindValue(':msg_id', $msgID);
+        $statement->bindValue(':name', $name);
+        $statement->bindValue(':comment', $comment);
+        $statement->execute();
+        /// @todo this insert-then-count is not really atomic - we should use a transaction
 
-function getComments($req)
-{
-    $err = "";
-    $ra = array();
-    $encoder = new PhpXmlRpc\Encoder();
-    $msgID = $encoder->decode($req->getParam(0));
-    $dbh = dba_open("/tmp/comments.db", "r", "db2");
-    if ($dbh) {
-        $countID = "{$msgID}_count";
-        if (dba_exists($countID, $dbh)) {
-            $count = dba_fetch($countID, $dbh);
-            for ($i = 0; $i < $count; $i++) {
-                $name = dba_fetch("{$msgID}_name_{$i}", $dbh);
-                $comment = dba_fetch("{$msgID}_comment_{$i}", $dbh);
-                // push a new struct onto the return array
-                $ra[] = array(
-                    "name" => $name,
-                    "comment" => $comment,
-                );
-            }
-        }
-    } else {
-        $err = "Unable to open comments database.";
+        $statement = $db->prepare("SELECT count(*) AS tot FROM comments WHERE msg_id = :id");
+        $statement->bindValue(':id', $msgID);
+        $results = $statement->execute();
+        $row = $results->fetchArray(SQLITE3_ASSOC);
+        $results->finalize();
+        $count = $row['tot'];
+
+        $db->close();
+
+        return $count;
     }
-    // if we generated an error, create an error return response
-    if ($err) {
-        return new PhpXmlRpc\Response(0, PhpXmlRpc\PhpXmlRpc::$xmlrpcerruser, $err);
-    } else {
-        // otherwise, we create the right response
-        return new PhpXmlRpc\Response($encoder->encode($ra));
+
+    /**
+     * @param string $msgID
+     * @return Response|array[]
+     * @throws \Exception
+     */
+    public function getComments($msgID)
+    {
+        $db = new SQLite3($this->dbFile);
+        $this->createTable($db);
+
+        $ra = array();
+        $statement = $db->prepare("SELECT name, comment FROM comments WHERE msg_id = :id ORDER BY rowid");
+        $statement->bindValue(':id', $msgID);
+        $results = $statement->execute();
+        while ($row = $results->fetchArray(SQLITE3_ASSOC)) {
+            $ra[] = $row;
+        }
+        $results->finalize();
+
+        $db->close();
+
+        return $ra;
     }
 }
 
+$manager = new CommentManager();
+
+$addComment_sig = array(array(Value::$xmlrpcInt, Value::$xmlrpcString, Value::$xmlrpcString, Value::$xmlrpcString));
+
+$addComment_doc = 'Adds a comment to an item. The first parameter is the item ID, the second the name of the commenter, ' .
+    'and the third is the comment itself. Returns the number of comments against that ID.';
+
+$getComments_sig = array(array(Value::$xmlrpcArray, Value::$xmlrpcString));
+
+$getComments_doc = 'Returns an array of comments for a given ID, which is the sole argument. Each array item is a struct ' .
+    'containing name and comment text.';
+
 // NB: take care not to output anything else after this call, as it will mess up the responses and it will be hard to
 // debug. In case you have to do so, at least re-emit a correct Content-Length http header (requires output buffering)
-
-$srv = new PhpXmlRpc\Server(array(
+$srv = new Server(array(
     "discuss.addComment" => array(
-        "function" => "addComment",
+        "function" => array($manager, "addComment"),
         "signature" => $addComment_sig,
         "docstring" => $addComment_doc,
     ),
     "discuss.getComments" => array(
-        "function" => "getComments",
+        "function" => array($manager, "getComments"),
         "signature" => $getComments_sig,
         "docstring" => $getComments_doc,
     ),
-));
+), false);
+
+// let the xml=rpc server know that the method-handler functions expect plain php values
+$srv->functions_parameters_type = 'phpvals';
+
+// let code exceptions float all the way to the remote caller as xml-rpc faults - it helps debugging
+$srv->exception_handling = 1;
+
+$srv->service();