Hoppa till innehåll

Data Objects for Osclass plugins using dliCore

As mentioned in our previous post regarding database tables for Osclass plugins written using dliCore the library offers another way to access the data stored in your tables. It was a thought that originated in an old library I did many years ago that I simplified for this case. The old approach consisted of something I called data gateways. These gateways would fill objects (that knew nothing about the back end storing the data) with data. The objects could be loaded and saved from each back end through the respective gate way. This made it quick and easy to change your code from working with the database to testing using mock-up data in xml files.

For dliCore I took parts of this an made a system that would abstract the database layer for the developer and allow them to work with objects instead. I made it so that it would not require a huge overhead and it would also keep track of the fact that objects and databases were in sync. By that I mean that if you add a column to your table and you don’t allow it to have a default value then it must be present in the object or an exception is thrown.

Here I give a very simple presentation about how to connect an object to a table. Let’s use a simple messages table in a plugin called userMessages in our example.

Create table

First we create our table class.

<?php
namespace userMessages\Table;

use dliLib\Db\AbstractTable;

class MessageTable extends AbstractTable
{
    protected $_tableName = 't_message';

    protected function _init() {
        $this->_struct ="CREATE TABLE IF NOT EXISTS /*TABLE_NAME*/ (
        pk_i_id INT UNSIGNED AUTO INCREMENT,
        fk_i_user_id INT UNSIGNED,
        fk_i_sender_id INT UNSIGNED,
        s_title VARCHAR(64) NOT NULL,
        s_text  VARCHAR(256) DEFAULT NULL,
        dt_date DATETIME NOT NULL,
        PRIMARY KEY (pk_i_id),
        FOREIGN KEY (fk_i_user_id) REFERENCES /*TABLE_PREFIX*/t_user (pk_i_id) ON DELETE CASCADE,
        FOREIGN KEY (fk_i_sender_id) REFERENCES /*TABLE_PREFIX*/t_user (pk_i_id) ON DELETE SET NULL
      ) ENGINE=InnoDB DEFAULT CHARACTER SET 'UTF8' COLLATE 'UTF8_GENERAL_CI';";
    }
}

Our messages contains a id, a foreign key to the receiving user, a foreign key to the sending user, a title, the contents and a date time of when the message was sent. Indexes to speed up access by date etc could of course be added.

Register table

Now we register the table with our plugin to it will be installed when the plugin is installed.

class userMessagesPlugin extends Plugin
{
    protected function _init() {       
        /* Register Tables */
        $this->_registerTable('userMessages\Table\MessageTable', 'message');
    }

Creating our data object

Now we create an object that extends DbModel. We tell it which table it’s connected to and we give it the member variables needed to carry the data. Note that we could add more variables here than what is available in the table and add additional logic as well.

<?php
namespace userMessages\Model;

use dliLib\Model\DbModel;

class Message extends DbModel
{
    protected static $_dbTableClass = 'userMessages\Table\UserMessagesTable';

    protected $_id        = null;
    protected $_userId    = null;
    protected $_senderId  = null;
    protected $_title     = null;
    protected $_message   = null;
    protected $_date      = null;

    public function __construct($title, $message, receiver) {
      $this->_userId  = $receiver;
      $this->_title   = $title;
      $this->_message = $message;
      $this->_sender  = osc_logged_user_id();
      $this->_date    = date('Y-m-d H:m:s');
    }
    public function getId()
    {
        return $this->_id;
    }

    public function setId($_id)
    {
        $this->_id = $_id;
        return $this;
    }

    public function getUserId()
    {
        return $this->_userId;
    }

    public function setUserId($userId)
    {
        $this->_userId = $userId;
        return $this;
    }
    
    public function getSenderId()
    {
        return $this->_senderId;
    }

    public function setSenderId($senderId)
    {
        $this->_senderId = $senderId;
        return $this;
    }
    
    public function getTitle()
    {
        return $this->_title;
    }

    public function setTitle($title)
    {
        $this->_title = $title;
        return $this;
    }

...

If a set function is present, that will be used when creating the object when reading from the database. So any extra logic needed on data read from the database can be put there. For instance you might store a data in some specific format in the database but want it to be stored differently within the object. If this need does not exist and there is no wish for any public get or set functions they can be left out.

Functionality to save a single or multiple items and fetch items based on their primary key exists by default. Even multi-column primary keys are supported. To add extended functionality like we did in our old DAO object we can do things like this to our object.

static public function fetchAllForUser($userId) {
    return static::_fetchAll(static::getDbTable()->dao->select()->from(static::getDbTable()->getTableName())->where('fk_i_user_id', $userId));
}

Working with your objects

By these simple steps you can now do things like

<?php

use userMessages\Model\UserMessage;

// Create message with user 10 as receipient
$message = new UserMessage('Hello!', 'I would just like to say hello.', 10);

// Store the message in the database
$message->save();

//-----------------------------------------------------

// Create and store a batch of messages at once

$userIds  = [1, 2, 3, 4, 5, 6, 7, 8];
$messages = [];

foreach($userIds as $userId) {
  $messages[] = new UserMessage('Hello!', 'I would just like to say hello.', userId);
}

UserMessage::saveBatch(messages);

//-----------------------------------------------------

// Fetch all messages for a given user and echo them
$myMessages = UserMessage::fetchAllForUser(osc_logged_user_id());

foreach($myMessages as $myMessage) {
  echo $myMessage->getTitle() . '<br/>';
  echo $myMessage->getMessage() . '<br/>';
  
  // Deletes the entry in the database and sets object to null
  // _beforeDelete is called on the object before object is deleted from db
  $myMessage->delete();
}

Closing thoughts

If one opts-in to use this style you get an easy encapsulation of objects without much work. For the standard tables like User these objects will also be made available by the library. That way, user objects can be passed around instead of user id´s or associative arrays.

Note that just as with most parts of dliCore, the use of these objects are purely optional. You can stick to just creating the tables in this new way, or doing it the old manual way and sticking with DAO your old objects. For older plugins being moved to use dliCore this can help reduce the needed modifications.

Kommentarer

Dela i ditt aktivitets flöde

Powered by WP LinkPress

Kommentarer

Dela i ditt aktivitets flöde

Powered by WP LinkPress