public function executeNormalView() { $this->setup(); $this->options['constraints'] = $this->getOption('constraints', array()); // Behave well if it's not set yet! if (strlen($this->slot->value)) { $items = $this->slot->MediaItems; $data = $this->slot->getArrayValue(); $order = $data['order']; $itemsById = aArray::listToHashById($items); $this->items = array(); foreach ($order as $id) { if (isset($itemsById[$id])) { $this->items[] = $itemsById[$id]; } } $this->itemIds = aArray::getIds($this->items); foreach ($this->items as $item) { $this->itemIds[] = $item->id; } if ($this->getOption('random', false)) { shuffle($this->items); } } else { $this->items = array(); $this->itemIds = array(); } }
/** * DOCUMENT ME */ protected function getLinkedItems() { // Behave well if it's not set yet! $data = $this->slot->getArrayValue(); if (isset($data['order'])) { $this->items = $this->slot->getOrderedMediaItems(); $this->itemIds = aArray::getIds($this->items); } else { $this->items = array(); $this->itemIds = array(); } }
public function getFilterForEngineParams() { $request = $this->getRequest(); $options = array('q' => $request->getParameter('q'), 'categoryIds' => aArray::getIds($this->page->Categories), 'categorySlug' => $request->getParameter('cat'), 'author' => $request->getParameter('author'), 'tag' => $request->getParameter('tag'), 'slugStem' => $this->slugStem, 'year' => $request->getParameter('year'), 'month' => $request->getParameter('month'), 'day' => $request->getParameter('day'), 'byPublishedAt' => true); // For the show action we don't want to limit the filters // to posts for the same day, it's only in the URL for show if ($request->getParameter('action') === 'show') { unset($options['year']); unset($options['month']); unset($options['day']); } return $options; }
public function executeEdit(sfRequest $request) { $this->logMessage("====== in aSlideshowSlotActions::executeEdit", "info"); if ($request->getParameter('aMediaCancel')) { return $this->redirectToPage(); } $this->editSetup(); $ids = preg_split('/,/', $request->getParameter('aMediaIds')); $q = Doctrine::getTable('aMediaItem')->createQuery('m')->select('m.*')->whereIn('m.id', $ids)->andWhere('m.type = "image"'); // Let the query preserve order for us $items = aDoctrine::orderByList($q, $ids)->execute(); $this->slot->unlink('MediaItems'); $links = aArray::getIds($items); $this->slot->link('MediaItems', $links); // Save just the order in the value field. Use a hash so we can add // other metadata later $this->slot->value = serialize(array('order' => $links)); $this->editSave(); }
/** * DOCUMENT ME * @return mixed */ protected function getTaggedItems() { $value = $this->slot->getArrayValue(); $this->items = array(); $this->itemIds = array(); // Not set yet if (!count($value)) { return; } if (isset($value['form'])) { // Tolerate what my early alphas did to save our devs some grief, but don't // respect it return; } // We have getBrowseQuery, so reuse it! $params = array(); if (isset($value['categories_list'])) { $params['allowed_categories'] = aCategoryTable::getInstance()->createQuery('c')->whereIn('c.id', $value['categories_list'])->execute(); } if (isset($value['tags_list'])) { $params['allowed_tags'] = $value['tags_list']; } if (isset($this->options['constraints'])) { foreach ($this->options['constraints'] as $k => $v) { $params[$k] = $v; } } $params['type'] = 'image'; $q = aMediaItemTable::getBrowseQuery($params); $q->andWhere('(aMediaItem.view_is_secure IS NULL OR aMediaItem.view_is_secure IS FALSE)'); $q->limit($value['count']); $q->orderBy('aMediaItem.created_at DESC'); $this->items = $q->execute(); // shuffle likes real arrays better $a = array(); foreach ($this->items as $item) { $a[] = $item; } $this->items = $a; $this->itemIds = aArray::getIds($this->items); }
/** * DOCUMENT ME * @param sfRequest $request * @return mixed */ public function executeEdit(sfRequest $request) { $this->logMessage("====== in aSlideshowSlotActions::executeEdit", "info"); if ($request->getParameter('aMediaCancel')) { return $this->redirectToPage(); } $this->editSetup(); if ($request->hasParameter('aMediaIds')) { $ids = preg_split('/,/', $request->getParameter('aMediaIds')); $q = Doctrine::getTable('aMediaItem')->createQuery('m')->select('m.*')->whereIn('m.id', $ids)->andWhere('m.type = "image"'); // Let the query preserve order for us $items = aDoctrine::orderByList($q, $ids)->execute(); $this->slot->unlink('MediaItems'); $links = aArray::getIds($items); $this->slot->link('MediaItems', $links); // This isn't a normal form submission, but the act of selecting items for a // slideshow implies we picked the 'selected' radio button, so just save 'form' as if // that choice had been saved normally $this->slot->value = serialize(array('form' => array('type' => 'selected'), 'order' => $links)); return $this->editSave(); } }
public function executeEdit(sfRequest $request) { $this->logMessage("====== in aSlideshowSlotActions::executeEdit", "info"); if ($request->getParameter('aMediaCancel')) { return $this->redirectToPage(); } $this->editSetup(); $ids = preg_split('/,/', $request->getParameter('aMediaIds')); $q = Doctrine::getTable('aMediaItem')->createQuery('m')->select('m.*')->whereIn('m.id', $ids)->andWhere('m.type = "image"'); // Let the query preserve order for us $items = aDoctrine::orderByList($q, $ids)->execute(); $this->slot->unlink('MediaItems'); $links = aArray::getIds($items); $this->slot->link('MediaItems', $links); // Save just the order in the value field. Use a hash so we can add // other metadata later // Use getArrayValue and setArrayValue so that any additional fields that have been // added at the app level don't get smooshed $value = $this->slot->getArrayValue(); $value['order'] = $links; $this->slot->setArrayValue($value); $this->editSave(); }
/** * DOCUMENT ME * @param sfGuardUser $user * @param mixed $admin * @param Doctrine_Query $q * @return mixed */ public function addCategoriesForUser(sfGuardUser $user, $admin = false, Doctrine_Query $q = null) { if (is_null($q)) { $q = $this->createQuery(); } else { $q = clone $q; } if (!$admin) { // This will perform well if the user is the current user and Doctrine has // retained the relation to groups $groups = $user->getGroups(); $groupIds = aArray::getIds($groups); $q->leftJoin('aCategory.Groups g')->leftJoin('aCategory.Users u'); // This is necessary because Doctrine doesn't have proper grouping syntax // available except via DQL $where = ''; // Don't get burned by an empty IN clause matching everything if (count($groupIds)) { $where .= 'g.id IN (' . implode(',', $groupIds) . ') OR '; } $q->andWhere('(' . $where . 'u.id = ?)', array($user['id'])); } return $q; }
public function updatePageTagsAndCategories() { $this->Page->setTags($this->getTags()); $categories = $this->getCategories(); $ids = aArray::getIds($categories); $this->Page->unlink('Categories'); $this->Page->link('Categories', $ids); $this->Page->save(); }
/** * Select a media item or items, then redirect to the URL * specified by the $after parameter, at which time the above * information retrieving methods are valid for use. * The $actions parameter should be the current actions class * ($this, if you are writing an executeFoo method). * $after is the URL to redirect to after the selection is completed or cancelled. * For backwards compatibility this URL will receive several GET method parameters, * however you should use the methods above rather than consulting them. The methods * above are not limited by URL length considerations. * $currentIds should contain a list of ids or a list of aMediaItems that are * currently selected (allowing the user to modify the list rather than making * an entirely new selection), or a single item or id, or false for no current selection. * $options is a hash which may contain: * multiple => true: allow multiple media items to be selected * 'type', 'aspect-width', 'aspect-height', 'minimum-width', 'minimum-height', * 'width', 'height': enforce these constraints on type or dimensions * type can currently be image, video or pdf * 'label': set the reminder message that appears at the top of the media browser * to remind the user why they are there and what they are looking for * 'cropping' => true: allow the user to crop each selected item. Cropping * parameters can be retrieved later with getCroppingInfo() * 'croppingInfo' => an array of existing cropping info as returned by * getCroppingInfo after a previous successful selection. Allows the user to * edit a selection with existing cropping choices * @param mixed $actions * @param mixed $after * @param mixed $currentIds * @param mixed $options * @return mixed */ public function select($actions, $after, $currentIds = false, $options = array()) { if ($currentIds === false) { $currentIds = array(); } elseif ($currentIds instanceof aMediaItem) { $currentIds = array($currentIds); } elseif (!is_array($currentIds)) { $currentIds = array($currentIds); } if ($currentIds[0] instanceof aMediaItem) { $currentIds = aArray::getIds($currentIds); } aMediaTools::setSelecting($after, $options['multiple'], $ids, $options); return $actions->redirect("aMedia/index"); }
public function getMediaCategoriesInfo() { // Returns an array of info about media categories that are appropriate to display in the // media browser for the current engine page. They are sorted in alphabetical order by name, // with a media item count included as well // TODO: I can probably cut this down to fewer queries // Only related categories, unless this engine has none, in which case we return all categories $categories = Doctrine::getTable('aMediaCategory')->createQuery('mc')->innerJoin('mc.Pages p WITH p.id = ?', $this->id)->orderBy('mc.name ASC')->execute(); if (!count($categories)) { return Doctrine::getTable('aMediaCategory')->findAllAlphaInfo(); } $ids = aArray::getIds($categories); $qresults = Doctrine_Query::create()->from('aMediaCategory mc')->select('mc.name, mc.slug, COUNT(mi.id) as mc_count')->whereIn('mc.id', $ids)->innerJoin('mc.MediaItems mi')->groupBy('mc.id')->orderBy('mc.name asc')->fetchArray(); $info = array(); foreach ($qresults as $qresult) { $info[] = array('name' => $qresult['name'], 'slug' => $qresult['slug'], 'count' => $qresult['mc_count']); } if (count($categories) == 1) { // Selecting amongst just one category is not interesting return array(); } return $info; }
/** * Returns categories that were added to this object by someone else which this user * is not eligible to remove * @return mixed */ public function getAdminCategories() { $reserved = array(); $existing = Doctrine::getTable('aCategory')->createQuery('c')->select('c.*')->innerJoin('c.MediaItems mi WITH mi.id = ?', $this->id)->execute(); $categoriesForUser = aCategoryTable::getInstance()->addCategoriesForUser(sfContext::getInstance()->getUser()->getGuardUser(), $this->isAdmin())->execute(); $ours = array_flip(aArray::getIds($categoriesForUser)); foreach ($existing as $category) { if (!isset($ours[$category->id])) { $reserved[] = $category; } } return $reserved; }
/** * DOCUMENT ME * @param sfWebRequest $request * @return mixed */ public function executeSelected(sfWebRequest $request) { $this->hasPermissionsForSelect(); $this->forward404Unless(aMediaTools::isSelecting()); $selection = aMediaTools::getSelection(); $imageInfo = aMediaTools::getAttribute('imageInfo'); // Get all the items in preparation for possible cropping if (count($selection)) { $items = Doctrine::getTable('aMediaItem')->createQuery('m')->whereIn('m.id', $selection)->execute(); } else { $items = array(); } $items = aArray::listToHashById($items); $newSelection = array(); foreach ($selection as $id) { $nid = $id; // Try not to make gratuitous crops if (isset($imageInfo[$id])) { $item = $items[$id]; $i = $imageInfo[$id]; if ($item->getCroppable() && isset($i['cropLeft']) && ($i['cropLeft'] > 0 || $i['cropTop'] > 0 || $i['cropWidth'] != $item->width || $i['cropHeight'] != $item->height)) { // We need to make a crop $item = $items[$id]; $crop = $item->findOrCreateCrop($imageInfo[$id]); $crop->save(); $nid = $crop->id; } $newSelection[] = $nid; } } // Ooops best to get this before clearing it huh $after = aMediaTools::getAfter(); // addParamsNoDelete never attempts to eliminate a field just because // its value is empty. This is how we distinguish between cancellation // and selecting zero items if (!aMediaTools::isMultiple()) { // Call this too soon and you lose isMultiple aMediaTools::clearSelecting(); if (count($newSelection)) { $after = aUrl::addParams($after, array("aMediaId" => $newSelection[0])); return $this->redirect($after); } else { // Our image UI lets you trash your single selection. Which makes sense. // So implement a way of passing that back. It's up to the // receiving action to actually respect it of course $after = aUrl::addParams($after, array("aMediaUnset" => 1)); return $this->redirect($after); } } else { aMediaTools::clearSelecting(); $url = aUrl::addParamsNoDelete($after, array("aMediaIds" => implode(",", $newSelection))); return $this->redirect($url); } }
/** * Fetch an array of information about categories related to this page. If the page is restricted by * category then only those categories are candidates for inclusion, otherwise any category might be * included in the results. The results are further filtered by whether any objects (or any objects * of the specified model class, if not null) are actually associated with those categories. An * a.get_count_by_category event is posted to determine the overall item counts by model class * for each category in an extensible way. The result is an associative array by model class, * the values of which are associative arrays with a single "counts" key, the value of * which is an associative array by category id of category information including name and * count keys * @param mixed $class * @return array */ public function getCategoriesInfo($class = null) { $event = new sfEvent(null, 'a.get_count_by_category'); sfContext::getInstance()->getEventDispatcher()->filter($event, array()); $counts = $event->getReturnValue(); $fcounts = array(); $categories = $this->getCategories(); if (!count($categories)) { $categories = Doctrine::getTable('aCategory')->findAll(); } $ids = aArray::listToHashById($categories); foreach ($counts as $cclass => $countsInfo) { $fcountsInfo = $countsInfo; foreach ($countsInfo['counts'] as $id => $info) { if (!isset($ids[$id])) { unset($fcountsInfo['counts'][$id]); } } $fcounts[$cclass] = $fcountsInfo; } if (!is_null($class)) { if (isset($fcounts[$class])) { return $fcounts[$class]; } else { return 0; } } else { return $fcounts; } }
/** * DOCUMENT ME * @param mixed $validator * @param mixed $value * @return mixed */ public function validateViewGroups($validator, $value) { $values = json_decode($value, true); if (!is_array($values)) { throw new sfValidatorError($validator, 'Bad permissions JSON'); } $candidates = Doctrine::getTable('aPage')->getViewCandidateGroups(); $candidates = aArray::listToHashById($candidates); foreach ($values as $info) { if ($info['id'] === 'editors_and_guests') { continue; } if (!isset($candidates[$info['id']])) { throw new sfValidatorError($validator, 'noncandidate'); } } return $value; }
public static function getBrowseQuery($params) { $query = Doctrine_Query::create(); // We can't use an alias because that is incompatible with getObjectTaggedWithQuery $query->from('aMediaItem'); if (isset($params['ids'])) { $query->select('aMediaItem.*'); aDoctrine::orderByList($query, $params['ids']); $query->andWhereIn("aMediaItem.id", $params['ids']); } if (isset($params['tag'])) { $query = TagTable::getObjectTaggedWithQuery('aMediaItem', $params['tag'], $query); } if (isset($params['type'])) { $query->andWhere("aMediaItem.type = ?", array($params['type'])); } if (isset($params['allowed_categories'])) { $query->innerJoin('aMediaItem.MediaCategories mc1 WITH mc1.id IN (' . implode(',', aArray::getIds($params['allowed_categories'])) . ')'); } if (isset($params['category'])) { $query->innerJoin('aMediaItem.MediaCategories mc2 WITH mc2.slug = ?', array($params['category'])); } if (isset($params['search'])) { $query = Doctrine::getTable('aMediaItem')->addSearchQuery($query, $params['search']); } elseif (isset($params['ids'])) { // orderBy added by aDoctrine::orderByIds } else { // Reverse chrono order if we're not ordering them by search relevance $query->orderBy('aMediaItem.id desc'); } // This will be more interesting later if (!isset($params['user'])) { $query->andWhere('aMediaItem.view_is_secure = false'); } if (isset($params['aspect-width']) && isset($params['aspect-height'])) { $query->andWhere('(aMediaItem.width * ? / ?) = aMediaItem.height', array($params['aspect-height'] + 0, $params['aspect-width'] + 0)); } if (isset($params['minimum-width'])) { $query->andWhere('aMediaItem.width >= ?', array($params['minimum-width'] + 0)); } if (isset($params['minimum-height'])) { $query->andWhere('aMediaItem.height >= ?', array($params['minimum-height'] + 0)); } if (isset($params['width'])) { $query->andWhere('aMediaItem.width = ?', array($params['width'] + 0)); } if (isset($params['height'])) { $query->andWhere('aMediaItem.height = ?', array($params['height'] + 0)); } return $query; }
public static function searchBody($action, $slugMatch, $modelClass, $categories, sfWebRequest $request) { $now = date('YmdHis'); // create the array of pages matching the query $ajax = false; if ($request->hasParameter('term')) { $ajax = true; $q = $request->getParameter('term'); // Wildcarding is better for autocomplete $q .= '*'; } else { $q = $request->getParameter('q'); if ($request->hasParameter('x')) { // We sometimes like to use input type="image" for presentation reasons, but it generates // ugly x and y parameters with click coordinates. Get rid of those and come back. Keep // all the other stuff return $action->redirect(sfContext::getInstance()->getController()->genUrl(aUrl::addParams($request->getParameter('module') . '/' . $request->getParameter('action'), array('q' => $q, 'cat' => $request->getParameter('cat'), 'tag' => $request->getParameter('tag'), 'year' => $request->getParameter('year'), 'month' => $request->getParameter('month'), 'day' => $request->getParameter('day'))))); } } $key = strtolower(trim($q)); $key = preg_replace('/\\s+/', ' ', $key); $replacements = sfConfig::get('app_a_search_refinements', array()); if (isset($replacements[$key])) { $q = $replacements[$key]; } try { $q = "({$q}) AND slug:{$slugMatch}"; $values = aZendSearch::searchLuceneWithValues(Doctrine::getTable('aPage'), $q, aTools::getUserCulture()); } catch (Exception $e) { // Lucene search error. TODO: display it nicely if they are always safe things to display. For now: just don't crash $values = array(); } $nvalues = array(); // The truth is that Zend cannot do all of our filtering for us, especially // permissions-based. So we can do some other filtering as well, although it // would be bad not to have Zend take care of the really big cuts (if 99% are // not being prefiltered by Zend, and we have a Zend max results of 1000, then // we are reduced to working with a maximum of 10 real results). if ($request->hasParameter('cat')) { $categories = Doctrine::getTable('aCategory')->createQuery()->where('slug = ?', array($request->getParameter('cat')))->execute(array(), Doctrine::HYDRATE_ARRAY); } if (is_null($categories)) { $categoryIds = array(); } else { $categoryIds = aArray::getIds($categories); } foreach ($values as $value) { if ($ajax && count($nvalues) >= sfConfig::get('app_aBlog_autocomplete_max', 10)) { break; } // 1.5: the names under which we store columns in Zend Lucene have changed to // avoid conflict with also indexing them $info = unserialize($value->info_stored); // Do a whole bunch of filtering that can't be easily done at the Lucene level. // This is not ideal because the 1000 results we consider might not meet the // criteria and some later set of results might. For 2.0 we need to find something // that fully merges text search and other criteria without complaint // The main performance killer isn't MySQL, it's Doctrine object hydration. Just keep it light if (count($categoryIds) && !count(Doctrine::getTable('aPage')->createQuery('p')->where('p.id = ?', $info['id'])->innerJoin('p.Categories c')->select('p.id, c.id')->andWhereIn('c.id', $categoryIds)->execute(array(), Doctrine::HYDRATE_NONE))) { continue; } if ($request->hasParameter('tag') && !count(Doctrine::getTable('Tagging')->createQuery('ta')->innerJoin('ta.Tag t WITH t.name = ?', $request->getParameter('tag'))->where('ta.taggable_model = ? AND ta.taggable_id = ?', array('aPage', $info['id']))->execute(array(), Doctrine::HYDRATE_NONE))) { continue; } // Filter search results chronologically. How to do this depends on whether // we're dealing with blog or events $year = sprintf("%04d", $request->getParameter('year')); $month = sprintf("%02d", $request->getParameter('month')); $day = sprintf("%02d", $request->getParameter('day')); // This if is gross and ought to be refactored by calling a method on // the actions class which is differently implemented by the two classes if (get_class($action) === 'aEventActions') { if ($day > 0) { if (!aBlogToolkit::between("{$year}-{$month}-{$day}", $value->start_date, $value->end_date)) { continue; } } elseif ($month > 0) { if (!aBlogToolkit::between("{$year}-{$month}", substr($value->start_date, 0, 7), substr($value->end_date, 0, 7))) { continue; } } elseif ($year > 0) { if (!aBlogToolkit::between("{$year}", substr($value->start_date, 0, 4), substr($value->end_date, 0, 4))) { continue; } } } else { // We store this one real picky in a keyword so it's searchable at the lucene level if (preg_match('/^(\\d\\d\\d\\d)(\\d\\d)(\\d\\d)/', $value->published_at, $matches)) { list($dummy, $pyear, $pmonth, $pday) = $matches; if ($year > 0) { if ($pyear != $year) { continue; } } if ($month > 0) { if ($pmonth != $month) { continue; } } if ($day > 0) { if ($pday != $day) { continue; } } } } // Regardless of the above if it ain't published yet we can't see it if ($value->published_at > $now) { continue; } if (!aPageTable::checkPrivilege('view', $info)) { continue; } $nvalue = $value; $nvalue->page_id = $info['id']; $nvalue->slug = $nvalue->slug_stored; $nvalue->title = $nvalue->title_stored; $nvalue->summary = $nvalue->summary_stored; // Virtual page slug is a named Symfony route, it wants search results to go there $nvalue->url = $action->getController()->genUrl($nvalue->slug, true); $nvalue->class = $modelClass; $nvalues[] = $nvalue; } $values = $nvalues; if ($ajax) { // We need the IDs of the blog posts, not their virtual pages $pageIds = array(); foreach ($values as $value) { $pageIds[] = $value->page_id; } $action->results = array(); if (count($pageIds)) { $infos = Doctrine::getTable($modelClass)->createQuery('p')->select('p.id, p.page_id, p.status')->whereIn('p.page_id', $pageIds)->fetchArray(); // At this point, if we're an admin, we have some posts on our list that are not actually // useful to return as AJAX results because we only care about posts that are published when // we're building up a posts slot foreach ($infos as $info) { if ($info['status'] !== 'published') { continue; } $pageIdToPostId[$info['page_id']] = $info['id']; } foreach ($values as $value) { if (isset($pageIdToPostId[$value->page_id])) { // Titles are stored as entity-escaped HTML text, so decode to meet // the expectations of autocomplete $action->results[] = array('label' => html_entity_decode($value->title, ENT_COMPAT, 'UTF-8'), 'value' => $pageIdToPostId[$value->page_id]); } } } return 'Autocomplete'; } $action->pager = new aArrayPager(null, sfConfig::get('app_a_search_results_per_page', 10)); $action->pager->setResultArray($values); $action->pager->setPage($request->getParameter('page', 1)); $action->pager->init(); $action->pagerUrl = "aBlog/search?" . http_build_query(array("q" => $q)); // setTitle takes care of escaping things $action->getResponse()->setTitle(aTools::getOptionI18n('title_prefix') . 'Search for ' . $q . aTools::getOptionI18n('title_suffix')); $action->results = $action->pager->getResults(); }
/** * DOCUMENT ME * @return mixed */ public function getOrderedMediaItems() { $order = $this->getMediaItemOrder(); $items = $this->getMediaItems(); if ($order) { $itemsById = aArray::listToHashById($items); $ordered = array(); foreach ($order as $id) { if (isset($itemsById[$id])) { $ordered[] = $itemsById[$id]; } } return $ordered; } return $items; }
/** * Given an array of blogItems this function will populate its virtual page * areas with the current slot versions. * @param aBlogItem $blogItems */ public static function populatePages($blogItems) { $pageIds = array(); foreach ($blogItems as $aBlogItem) { $pageIds[] = $aBlogItem['page_id']; } $pages = array(); if (count($pageIds)) { $q = aPageTable::queryWithSlots(); $q->whereIn('id', $pageIds); $fast = sfConfig::get('app_a_fasthydrate', false); $pagesInfo = $q->execute(array(), $fast ? Doctrine::HYDRATE_ARRAY : Doctrine::HYDRATE_RECORD); foreach ($pagesInfo as $pageInfo) { $pages[] = aTools::cacheVirtualPage($pageInfo); } } $pagesById = aArray::listToHashById($pages); foreach ($blogItems as $aBlogItem) { if (isset($pagesById[$aBlogItem->page_id])) { $aBlogItem->Page = $pagesById[$aBlogItem->page_id]; } } }
public function getFilterForEngineParams() { $request = $this->getRequest(); return array('q' => $request->getParameter('q'), 'categoryIds' => aArray::getIds($this->page->Categories), 'categorySlug' => $request->getParameter('cat'), 'tag' => $request->getParameter('tag'), 'slugStem' => $this->slugStem, 'year' => $request->getParameter('year'), 'month' => $request->getParameter('month'), 'day' => $request->getParameter('day'), 'byPublishedAt' => true); }
/** * Accepts array('info' => [page info array], 'where' => [where clause]) * * Returns results the current user is permitted to see. You can override this if you specify the * following options (must specify all or none): * 'user_id', 'has_view_locked_permission', 'group_ids', 'has_cms_admin_permission' * * You can override the user's culture by specifying 'culture' * @param mixed $options * @return mixed */ public static function getPagesInfo($options) { $whereClauses = array(); $ignorePermissions = false; if (isset($options['ignore_permissions'])) { // getAncestorsInfo has to return everything in some contexts to work properly $ignorePermissions = $options['ignore_permissions']; } if (!isset($options['culture'])) { $options['culture'] = aTools::getUserCulture(); } // In the absence of a bc option for page visibility, we can make a better // determination based on the user's access rights (1.5) $joins = ''; if (isset($options['user_id'])) { // If you pass this in you have to pass all of it in. But if you are just // interested in the current user you needn't bother (see the else clause) $user_id = $options['user_id']; $group_ids = $options['group_ids']; if (!count($group_ids)) { // Should never be empty due to IN's limitations $group_ids = array(0); } $hasViewLockedPermission = $options['has_view_locked_permission']; $hasCmsAdmin = $options['has_cms_admin_permission']; } else { // Get it automatically for the current user $user = sfContext::getInstance()->getUser(); $user_id = 0; $hasViewLockedPermission = false; $group_ids = array(0); $hasCmsAdmin = false; if ($user->isAuthenticated()) { $user_id = $user->getGuardUser()->id; // In 1.5 this one is a little bit of a misnomer because of the new provision for locking // to individuals or groups rather than "Editors & Guests". In the new use case it is // merely a prerequisite $credentials = sfConfig::get('app_a_view_locked_sufficient_credentials', 'view_locked'); $hasViewLockedPermission = $user->hasCredential($credentials); $group_ids = aArray::getIds($user->getGroups()); // Careful: empty IN clauses do not work if (!count($group_ids)) { $group_ids = array(0); } $hasCmsAdmin = $user->hasCredential('cms_admin'); } } $joins .= 'LEFT JOIN a_access aa ON aa.page_id = p.id AND aa.user_id = ' . $user_id . ' '; if (!count($group_ids)) { // A group that can never be $group_ids = array(0); } $joins .= 'LEFT JOIN a_group_access ga ON ga.page_id = p.id AND ga.group_id IN (' . implode(',', $group_ids) . ') '; $viewLockedClause = ''; if ($hasViewLockedPermission) { $viewLockedClause = 'OR p.view_guest IS TRUE '; } // CMS admin can always view if (!$hasCmsAdmin && !$ignorePermissions) { // YOU CAN VIEW IF // * view_admin_lock is NOT set, AND // * You can edit // OR // p.archived is false AND p.published_at is in the past AND p.view_is_secure is false // OR // p.archived is false AND p.published_at is in the past AND p.view_is_secure is true AND (p.view_guest is true OR you have view_locked OR you have an explicit view privilege // However note that if you have a group privilege you don't need to have hasViewLockedPermission (all groups are candidates) $whereClauses[] = '(p.view_admin_lock IS FALSE AND (((aa.privilege = "edit") || (ga.privilege = "edit")) OR ' . '((p.archived IS FALSE OR p.archived IS NULL) AND p.published_at < NOW() AND ' . '((p.view_is_secure IS FALSE OR p.view_is_secure IS NULL) OR ' . '(p.view_is_secure IS TRUE AND ' . '(ga.privilege = "view_custom" OR ' . ($hasViewLockedPermission ? '(p.view_guest IS TRUE OR aa.privilege = "view_custom")' : '(0 <> 0)') . '))))))'; } if (!isset($options['admin'])) { $options['admin'] = false; } if (!isset($options['where'])) { throw new sfException("You must specify a where clause when calling getPagesInfo"); } $culture = $options['culture']; $admin = $options['admin']; $where = $options['where']; // Raw PDO for performance $connection = Doctrine_Manager::connection(); $pdo = $connection->getDbh(); // When we look for the current culture, we need to do it in the ON clause, not // in the WHERE clause. Otherwise we don't get any information at all about pages // not i18n'd yet $escCulture = $connection->quote($culture); $query = "SELECT p.id, p.slug, p.view_is_secure, p.view_guest, p.view_admin_lock, p.edit_admin_lock, p.archived, p.lft, p.rgt, p.level, p.engine, p.template, s.value AS title FROM a_page p\n LEFT JOIN a_area a ON a.page_id = p.id AND a.name = 'title' AND a.culture = {$escCulture}\n LEFT JOIN a_area_version v ON v.area_id = a.id AND a.latest_version = v.version \n LEFT JOIN a_area_version_slot avs ON avs.area_version_id = v.id\n LEFT JOIN a_slot s ON s.id = avs.slot_id {$joins}"; // admin pages are almost never visible in navigation if (!$admin) { $whereClauses[] = '(p.admin IS FALSE OR p.admin IS NULL)'; } // Virtual pages are never appropriate for getPagesInfo. Note that privileges for virtual pages // are by definition always the responsibility of the code that brought them into being and never // based on "normal" page permissions, so getPagesInfo is entirely the wrong API for them $whereClauses[] = '(substr(p.slug, 1, 1) = "/")'; $whereClauses[] = $where; $query .= "WHERE " . implode(' AND ', $whereClauses); $query .= " ORDER BY p.lft"; $resultSet = $pdo->query($query); // Turn it into an actual array rather than some iterable almost-array thing $results = array(); $seenId = array(); foreach ($resultSet as $result) { // Careful: with the new LEFT JOINs on access rights we have extra rows. // Get only one for each page if (isset($seenId[$result['id']])) { continue; } $seenId[$result['id']] = true; // If there is no title yet, supply one to help the translator limp along if (!strlen($result['title'])) { if ($result['slug'] === '/') { $result['title'] = 'home'; } else { if (preg_match('|([^/]+)$|', $result['slug'], $matches)) { $result['title'] = $matches[1]; } } } $results[] = $result; } return $results; }
/** * Returns a query matching media items satisfying the specified parameters, all of which * are optional: * * tag * search * type (video, image, etc) * user (a username, to determine access rights) * aspect-width and aspect-height (returns only images with the specified aspect ratio) * minimum-width * minimum-height * width * height * ids * downloadable * embeddable * * Parameters are passed safely via wildcards so it should be OK to pass unsanitized * external API inputs to this method. * * 'ids' is an array of item IDs. If it is present, only items with one of those IDs are * potentially returned. * * If 'search' is present, results are returned in descending order by match quality. * Otherwise, if 'ids' is present, results are returned in that order. Otherwise, * results are returned newest first. * @param mixed $params * @return mixed */ public static function getBrowseQuery($params) { $query = Doctrine_Query::create(); // We can't use an alias because that is incompatible with getObjectTaggedWithQuery $query->from('aMediaItem'); if (isset($params['ids'])) { $query->select('aMediaItem.*, c.*'); aDoctrine::orderByList($query, $params['ids']); $query->andWhereIn("aMediaItem.id", $params['ids']); } // New: at least one of the specified tags must be present. This is kind of a pain to check for because // tags can be specified as arrays or a comma separated string if (isset($params['allowed_tags']) && (strlen($params['allowed_tags']) || is_array($params['allowed_tags']) && count($params['allowed_tags']))) { $query = TagTable::getObjectTaggedWithQuery('aMediaItem', $params['allowed_tags'], $query, array('nb_common_tags' => 1)); } elseif (isset($params['tag'])) { $query = TagTable::getObjectTaggedWithQuery('aMediaItem', $params['tag'], $query); } if (isset($params['type'])) { // Supports metatypes like _downloadable $types = array(); $typeInfos = aMediaTools::getTypeInfos($params['type']); foreach ($typeInfos as $name => $info) { $types[] = $name; } if (count($types)) { $query->andWhereIn("aMediaItem.type", $types); } else { $query->andWhere("0 <> 0"); } } if (isset($params['allowed_categories'])) { if (!count($params['allowed_categories'])) { $query->andWhere('0 <> 0'); } else { $query->innerJoin('aMediaItem.Categories mc1 WITH mc1.id IN (' . implode(',', aArray::getIds($params['allowed_categories'])) . ')'); } } if (isset($params['category'])) { $query->innerJoin('aMediaItem.Categories mc2 WITH mc2.slug = ?', array($params['category'])); } if (isset($params['search'])) { $query = Doctrine::getTable('aMediaItem')->addSearchQuery($query, $params['search']); } elseif (isset($params['ids'])) { // orderBy added by aDoctrine::orderByIds } else { // Reverse chrono order if we're not ordering them by search relevance $query->orderBy('aMediaItem.id desc'); } if (!sfContext::getInstance()->getUser()->hasCredential(sfConfig::get('app_a_view_locked_sufficient_credentials', 'view_locked'))) { $query->andWhere('aMediaItem.view_is_secure = false'); } if (isset($params['aspect-width']) && isset($params['aspect-height'])) { $query->andWhere('(aMediaItem.width * ? / ?) = aMediaItem.height', array($params['aspect-height'] + 0, $params['aspect-width'] + 0)); } if (isset($params['minimum-width'])) { $query->andWhere('aMediaItem.width >= ?', array($params['minimum-width'] + 0)); } if (isset($params['minimum-height'])) { $query->andWhere('aMediaItem.height >= ?', array($params['minimum-height'] + 0)); } if (isset($params['width'])) { $query->andWhere('aMediaItem.width = ?', array($params['width'] + 0)); } if (isset($params['height'])) { $query->andWhere('aMediaItem.height = ?', array($params['height'] + 0)); } // No crops in the browser please $query->andWhere("aMediaItem.slug NOT LIKE '%.%'"); $query->leftJoin("aMediaItem.Categories c"); return $query; }
/** * DOCUMENT ME * @param mixed $parents * @return mixed */ protected function getParentClasses($parents) { $result = ''; foreach ($parents as $p) { $result .= " descendantof-{$p}"; } if (count($parents)) { $lastParent = aArray::last($parents); $result .= " childof-{$lastParent}"; } if (count($parents) < 2) { $result .= " toplevel"; } return $result; }
/** * DOCUMENT ME * @param mixed $values * @return mixed */ public function updateCategoriesList(&$values) { $cvalues = isset($values['categories_list_add']) ? $values['categories_list_add'] : array(); $link = array(); if (!is_array($cvalues)) { $cvalues = array(); } foreach ($cvalues as $value) { $existing = Doctrine::getTable('aCategory')->findOneBy('name', $value); if ($existing) { $aCategory = $existing; } else { $aCategory = new aCategory(); $aCategory['name'] = $value; } $aCategory->save(); $link[] = $aCategory['id']; } if (!is_array($values['categories_list'])) { $values['categories_list'] = array(); } $values['categories_list'] = array_merge($link, $values['categories_list']); // Never allow a non-admin to remove categories they are not eligible to add $reserved = aArray::getIds($this->getAdminCategories()); foreach ($reserved as $id) { if (!in_array($id, $values['categories_list'])) { $values['categories_list'][] = $id; } } // Needed when this is an embedded form return $values['categories_list']; }