public static function getValue($value, $settings, $model) { // Check if the src is set and the converted values are not - this means we need to check for // the progress file and possibly update the database if (is_array($value) && isset($value['src']) && strlen($value['src']) > 0 && (!isset($value['converted']) || empty($value['converted']))) { // See if the progress file exists $path = DOCROOT . $value['src']; if (file_exists($path . '.progress')) { $value['progress'] = json_decode(file_get_contents($path . '.progress')); } else { // It doesn't exist - populate the field if (isset($value['progress'])) { unset($value['progress']); } $path_info = pathinfo($value['src']); $value['poster'] = $path_info['dirname'] . '/' . $path_info['basename'] . '.jpg'; $value['converted'] = array('mp4' => $path_info['dirname'] . '/converted/' . $path_info['filename'] . '.mp4', 'webm' => $path_info['dirname'] . '/converted/' . $path_info['filename'] . '.webm'); //$class = \CMF::getClass($model); $field_name = $settings['mapping']['fieldName']; $model->set($field_name, $value); \D::manager()->persist($model); \D::manager()->flush(); } } return $value; }
public static function enableListener() { if (empty(static::$listener)) { return; } \D::manager()->getEventManager()->addEventSubscriber(static::$listener); }
/** * Purge all expired API keys from the database */ public function removeOldKeys() { $keys = \CMF\Model\User\Apikey::select('item')->andWhere('item.expires_at < :now')->setParameter('now', new \DateTime())->getQuery()->getResult(); foreach ($keys as $key) { \D::manager()->remove($key); } \D::manager()->flush(); }
public function action_languageCanonicals() { $lang = \Config::get('language'); $em = \D::manager(); if (empty($lang)) { throw new \Exception("You do not have set any language for this site , this action is not available"); } $canonicalLanguage = ""; if (isset($_SERVER["HTTP_CONTENT_LANGUAGE"])) { $canonicalLanguage = $_SERVER["HTTP_CONTENT_LANGUAGE"]; if ($canonicalLanguage == $lang) { throw new \Exception("Canonical Language id the same as Main site language"); } } else { throw new \Exception("The Request has got not language set"); } $jsonObject = null; try { $jsonObject = json_decode(file_get_contents('php://input')); } catch (\Exception $e) { } if (!empty($jsonObject) && !empty($jsonObject->data)) { foreach ($jsonObject->data as $table => $items) { foreach ($items as $canonical) { $class = $canonical->class; $item = $class::find($canonical->id); if (!empty($item) && !empty($item->settings)) { $settings = $item->settings; if (!isset($settings['languages'])) { $settings['languages'] = array(); } if (isset($canonical->url)) { if (!isset($settings['languages'][$canonicalLanguage])) { $settings['languages'][$canonicalLanguage] = \Uri::base(false) . $item->url; } $settings['languages'][$canonicalLanguage] = $canonical->url; } else { if (isset($settings['languages'][$canonicalLanguage])) { unset($settings['languages'][$canonicalLanguage]); } } $item->set('settings', $settings); $em->persist($item); } } } } $em->flush(); exit(true); }
public static function cleanOld() { $urls = \CMF\Model\URL::select('item')->getQuery()->getResult(); $deleted = 0; foreach ($urls as $url) { $item = $url->item(); if (empty($item)) { \D::manager()->remove($url); $deleted++; } } \D::manager()->flush(); return $deleted; }
public function startQuery($sql, array $params = null, array $types = null) { if ($this->logger) { $this->logger->startQuery($sql, $params, $types); } // Store select queries for later use if (substr($sql, 0, 6) == 'SELECT') { if ($params) { // Attempt to replace placeholders so that we can log a final SQL query for profiler's EXPLAIN statement // (this is not perfect-- getPlaceholderPositions has some flaws-- but it should generally work with ORM-generated queries) $is_positional = is_numeric(key($params)); list($sql, $params, $types) = \Doctrine\DBAL\SQLParserUtils::expandListParameters($sql, $params, $types); if (empty($types)) { $types = array(); } $placeholders = \Doctrine\DBAL\SQLParserUtils::getPlaceholderPositions($sql, $is_positional); if ($is_positional) { $map = array_flip($placeholders); } else { $map = array(); foreach ($placeholders as $name => $positions) { foreach ($positions as $pos) { $map[$pos] = $name; } } } ksort($map); $src_pos = 0; $final_sql = ''; $first_param_index = key($params); foreach ($map as $pos => $replace_name) { $final_sql .= substr($sql, $src_pos, $pos - $src_pos); if ($sql[$pos] == ':') { $src_pos = $pos + strlen($replace_name); $index = trim($replace_name, ':'); } else { $src_pos = $pos + 1; $index = $replace_name + $first_param_index; } $final_sql .= \D::manager()->getConnection()->quote($params[$index], \Arr::get($types, $index)); } $final_sql .= substr($sql, $src_pos); $this->queries[] = $final_sql; } else { $this->queries[] = $sql; } } }
/** inheritdoc */ public static function instance() { $called_class = get_called_class(); if (!isset($called_class::$instances[$called_class])) { $result = $called_class::select('item, start_page')->leftJoin('item.start_page', 'start_page')->setMaxResults(1)->getQuery()->getResult(); if (count($result) == 0) { // Create the item if it doesn't exist $result = new $called_class(); $result->blank(); \D::manager()->persist($result); \D::manager()->flush(); $called_class::$instances[$called_class] = $result; } else { $called_class::$instances[$called_class] = $result[0]; } } return $called_class::$instances[$called_class]; }
protected function pageTree($model = 'Model_Page_Base', $label = null, $active_url = null, $extra_fields = null) { $extra_fields_str = !is_null($extra_fields) ? ', page.' . implode(', page.', $extra_fields) : ''; if ($model == 'Model_Page_Base') { $extra_fields_str = ', TYPE(page) AS type'; } $nodes = $model::select('page.id, page.title, page.menu_title, page.lvl, page.lft, page.rgt' . $extra_fields_str . ', url.url, url.slug', 'page')->leftJoin('page.url', 'url')->where('page.lvl > 0')->andWhere('page.visible = true')->orderBy('page.root, page.lft', 'ASC')->getQuery(); // Set the query hint if multi lingual! if (\CMF\Doctrine\Extensions\Translatable::enabled()) { $nodes->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'); } $nodes = $nodes->getArrayResult(); $root_label = $label ? $label . '_level1' : 'level1'; $crumbs_label = $label ? $label . '_crumbs' : 'crumbs'; $uri = $active_url ? $active_url : \CMF::link(\CMF::original_uri()); $nodes = \D::manager()->getRepository($model)->buildTree($nodes, array()); $this->{$crumbs_label} = array(); $this->processNodes($nodes, $uri, 1, $label, $model); $crumbs = $this->{$crumbs_label}; ksort($crumbs); $this->{$crumbs_label} = $crumbs; return $this->{$root_label} = $nodes; }
/** * Deletes any imported local data that wasn't present in the import */ protected static function processDeletions($model) { if (!isset(static::$_updatedEntities[$model]) || !is_array(static::$_updatedEntities[$model])) { return; } $metadata = $model::metadata(); $polymorphic = $metadata->isInheritanceTypeJoined() || $metadata->isInheritanceTypeSingleTable(); $class = $metadata->name; // Find all the ids of database items that have been imported $localIds = $class::getImportedIds(); // Now get all the ids that have just been processed $processedClasses = array($metadata->name); $processedIds = array(); if ($polymorphic && count($metadata->subClasses)) { foreach ($metadata->subClasses as $subClass) { if (!in_array($subClass, $processedClasses)) { $processedClasses[] = $subClass; } } } foreach ($processedClasses as $processedClass) { if (!isset(static::$_updatedEntities[$processedClass]) || !is_array(static::$_updatedEntities[$processedClass])) { continue; } foreach (static::$_updatedEntities[$processedClass] as $id => $entity) { if (!in_array($entity->id, $processedIds)) { $processedIds[] = $entity->id; } } } // Find the difference between the two asort($localIds); asort($processedIds); $diff = array_diff($localIds, $processedIds); // Delete ones that weren't imported this time if (count($diff)) { $entities = $class::select('item')->where('item.id IN(:ids)')->setParameter('ids', $diff)->getQuery()->getResult(); foreach ($entities as $entity) { \D::manager()->remove($entity); } } }
/** * Adds default role to a new user if enabled in config * * @see \CMF\Model\User::_event_before_save() */ private function _add_default_role() { // Make sure no roles exist already if (empty($this->roles) || !static::query()->related('roles')->get_one()) { // Check for default role if ($default_role = \Config::get('cmf.auth.default_role')) { $em = \D::manager(); $query = $em->createQuery("SELECT r FROM CMF\\Model\\Role r WHERE r.name = '{$default_role}'"); $record = $query->getSingleResult(); if (!is_null($role)) { $this->roles[] = $role; } } } }
public static function getOptionsStatic(&$settings, $model) { $allow_empty = isset($settings['mapping']['nullable']) && $settings['mapping']['nullable'] && !(isset($settings['required']) && $settings['required']); if (static::$options !== null && is_array(static::$options)) { return $allow_empty ? array('' => '') + static::$options : static::$options; } $options = array(); $target_class = 'CMF\\Model\\URL'; $filters = array(); $tree_types = array(); $types = $target_class::select('item.type')->distinct()->where('item.item_id IS NOT NULL')->orderBy('item.type', 'ASC')->getQuery()->getScalarResult(); foreach ($types as $type) { $type = $type['type']; if (!class_exists($type)) { continue; } $metadata = $type::metadata(); $root_class = $metadata->rootEntityName; if (isset($root_class)) { $type = $root_class; } $name = $type::plural(); if (isset($options[$name])) { continue; } $group = \Arr::get($options, $name, array()); $repository = \D::manager()->getRepository($type); $prop = property_exists('menu_title', $type) ? 'menu_title' : 'title'; if ($repository instanceof \Gedmo\Tree\Entity\Repository\NestedTreeRepository && !in_array($name, $tree_types)) { $tree_types[] = $name; // Put in the tree data... $query = $type::select('item, url')->leftJoin('item.url', 'url')->where('item.lvl > 0'); if (count($filters) > 0) { foreach ($filters as $filter) { $query = $query->andWhere('item.' . $filter); } } $tree = $query->orderBy('item.root, item.lft', 'ASC')->getQuery(); // Set the query hint if multi lingual! if (\CMF\Doctrine\Extensions\Translatable::enabled()) { $tree->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'); } $tree = $tree->getArrayResult(); $tree = $repository->buildTree($tree, array()); $options[$name] = static::buildTreeOptionsStatic($tree, $prop, array()); continue; } $items = $type::select("item.id, item.{$prop}, url.url, url.id url_id")->leftJoin('item.url', 'url')->orderBy("item.{$prop}", "ASC")->getQuery(); // Set the query hint if multi lingual! if (\CMF\Doctrine\Extensions\Translatable::enabled()) { $items->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'); } $items = $items->getArrayResult(); if (is_array($items) && count($items) > 0) { foreach ($items as $item) { $group[strval($item[$prop])] = $item['url']; } $options[$name] = $group; } } foreach ($options as $group_name => &$group_value) { if (is_array($group_value) && !in_array($group_name, $tree_types)) { uasort($group_value, function ($a, $b) { return strcmp(strtolower($a), strtolower($b)); }); } } uksort($options, function ($a, $b) { return strcmp(strtolower($a), strtolower($b)); }); static::$options = $options; return $allow_empty ? array('' => '') + $options : $options; }
/** * Populates the 'tables > classes' and 'classes > tables' maps. * @return void */ protected static function initClassTableMap() { $em = \D::manager(); $driver = $em->getConfiguration()->getMetadataDriverImpl(); static::$tables_to_classes = array(); static::$classes_to_tables = array(); static::$active_classes = array(); // Populate translatable fields $translateListener = \CMF\Doctrine\Extensions\Translatable::getListener(); // Loop through all Doctrine's class names, get metadata for each and populate the maps foreach ($driver->getAllClassNames() as $class_name) { $metadata = $em->getClassMetadata($class_name); if ($translateListener !== null) { $tConfig = $translateListener->getConfiguration($em, $class_name); if (is_array($tConfig) && isset($tConfig['fields']) && is_array($tConfig['fields'])) { static::$translatable[$class_name] = $tConfig['fields']; } } if ($metadata->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_TABLE) { static::$tables_to_classes[$metadata->table['name']] = $metadata->rootEntityName; } else { static::$tables_to_classes[$metadata->table['name']] = $class_name; } static::$classes_to_tables[$class_name] = $metadata->table['name']; if (!$metadata->isMappedSuperclass && is_subclass_of($class_name, 'CMF\\Model\\Base') && $class_name::hasPermissions()) { if (count($metadata->parentClasses) > 0) { $parent_class = $metadata->parentClasses[0]; if (!isset(static::$active_classes[$parent_class])) { static::$active_classes[$parent_class] = array($parent_class, $class_name); } else { static::$active_classes[$parent_class][] = $class_name; } } else { if (!isset(static::$active_classes[$class_name])) { static::$active_classes[$class_name] = array($class_name); } } } } }
/** * Save everything in the entire DB again */ public function action_save_all() { try { set_time_limit(0); ini_set('memory_limit', '512M'); } catch (\Exception $e) { // Nothing! } // Get driver and get all class names $driver = \D::manager()->getConfiguration()->getMetadataDriverImpl(); $this->classNames = $driver->getAllClassNames(); foreach ($this->classNames as $class) { if (is_subclass_of($class, '\\CMF\\Model\\Base')) { $metadata = $class::metadata(); // Don't process super classes! if ($class::superclass() || $metadata->isMappedSuperclass) { continue; } $class::saveAll(); \D::manager()->clear(); sleep(1); } } \Session::set_flash('main_alert', array('attributes' => array('class' => 'alert-success'), 'msg' => \Lang::get('admin.messages.save_all_success'))); \Response::redirect_back(); }
protected function metadata1() { $metadata = \D::manager()->getClassMetadata('CMF\\Model\\Base'); }
/** * For asyncronous saving - populates a model with the posted data and responds in JSON */ public function action_populate($table_name, $id = null) { // Find class name and metadata etc $class_name = \Admin::getClassForTable($table_name); if ($class_name === false) { return $this->show404(null, "type"); } if (!\CMF\Auth::can('edit', $class_name)) { return $this->show403('action_singular', array('action' => \Lang::get('admin.verbs.edit'), 'resource' => strtolower($class_name::singular()))); } // Set the output content type $this->headers = array("Content-Type: text/plain"); // If $id is null, we're populating multiple items if ($id === null) { // Construct the output $result = array('success' => true, 'num_updated' => 0); $post_data = \Input::post(); $ids = array_keys($post_data); $em = \D::manager(); if (count($ids) == 0) { return \Response::forge(json_encode($result), $this->status, $this->headers); } // Get the items we need to save $items = $class_name::select('item')->where('item.id IN(?1)')->setParameter(1, $ids)->getQuery()->getResult(); if (count($items) == 0) { return \Response::forge(json_encode($result), $this->status, $this->headers); } foreach ($items as $item) { $id = $item->id; if (!isset($post_data[$id])) { continue; } $result['num_updated'] += 1; $data = $post_data[$id]; $item->populate($data, false); if (!$item->validate()) { $result['success'] = false; } $em->persist($item); } // Try and save them all try { $em->flush(); } catch (\Exception $e) { $result['success'] = false; $result['error'] = $e->getMessage(); } // Return the JSON response return \Response::forge(json_encode($result), $this->status, $this->headers); } // Find the model, return 404 if not found $model = $class_name::find($id); if (is_null($model)) { return $this->show404(null, "item"); } // Populate with the POST data $model->populate(\Input::post(), false); // Construct the output $result = array('success' => false); // Check validation if ($model->validate()) { $result['success'] = true; } else { $result['validation_errors'] = $model->errors; } // Try and save it try { $em = \D::manager(); $em->persist($model); $em->flush(); $result['updated_at'] = $model->updated_at->format("d/m/Y \\a\\t H:i:s"); } catch (\Exception $e) { $result['success'] = false; $result['error'] = $e->getMessage(); } // Return the JSON response return \Response::forge(json_encode($result), $this->status, $this->headers); }
/** * Performs hydrations for the class specified */ protected function performHydrations($class, $ids = null) { if (!isset($this->hydrations[$class])) { return; } $extra = ''; if (is_array($ids)) { if (!($class == $this->class && count($ids) == $this->meta['total'])) { $extra = " WHERE item.id IN(" . implode(',', $ids) . ")"; } } foreach ($this->hydrations[$class] as $assoc) { \D::manager()->createQuery("SELECT item, {$assoc} FROM {$class} item LEFT JOIN item.{$assoc} {$assoc}" . $extra)->getResult(); } }
/** inheritdoc */ public static function instance() { $called_class = get_called_class(); if (!isset($called_class::$instances[$called_class])) { $result = $called_class::select('item')->setMaxResults(1)->getQuery()->getResult(); if (count($result) == 0) { $root_node = $called_class::getRootNode(true); // Create the item if it doesn't exist $result = new $called_class(); $result->blank(); $called_class::repository()->persistAsFirstChildOf($result, $root_node); \D::manager()->flush(); $called_class::$instances[$called_class] = $result; } else { $called_class::$instances[$called_class] = $result[0]; } } return $called_class::$instances[$called_class]; }
/** * Converts any old image fields (strings) into the new style object ones */ public function convertimages() { $em = \D::manager(); $driver = $em->getConfiguration()->getMetadataDriverImpl(); $tables_fields = array(); $sql = array(); // Loop through all the model metadata and check for image fields foreach ($driver->getAllClassNames() as $class) { $metadata = $em->getClassMetadata($class); $fields = $metadata->fieldMappings; $convert = array(); foreach ($fields as $field_name => $field) { if ($field['type'] == 'image') { $convert[] = $field_name; } } if (count($convert) > 0) { $table = $metadata->table['name']; $refl_fields = $metadata->reflFields; foreach ($convert as $convert_field) { if (isset($refl_fields[$convert_field]) && $refl_fields[$convert_field]->class != $class) { $field_table = \Admin::getTableForClass($refl_fields[$convert_field]->class); } else { $field_table = $table; } $table_fields = \Arr::get($tables_fields, $field_table, array()); if (!in_array($convert_field, $table_fields)) { $table_fields[] = $convert_field; } $tables_fields[$field_table] = $table_fields; } } } foreach ($tables_fields as $table => $fields) { $results = \DB::query("SELECT id, " . implode(', ', $fields) . " FROM {$table}")->execute(); foreach ($results as $result) { foreach ($fields as $field) { $image = @unserialize($result[$field]); if ($image === false) { $newimage = array('src' => $result[$field], 'alt' => ''); $newimage = \DB::quote(serialize($newimage)); $sql[] = "UPDATE {$table} SET {$field} = {$newimage} WHERE id = " . $result['id']; } } } } foreach ($sql as $query) { \DB::query($query)->execute(); } \Cli::write('Done!', 'green'); }
/** * Sync files to the DB table */ public static function syncFileFields() { if (!\Config::get('cmf.cdn.enabled')) { return; } try { set_time_limit(0); ini_set('memory_limit', '512M'); } catch (\Exception $e) { // Nothing! } $em = \D::manager(); $driver = $em->getConfiguration()->getMetadataDriverImpl(); $tables_fields = array(); $sql = array(); $localAdaper = static::adapter(); $cdn = static::getCDNAdapter(); $useCdn = \Config::get('cmf.cdn.sync.enabled') && !empty($cdn); $staticFiles = array(); // Loop through all the model metadata and check for image fields foreach ($driver->getAllClassNames() as $class) { $metadata = $em->getClassMetadata($class); $fields = $metadata->fieldMappings; $file_fields = array(); foreach ($fields as $field_name => $field) { if ($field['type'] == 'image' || $field['type'] == 'file') { $file_fields[$field_name] = $field['type']; } } if (count($file_fields) === 0) { continue; } $items = $class::select('item')->getQuery()->getResult(); foreach ($items as $num => $item) { foreach ($file_fields as $field_name => $field_type) { $field_value = $item->{$field_name}; if (is_array($field_value) && !empty($field_value['src'])) { $path = static::getDocumentRoot() . $field_value['src']; if (file_exists($path)) { $files = \DB::query("SELECT * FROM `_files` WHERE `path` = :path AND `storage` = 'local' ORDER BY `id` DESC LIMIT 1")->bind('path', $field_value['src'])->execute()->as_array(); if (!count($files)) { // Update file entry to the database \DB::insert('_files')->set(array('path' => $field_value['src'], 'url' => '/' . $field_value['src'], 'storage' => 'local', 'type' => $metadata->name, 'field' => $field_name, 'created_at' => date('Y-m-d H:i:s', filectime($path)), 'updated_at' => date('Y-m-d H:i:s', filemtime($path))))->execute(); } if ($useCdn && $field_type == 'file') { $cachedFiles = \DB::query("SELECT * FROM `_files` WHERE `path` = :path AND `storage` = 'cdn' ORDER BY `id` DESC LIMIT 1")->bind('path', $field_value['src'])->execute(); if (!count($cachedFiles)) { // Update cached file entry to the database $cachedResult = \DB::insert('_files')->set(array('path' => $field_value['src'], 'url' => '/' . $field_value['src'], 'storage' => 'cdn', 'type' => $metadata->name, 'field' => $field_name, 'created_at' => date('Y-m-d H:i:s', filectime($path)), 'updated_at' => date('Y-m-d H:i:s', filemtime($path))))->execute(); $cachedFileId = intval(@$cachedResult[0]); } else { $cachedFileId = intval($cachedFiles->get('id')); } if (!empty($cachedFileId)) { // Just upload files straight to the CDN $staticFiles[] = $field_value['src']; } } } } } } } if ($useCdn) { foreach ($staticFiles as $staticFile) { try { // Write the file to CDN if it doesn't exist there if (!$cdn->has($staticFile)) { if (\Fuel::$is_cli) { \Cli::write("uploading '{$staticFile}' to CDN"); } $cdn->write($staticFile, $localAdaper->read($staticFile), array('visibility' => 'public')); } } catch (\Exception $e) { } } } }
/** * Create a new entity and inject request params into it * @return array */ public function action_add() { $model = $this->model; $data = \Arr::get(\Input::json(), 'data', array()); $entity = null; if (isset($data['id']) && $data['id']) { $entity = $model::find($data['id']); } if (!$entity) { $entity = new $model(); } $entity->populate($data); $success = true; $msg = ''; try { \D::manager()->persist($entity); \D::manager()->flush(); } catch (\Exception $e) { $success = false; $msg = $e->getMessage(); } if ($success) { $this->http_status = 201; $this->params['id'] = $this->id = $entity->id; $this->unique = true; $this->response->set_header('Location', \Uri::base(false) . 'api/' . $this->singular . '/' . $entity->id); $result = $this->getQuery()->getResult(); if (!count($result)) { throw new \HttpException(ucfirst($this->singular) . ' was not found', \HttpException::NOT_FOUND); } return $result; } return array('error' => $msg); }
/** * @param object $entity * @param Constraint $constraint * * @throws UnexpectedTypeException * @throws ConstraintDefinitionException */ public function validate($entity, Constraint $constraint) { if (!is_array($constraint->fields) && !is_string($constraint->fields)) { throw new UnexpectedTypeException($constraint->fields, 'array'); } if (null !== $constraint->errorPath && !is_string($constraint->errorPath)) { throw new UnexpectedTypeException($constraint->errorPath, 'string or null'); } $fields = (array) $constraint->fields; if (0 === count($fields)) { throw new ConstraintDefinitionException('At least one field has to be specified.'); } if ($constraint->em) { $em = \D::manager($constraint->em); } else { $em = \D::manager(); } $className = $this->context->getClassName(); $class = $em->getClassMetadata($className); /* @var $class \Doctrine\Common\Persistence\Mapping\ClassMetadata */ $criteria = array(); foreach ($fields as $fieldName) { if (!$class->hasField($fieldName) && !$class->hasAssociation($fieldName)) { throw new ConstraintDefinitionException(sprintf("The field '%s' is not mapped by Doctrine, so it cannot be validated for uniqueness.", $fieldName)); } $criteria[$fieldName] = $class->reflFields[$fieldName]->getValue($entity); if ($constraint->ignoreNull && null === $criteria[$fieldName]) { return; } if ($class->hasAssociation($fieldName)) { /* Ensure the Proxy is initialized before using reflection to * read its identifiers. This is necessary because the wrapped * getter methods in the Proxy are being bypassed. */ $em->initializeObject($criteria[$fieldName]); $relatedClass = $em->getClassMetadata($class->getAssociationTargetClass($fieldName)); $relatedId = $relatedClass->getIdentifierValues($criteria[$fieldName]); if (count($relatedId) > 1) { throw new ConstraintDefinitionException("Associated entities are not allowed to have more than one identifier field to be " . "part of a unique constraint in: " . $class->getName() . "#" . $fieldName); } $criteria[$fieldName] = array_pop($relatedId); } } $repository = $em->getRepository($className); $result = $repository->{$constraint->repositoryMethod}($criteria); /* If the result is a MongoCursor, it must be advanced to the first * element. Rewinding should have no ill effect if $result is another * iterator implementation. */ if ($result instanceof \Iterator) { $result->rewind(); } elseif (is_array($result)) { reset($result); } /* If no entity matched the query criteria or a single entity matched, * which is the same as the entity being validated, the criteria is * unique. */ if (0 === count($result) || 1 === count($result) && $entity === ($result instanceof \Iterator ? $result->current() : current($result))) { return; } $errorPath = null !== $constraint->errorPath ? $constraint->errorPath : $fields[0]; $this->context->addViolationAt($errorPath, $constraint->message, array(), $criteria[$fields[0]]); }
public function shutdown() { $queries = $this->logger->queries; $controller = $this->request->controller_instance; $tables = array(); $subqueries = array(); $queryTables = array(); $sql = ''; // Add the template files to be checked $template_loader = \View_Twig::loader(); if (!is_null($template_loader) && method_exists($template_loader, 'getFiles')) { $templates = $template_loader->getFiles(); $this->files = array_unique(array_merge($this->files, $templates)); } // Add all loaded files within the app root, excluding cache and model proxies $this->files = array_merge($this->files, array_filter(get_included_files(), function ($path) { return strpos($path, APPPATH) === 0 && strpos($path, APPPATH . 'cache') !== 0 && strpos($path, APPPATH . 'classes/proxy') !== 0; })); $model_classes = array_filter(get_declared_classes(), function ($class) { return strpos($class, 'Model_') !== false; }); // Construct an allowed list of tables for the cache queries $em = \D::manager(); foreach ($model_classes as $model) { $meta = $em->getClassMetadata($model); if ($meta->isMappedSuperclass || !isset($meta->columnNames['updated_at']) || $meta->rootEntityName != $meta->name) { continue; } if (!in_array($meta->table['name'], $tables)) { $tables[] = $meta->table['name']; } } // Remove the app path from each file path, making them relative $this->files = array_map(function ($path) { return str_replace(PROJECTROOT, '', $path); }, $this->files); // Construct ourselves a number of sub queries to check all the relevant records in the database $num = 0; foreach ($queries as $query) { $parser = new \PHPSQL\Parser(); $parsed = $parser->parse($query, true); if (!isset($parsed['FROM']) || count($parsed['FROM']) === 0) { continue; } $aliases = array(); foreach ($parsed['FROM'] as $part) { if ($part['expr_type'] == 'table' && in_array($part['table'], $tables)) { $aliases[] = isset($part['alias']['name']) ? $part['alias']['name'] : $part['table']; } } $from_pos = $parsed['FROM'][0]['position']; if (isset($parsed['ORDER']) && count($parsed['ORDER']) > 0) { $append = ' FROM ' . substr($query, $from_pos, $parsed['ORDER'][0]['position'] - $from_pos - 10); } else { $append = ' FROM ' . substr($query, $from_pos); } if (count($aliases) > 1) { $append = ', (COUNT(' . implode('.id)+COUNT(', $aliases) . '.id)) as count' . $append; } else { if (count($aliases) === 1) { $append = ', COUNT(' . $aliases[0] . '.id) as count' . $append; } else { continue; } } $subqueries[] = 'q' . $num; $queryTables[] = '(SELECT ' . (count($aliases) > 1 ? 'GREATEST(' : '') . 'COALESCE(MAX(' . implode('.updated_at),\'1000-01-01\'), COALESCE(MAX(', $aliases) . '.updated_at),\'1000-01-01\')' . (count($aliases) > 1 ? ')' : '') . ' AS updated_at' . $append . ') q' . $num; $num++; } if (count($this->queries) > 0) { foreach ($this->queries as $query) { $parser = new \PHPSQL\Parser(); $parsed = $parser->parse($query, true); $field = null; if (!isset($parsed['FROM']) || count($parsed['FROM']) === 0) { continue; } if (!isset($parsed['SELECT']) || count($parsed['SELECT']) === 0) { continue; } foreach ($parsed['SELECT'] as $select) { if ($select['expr_type'] == 'colref') { $field = $select['base_expr']; break; } } if ($field === null) { continue; } $aliases = array(); foreach ($parsed['FROM'] as $part) { if ($part['expr_type'] == 'table') { $aliases[] = isset($part['alias']['name']) ? $part['alias']['name'] : $part['table']; } } $from_pos = $parsed['FROM'][0]['position']; if (isset($parsed['ORDER']) && count($parsed['ORDER']) > 0) { $append = ' FROM ' . substr($query, $from_pos, $parsed['ORDER'][0]['position'] - $from_pos - 10); } else { $append = ' FROM ' . substr($query, $from_pos); } if (count($aliases) > 1) { $append = ', (COUNT(' . implode('.' . $field . ')+COUNT(', $aliases) . '.' . $field . ')) as count' . $append; } else { if (count($aliases) === 1) { $append = ', COUNT(' . $aliases[0] . '.' . $field . ') as count' . $append; } else { continue; } } $subqueries[] = 'q' . $num; $queryTables[] = '(SELECT ' . (count($aliases) > 1 ? 'GREATEST(' : '') . 'COALESCE(MAX(' . implode('.' . $field . '),\'1000-01-01\'), COALESCE(MAX(', $aliases) . '.' . $field . '),\'1000-01-01\')' . (count($aliases) > 1 ? ')' : '') . ' AS updated_at' . $append . ') q' . $num; $num++; } } if (count($queryTables)) { // TODO: proper chunking of subqueries! For now, we will truncate them if they exeed MySQL's limit of 61 if (count($queryTables) > 60) { $queryTables = array_slice($queryTables, 0, 60); $subqueries = array_slice($subqueries, 0, 60); } // Complete the mega query that will check if items are updated or not... if (count($subqueries) > 1) { $sql = 'SELECT GREATEST(' . implode('.updated_at, ', $subqueries) . '.updated_at) AS updated_at, (' . implode('.count+', $subqueries) . '.count) AS count FROM ' . implode(', ', $queryTables); } else { $sql = 'SELECT q0.updated_at, q0.count FROM ' . implode(', ', $queryTables); } // Run the query - this must be done now because we can't reliably get the correct results from what we have try { $result = \DB::query($sql)->execute()->as_array(); $result = $result[0]; $result['updated_at'] = strtotime($result['updated_at']); } catch (\Exception $e) { // We can't continue if the query doesn't work return; } } // Add the rest of the stuff to the result $result['query_count'] = $num; $result['sql'] = $sql; $result['files'] = $this->files; $result['content'] = strval($this->request->response); $result['nocache'] = \CMF\Cache::getNoCacheAreas($result['content']); $result['logs_made'] = \CMF\Log::$logs_made; $result['content-type'] = 'text/html; charset=utf-8'; $result['template'] = \CMF::$template; $result['module'] = \CMF::$module; // Store the content type header if it's set $headers = headers_list(); foreach ($headers as $header) { if (stripos($header, 'content-type: ') === 0) { $result['content-type'] = substr($header, 14); break; } } // serialize and write it to disk \CMF\Cache::writeCacheFile($this->path, serialize($result)); }
/** * Ensures that there is at least an 'all' permission set for every resource * @return void */ public static function create_permissions() { $actions = static::all_actions(); $actions[] = 'all'; $activeClasses = \CMF\Admin::activeClasses(); $activeClasses['user_defined'] = array_keys(\Config::get('cmf.auth.resources', array())); $roles = Role::select('item')->getQuery()->getResult(); $em = \D::manager(); foreach ($activeClasses as $parent_class => $classes) { foreach ($classes as $class_name) { $count = intval(Permission::select("count(item)")->where("item.resource = '{$class_name}'")->andWhere("item.action = 'all'")->getQuery()->getSingleScalarResult()); if ($count == 0) { $permission = new Permission(); $permission->set('action', 'all'); $permission->set('resource', $class_name); $em->persist($permission); foreach ($roles as $role) { $role->add('permissions', $permission); $em->persist($role); } } } } $em->flush(); }
/** * Get the auto translatable fields which have changed for an entity */ protected function getChangeset($entity) { $entity_class = $entity->metadata()->name; $translatableFields = \CMF\Admin::getTranslatable($entity_class); $excludedFields = $entity_class::excludeAutoTranslations(); if (\Input::param('force_translate', false) !== false) { return array_values(array_diff(array_values($translatableFields), $excludedFields)); } else { $changeset = \D::manager()->getUnitOfWork()->getEntityChangeSet($entity); if (is_array($changeset)) { $changeset = array_keys($changeset); } else { $changeset = array(); } } return array_diff(array_values(array_intersect($translatableFields, $changeset)), $excludedFields); }
/** * Returns a new duplicate copy of the entity */ public function duplicate($flushdb = true, &$translations = array(), &$entityMap = array(), $excludeFields = array()) { $metadata = $this->metadata(); $class = $metadata->getName(); $fieldNames = $metadata->getFieldNames(); $associationNames = $metadata->getAssociationNames(); $duplicate = new $class(); $isTree = $this->isTreeNode(); if ($class::_static()) { throw new \Exception($class::singular() . ' is a static type and cannot be duplicated'); } // Copy field names across foreach ($fieldNames as $fieldName) { if (in_array($fieldName, $excludeFields)) { continue; } $value = $this->get($fieldName); $duplicate->set($fieldName, $value); } // Copy associations across foreach ($associationNames as $associationName) { if (in_array($associationName, $excludeFields)) { continue; } $associationMapping = $metadata->getAssociationMapping($associationName); $value = $this->get($associationName); $shouldCopy = $associationMapping['orphanRemoval'] || $associationMapping['isCascadeRemove']; $isTreeChildren = $isTree && $associationName == 'children'; $targetPropName = $associationMapping['isOwningSide'] ? @$associationMapping['inversedBy'] : @$associationMapping['mappedBy']; if (!empty($value) && ($shouldCopy || $isTreeChildren)) { if ($metadata->isCollectionValuedAssociation($associationName)) { $duplicateCollection = array(); foreach ($value as $item) { $itemClass = $item->metadata()->name; if (!$itemClass::_static()) { $duplicateItem = $item->duplicate(false, $translations, $entityMap, array($targetPropName)); if (!empty($duplicateItem)) { $duplicateCollection[] = $duplicateItem; } } } $value = $duplicateCollection; } else { $itemClass = $value->metadata()->name; if (!$itemClass::_static()) { $value = $value->duplicate(false, $translations, $entityMap, array($targetPropName)); } else { $value = null; } } } $duplicate->set($associationName, $value); } if (!$flushdb) { \D::manager()->persist($duplicate); } // If languages are enabled, add its translations to the array reference using the new oid if ($this->id && \CMF::langEnabled()) { $oid = spl_object_hash($duplicate); $entityMap[$oid] = $duplicate; if (!isset($translations[$oid])) { $translations[$oid] = \DB::query("SELECT * FROM ext_translations WHERE object_class = '{$metadata->rootEntityName}' AND foreign_key = '{$this->id}'")->execute()->as_array(); } } if ($flushdb) { // Persist the item if ($isTree) { $class::repository()->persistAsNextSiblingOf($duplicate, $this); } else { \D::manager()->persist($duplicate); } $displayField = $this->findFieldUsedInDisplay(); if (!empty($displayField)) { $duplicate->setUniqueValueForField($displayField); } \D::manager()->flush(); // Add translations after all the entities have been committed to the db if (!empty($translations)) { foreach ($translations as $objectHash => $objectTranslations) { $entity = isset($entityMap[$objectHash]) ? $entityMap[$objectHash] : null; if (empty($entity) || empty($entity->id) || empty($objectTranslations)) { continue; } $cols = null; $qb = \DB::insert('ext_translations'); foreach ($objectTranslations as $translation) { unset($translation['id']); $translation['foreign_key'] = strval($entity->id); if (is_null($cols)) { $cols = array_keys($translation); $qb->columns($cols); } // Insert the new translations $qb->values($translation); } $qb->execute(); } } try { if (is_subclass_of($class, 'CMF\\Model\\Node')) { $repo = \D::manager()->getRepository($class); $repo->recover(); \D::manager()->flush(); } } catch (\Exception $e) { } } return $duplicate; }
/** * Creates a super user * @return array */ public static function createSuperUser($email = '*****@*****.**', $username = '******', $password = null) { // Load up the admin module and it's classes, otherwise we won't get // access to the admin user class \Module::load('admin'); if (\Fuel::$is_cli) { $email = \Cli::prompt('Enter an email address', $email); $username = \Cli::prompt('Enter a user name', $username); $first = true; while ($first || strlen($password) > 0 && strlen($password) < 6) { $password = \Cli::prompt('Enter a password (leave blank to generate one)'); if (strlen($password) > 0 && strlen($password) < 6) { \Cli::error('The password must be 6 characters or more!'); } $first = false; } $confirm_password = ''; if (empty($password)) { // The user left the password field blank, so we are generating one $gen = new PWGen(3, false, false, false, false, false, false); $password = $confirm_password = $gen->generate() . '-' . $gen->generate() . '-' . $gen->generate(); } else { // If the user entered a password, we need them to confirm it while ($confirm_password != $password) { $confirm_password = \Cli::prompt('Confirm password'); if ($confirm_password != $password) { \Cli::error('The passwords do not match!'); } } } } // Check if the user exists $em = \D::manager(); $user = \Admin\Model_User::select('item')->where("item.username = '******'")->getQuery()->getResult(); $exists = count($user) > 0; if ($exists) { $user = $user[0]; } else { $user = new \Admin\Model_User(); } // Populate the user $user->set('email', $email); $user->set('username', $username); $user->set('password', $password); $user->set('confirm_password', $confirm_password); $user->set('super_user', true); // Create the admin role $role = \CMF\Model\Role::findBy(array("name = 'admin'"))->getQuery()->getResult(); if (count($role) == 0) { $role = new \CMF\Model\Role(); $role->set('name', 'admin'); $role->set('description', 'users of this admin site'); $em->persist($role); } else { $role = $role[0]; } $user->add('roles', $role); // Validate the newly created user if (!$user->validate()) { if (\Fuel::$is_cli) { \Cli::write('There was something wrong with the info you entered. Try again!', 'red'); static::createSuperUser(); } else { return array('errors' => $user->errors); } } $em->persist($user); $em->flush(); \Cli::write($exists ? "\n\tExisting super user updated:" : "\n\tNew super user created:", 'light_gray'); \Cli::write("\tusername: "******"\n\tpassword: "******"\n", 'light_cyan'); }
/** * Adds a URL that will redirect to another by ID */ public static function addRedirectUrl($url, $parentId, $type = 301, $limit = 2) { if (empty($url)) { return; } if (empty($parentId)) { return; } // Don't bother if the parent doesn't exist $parentCount = intval(\CMF\Model\URL::select("count(item.id)")->where('item.id = :parentid')->setParameter('parentid', intval($parentId))->getQuery()->getSingleScalarResult()); if ($parentCount === 0) { return; } // Standardise the passed URL $url = trim($url, '/'); if (stripos($url, 'http') === 0 && ($urlInfo = parse_url($url))) { $url = trim($url['path'], '/'); } $parts = explode('/', $url); if (empty($parts)) { return; } // Get existing redirects $existing = \CMF\Model\URL::select('item')->where('item.parent_id = :parentid')->setParameter('parentid', intval($parentId))->orderBy('item.updated_at', 'ASC')->getQuery()->getResult(); // Check for redirects with the same URL foreach ($existing as $existingUrl) { if ($existingUrl->url == '/' . $url) { $existingUrl->set('updated_at', new \DateTime()); $existingUrl->set('type', strval($type)); \D::manager()->persist($existingUrl); \D::manager()->flush($existingUrl); return $existingUrl; } } // Create the url unless the limit has been reached if (count($existing) >= $limit) { $redirect = $existing[0]; } else { $redirect = new \CMF\Model\URL(); } // Populate, save and return the new url object $redirect->populate(array('parent_id' => intval($parentId), 'item_id' => null, 'url' => '/' . $url, 'slug' => array_pop($parts), 'prefix' => '/' . implode('/', $parts) . (count($parts) ? '/' : ''), 'type' => strval($type))); \D::manager()->persist($redirect); \D::manager()->flush($redirect); return $redirect; }
/** * Gets called from action_index() when a model is found to extend CMF\Model|Node * @param string $class_name * @return void */ public function treeView($class_name) { \Admin::setCurrentClass($class_name); $metadata = $class_name::metadata(); // Create static items \Admin::createStaticInstances($metadata); // Add some context for the template $this->plural = $class_name::plural(); $this->singular = $class_name::singular(); $this->icon = $class_name::icon(); // Get permissions $can_create = \CMF\Auth::can('create', $class_name); $can_edit = \CMF\Auth::can('edit', $class_name); $can_delete = \CMF\Auth::can('delete', $class_name); $can_manage = \CMF\Auth::can(array('view', 'edit'), 'CMF\\Model\\Permission'); $classes = array(); $classes[$class_name] = array('plural' => $this->plural, 'singular' => $this->singular, 'icon' => $this->icon, 'table_name' => $metadata->table['name'], 'can_create' => $can_create && $can_edit, 'can_edit' => $can_edit, 'can_delete' => $can_delete, 'superclass' => $class_name::superclass(), 'allowed_children' => $class_name::allowedChildren(), 'allowed_parents' => $class_name::allowedParents()); foreach ($metadata->subClasses as $sub_class) { $subclass_metadata = $sub_class::metadata(); $classes[$sub_class] = array('static' => $sub_class::_static(), 'superlock' => $sub_class::superlock(), 'plural' => $sub_class::plural(), 'singular' => $sub_class::singular(), 'icon' => $sub_class::icon(), 'table_name' => $subclass_metadata->table['name'], 'can_create' => \CMF\Auth::can('create', $sub_class), 'can_edit' => \CMF\Auth::can('edit', $sub_class), 'can_delete' => \CMF\Auth::can('delete', $sub_class), 'superclass' => false, 'allowed_children' => $sub_class::allowedChildren(), 'allowed_parents' => $sub_class::allowedParents(), 'disallowed_children' => $sub_class::disallowedChildren(), 'disallowed_parents' => $sub_class::disallowedParents()); } // Item-specific permissions $user = \CMF\Auth::current_user(); $item_permissions = array(); $ids = array(); $excluded_ids = array(); $root_node = $class_name::getRootNode(true); $repo = \D::manager()->getRepository($class_name); $qb = $repo->getNodesHierarchyQueryBuilder($root_node); $this->tree_errors = null; $this->tree_is_valid = true; // If we have URLs, join them to the query if ($class_name::hasUrlField()) { $qb->addSelect('url, alias')->leftJoin('node.url', 'url')->leftJoin('url.alias', 'alias'); } $q = $qb->getQuery(); // Set the query hint if multi lingual! if (\CMF\Doctrine\Extensions\Translatable::enabled()) { $q->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'); } //$tree = $this->processTreeNodes(\D::manager()->getRepository($class_name)->childrenHierarchy($root_node), $metadata, $ids); $tree = $this->processTreeNodes($repo->buildTree($q->getArrayResult()), $metadata, $ids); if (!$user->super_user) { $permissions = \CMF\Model\Permission::select('item.id, item.action, item.resource, item.item_id')->leftJoin('item.roles', 'roles')->where("item.resource = '{$class_name}'")->andWhere("item.item_id IN(?1)")->andWhere("roles IN (?2)")->setParameter(1, $ids)->setParameter(2, $user->roles->toArray())->getQuery()->getArrayResult(); foreach ($permissions as $permission) { $item_actions = isset($item_permissions[$permission['item_id']]) ? $item_permissions[$permission['item_id']] : array(); $item_actions[] = $permission['action']; $item_permissions[$permission['item_id']] = $item_actions; } foreach ($item_permissions as $item_id => $item_actions) { if (in_array('none', $item_actions) || count($item_actions) > 0 && !in_array('view', $item_actions)) { $excluded_ids[] = $item_id; } } $tree = $this->filterTreeNodes($tree, $excluded_ids); } else { $this->tree_errors = $repo->verify(); $this->tree_is_valid = $this->tree_errors === true; } // Import actions $importMethods = $class_name::importMethods(); // Add more context for the template $this->table_name = $metadata->table['name']; $this->template = 'admin/item/tree.twig'; $this->superlock = $class_name::superlock(); $this->num_nodes = count($tree); // Permissions $this->can_create = $can_create && $can_edit; $this->can_edit = $can_edit; $this->can_delete = $can_delete; $this->can_manage = $can_manage; $this->can_import = !empty($importMethods) && $can_manage; // Add the stuff for JS $this->js['tree'] = $tree; $this->js['item_permissions'] = $item_permissions; $this->js['excluded_ids'] = $excluded_ids; $this->js['classes'] = $classes; $this->js['table_name'] = $metadata->table['name']; $this->js['plural'] = $this->plural; $this->js['singular'] = $this->singular; $this->js['class_name'] = $class_name; // Permissions for JS $this->js['can_create'] = $can_create && $can_edit; $this->js['can_edit'] = $can_edit; $this->js['can_delete'] = $can_delete; $this->js['can_manage'] = $can_manage; }