* @category class * @package core * @subpackage version * @copyright 2005-2017 Titan Framework * @license http://www.titanframework.com/license/ BSD License (3 Clause) * @see VersionForm, VersionView, VersionSearch */ class Version { static private $version = FALSE; private $array = array (); private final function __construct () { $fromXml = Instance::singleton ()->getVersionControl (); $this->array = array ('schema' => 'public'); foreach ($this->array as $key => $trash) if (array_key_exists ($key, $fromXml)) $this->array [$key] = trim ($fromXml [$key]); } static public function singleton () { if (self::$version !== FALSE) return self::$version; $class = __CLASS__; self::$version = new $class (); return self::$version; } public function getSchema () { return $this->array ['schema']; } public function vcTable ($table, $schema = FALSE) { $array = explode ('.', $table); $db = Database::singleton (); if (sizeof ($array) == 2) { $schema = $schema === FALSE ? $array [0] : $schema; $table = $array [1]; } elseif ($schema === FALSE) $schema = $db->getSchema (); return $this->getSchema () .'._tvc_'. $schema .'_'. $table; } public function hasControl ($table, $schema = FALSE) { return tableExists ($this->vcTable ($table, $schema)); } public function make ($table, $primary, $schema = FALSE) { $array = explode ('.', $table); $db = Database::singleton (); if (sizeof ($array) == 2) { $schema = !$schema ? $array [0] : $schema; $table = $array [1]; } elseif (!$schema) $schema = $db->getSchema (); if ($this->hasControl ($table, $schema)) throw new Exception ('A tabela indicada já esta sob controle de versões!'); $sql = "SELECT attnum AS number, attname AS name, typname AS type, atttypmod-4 AS size, attnotnull AS not_null, atthasdef AS has_default, adsrc AS value_default FROM ( ( SELECT attnum, attname, typname, atttypmod, attnotnull, atthasdef, adsrc FROM pg_attribute, pg_class, pg_type, pg_attrdef WHERE pg_class.oid = attrelid AND pg_type.oid = atttypid AND attnum > 0 AND pg_class.oid = adrelid AND adnum = attnum AND atthasdef = 't' AND lower(relname) = '". $table ."' ) UNION ( SELECT attnum, attname, typname, atttypmod, attnotnull, atthasdef, NULL AS adsrc FROM pg_attribute, pg_class, pg_type WHERE pg_class.oid = attrelid AND pg_type.oid = atttypid AND attnum > 0 AND atthasdef = 'f' AND lower(relname) = '". $table ."' ) ) sq ORDER BY sq.attnum"; $sth = $db->prepare ($sql); $sth->execute (); $fields = array (); while ($field = $sth->fetch (PDO::FETCH_OBJ)) $fields [] = '"'. $field->name .'" '. (trim ($field->type) == 'bpchar' ? 'CHAR' : strtoupper ($field->type)) . ((int) $field->size > 0 ? '('. $field->size .')' : '') . ((int) $field->not_null ? ' NOT NULL' : ''); $fields [] = '"_tvc_date" TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL'; $fields [] = '"_tvc_version" INTEGER NOT NULL'; $fields [] = '"_tvc_action" CHAR(1) NOT NULL'; $commands = array (); $commands [] = 'CREATE TABLE "'. $this->getSchema () .'"."_tvc_'. $schema .'_'. $table .'" ('. implode (', ', $fields) .') WITHOUT OIDS;'; $commands [] = 'ALTER TABLE "'. $this->getSchema () .'"."_tvc_'. $schema .'_'. $table .'" ADD CONSTRAINT "_tvc_'. $schema .'_'. $table .'_pkey" PRIMARY KEY ("'. $primary .'", "_tvc_version");'; ob_start (); ?> CREATE OR REPLACE FUNCTION ""."_tvc__" () RETURNS trigger AS $body$ DECLARE version integer; BEGIN IF (TG_OP = 'UPDATE') THEN SELECT INTO version max(_tvc_version) FROM "getSchema () ?>"."_tvc__" WHERE = OLD.; IF (version IS NULL) THEN version = '1'; ELSE version = version + 1; END IF; INSERT INTO "getSchema () ?>"."_tvc__" SELECT NEW.*, CURRENT_TIMESTAMP, version, 'U'; RETURN NEW; ELSIF (TG_OP = 'INSERT') THEN INSERT INTO "getSchema () ?>"."_tvc__" SELECT NEW.*, CURRENT_TIMESTAMP, '1', 'I'; RETURN NEW; ELSIF (TG_OP = 'DELETE') THEN SELECT INTO version max(_tvc_version) FROM "getSchema () ?>"."_tvc__" WHERE = OLD.; IF (version IS NULL) THEN version = '1'; ELSE version = version + 1; END IF; INSERT INTO "getSchema () ?>"."_tvc__" SELECT OLD.*, CURRENT_TIMESTAMP, version, 'D'; RETURN OLD; END IF; END $body$ LANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY INVOKER; beginTransaction (); foreach ($commands as $trash => $command) $db->exec ($command); $db->commit (); } catch (PDOException $e) { $db->rollBack (); throw new Exception ($e->getMessage () .' ['. $command .']'); } return TRUE; } }