示例#1
0
    /**
     * @inheritDoc
     */
    public function parse(QuoteInterface $quoting)
    {
        // get the columns of the inherited table
        $schema = $quoting->quoteIdent($this->relationLog->get('schema'));
        $name = $this->relationLog->get('name');
        $parent = $this->relationLog->get('parent');
        $primaryKeys = $this->relationOriginal->getPrimaryKeys();
        // get attribute definition
        $attrDefinition = function ($attribute) use($quoting) {
            if (!$attribute->getType()) {
                d_pr($attribute);
            }
            return sprintf('%s %s', $quoting->quoteIdent($attribute->get('name')), $quoting->quoteIdent($attribute->getType()->get('fullyQualifiedName')));
        };
        $getNameQuoted = function ($attribute) use($quoting) {
            return $quoting->quoteIdent($attribute->get('name'));
        };
        $output = sprintf(<<<SQL
CREATE TYPE {$schema}."{$name}_history" AS (
    key key,
    data %s,
    %s
);

CREATE OR REPLACE FUNCTION {$schema}."{$name}"( "key" )
RETURNS SETOF {$schema}."{$name}_history" AS \$\$
DECLARE%s
BEGIN%s
    RETURN QUERY
    SELECT
        %s::key AS key,
        ROW(%s)::%s AS data,
        %s
    FROM
        {$schema}."{$name}"
    WHERE
        %s
    ;
END;
\$\$ LANGUAGE plpgsql IMMUTABLE;

SQL
, $quoting->quoteIdent($this->relationOriginal->get('fullyQualifiedName')), $parent->getAttributes()->implode(', ', $attrDefinition), $this->getDeclareBlock($primaryKeys), $primaryKeys->count() === 10 ? '' : "\n    key := string_to_array( \$1::text, '|' );", $this->relationOriginal->getKeySql($quoting), $this->relationOriginal->getAttributes()->implode(', ', $getNameQuoted), $quoting->quoteIdent($this->relationOriginal->get('fullyQualifiedName')), $parent->getAttributes()->implode(', ', $getNameQuoted), $this->getWhereBlock($quoting, $primaryKeys));
        return $output;
    }
示例#2
0
    /**
     * See, http://www.postgresql.org/docs/8.4/interactive/catalog-pg-constraint.html
     * @return bool. Populate the static variables $this->references $this->isReferencedBy
     */
    private function loadReferences()
    {
        // References defined in pg_catalog
        $sql = new Raw('SELECT * FROM dev."vAttributeReferences" WHERE "isInherited" = false');
        $sql = new Raw(<<<SQL
-- Based on. http://code.google.com/p/pgutils/ but very heavily modified
-- Potentially inheritance aware/compensating. Be careful. Use the unit tests.
WITH "vRelationDescendants" as (
    SELECT
        c.oid,
        c.relname,
        (
            WITH RECURSIVE
            q( oid ) AS
            (
                SELECT
                    crd.oid
                FROM
                    pg_class crd
                WHERE
                    crd.oid = c.oid

                UNION ALL

                SELECT i.inhrelid FROM q INNER JOIN pg_inherits i ON q.oid = i.inhparent
            )
            SELECT oid FROM q WHERE oid = c.oid
        ) as childoid
    FROM
        pg_class c
    INNER JOIN
        pg_namespace n ON n.oid = c.relnamespace
    ORDER BY
        n.nspname, c.relname
), "vAttributeReferences"  as (
    SELECT
        fkr.oid <> fkrd.oid AS "isInheritedSource",
        pkr.oid <> pkrd.oid AS "isInheritedTarget",
        ( fkr.oid <> fkrd.oid OR pkr.oid <> pkrd.oid ) as "isInherited",

        fkn.nspname AS fk_namespace,
        fkr.relname AS fk_relation,
        fkr.oid AS fk_oid,
        fka.attname AS fk_column,
        fka.attnum as "fk_attnum",

        -- initByData
        fkr.oid::text || '.' || fka.attnum::text AS fk_key,

        (
            EXISTS (
                SELECT
                    pg_index.indexrelid,
                    pg_index.indrelid,
                    pg_index.indkey,
                    pg_index.indclass,
                    pg_index.indnatts,
                    pg_index.indisunique,
                    pg_index.indisprimary,
                    pg_index.indisclustered,
                    pg_index.indexprs,
                    pg_index.indpred
                FROM
                    pg_index
                WHERE
                    pg_index.indrelid = fkr.oid AND pg_index.indkey[0] = fka.attnum
            )
        ) AS fk_indexed,
        pkn.nspname AS pk_namespace,
        pkr.relname AS pk_relation,
        pkr.oid AS pk_oid,
        pka.attname AS pk_column,
        pka.attnum as "pk_attnum",

        -- initByData
        pkr.oid::text || '.' || pka.attnum::text AS pk_key,

        (
            EXISTS (
                SELECT
                    pg_index.indexrelid,
                    pg_index.indrelid,
                    pg_index.indkey,
                    pg_index.indclass,
                    pg_index.indnatts,
                    pg_index.indisunique,
                    pg_index.indisprimary,
                    pg_index.indisclustered,
                    pg_index.indexprs,
                    pg_index.indpred
                FROM
                    pg_index
                WHERE
                    pg_index.indrelid = pkr.oid AND
                    pg_index.indkey[0] = pka.attnum
            )
        ) AS pk_indexed,
        c.confupdtype::text || c.confdeltype::text AS ud,
        cn.nspname AS c_namespace,
        c.conname AS c_name
    FROM (
        (
            (
                (
                    (
                        (
                            (
                                pg_constraint c
                                    JOIN
                                pg_namespace cn ON cn.oid = c.connamespace
                            )
                            INNER JOIN
                                "vRelationDescendants" as fkrd ON c.conrelid = fkrd.oid
                            INNER JOIN
                                pg_class fkr ON fkr.oid = fkrd.childoid
                        )
                        JOIN
                            pg_namespace fkn ON fkn.oid = fkr.relnamespace
                    )
                    JOIN
                        pg_attribute fka ON fka.attrelid = c.conrelid AND fka.attnum = ANY (c.conkey)
                )
                INNER JOIN
                    "vRelationDescendants" as pkrd ON c.confrelid = pkrd.oid
                INNER JOIN
                    pg_class pkr ON pkr.oid = pkrd.childoid
            )
            JOIN
                pg_namespace pkn ON pkn.oid = pkr.relnamespace
        )
        JOIN
            pg_attribute pka ON pka.attrelid = c.confrelid AND pka.attnum = ANY (c.confkey)
    )
    WHERE
        c.contype = 'f'::"char" AND
        fkn.nspname = ANY( current_schemas(false) ) AND
        pkn.nspname = ANY( current_schemas(false) )
)
SELECT * FROM "vAttributeReferences" WHERE "isInherited" = false
SQL
);
        $relationships = $this->db->query($sql);
        foreach ($relationships as $relationship) {
            $fk = $this->pgAttributes->findOneByKey($relationship['fk_key']);
            $pk = $this->pgAttributes->findOneByKey($relationship['pk_key']);
            if (!$fk or !$pk) {
                d_pr($relationship);
                die;
            }
            $fk->addReference($pk);
        }
        // look for normality defined relationships
        $profiler = new Profiler(__FUNCTION__);
        $profiler->log();
        foreach ($this->pgClasses as $relation) {
            $tags = $relation->getTags();
            if (isset($tags['references'])) {
                foreach ($tags['references'] as $reference) {
                    $reference = array_map('trim', explode('=', $reference));
                    $reference[1] = explode('.', $reference[1]);
                    $fk = $relation->getAttributeByName($reference[0]);
                    // referencing
                    $pkTable = $this->pgClasses->findOneByName($reference[1][0]);
                    $pk = $pkTable->getAttributeByName($reference[1][1]);
                    $fk->addReference($pk);
                }
            }
        }
        //        echo $profiler->log()->output();
    }
示例#3
0
 /**
  * Is this Entity 'new'? A new Entity exists in the $instancesUpersisted array
  * @param Set a new isNew() state
  * @return bool
  */
 public function isNew(Base $entity, $state = null)
 {
     if (is_bool($state)) {
         // mark entity as new
         if ($state) {
             // remove from instances persisted cache if exists there.
             // This could also be done by self::garbageCollect but this is a lighter and doesn't need to check all cases
             if (false !== ($_key = array_search($entity, $this->instancesPersisted, true))) {
                 unset($this->instancesPersisted[$_key]);
             }
             if (false !== array_search($entity, $this->instancesUnpersisted, true)) {
                 d_pr(sane_debug_backtrace());
                 die;
             }
             $this->instancesUnpersisted[] = $entity;
             return true;
             // mark entity as persisted
         } else {
             $key = $entity->keyGet($entity);
             if (is_null($key)) {
                 $this->detach($entity);
                 return false;
             }
             // remove from instances unpersisted cache if exists there.
             // This could also be done by self::garbageCollect but this is a lighter and doesn't need to check all cases
             if (false !== ($_key = array_search($entity, $this->instancesUnpersisted, true))) {
                 unset($this->instancesUnpersisted[$_key]);
             }
             if (isset($this->instancesPersisted[$key]) and $this->instancesPersisted[$key] !== $entity) {
                 throw new MultitonKeyCollisionException("Unable to set new. A {$this->entity} with key `{$key}` already exists in static::\$instancesPersisted");
             }
             $this->instancesPersisted[$key] = $entity;
             return false;
         }
     }
     $isUnpersisted = false !== array_search($entity, $this->instancesUnpersisted, true);
     $isCached = $this->isCached($entity);
     if ($isUnpersisted and $isCached) {
         // debuggin' shit
         // d_pr( "Entity " . __CLASS__ . "has entity's both persisted and unpersisted." );
         // d_vd( $entity );
         // die();
         throw new \LogicException("Something is very wrong. This entity is in both the persisted and unpersisted respository caches. This isn't right.");
     } elseif (!$isUnpersisted and !$isCached) {
         // Pete. This original behaviour caused problems with double attachments of entities when $entity->isNew() was called
         // before a entity was attached to the multiton array. I think I'm going to depreciate this unexpected, magical behaviour.
         // I don't think this is exception worthy. Instead this deserves a new, third, state -> null to singify not cached. Don't know.
         return null;
         // original behaviour below
         // $this->attach( $entity, $restingPlace );
         //
         // switch( $restingPlace ) {
         //    case self::PERSISTED:
         //        return false;
         //    case self::UNPERSISTED:
         //        return true;
         //    default:
         //        throw new \RuntimeException("Bad response from repository->attach()");
         // }
         // not sure if this should be a exception
         throw new EntityStateUndeterminableException("This entity didn't come from the repository. Its isNew() state cannot be determined.");
     }
     return $isUnpersisted;
 }
示例#4
0
 /**
  * See, http://www.postgresql.org/docs/8.4/interactive/catalog-pg-constraint.html
  * @return bool. Populate the static variables $this->references $this->isReferencedBy
  */
 private function preloadReferences()
 {
     // References defined in pg_catalog
     $sql = 'SELECT * FROM dev."vAttributeReferences" WHERE "isInherited" = false';
     $relationships = $this->db->query(new Query($sql));
     foreach ($relationships->fetch() as $relationship) {
         $fk = $this->instancesPersisted[$relationship['fk_key']];
         $pk = $this->instancesPersisted[$relationship['pk_key']];
         if (!$fk or !$pk) {
             d_pr($relationship);
             die;
         }
         // slower alternatives. They all do the same thing
         // $fk = $this->persistedGet()->findOneByKey( $relationship['fk_key'] );
         // $pk = $this->persistedGet()->findOneByKey( $relationship['pk_key'] );
         // $fk = $this->find( $relationship['fk_key'] );
         // $pk = $this->find( $relationship['pk_key'] );
         $fk->addReference($pk);
     }
     // look for normality defined relationships
     $profiler = new Profiler(__FUNCTION__);
     $profiler->log();
     foreach (EntityRelation::r()->findAll() as $relation) {
         $tags = $relation->getNormalityTags();
         if (isset($tags['references'])) {
             foreach ($tags['references'] as $reference) {
                 $reference = array_map('trim', explode('=', $reference));
                 $fk = $this->findByRelation($relation)->findOneByName($reference[0]);
                 $pk = $this->findByIdentifier($reference[1]);
                 // go the database to get child records, using the Relation repo methods causes a infinite preload loop
                 $query = new Query("SELECT oid::text || '.' || %attnum:int%::text FROM dev.relationDescendants( %oid:int%::oid ) as _ ( oid );", array('attnum' => $pk->get('attnum'), 'oid' => $pk->getRelation()->get('oid')));
                 foreach ($this->db->query($query)->fetch() as $pk_key) {
                     $fk->addReference($this->find($pk_key));
                 }
             }
         }
     }
     //        echo $profiler->log()->output();
 }
示例#5
0
 public function emit($eventName)
 {
     $args = func_get_args();
     array_shift($args);
     $event = new Event($eventName, $args, $this);
     if (isset($this->listeners[$eventName])) {
         foreach ($this->listeners[$eventName] as $listener) {
             $event->dispatch($listener);
         }
     }
     if (isset($this->listenersOnce[$eventName])) {
         foreach ($this->listenersOnce[$eventName] as $key => $listener) {
             $event->dispatch($listener);
             unset($this->listenersOnce[$eventName][$key]);
         }
     }
     // iterate over our listenercallbacks and see if we've got anything to test against
     if ($this->listenersCallback) {
         // it's a mild hack but use 'Event' to manage the dispatch of new callback this gives a whole load of syntatic sugar for free and presents a common interface
         foreach ($this->listenersCallback as $value) {
             if ($event->dispatch($value[0], 0)) {
                 $event->dispatch($value[1]);
             }
         }
     }
     if ($this->eventDebug) {
         d_pr(sprintf("%s %s %s", $event->name, $event->dispatchCount, json_encode($event->dispatchArgs)));
     }
     $this->tick();
     return $event;
 }