public function find($templateName, $currentSkin = null) { assert('\\de\\toxa\\txf\\txf::current()'); $folders = array(TXF_APPLICATION_PATH . '/skins/', dirname(dirname(__FILE__)) . '/skins/' . TXF_APPLICATION, dirname(dirname(__FILE__)) . '/skins/default'); $skins = array('default'); if ($currentSkin !== null) { $currentSkin = data::isKeyword($currentSkin); } if ($currentSkin) { if ($currentSkin != 'default') { array_unshift($skins, $currentSkin); } } foreach ($folders as $folder) { foreach ($skins as $skin) { $pathname = path::glue($folder, $skin, $templateName . '.phpt'); if (is_file($pathname)) { return $pathname; } } } throw new \UnexpectedValueException(sprintf('template not found: %s (%s)', $templateName, $currentSkin)); }
/** * Retrieves items matching selector from datasource. * * @param connection|null $source data source to fetch items from, * null to use default of model mentioned in selector * @param array $selector selector retrieved from _getSelectorOfAvailable() * or _getSelectorOfExisting() * @return array */ protected function _select(connection $source = null, $selector) { // get list of items /** @var model_relation_model $model */ $model = $selector['model']; $items = $model->listItems($source, $selector['properties'], $selector['filter']['properties'], $selector['filter']['values']); // ensure additionally fetched properties are suitable for instantly // binding (due to having proper sorting order) foreach ($items as $id => $item) { $items[$id]['data'] = data::rearrangeArray($item['data'], $selector['properties']); } return $items; }
/** * Searches node in relation matching model and/or alias/name of model * either at ends of relation or on all of them. * * @param model|\ReflectionClass|null $model model of node to look for * @param string|null $nameOrAlias name of model or alias of node to look for * @param bool $endpointsOnly false to search whole relation instead * @param array|mixed $value first value to bind, or all values as array * @return $this */ public function bindOnMatching($model = null, $nameOrAlias = null, $endpointsOnly = true, $value) { if (!$model && !$nameOrAlias) { throw new \InvalidArgumentException('select either associated model or its name/alias to search for matching node in relation'); } return $this->_bindOnModel($model, $nameOrAlias, !!$endpointsOnly, data::normalizeVariadicArguments(func_get_args(), 3)); }
protected function configure($configuration) { $this->setup = new set($configuration); $this->server = new LDAP\server($this->setup->read('server', 'ldapi:///'), $this->setup->basedn); if (data::autoType($this->setup->tls, 'boolean')) { $this->server->startTls(); } if ($this->setup->binddn) { if (!$this->bindAs($this->setup->binddn, $this->setup->bindpw)) { throw new LDAP\protocol_exception('failed to bind', $this->server); } } return true; }
/** * Validates and normalizes provided set of properties. * * Normalizations includes rearranging elements of provided array according * to sequence of property names declared in current reference. Validation * includes checking for provided and resulting set of values is matching * each other as well as matching number of properties in current reference. * * @throws \InvalidArgumentException on mismatching size of provided values * @param array $identifyingProperties set of unqualified property names * mapping into values to be used on binding reference afterwards * @return array properly sorted set of names mapping into values */ public function normalizeValuesForBinding($identifyingProperties) { $bindingProperties = $this->getReferencingPropertyNames(false, null); $normalized = data::rearrangeArray($identifyingProperties, $bindingProperties); if (count($normalized) !== count($identifyingProperties) || count($normalized) !== count($bindingProperties)) { throw new \InvalidArgumentException('mismatching size of identifying properties'); } return $normalized; }
/** * * @param string $dsn name of datasource to connect to * @param string $username optional username for authenticating * @param string $password optional password to use for authentication */ public function __construct($dsn = null, $username = null, $password = null) { // got DSN in parameters? if ($dsn === null) { // no -> use simple definition in runtime configuration /** * @note This case isn't preferred one. * @see datasource::selectConfigured() */ $setup = config::get('datasource'); $dsn = data::qualifyString(@$setup['dsn']); $username = @$setup['user']; $password = @$setup['password']; } // store normalized name of driver used to connect with datasource $this->driver = strtolower(trim(strtok($dsn, ':'))); // establish connection to datasource $this->link = new \PDO($dsn, $username, $password); /** * ensure connection is using utf8 encoding unless disabled in configuration */ if (config::get('datasource.set-utf8-encoding', true)) { switch ($this->driver) { case 'mysql': $this->link->exec('SET NAMES utf8'); break; case 'mssql': $this->link->setAttribute(PDO::SQLSRV_ENCODING_UTF8, 1); break; } } $this->transaction = new transaction($this, function (connection $c) { txf\log::debug("starting transaction"); return $c->link->beginTransaction(); }, function (connection $c) { txf\log::debug("committing transaction"); return $c->link->commit(); }, function (connection $c) { txf\log::debug("reverting transaction"); return $c->link->rollBack(); }); }
public function getCode() { $code = markup::block($this->processInput()->code, 'view'); if (count($this->panel)) { if (is_array($this->panelSorting)) { data::rearrangeArray($this->panel, $this->panelSorting, true); } $code .= markup::block(implode("\n", $this->panel), 'panel'); } return $code; }
/** * Retrieves relation according to declaration selected by given name. * * Relations may be declared in static property $relations of a model. * * @example - have user relate to address via immediately related person (user.person_id => person.id - person.address_id => contact.id) user::$relations = array( 'contact_address' => array( // <- declaring name of relation 'referencing' => array( // <- declaring user referring to some 'model' => 'person', // <- ... person. ... 'with' => 'person_id', // <- declaring user.person_id to contain foreign key of ... 'on' => 'id', // <- ... person.id thus: user.person_id => person.id 'referencing' => array( // <- declaring person is then referring to another model ... 'model' => 'address', // <- ... address ... 'alias' => 'contact', // <- ... calling it "contact" here ... 'with' => 'address_id', // <- ... with person.address_id containing foreign key of ... 'on' => 'id', // <- ... contact.id thus: person.address_id => contact.id ) ) ), ); - same relation declared in reverse direction (contact.id <= person.address_id - person.id <= user.person_id) address::$relations = array( 'user' => array( // <- declaring name of relation 'alias' => 'contact', // <- declaring alias of initial node in relation being contact 'referencedBy' => array( // <- declaring address (called contact) referred to by some 'model' => 'person', // <- ... person. ... 'with' => 'address_id', // <- ... using its property address_id to contain foreign key of ... 'on' => 'id', // <- ... contact.id thus: contact.id <= person.address_id 'referencedBy' => array( // <- declaring person is then referred to by another model ... 'model' => 'user', // <- ... user ... 'with' => 'person_id', // <- ... using its property person_id to contain foreign key of ... 'on' => 'id', // <- ... person.id thus: person.id <= user.person_id ) ) ), ); - example of an m:n-relation (customer.id <= ordered.customer_id - ordered.product_id => goods.id) customer::$relations = array( 'ordered_goods' => array( 'referencedBy' => array( 'model' => 'ordered', 'with' => 'customer_id', 'on' => 'id', 'referencing' => array( 'model' => 'product', 'alias' => 'goods', 'with' => 'product_id', 'on' => 'id', ) ) ), ); - same m:n-relation with multi-dimensional reference (customer.id <= ordered.customer_id - [ordered.type,ordered.product_id] => [goods.type,goods.id]) customer::$relations = array( 'ordered_goods' => array( 'referencedBy' => array( 'model' => 'ordered', 'with' => 'customer_id', 'on' => 'id', 'referencing' => array( 'model' => 'product', 'alias' => 'goods', 'with' => array( 'type', 'product_id' ), 'on' => array( 'type', 'id' ), ) ) ), ); - again, same m:n-relation with multi-dimensional reference, this time relying on implicitly inserted virtual model (named explicitly) (customer.id <= ordered.customer_id - [ordered.type,ordered.product_id] => [goods.type,goods.id]) customer::$relations = array( 'ordered_goods' => array( 'referencedBy' => array( 'dataset' => 'ordered', 'with' => 'customer_id', 'on' => 'id', 'referencing' => array( 'model' => 'product', 'alias' => 'goods', 'with' => array( 'type', 'product_id' ), 'on' => array( 'type', 'id' ), ) ) ), ); - again, same m:n-relation with multi-dimensional reference, this time relying on implicitly inserted virtual model (not named explicitly) (customer.id <= customer_goods.customer_id - [customer_product.type,customer_product.product_id] => [goods.type,goods.id]) The inner set's name is derived by combining names of neighbouring sets. customer::$relations = array( 'ordered_goods' => array( 'referencedBy' => array( 'with' => 'customer_id', 'on' => 'id', 'referencing' => array( 'model' => 'product', 'alias' => 'goods', 'with' => array( 'type', 'product_id' ), 'on' => array( 'type', 'id' ), ) ) ), ); - finally, same m:n-relation with multi-dimensional reference, this time relying on implicitly inserted virtual model (not named explicitly) and deriving property names from referenced properties' names (customer.id <= customer_product.customer_id - [customer_product.product_type,customer_product.product_id] => [goods.type,goods.id]) The inner set's name is derived by combining names of neighbouring sets. customer::$relations = array( 'ordered_goods' => array( 'referencedBy' => array( 'on' => 'id', 'referencing' => array( 'model' => 'product', 'alias' => 'goods', 'on' => array( 'type', 'id' ), ) ) ), ); * * @param string $name name of model's relation to retrieve * @param model $bindOnInstance instance of current model to bind relation on * @return model_relation */ public static function relation($name, model $bindOnInstance = null) { $name = data::isKeyword($name); if (!$name) { throw new \InvalidArgumentException('invalid relation name'); } $fullName = static::getReflection()->getName() . '::' . $name; if (array_key_exists($fullName, self::$_relationCache)) { // read existing relation from runtime cache $relation = self::$_relationCache[$fullName]; } else { if (!array_key_exists($name, static::$relations)) { throw new \InvalidArgumentException(sprintf('no such relation: %s', $name)); } try { $relation = static::_compileRelation(null, static::$relations[$name]); if (!$relation->isComplete()) { throw new \InvalidArgumentException('incomplete relation definition: %s'); } $relation->setName($name); // write this relation (unbound) into runtime cache self::$_relationCache[$fullName] = $relation; } catch (\InvalidArgumentException $e) { throw new \InvalidArgumentException(sprintf('%s: %s', $e->getMessage(), $name), $e->getCode(), $e); } } // clone cached relation $relation = clone $relation; // bind on provided instance if that is a subclass of current one if ($bindOnInstance) { $expectedClass = new \ReflectionClass(get_called_class()); $givenClass = $bindOnInstance->getReflection(); if ($givenClass->getName() !== $expectedClass->getName() && !$givenClass->isSubclassOf($expectedClass)) { throw new \InvalidArgumentException('provided instance is not compatible'); } $relation->bindNodeOnItem(0, $bindOnInstance); } return $relation; }
/** * Maps viewports onto regions of page. * * This mapping is supported to improve content/view abstraction by enabling * content of viewports being assembled into code of page's regions in a * configurable way ... * * @param array $viewports content of viewports * @return array content of regions */ protected function collectRegions($viewports) { $configs = array(config::getList('view.region'), array(array('name' => 'main', 'viewport' => array('flash', 'title', 'error', 'main')), array('name' => 'head', 'viewport' => array('header')), array('name' => 'foot', 'viewport' => array('footer', 'debug')), array('name' => 'left', 'viewport' => array('navigation')), array('name' => 'right', 'viewport' => array('aside')))); $regions = array(); foreach ($configs as $config) { if (is_array($config)) { foreach ($config as $region) { // get name of region to customize $name = trim(@$region['name']); if ($name === '') { log::debug('ignoring nameless region configuration'); continue; } if (!array_key_exists($name, $regions)) { // region haven't been collected before ... if (array_key_exists('code', $region)) { // there is a line of code containing markers selecting viewports to collect their content in current region // e.g. "{{title}}<some-literal-content-to-insert/>{{main}}" $regions[$name] = data::qualifyString($region['code'], $viewports); } else { if (is_array(@$region['viewport'])) { // collect set of viewports named in configuration foreach (@$region['viewport'] as $viewportName) { $regions[$name] .= \de\toxa\txf\view::wrapNotEmpty(@$viewports[$viewportName], config::get('view.viewport.wrap.' . $viewportName, '')); } } } // support default content to show if a region keeps empty finally if (trim($regions[$name]) === '') { $regions[$name] = trim(@$region['default']); } // process any additionally contained markers $regions[$name] = data::qualifyString($regions[$name]); } } } } return $regions; }
/** * Renders editor with fields limited to displaying values instead of * providing controls for editing them. * * @return string * @throws http_exception on trying to render without selecting item first */ public function renderReadonly() { if (!$this->item) { throw new http_exception(400, \de\toxa\txf\_L('Your request is not including selection of item to be displayed.')); } $fields = $this->fields; $editor = $this; $modelLabelFormatter = array($this->class->getName(), 'formatHeader'); $modelCellFormatter = array($this->class->getName(), 'formatCell'); $labelFormatter = function ($name) use($modelLabelFormatter, $fields, $editor) { if (array_key_exists($name, $fields)) { $label = $fields[$name]->label(); if ($label) { return sprintf('%s:', $label); } else { if ($label === false) { return ''; } } } return call_user_func($modelLabelFormatter, $name); }; $cellFormatter = function ($value, $name, $record, $id) use($modelCellFormatter, $fields, $editor) { $field = @$fields[$name]; /** @var model_editor_field $field */ return $field ? $field->type()->formatValue($name, $value, $editor, $field) : null; }; $record = $this->item->published(); data::rearrangeArray($record, $this->sortingOrder ? $this->sortingOrder : array_keys($fields)); return html::arrayToCard($record, strtolower(basename(strtr($this->class->getName(), '\\', '/'))) . 'Details', $cellFormatter, $labelFormatter, \de\toxa\txf\_L('-')); }