Пример #1
0
 /**
  * Add a item to the queue for persitance on flush
  *
  * @param $trancation
  * @param $onFailure
  *
  * @return bool
  */
 public function flush($transaction = null, $onFailure = self::FLUSH_ABORT, $throwExceptions = true)
 {
     if (is_null($transaction)) {
         $transaction = self::TRANSACTIONS_ALL;
     }
     if (is_null($onFailure)) {
         $onFailure = self::FLUSH_ABORT;
     }
     $response = new Response();
     $exceptions = [];
     $haveAnyTransactionsFailed = false;
     // simulate
     $simulate = $this->debug & self::DEBUG_SIMULATE;
     // profiler
     $profiler = new Profiler("Record manager");
     $profiler->log();
     // debugging query show
     $debugQuery = null;
     if ($this->debug & self::DEBUG_SHOW_QUERY) {
         $debugQuery = function ($e, $event, $data) {
             echo $data . "\n";
         };
         $this->db->debug->on(Debug::INFO, $debugQuery);
     }
     // trap all throw exceptions so that we can properly unattach the $db->debug->on( Pg::QueryPassed $listener )
     try {
         // iterate selected transactions
         foreach ($this->getQueue($transaction, true, true) as $transaction => $queue) {
             unset($this->queue[$transaction]);
             $taskResponse = null;
             $hasTransactionFailed = false;
             $beginTransaction = new Query("BEGIN TRANSACTION READ WRITE; /* %transaction:% */");
             $beginTransaction->transaction = $transaction;
             $this->db->query($beginTransaction);
             $this->eventEmitter->emit(EventEmitter::TRANSACTION_START, $this, $transaction, $queue);
             // loop over our tasks
             foreach ($queue as $task) {
                 // are we continuing to process?
                 if ($hasTransactionFailed or $haveAnyTransactionsFailed && $onFailure === self::FLUSH_ABORT) {
                     $taskResponse = Response::ABORTED;
                 } else {
                     try {
                         $taskResponse = $task->execute($this->db, $simulate) ? Response::SUCCESS : Response::FAILED;
                     } catch (\Exception $e) {
                         // It'd be nice if we could just test for Query exceptions here but unfortunately PHPUnit dicks pretty hard with exception types.
                         // @Mr Beale. I realise this violates the "only handle exceptions that you understand" rule but I can't find a way round this. Pete
                         $taskResponse = $e;
                         $exceptions[] = $e;
                     }
                 }
                 // transaction success
                 if ($taskResponse !== Response::SUCCESS) {
                     $hasTransactionFailed = true;
                     $haveAnyTransactionsFailed = true;
                 }
                 $response->add($transaction, $task, $taskResponse);
             }
             // end or rollback transaction
             $endTransaction = new Query("%commitOrRollback:% TRANSACTION; /* %transaction:% */");
             $endTransaction->commitOrRollback = new Raw($hasTransactionFailed ? 'ROLLBACK' : 'COMMIT');
             $endTransaction->transaction = $transaction;
             $this->db->query($endTransaction);
             // response rollback
             if ($hasTransactionFailed) {
                 $response->rollback($transaction);
             }
             $profiler->log($transaction);
         }
         // if we've gathered any exceptions throw them here
         if ($throwExceptions and $exceptions) {
             throw $exceptions[0];
         }
         $response->profilerAssign($profiler);
     } catch (\Exception $e) {
         $this->db->debug->removeListener(Pg::QUERY_PARSED, $debugQuery);
         throw $e;
     }
     return $response;
 }
Пример #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 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();
 }
Пример #3
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();
    }
Пример #4
0
 /**
  * {@inheritDoc}
  * @param string $qty
  * @param array $filterComponents
  * @param int Bitmask fo class constants
  * @return Bond\Container
  */
 public function findByFilterComponents($qty, array $filterComponents, $source = null)
 {
     $source = $this->findByFilterComponentsSourceSetup($source);
     $output = $this->makeNewContainer();
     $profiler = new Profiler(__FUNCTION__);
     $profiler->log("setup");
     if ($source & self::UNPERSISTED) {
         $output->add($this->findByFilterComponentsMultiton($filterComponents, $source));
     }
     $profiler->log("multiton");
     if ($source & self::PERSISTED) {
         $cannotMatch = function ($entity) {
             return $entity instanceof Base ? $entity->isNew() : false;
         };
         // If all of the filter components can't match - that is return true - there isn't any point in going to the db
         $checkDatabase = !\Bond\array_check(function ($filterComponent) use($cannotMatch) {
             return $filterComponent->getCannotMatch($cannotMatch);
         }, $filterComponents, false);
         if ($checkDatabase) {
             $output->add($this->findByFilterComponentsDatabase($filterComponents, $source));
         }
     }
     $profiler->log("database");
     return $this->findByFilterComponentsFormatReturnValue($qty, $output);
 }