<commit_before><?php

namespace Phormium;

/**
 * Parent class for database-mapped classes.
 */
abstract class Model
{
    // ******************************************
    // *** Statics                            ***
    // ******************************************

    /**
     * User-populated meta-data. Used to construct a Meta object.
     * @var array
     */
    protected static $_meta;

    /**
     * The Meta object contructed from Model properties and data in <var>$_meta</var>.
     * @var Meta
     */
    protected static $_parsedMeta;

    /**
     * The Query object used to construct an execute SQL queries for this model.
     * @var Query
     */
    protected static $_query;

    /**
     * Returns the Model's Meta object.
     * @return Meta
     */
    public static function getMeta()
    {
        if (!isset(self::$_parsedMeta)) {
            self::$_parsedMeta = self::parseMeta();
        }
        return self::$_parsedMeta;
    }

    public static function getQuery()
    {
        if (!isset(self::$_query)) {
            self::$_query = new Query(self::getMeta());
        }
        return self::$_query;
    }

    /**
     * Constructs a QuerySet for the model.
     */
    public static function objects()
    {
        $meta = self::getMeta();
        $query = self::getQuery();
        return new QuerySet($query, $meta);
    }

    protected static function parseMeta()
    {
        // Late static binding at work
        $class = get_called_class();
        $_meta = static::$_meta;

        if (!is_array($_meta)) {
            throw new \Exception("Invalid $class::\$_meta. Not an array.");
        }

        if (empty($_meta['database'])) {
            throw new \Exception("Invalid $class::\$_meta. Missing 'database'.");
        }

        if (empty($_meta['table'])) {
            throw new \Exception("Invalid $class::\$_meta. Missing 'table'.");
        }

        if (empty($_meta['pk'])) {
            throw new \Exception("Invalid $class::\$_meta. Missing 'pk'.");
        }

        $meta = new Meta();
        $meta->class = $class;
        $meta->database = $_meta['database'];
        $meta->table = $_meta['table'];
        $meta->pk = $_meta['pk'];
        $meta->nonPK = array();
        $meta->columns = array();

        // Fetch class' public properties which correspond to column names
        $rc = new \ReflectionClass($class);
        $props = $rc->getProperties(\ReflectionProperty::IS_PUBLIC);

        foreach ($props as $prop) {
            $name = $prop->name;
            $meta->columns[] = $name;
            if ($name != $meta->pk) {
                $meta->nonPK[] = $name;
            }
        }

        // Check the given primary key exists as column
        if (!in_array($meta->pk, $meta->columns)) {
            throw new \Exception("Invalid $class::\$_meta. Given primary key [{$meta->pk}] is not a column.");
        }

        return $meta;
    }

    // ******************************************
    // *** Dynamics                           ***
    // ******************************************

    public function __construct($data = null)
    {
        if (isset($data)) {

            if (!is_array($data)) {
                throw new \Exception("\$data must be an array");
            }

            foreach ($data as $name => $value) {
                if (property_exists($this, $name)) {
                    $this->$name = $value;
                } else {
                    $class = get_class($this);
                    throw new \Exception("Property [$name] does not exist in class [$class].");
                }
            }
        }
    }

    /**
     * Saves the current Model.
     * If it already exists, performs an UPDATE, otherwise an INSERT.<commit_msg>Added fromJSON and fromArray methods to Model.<commit_after><?php

namespace Phormium;

/**
 * Parent class for database-mapped classes.
 */
abstract class Model
{
    // ******************************************
    // *** Statics                            ***
    // ******************************************

    /**
     * User-populated meta-data. Used to construct a Meta object.
     * @var array
     */
    protected static $_meta;

    /**
     * The Meta object contructed from Model properties and data in <var>$_meta</var>.
     * @var Meta
     */
    protected static $_parsedMeta;

    /**
     * The Query object used to construct an execute SQL queries for this model.
     * @var Query
     */
    protected static $_query;

    /**
     * Returns the Model's Meta object.
     * @return Meta
     */
    public static function getMeta()
    {
        if (!isset(self::$_parsedMeta)) {
            self::$_parsedMeta = self::parseMeta();
        }
        return self::$_parsedMeta;
    }

    public static function getQuery()
    {
        if (!isset(self::$_query)) {
            self::$_query = new Query(self::getMeta());
        }
        return self::$_query;
    }

    /**
     * Constructs a QuerySet for the model.
     */
    public static function objects()
    {
        $meta = self::getMeta();
        $query = self::getQuery();
        return new QuerySet($query, $meta);
    }

    protected static function parseMeta()
    {
        // Late static binding at work
        $class = get_called_class();
        $_meta = static::$_meta;

        if (!is_array($_meta)) {
            throw new \Exception("Invalid $class::\$_meta. Not an array.");
        }

        if (empty($_meta['database'])) {
            throw new \Exception("Invalid $class::\$_meta. Missing 'database'.");
        }

        if (empty($_meta['table'])) {
            throw new \Exception("Invalid $class::\$_meta. Missing 'table'.");
        }

        if (empty($_meta['pk'])) {
            throw new \Exception("Invalid $class::\$_meta. Missing 'pk'.");
        }

        $meta = new Meta();
        $meta->class = $class;
        $meta->database = $_meta['database'];
        $meta->table = $_meta['table'];
        $meta->pk = $_meta['pk'];
        $meta->nonPK = array();
        $meta->columns = array();

        // Fetch class' public properties which correspond to column names
        $rc = new \ReflectionClass($class);
        $props = $rc->getProperties(\ReflectionProperty::IS_PUBLIC);

        foreach ($props as $prop) {
            $name = $prop->name;
            $meta->columns[] = $name;
            if ($name != $meta->pk) {
                $meta->nonPK[] = $name;
            }
        }

        // Check the given primary key exists as column
        if (!in_array($meta->pk, $meta->columns)) {
            throw new \Exception("Invalid $class::\$_meta. Given primary key [{$meta->pk}] is not a column.");
        }

        return $meta;
    }

    /** Creates a Model instance from data in the given array. */
    public static function fromArray($array)
    {
        $class = get_called_class();
        $instance = new $class();

        if (!is_array($array)) {
            throw new \Exception("Given argument is not an array.");
        }

        foreach ($array as $name => $value) {
            if (property_exists($instance, $name)) {
                $instance->{$name} = $value;
            } else {
                throw new \Exception("Property [$name] does not exist in class [$class].");
            }
        }

        return $instance;
    }

    /** Creates a Model instance from data in the given array. */
    public static function fromJSON($json)
    {
        $array = json_decode($json);

        $error = json_last_error();
        if ($error !== JSON_ERROR_NONE) {
            throw new \Exception("Invalid JSON string. Error code [$error].");
        }

        return self::fromArray($array);
    }

    // ******************************************
    // *** Dynamics                           ***
    // ******************************************

    /**
     * Saves the current Model.
     * If it already exists, performs an UPDATE, otherwise an INSERT.
{'fraction_non_alphanumeric': 0.1812726590823853, 'fraction_numerical': 0.0, 'mean_word_length': 1.8399006034788783, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '762168', 'n_tokens_mistral': 2167, 'n_tokens_neox': 2085, 'n_words': 592}