/**
  * Convert a single URL, assumes $url has been verified to be 
  * a real URL
  * 
  * @param string $url 
  */
 public function convertUrl($url)
 {
     $oembed = Oembed::get_oembed_from_url($url, false, $this->oembedOptions);
     if ($oembed) {
         return array('Title' => '', 'Content' => $oembed->forTemplate());
     }
     $graph = OpenGraph::fetch($url);
     if ($graph) {
         foreach ($graph as $key => $value) {
             $data[$key] = Varchar::create_field('Varchar', $value);
         }
         if (isset($data['url'])) {
             return array('Title' => $graph->Title, 'Content' => MicroPost::create()->customise($data)->renderWith('OpenGraphPost'));
         }
     }
     // get the post and take its <title> tag at the very least
     $service = new RestfulService($url);
     $response = $service->request();
     if ($response && $response->getStatusCode() == 200) {
         if (preg_match('/<title>(.*?)<\\/title>/is', $response->getBody(), $matches)) {
             $title = Convert::raw2xml(trim($matches[1]));
             return array('Title' => $title, 'Content' => "<a href='{$url}'>{$title}</a>");
         }
     }
 }
    public function testTagExtract()
    {
        $this->logInWithPermission();
        $post = MicroPost::create();
        $post->Content = <<<POST
\tThis is #content
\t\t
being created in this #post
\t\t
POST;
        $post->write();
        $tags = singleton('MicroBlogService')->extractTags($post);
    }
 /**
  * Creates a new post for the given member
  *
  * @param Member $member
  *			The member creating the post. Will default to the calling member if not specified
  * @param string $content
  *			The content being loaded into the post
  * @param array $properties
  *			Additional properties to be bound into the post. 
  * @param int $parentId
  *			The ID of a micropost that is considered the 'parent' of this post
  * @param mixed $target
  *			The "target" of this post; may be a data object (ie context of the post) or a user/group
  * @param array $to
  *			The people/groups this post is being sent to. This is an array of
  *			- logged_in: boolean (logged in users; uses a system config setting to determine which group represents 'logged in'
  *			- members: an array, or comma separated string, of member IDs
  *			- groups: an array, or comma separated string, of group IDs
  * @return MicroPost 
  */
 public function createPost(DataObject $member, $content, $properties = null, $parentId = 0, $target = null, $to = null)
 {
     // backwards compatible
     if (is_string($properties)) {
         $properties = array('Title' => $properties);
     }
     if (!$member) {
         $member = $this->securityContext->getMember();
     }
     if (!$member->exists() && !$this->allowAnonymousPosts) {
         throw new Exception("Anonymous posting disallowed");
     }
     $post = MicroPost::create();
     $post->Content = $content;
     if ($properties && count($properties)) {
         foreach ($properties as $field => $value) {
             if (isset($this->allowedProperties[$field])) {
                 $post->{$field} = $value;
             }
         }
     }
     $post->OwnerID = $member->ID;
     $post->Target = $target;
     if ($parentId) {
         $parent = MicroPost::get()->restrictedByID($parentId);
         if ($parent) {
             $post->ParentID = $parentId;
             $post->ThreadID = $parent->ThreadID;
             $post->Target = $parent->Target;
         }
     }
     if (isset($to['public'])) {
         $post->PublicAccess = (bool) $to['public'];
     }
     $post->write();
     // if we're a good poster, scan its content, otherwise post process it for spam
     if ($member->Balance >= MicroBlogMember::BALANCE_THRESHOLD) {
         $post->analyseContent();
         $post->write();
     } else {
         $this->queuedJobService->queueJob(new ProcessPostJob($post));
     }
     // set its thread ID
     if (!$post->ParentID) {
         $post->ThreadID = $post->ID;
         $post->write();
     }
     if ($post->ID != $post->ThreadID) {
         $thread = MicroPost::get()->restrictedByID($post->ThreadID);
         if ($thread) {
             $owner = $thread->Owner();
             $this->transactionManager->run(function () use($post, $thread) {
                 $thread->NumReplies += 1;
                 $thread->write();
             }, $owner);
         }
     }
     $this->rewardMember($member, 2);
     if ($to) {
         $post->giveAccessTo($to);
     }
     // we stick this in here so the UI can update...
     $post->RemainingVotes = $member->VotesToGive;
     $post->extend('onCreated', $member, $target);
     if ($this->notificationService) {
         $this->notificationService->notify('MICRO_POST_CREATED', $post);
     }
     return $post;
 }