Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
76.92% covered (warning)
76.92%
10 / 13
CRAP
94.74% covered (success)
94.74%
144 / 152
ModelBase
0.00% covered (danger)
0.00%
0 / 1
78.57% covered (warning)
78.57%
11 / 14
59.51
94.74% covered (success)
94.74%
144 / 152
 install
100.00% covered (success)
100.00%
1 / 1
1  
 
 __construct
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
5 / 5
 init
0.00% covered (danger)
0.00%
0 / 1
5.93
66.67% covered (warning)
66.67%
4 / 6
 getDbPrefix
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getTableName
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 setup
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
15 / 15
 getMeta
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 __get
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
7 / 7
 __set
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
9 / 9
 save
100.00% covered (success)
100.00%
1 / 1
9
100.00% covered (success)
100.00%
35 / 35
 delete
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
13 / 13
 selects
0.00% covered (danger)
0.00%
0 / 1
12.12
90.48% covered (success)
90.48%
38 / 42
 selectById
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
6 / 6
 populate
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
9 / 9
<?php
namespace Entity;
abstract class ModelBase
{
    private $fieldsValues = array();
    protected static $dbo = null;
    private $changed = array();
    private static $config = null;
    private $id;
    protected abstract function install();
    public function __construct($id = null)
    {
        self::init();
        $this->id = null;
        if ($id !== null && is_numeric($id))
            $this->selectById($id);
    }
    public static function init($config = null)
    {
        if (self::$dbo !== null)
            return true;
        // @codeCoverageIgnoreStart
        // Load config from written file; this file is created from setup script
        if ($config === null && self::$config === null)
        {
            self::$config = @include("core/config.inc.php");
            if (empty(self::$config))
                return false;
        }
        // @codeCoverageIgnoreEnd
        else
            self::$config = $config;
        self::$dbo = new \PDO(self::$config[0], self::$config[1], self::$config[2]);
        return true;
    }
    public static function getDbPrefix()
    {
        return self::$config[3];
    }
    public function getTableName()
    {
        $className = new \ReflectionClass($this);
        return $this->getDbPrefix().strtolower($className->getShortName());
    }
    public static function setup()
    {
        $tables = array("Admin", "User", "Address", "Cart", "Category", "Product", "CartProduct", "Meta", "Cms", "Config", "Module", "ModuleHook");
        self::init();
        self::$dbo->beginTransaction();
        try
        {
            foreach ($tables as $i)
            {
                $i = "Entity\\".$i;
                $table = new $i();
                if ($table->install() != true)
                    throw new \Exception("{$i}: Cannot table setup failure");
            }
        }
        catch (\Exception $e)
        {
            self::$dbo->rollBack();
            error_log($e->getMessage());
            return false;
        }
        self::$dbo->commit();
        return true;
    }
    public function getMeta($lang=null)
    {
        $fetcher = new \Entity\Meta();
        return $fetcher->query(array("type" => get_class($this)));
    }
    public function __get($key)
    {
        if ($key == "meta")
            return $this->getMeta();
        if ($key == "id")
            return $this->id === null ? null : (int) $this->id;
        if (!isset($this->fieldsValues[$key]))
            return null;
        return $this->fieldsValues[$key];
    }
    public function __set($key, $value)
    {
        if ($value instanceof \DateTime)
            $value = $value->format("Y-m-d");
        $this->fieldsValues[$key] = $value;
        if (is_bool($value))
            $this->changed[$key] = $value ? 1 : 0;
        else if ($value === null)
            $this->changed[$key] = "NULL";
        else
            $this->changed[$key] = self::$dbo->quote($value);
        return $value;
    }
    public function save()
    {
        \Tools\Hooks::trigger("onBeforeEntitySave");
        \Tools\Hooks::trigger("onBeforeEntitySave".$this->getTableName());
        if ($this->id === null)
        {
            if (empty ($this->changed))
            {
                $query = "INSERT INTO `{$this->getTableName()}` () VALUES ()";
                $result = self::$dbo->exec($query);
                if (!$result)
                    throw new \Exception(self::$dbo->errorInfo()[2]);
            }
            else
            {
                $query = "INSERT INTO `{$this->getTableName()}` (`" .implode("`,`", array_keys($this->changed)) . "`) VALUES (" . implode(",", $this->changed) . ")";
                $result = self::$dbo->exec($query);
                if (!$result)
                    throw new \Exception(self::$dbo->errorInfo()[2]);
                $this->changed = array();
            }
            $this->id = self::$dbo->lastInsertId();
        }
        else
        {
            if (!empty($this->changed))
            {
                if ($this->id === false)
                    throw new \Exception("Cannot update private row");
                $query = "UPDATE {$this->getTableName()} SET ";
                $newValues = array();
                foreach ($this->changed as $i => $j)
                    $newValues[] = "`{$i}`=" . $j;
                $query .= implode(",",$newValues)." WHERE id={$this->id}";
                $result = self::$dbo->exec($query);
                if (!$result)
                    throw new \Exception(self::$dbo->errorInfo()[2]);
                $this->changed = array();
            }
        }
        \Tools\Hooks::trigger("onAfterEntitySave");
        \Tools\Hooks::trigger("onAfterEntitySave".$this->getTableName());
    }
    /**
     * Remove entity from database
     * $entity->delete() then $entity->save() should save entity with a new id and the same data
     * @return Boolean true on success
    **/
    public function delete()
    {
        if ($this->id === false)
            return true;
        \Tools\Hooks::trigger("onBeforeEntityDelete");
        \Tools\Hooks::trigger("onBeforeEntityDelete".$this->getTableName());
        $id = (int) $this->id;
        foreach ($this->fieldsValues as $i => $j)
            if (!isset($this->changed[$i]))
                $this->changed[$i] = $j;
        if (self::$dbo->exec("DELETE FROM {$this->getTableName()} WHERE `id`={$id}") === false)
            return false;
        \Tools\Hooks::trigger("onAfterEntityDelete");
        \Tools\Hooks::trigger("onAfterEntityDelete".$this->getTableName());
        return true;
    }
    public function selects($criteria = null, $orderBy = null)
    {
        $query = "SELECT * FROM {$this->getTableName()}";
        if (!empty($criteria))
        {
            $subQuery = array();
            foreach ($criteria as $i => $j)
            {
                if ($j == null)
                    $subQuery[] = "`{$i}` IS NULL";
                else if (is_array($j))
                {
                    $inArray = [];
                    foreach ($j as $k)
                        $inArray[] = self::$dbo->quote($k);
                    $subQuery[] = "`{$i}` IN (".implode(",", $inArray).")";
                }
                else
                    $subQuery[] = "`{$i}`=".self::$dbo->quote($j);
            }
            $query .= " WHERE ".implode(" AND ", $subQuery);
        }
        if (!empty($orderBy))
        {
            $_orderBy = array();
            foreach ($orderBy as $i => $j)
            {
                if (is_numeric($i))
                    $_orderBy[] = "`{$j}` ASC";
                else
                {
                    $orderType = "ASC";
                    if (strtoupper($j == "DESC"))
                        $orderType = "DESC";
                    $_orderBy[] = "`{$i}{$orderType}";
                }
            }
            $query .= " ORDER BY ".implode(",", $_orderBy);
        }
        $result = self::$dbo->query($query, \PDO::FETCH_ASSOC);
        if ($result === false)
            throw new \Exception(self::$dbo->errorInfo()[2]);
        $resultObj = array();
        $className = get_class($this);
        foreach ($result as $i)
        {
            $iObj = new $className();
            $iObj->populate($i);
            $resultObj[] = $iObj;
        }
        return $resultObj;
    }
    public function selectById($id)
    {
        $query = "SELECT * FROM {$this->getTableName()} WHERE id=".(int)$id." LIMIT 1";
        $result = self::$dbo->query($query, \PDO::FETCH_ASSOC);
        if ($result === false || empty($result))
            throw new \Exception("Cannot fetch data: ".self::$dbo->errorInfo()[2]);
        $this->populate($result->fetch());
    }
    private function populate($data)
    {
        $this->id = FALSE;
        if ($data === false)
            throw new \Exception("Cannot load entity: no result found");
        foreach ($data as $i => $j)
            $this->fieldsValues[$i] = $j;
        if (isset($this->fieldsValues["id"]))
            $this->id = (int) $this->fieldsValues["id"];
        $this->changed = array();
    }
}