Site:Integration

From Metrixstream
Jump to: navigation, search

Contents

Integration

Integration into Metrixstream is necessary when developing features outside the core platform. This can be done through a GitHub.com account. Once you have your account setup and repository created, contact support@metrixstream.com, so that we can configure your license so it fetches resources from GitHub.com for your extensions.

Class Autoloader

Metristream uses a class autoloader to make integration easier. As long as you place your files in the right location, then your classes can be accessed from other classes without any file inclusion. This means that you should always be wrapping your code inside a class rather than using global functions.

Good

class InputHelper {
  public static function filterInteger($value) {
    return intval($value);
  }
}

Bad

function filterInteger($value) {
  return intval($value);
}

Code Location

/query/backend
This code location houses all of the BackendQueries. Each class in this location must be derived from the BackendQuery interface.
/query/api
This code location houses all of the ApiQueries. Each class in this location must be derived from the ApiQuery interface.
/output/backend
This code location houses all of the backend output factory classes. These output factory classes transform a Database object into a BackendOutput.
/tasks/background
This code location houses all of the BackgroundTasks. Each class in this location must be derived from the BackgroundTask.
/includes/db
This code location houses all of the database objects. A Database object is a PHP class that represents the appropriate database table.
/includes/misc
This code location is the catch-all for all classes that aren't big enough for their own directory. Helper classes typically reside here.

BackendQuery

A BackendQuery are a major component of the site engine. You can create your own Backend Query by simply extending the BackendQuery interface.

The most important functions to override here are the execute and processResult functions. The execute function is responsible for performing some type of operation and then returning the result. The result is then passed into the processResult function where it is turned into a BackendOutput via the BackendOutputFactory. The reason for having two functions instead of one is because the platform can cache the result of the execute function. The execute function result can be cached, but the BackendOutput can't due to environmental variables.

The execute function's parameters include the following:

BackendContext
this provides information on how to fulfill the BackendQuery. When you were creating your page you were choosing information like number of items on the page, sort order, etc. All of this information is accessed through the BackendContext.
ScopeContext
this provides "scope" from previous contexts. This is only relevant when you are using additional contexts on the same page. An example of this would be if your primary context was referencing a profile object and then your additional context was referencing profile content. The ScopeContext would have the profile object being referenced so that the profile content query could reference the right content which would belong to that profile object.

The processResult function's parameters include the following:

BackendContext
this provides information on how to fulfill the BackendQuery. When you were creating your page you were choosing information like number of items on the page, sort order, etc. All of this information is accessed through the BackendContext.
BackendOutputFactory
this is responsible for creating a BackendOutput object that allows you to store the response of your query in a format that the Backend understands. Once you are done with your BackendOutput object, you must return it at the end of your execute function.
result
this is the result returned to us from execute.

Also keep in mind that the ApplicationContext is always available via a member function.

ApplicationContext
this one isn't an actual paramater but it is extremely important because it is your gateway into various functionality, such as: Authentication, License Properties, Database Access, etc. The ApplicationContext is made available through the BackendQuery's getApplicationContext() member function.

BackendQuery_Example

Below is BackendQuery_Example, which simply is accepting a value via URL through the "hello" parameter. It then takes that parameter and sets it into it's HDF object.

class BackendQuery_Example extends BackendQuery {
  public function getInternalName() {
    return "example";
  }

  public function getDisplayName() {
    return "My Example Context";
  }

  public function isDependentOnScope($scopeKey) {
    return false;
  }

  public function getConsumableParams() {
    return Array("hello");
  }

  public function filterParam($paramName, $paramValue, $whitelist = Array()) {
    switch($paramName) {
      case "hello": return $paramValue;
    }
    return null;
  }

  public function isCacheable() {
    return true;
  }

  public function execute(BackendContext $Backend, ScopeContext &$Scope) {
    $App =& $this->getApplicationContext();

    $params = Array(
      "hello" => $this->getParam($Page, "hello", "")
    );

    // normally we would do some database request here, but for making this example simple we are skipping that

    $result->hello = $params["hello";
    return $result;
  }

  public function processResult(BackendContext $Backend, BackendOutputFactory $OutputFactory, $result) {
    $Output =& $OutputFactory->create();
    $Output->set("hello", $result->hello);
    return $Output;
  }
}

Code Location

Each BackendQuery class must be placed within the backend/query folder. Make sure your class name starts with "BackendQuery". This is a "poor man" namespace because php5.3 isn't common enough, which means we can't use the namespace feature.

Here is a sample of this would look inside Github. https://github.com/metrixsean/Metrixstream-Sample-Integration/blob/master/backend/query/example.php

Page Integration

Once your new BackendQuery is checked into Github, you need to go to the Metrixstream Setup Panel, click on Shortcuts -> License Manager, and then click the "UPDATE GITHUB" button. This will cause all of your servers to get the latest updates from Github.

Now you can choose your new BackendQuery on a sitepage within the system. Each BackendQuery located in the query/backend folder automatically appears as a possible selection on the page creator.

Within your Site, choose "ADD PAGE". Give your page a name and then scroll down to the Backend Context section. Make sure to pick "My Example" and click the "SAVE" button.

Within your Site Page, you can now access the HDF key that you set in your context. This is as simple as the following:

Hello... my new context lets me reference the following key:

MS.hello = <?cs var:MS.hello ?>

ApiQuery

An ApiQuery is another major component of the site engine. ApiQueries generally go hand in hand with a BackendQuery. A BackendQuery lets us display information on a page and an ApiQuery lets us manipulate that information.

ApiQuery_UpdateLastLoginTimestamp

Below is a simply ApiQuery implementation that updates the authenticated user's last login timestamp.

class ApiQuery_UpdateLastLoginTimestamp extends ApiQuery {
  public function getInternalName() {
    return "authuser_updatelastlogintimestamp";
  }

  public function execute(ApiContext &$Api, ApiOutputFactory &$OutputFactory) {
    $App =& $this->getApplicationContext();
    $Auth =& $App->getAuthContext();

    if (!$Auth->hasUser()) {
      return $OutputFactory->error("This is an authenticated request.");
    }

    $User =& $Auth->getUser();
    $User->last_login = time();
    $ret = $User->updateParams(Array("last_login"), true);
    if (!$ret) {
      $OutputFactory->error("Unable to update user.");
    }

    return $OutputFactory->success();
  }
}

Code Location

Each ApiQuery class must be placed within the api/query folder. Make sure your class name starts with "ApiQuery". This is a "poor man" namespace because php5.3 isn't common enough, which means we can't use the namespace feature.

Here is a sample of this would look inside Github. https://github.com/metrixsean/Metrixstream-Sample-Integration/blob/master/api/query/updatelastlogintimestamp.php

Page Integration

Once your new ApiQuery is checked into Github, you need to go to the Metrixstream Setup Panel, click on Shortcuts -> License Manager, and then click the "UPDATE GITHUB" button. This will cause all of your servers to get the latest updates from Github.

This example below is using jQuery.

<html>
<head>
  <script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
  <script>
    $(document).ready(function() {
      $("#mybutton").click(function(evt) {
        $.ajax({
          type: 'POST',
          url:  '<?cs call:getBasePostUrl() ?>',
          data: {
            'mode'     :'json',
            'action'   :'updatelastlogintimestamp'
          },
          success: function(data) {
            if(data.status == 'ok') {
              alert("Success!");
            } else {
              alert(data.message);
            }
          },
          error: function() {
            alert('An error has occured.');
          }
        });
      });
    });
  </script>
</head>
<body>

<input type="button" id="mybutton" value="Click to update last login timestamp.">

</body>
</html>

BackgroundTask

A BackgroundTask is another major component of Metrixstream. BackgroundTasks do routine operations behind the scenes, such as: backing up the database, processing log files, encoding content, etc.

Below is a simply BackgroundTask that sends an email daily on the number of users within the system.

class BackgroundTask_UserSummaryEmail extends BackgroundTask {
  public function getServerOption() {
    return "usersummaryemail";
  }

  public function getTaskStartTime() {
    $start = strtotime("5 am");

    if ($start < time()) {
      $start += 24*60*60;
    }

    return $start;
  }

  public function getIdleTimeout() {
    return 24*60*60;
  }

  function run() {
    $task =& $this->getContext();
    $pRet =& $this->getPubSubResult();

    $DB =& $task->getDatabaseContext();

    $numUsers = $DB->getBackDB()->queryCount("SELECT COUNT(1) AS CNT FROM site_user WHERE 1", "CNT");

    $pRet->log("%d users detected", $numUsers);

    $mail = new htmlMimeMail();
    $mail->setHeadCharset("UTF-8");
    $mail->setFrom("no-reply@metrixstream.com");
    $mail->setSubject("# of users summary");
    $mail->setText(sprintf("There are %d users.", $numUsers);
    $mail->send(Array("test@test.com"));

    return $pRet->success();
  }
}

Code Location

Each BackgroundTask class must be placed within the background/task folder. Make sure your class name starts with "BackgroundTask". This is a "poor man" namespace because php5.3 isn't common enough, which means we can't use the namespace feature.

Here is a sample of this would look inside Github. https://github.com/metrixsean/Metrixstream-Sample-Integration/blob/master/background/task/usersummaryemail.php

iSystemHook

The iSystemHook interface allows you to hook into various mechanisms of Metrixstream and provide custom functionality.

Code Location

Your SystemHook class must be placed within the hook directory. Your class must also be named "SystemHook" and stored in the file "system.php".

Here is an example of a SystemHook stored in GitHub: https://github.com/metrixsean/Metrixstream-Sample-Integration/blob/master/hook/system.php

Overridable Functions

To provide your own implementation, simply extend the iSystemHook abstract class and override any of the functions below.

updateDatabase(DatabaseContext db)
this function is called when a build update is performed. You can use this to perform custom database operations outside of the core Metrixstream framework.
Personal tools