public function createSubscription($topic, PushHub $hub)
 {
     $subscription = ['topic' => $topic, 'hub' => $hub->getUrl()];
     $existingSubscription = $this->db->prepare('SELECT * FROM ' . $this->prefix . 'subscriptions WHERE topic = :topic AND hub = :hub;');
     $existingSubscription->execute($subscription);
     if ($existingSubscription->rowCount() !== 0) {
         $subscription = $existingSubscription->fetch();
         if ($subscription['mode'] !== 'subscribe') {
             if ($this->db->prepare("UPDATE {$this->prefix}subscriptions SET mode='subscribe' WHERE id = :id;")->execute($subscription) === false) {
                 return [null, new Exception('Failed updating subscription: ' . print_r($this->db->errorInfo(), true))];
             }
         }
     } else {
         // Create a sufficiently random ID for the subscription.
         // Not relying on database autoincrement as this ID is used in public endpoints. In the case of unsigned ping requests
         // this provides minimal security by obscurity.
         $subscription['id'] = uniqid(time(), true);
         $insertStatement = $this->db->prepare('INSERT INTO ' . $this->prefix . 'subscriptions (id, topic, hub) VALUES (:id, :topic, :hub);');
         if ($insertStatement->execute($subscription) === false) {
             return [null, new Exception('Failed saving subscription: ' . print_r($insertStatement->errorInfo(), true))];
         }
         $existingSubscription->execute(['topic' => $subscription['topic'], 'hub' => $subscription['hub']]);
         $subscription = $existingSubscription->fetch();
         if ($subscription === false) {
             return [null, new Exception('Failed retrieving subscription: ' . print_r($existingSubscription->errorInfo(), true))];
         }
     }
     return [$subscription, null];
 }
 public function testCanCreateHub()
 {
     $url = 'http://pubsubhubbub.example.com';
     $hub = new PushHub($url);
     $this->assertEquals($url, $hub->getUrl());
 }