/** * @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; }
/** * 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(); }
/** * 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; }
/** * 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(); }
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; }