/** * Respond to Javascript callbacks * The name of this method is action_ajax_ followed by what you passed to the context parameter above. */ public function action_ajax_auto_tags( $handler ) { $selected = array(); if( isset( $handler->handler_vars['selected'] ) ) { $selected = Utils::single_array( $handler->handler_vars['selected'] ); } if( isset( $handler->handler_vars['term'] ) && MultiByte::strlen( $handler->handler_vars['term'] ) ) { $search = $handler->handler_vars['term'] . '%'; $tags = new Terms( DB::get_results( "SELECT * FROM {terms} WHERE vocabulary_id = :vid and LOWER(term_display) LIKE LOWER(:crit) ORDER BY term_display ASC", array( 'vid' => Tags::vocabulary()->id, 'crit' => $search ), 'Term' ) ); } else { $tags = Tags::vocabulary()->get_tree( 'term_display ASC' ); } $resp = array(); foreach ( $tags as $tag ) { $resp[] = MultiByte::strpos( $tag->term_display, ',' ) === false ? $tag->term_display : $tag->tag_text_searchable; } if( count( $selected ) ) { $resp = array_diff($resp, $selected ); } // Send the response // $ar = new AjaxResponse(); // $ar->data = $resp; // $ar->out(); echo json_encode( $resp ); }
/** * Match the stub against this rule * Also sets internal structures based on a successful match * @param string $stub The URL stub to match against * @return boolean True if this rule matches the stub, false if not */ public function match($stub) { if (preg_match($this->parse_regex, $stub, $pattern_matches) > 0) { $this->entire_match = array_shift($pattern_matches); // The entire matched string is returned at index 0 $named_args = $this->named_args; // Direct call shows a PHP notice $result = true; if (is_string($this->parameters) && ($parameters = unserialize($this->parameters)) || is_array($this->parameters) && ($parameters = $this->parameters)) { $this->named_arg_values = array_merge($this->named_arg_values, $parameters); } foreach ($named_args as $keys) { foreach ($keys as $key) { if (!empty($pattern_matches[$key])) { $this->named_arg_values[$key] = urldecode(str_replace('%252F', '%2F', $pattern_matches[$key])); } } } if (preg_match('/^\\{\\$(\\w+)\\}$/u', $this->action, $matches) > 0) { $this->action = $this->named_arg_values[$matches[1]]; } if (isset($parameters['require_match'])) { $result = call_user_func($parameters['require_match'], $this, $stub, $parameters); } if ($result && isset($parameters['require_permission'])) { foreach ($parameters['require_permission'] as $token => $access) { $access = Utils::single_array($access); foreach ($access as $mask) { if (is_bool($mask) && User::identify()->can($token)) { $result = true; break; } elseif (User::identify()->can($token, $mask)) { $result = true; break 2; } } } } return $result; } return false; }
/** * Checks if the currently logged in user has access to a page and post type. */ private function access_allowed($page, $type) { $user = User::identify(); $require_any = array(); $result = false; switch ($page) { case 'comment': case 'comments': case 'ajax_comments': case 'ajax_in_edit': case 'ajax_update_comment': $require_any = array('manage_all_comments' => true, 'manage_own_post_comments' => true); break; case 'tags': case 'ajax_tags': $require_any = array('manage_tags' => true); break; case 'options': $require_any = array('manage_options' => true); break; case 'themes': $require_any = array('manage_themes' => true, 'manage_theme_config' => true); break; case 'activate_theme': $require_any = array('manage_themes' => true); break; case 'preview_theme': $require_any = array('manage_themes' => true); break; case 'plugins': $require_any = array('manage_plugins' => true, 'manage_plugins_config' => true); break; case 'plugin_toggle': $require_any = array('manage_plugins' => true); break; case 'import': $require_any = array('manage_import' => true); break; case 'users': case 'ajax_update_users': case 'ajax_users': $require_any = array('manage_users' => true); break; case 'user': $require_any = array('manage_users' => true, 'manage_self' => true); break; case 'groups': case 'group': case 'ajax_update_groups': case 'ajax_groups': $require_any = array('manage_groups' => true); break; case 'logs': case 'ajax_delete_logs': case 'ajax_logs': $require_any = array('manage_logs' => true); break; case 'publish': case 'ajax_media': case 'ajax_media_panel': $type = Post::type_name($type); $require_any = array('post_any' => array(ACL::get_bitmask('create'), ACL::get_bitmask('edit')), 'post_' . $type => array(ACL::get_bitmask('create'), ACL::get_bitmask('edit')), 'own_posts' => array(ACL::get_bitmask('create'), ACL::get_bitmask('edit'))); break; case 'delete_post': $type = Post::type_name($type); $require_any = array('post_any' => ACL::get_bitmask('delete'), 'post_' . $type => ACL::get_bitmask('delete'), 'own_posts' => ACL::get_bitmask('delete')); break; case 'posts': case 'ajax_posts': case 'ajax_delete_entries': case 'ajax_update_entries': $require_any = array('post_any' => array(ACL::get_bitmask('delete'), ACL::get_bitmask('edit')), 'own_posts' => array(ACL::get_bitmask('delete'), ACL::get_bitmask('edit'))); foreach (Post::list_active_post_types() as $type => $type_id) { $require_any['post_' . $type] = array(ACL::get_bitmask('delete'), ACL::get_bitmask('edit')); } break; case 'sysinfo': $require_any = array('super_user' => true); break; case 'dashboard': case 'ajax_dashboard': $result = true; break; case 'ajax_add_block': $result = true; break; case 'ajax_delete_block': $result = true; break; case 'configure_block': $result = true; break; case 'ajax_save_areas': $result = true; break; default: break; } $require_any = Plugins::filter('admin_access_tokens', $require_any, $page, $type); foreach ($require_any as $token => $access) { $access = Utils::single_array($access); foreach ($access as $mask) { if (is_bool($mask) && $user->can($token)) { $result = true; break; } elseif ($user->can($token, $mask)) { $result = true; break 2; } } } $result = Plugins::filter('admin_access', $result, $page, $type); return $result; }
/** * Returns a LogEntry or EventLog array based on supplied parameters. * By default,fetch as many entries as pagination allows and order them in a descending fashion based on timestamp. * * @todo Cache query results. * @param array $paramarray An associated array of parameters, or a querystring * The following keys are supported: * - id => an entry id or array of post ids * - user_id => id of the logged in user for which to return entries * - severity => severity level for which to return entries * - type_id => the numeric id or array of ids for the type of entries for which which to return entries * - module => a name or array of names of modules for which to return entries * - type => a single type name or array of type names for which to return entries * - ip => the IP number for which to return entries * - criteria => a literal search string to match entry message content or a special search * - day => a day of entry creation, ignored if month and year are not specified * - month => a month of entry creation, ignored if year isn't specified * - year => a year of entry creation * - orderby => how to order the returned entries * - fetch_fn => the function used to fetch data, one of 'get_results', 'get_row', 'get_value' * - count => return the number of entries that would be returned by this request * - month_cts => return the number of entries created in each month * - nolimit => do not implicitly set limit * - limit => the maximum number of entries to return, implicitly set for many queries * - index => * - offset => amount by which to offset returned entries, used in conjunction with limit * - where => manipulate the generated WHERE clause * - return_data => set to return the data associated with the entry * * @return array An array of LogEntry objects, or a single LogEntry object, depending on request */ public static function get($paramarray = array()) { $params = array(); $fns = array('get_results', 'get_row', 'get_value'); $select_ary = array(); $select_distinct = array(); // Put incoming parameters into the local scope $paramarray = Utils::get_params($paramarray); if ($paramarray instanceof \ArrayIterator) { $paramarray = $paramarray->getArrayCopy(); } $select_fields = LogEntry::default_fields(); if (!isset($paramarray['return_data'])) { unset($select_fields['data']); } foreach ($select_fields as $field => $value) { if (preg_match('/(?:(?P<table>[\\w\\{\\}]+)\\.)?(?P<field>\\w+)(?:(?:\\s+as\\s+)(?P<alias>\\w+))?/i', $field, $fielddata)) { if (empty($fielddata['table'])) { $fielddata['table'] = '{log}'; } if (empty($fielddata['alias'])) { $fielddata['alias'] = $fielddata['field']; } } $select_ary[$fielddata['alias']] = "{$fielddata['table']}.{$fielddata['field']} AS {$fielddata['alias']}"; $select_distinct[$fielddata['alias']] = "{$fielddata['table']}.{$fielddata['field']}"; } // Transact on possible multiple sets of where information that is to be OR'ed if (isset($paramarray['where']) && is_array($paramarray['where'])) { $wheresets = $paramarray['where']; } else { $wheresets = array(array()); } $query = Query::create('{log}'); $query->select($select_ary); if (isset($paramarray['where']) && is_string($paramarray['where'])) { $query->where()->add($paramarray['where']); } foreach ($wheresets as $paramset) { $where = new QueryWhere(); $paramset = array_merge((array) $paramarray, (array) $paramset); if (isset($paramset['id'])) { $where->in('{log}.id', $paramset['id'], 'log_id', 'intval'); } if (isset($paramset['user_id'])) { $where->in('{log}.user_id', $paramset['user_id'], 'log_user_id', 'intval'); } if (isset($paramset['severity']) && 'any' != LogEntry::severity_name($paramset['severity'])) { $where->in('{log}.severity_id', $paramset['severity'], 'log_severity_id', function ($a) { return LogEntry::severity($a); }); } if (isset($paramset['type_id'])) { $where->in('{log}.type_id', $paramset['type_id'], 'log_type_id', 'intval'); } if (isset($paramset['module'])) { $paramset['module'] = Utils::single_array($paramset['module']); $qry = Query::create('{log_types}'); $qry->select('{log_types}.id')->distinct(); $qry->where()->in('{log_types}.module', $paramset['module'], 'log_subquery_module'); $where->in('{log}.type_id', $qry, 'log_module'); } if (isset($paramset['type'])) { $paramset['type'] = Utils::single_array($paramset['type']); $qry = Query::create('{log_types}'); $qry->select('{log_types}.id')->distinct(); $qry->where()->in('{log_types}.type', $paramset['type'], 'log_subquery_type'); $where->in('{log}.type_id', $qry, 'log_type'); } if (isset($paramset['ip'])) { $where->in('{log}.ip', $paramset['ip']); } /* do searching */ if (isset($paramset['criteria'])) { // this regex matches any unicode letters (\p{L}) or numbers (\p{N}) inside a set of quotes (but strips the quotes) OR not in a set of quotes preg_match_all('/(?<=")(\\w[^"]*)(?=")|([:\\w]+)/u', $paramset['criteria'], $matches); foreach ($matches[0] as $word) { if (preg_match('%^id:(\\d+)$%i', $word, $special_crit)) { $where->in('{log}.id', $special_crit[1], 'log_special_criteria'); } else { $crit_placeholder = $query->new_param_name('criteria'); $where->add("( LOWER( {log}.message ) LIKE :{$crit_placeholder}", array($crit_placeholder => '%' . MultiByte::strtolower($word) . '%')); } } } /** * Build the pubdate * If we've got the day, then get the date. * If we've got the month, but no date, get the month. * If we've only got the year, get the whole year. * * @todo Ensure that we've actually got all the needed parts when we query on them */ if (isset($paramset['day']) && isset($paramset['month']) && isset($paramset['year'])) { $start_date = sprintf('%d-%02d-%02d', $paramset['year'], $paramset['month'], $paramset['day']); $start_date = DateTime::create($start_date); $where->add('timestamp BETWEEN :start_date AND :end_date', array('start_date' => $start_date->sql, 'end_date' => $start_date->modify('+1 day -1 second')->sql)); } elseif (isset($paramset['month']) && isset($paramset['year'])) { $start_date = sprintf('%d-%02d-%02d', $paramset['year'], $paramset['month'], 1); $start_date = DateTime::create($start_date); $where->add('timestamp BETWEEN :start_date AND :end_date', array('start_date' => $start_date->sql, 'end_date' => $start_date->modify('+1 month -1 second')->sql)); } elseif (isset($paramset['year'])) { $start_date = sprintf('%d-%02d-%02d', $paramset['year'], 1, 1); $start_date = DateTime::create($start_date); $where->add('timestamp BETWEEN :start_date AND :end_date', array('start_date' => $start_date->sql, 'end_date' => $start_date->modify('+1 year -1 second')->sql)); } // Concatenate the WHERE clauses $query->where()->add($where); } // Default parameters. $orderby = 'timestamp DESC, id DESC'; // $limit = Options::get( 'pagination' ); // Get any full-query parameters $paramarray = new SuperGlobal($paramarray); $extract = $paramarray->filter_keys('orderby', 'fetch_fn', 'count', 'month_cts', 'nolimit', 'index', 'limit', 'offset'); foreach ($extract as $key => $value) { ${$key} = $value; } if (isset($index) && is_numeric($index)) { $offset = (intval($index) - 1) * intval($limit); } if (isset($fetch_fn)) { if (!in_array($fetch_fn, $fns)) { $fetch_fn = $fns[0]; } } else { $fetch_fn = $fns[0]; } if (isset($count)) { $query->set_select("COUNT({$count})"); $fetch_fn = isset($paramarray['fetch_fn']) ? $fetch_fn : 'get_value'; $orderby = null; $groupby = null; $having = null; } // If the month counts are requested, replace the select clause if (isset($paramset['month_cts'])) { // @todo shouldn't this hand back to habari to convert to DateTime so it reflects the right timezone? $query->set_select('MONTH(FROM_UNIXTIME(timestamp)) AS month, YEAR(FROM_UNIXTIME(timestamp)) AS year, COUNT(*) AS ct'); $groupby = 'year, month'; if (!isset($paramarray['orderby'])) { $orderby = 'year, month'; } } if (isset($nolimit) || isset($month_cts)) { $limit = null; } // Define the LIMIT, OFFSET, ORDER BY, GROUP BY if they exist if (isset($limit)) { $query->limit($limit); } if (isset($offset)) { $query->offset($offset); } if (isset($orderby)) { $query->orderby($orderby); } if (isset($groupby)) { $query->groupby($groupby); } /* if(isset($paramarray['type'])) { print_r($query->params()); print_r($query->get());die(); } */ /* All SQL parts are constructed, on to real business! */ DB::set_fetch_mode(\PDO::FETCH_CLASS); DB::set_fetch_class('LogEntry'); $results = DB::$fetch_fn($query->get(), $query->params(), 'LogEntry'); // If the fetch callback function is not get_results, // return an EventLog ArrayObject filled with the results as LogEntry objects. if ('get_results' != $fetch_fn) { return $results; } elseif (is_array($results)) { $c = __CLASS__; $return_value = new $c($results); $return_value->get_param_cache = $paramarray; return $return_value; } }
/** * A theme function for outputting CSS classes based on the requested content * @param Theme $theme A Theme object instance * @param mixed $args Additional classes that should be added to the ones generated * @return string The resultant classes */ function theme_body_class($theme, $args = array()) { $body_class = array(); foreach (get_object_vars($this->request) as $key => $value) { if ($value) { $body_class[$key] = $key; } } $body_class = array_unique(array_merge($body_class, Stack::get_named_stack('body_class'), Utils::single_array($args))); $body_class = Plugins::filter('body_class', $body_class, $theme); return implode(' ', $body_class); }
/** * Produce a form with the contained fields. * * @param boolean $process_for_success Set to true to display the form as it would look if the submission succeeded, but do not execute success methods. * @return string HTML form generated from all controls assigned to this form */ public function get($use_theme = null, $process_for_success = true) { $forvalidation = false; Plugins::act('modify_form_' . Utils::slugify($this->formtype, '_'), $this); Plugins::act('modify_form', $this); if (isset($use_theme)) { $theme = $use_theme; } else { $theme = $this->get_theme($forvalidation, $this); } $theme->start_buffer(); $theme->success = false; $this->success = false; $this->submitted = false; $this->properties['id'] = isset($this->properties['id']) ? $this->properties['id'] : Utils::slugify($this->name); // Should we be validating? if (isset($_POST['FormUI']) && $_POST['FormUI'] == $this->salted_name()) { $this->submitted = true; $validate = $this->validate(); if (count($validate) == 0) { if ($process_for_success) { $result = $this->success(); if ($result) { return $result; } } $theme->success = true; $this->success = true; $theme->message = $this->options['success_message']; } else { $forvalidation = true; if (!isset($_SESSION['forms'][$this->salted_name()]['url'])) { $_SESSION['forms'][$this->salted_name()]['url'] = Site::get_url('habari', true) . Controller::get_stub() . '#' . $this->properties['id']; } } } else { $_SESSION['forms'][$this->salted_name()]['url'] = Site::get_url('habari', true) . Controller::get_stub() . '#' . $this->properties['id']; } if (isset($_SESSION['forms'][$this->salted_name()]['error_data'])) { foreach ($_SESSION['forms'][$this->salted_name()]['error_data'] as $key => $value) { $_POST[$key] = $value; } unset($_SESSION['forms'][$this->salted_name()]['error_data']); $forvalidation = true; } $out = ''; $theme->controls = $this->output_controls($forvalidation); $theme->form = $this; foreach ($this->properties as $prop => $value) { $theme->{$prop} = $value; } $theme->class = Utils::single_array($this->class); $this->action = $this->options['form_action']; $theme->salted_name = $this->salted_name(); $theme->pre_out = $this->pre_out_controls(); $out = $this->prefix . $theme->display_fallback($this->options['template'], 'fetch') . $this->postfix; $theme->end_buffer(); return $out; }
/** * Remove one or more permissions from a group * @param mixed a permission ID, name, or array of the same */ public function revoke( $tokens ) { $tokens = Utils::single_array( $tokens ); $tokens = array_map( array( 'ACL', 'token_id' ), $tokens ); foreach ( $tokens as $token ) { ACL::revoke_group_token( $this->id, $token ); } }
/** * Add links to the main atom feed */ public function filter_atom_get_collection_content_type($content_type) { $content_type = Utils::single_array($content_type); $content_type[] = Post::type('link'); return $content_type; }
/** * Return the property value that is associated with the first present property from an array list * This version only searches the list of the class' $properties array, because __get() on this objcet returns named FormControls instances * @param array $tag_fields A list of potential fields to try * @return bool|string False if no value found, string of the property value found */ public function get_value_out($tag_fields) { $properties = array_merge($this->properties, get_object_vars($this)); $value_out = false; foreach (Utils::single_array($tag_fields) as $tag_field) { if (isset($properties[$tag_field])) { $value_out = $properties[$tag_field]; break; } } return $value_out; }
/** * Sets fields for the SELECT statement * @param array|string $fields A field or list of fields to set as the fields to select, replaces existing selected fields * @return Query Returns $this for fluid interface */ public function set_select($fields) { $this->fields = Utils::single_array($fields); return $this; }
/** * Search directories for templates to use * Templates are always taken from the first directory they're found in. * To override this behavior, the template must be specifically added via ->add_template() * @see add_template * @param string|array $dirs A directory to look for templates in */ public function queue_dirs($dirs) { $dirs = Utils::single_array($dirs); $alltemplates = array(); // If multiple directories are passed, the earlier ones should override the later ones $dirs = array_reverse($dirs); foreach ($dirs as $dir) { $templates = Utils::glob(Utils::end_in_slash($dir) . '*.*'); $alltemplates = array_merge($alltemplates, $templates); } // Convert the template files into template names and produce a map from name => file $available_templates = array_map('basename', $alltemplates, array_fill(1, count($alltemplates), '.php')); $template_map = array_combine($available_templates, $alltemplates); $this->template_map = array_merge($this->template_map, $template_map); // Workaround for the 404 template key being merged into the 0 integer index unset($this->template_map[0]); if (isset($template_map[404])) { $this->template_map['404'] = $template_map[404]; } // The templates in the list should be uniquely identified array_unique($available_templates); // Filter the templates that are available $available_templates = Plugins::filter('available_templates', $available_templates, __CLASS__); $this->available_templates = array_merge($available_templates, $this->available_templates); }
/** * Display an object using a template designed for the type of object it is * The $object is assigned into the theme using the $content template variable * * @param Theme $theme The theme used to display the object * @param object $object An object to display * @param string $context The context in which the object will be displayed * @return */ public function theme_content($theme, $object, $context = null) { $fallback = array(); $content_types = array(); if ($object instanceof IsContent) { $content_types = Utils::single_array($object->content_type()); } $content_types[] = 'content'; $content_types = array_flip($content_types); if (isset($context)) { foreach ($content_types as $type => $type_id) { $content_type = $context . $object->content_type(); $fallback[] = strtolower($context . '.' . $type); } $fallback[] = strtolower($context); } foreach ($content_types as $type => $type_id) { $fallback[] = strtolower($type); } $this->content = $object; return $this->display_fallback($fallback, 'fetch'); }
/** * Add the 'events' type to the list of templates that we can use. **/ public function filter_template_user_filters($filters) { if(isset($filters['content_type'])) { $filters['content_type']= Utils::single_array( $filters['content_type'] ); $filters['content_type'][]= Post::type('product'); } return $filters; }
public function filter_posts_get_update_preset($preset_parameters, $presetname, $paramarray) { switch ($presetname) { case 'home': $content_type = isset($preset_parameters['content_type']) ? Utils::single_array($preset_parameters['content_type']) : array(); $content_type[] = 'tweet'; $preset_parameters['content_type'] = $content_type; break; } return $preset_parameters; }
/** * Remove permissions to one or more tokens from a user * @param mixed a token ID, name, or array of the same **/ public function revoke($tokens) { $tokens = Utils::single_array($tokens); // get token IDs $tokens = array_map(array('ACL', 'token_id'), $tokens); foreach ($tokens as $token) { ACL::revoke_user_permission($this->id, $token); EventLog::log(_t('User %1$s: Permission to %2$s revoked.', array($this->username, ACL::token_name($token))), 'notice', 'user', 'habari'); } }
/** * Accepts a set of term query qualifiers and converts it into a multi-dimensional array * of vocabulary (ie: tags), matching method (any, all, not), matching field (id, term, term_display), and list of terms * * @return array An array of parsed term-matching conditions */ private static function vocabulary_params($params) { $return = array(); foreach ($params as $key => $value) { // split vocab off the beginning of the key if (strpos($key, ':') !== false) { list($newkey, $subkey) = explode(':', $key, 2); $params[$newkey][$subkey] = $value; unset($params[$key]); } } foreach ($params as $vocab => $values) { foreach ($values as $key => $value) { $value = Utils::single_array($value); // if there's a colon we've got a mode and a field if (strpos($key, ':') !== false) { list($mode, $by_field) = explode(':', $key, 2); foreach ($value as $v) { $return[$mode][$vocab][$by_field][] = $v; } } else { // if there's no colon we've got a single field name foreach ($value as $v) { if ($v instanceof Term) { // $vocab is not a vocab, but the mode - always match by its ID for the best performance $return[$vocab][$v->vocabulary->name]['id'][] = $v->id; } else { $return['any'][$vocab][$key][] = $v; } } } } } return $return; }
/** * Changes the status of comments * @param array|Comments $comments Comments to be moderated * @param int|string $status The new status for the provided array of comments, "unapproved" if not provided * @return bool True if all the comments were successfully changed * @internal param \Comment $mixed IDs to moderate. May be a single ID, or an array of IDs */ public static function moderate_these($comments, $status = null) { if (empty($status)) { $status = Comment::status('unapproved'); } // Ensure we have an id, not a string $status = Comment::status($status); $comments = Utils::single_array($comments); if (count($comments) == 0) { return false; } if ($comments[0] instanceof Comment) { // We were passed an array of comment objects. Use them directly. $result = true; /** @var Comment $comment */ foreach ($comments as $comment) { $comment->status = $status; $result &= $comment->update(); EventLog::log(_t('Comment %1$s moderated from %2$s', array($comment->id, $comment->post->title)), 'info', 'comment', 'habari'); } } else { if (is_numeric($comments[0])) { $result = true; foreach ($comments as $commentid) { $result &= DB::update(DB::table('comments'), array('status' => $status), array('id' => $commentid)); EventLog::log(_t('Comment %1$d moderated', array($commentid)), 'info', 'comment', 'habari'); } } else { // We were passed a type we could not understand. return false; } } return $result; }
/** * Add one or more CSS classes to this control's template * @param string $target The name of the targeted element in the control template * @param array|string $classes An array or a string of classes to add to this control's template * @return FormControl $this */ public function add_template_class($target, $classes) { if (!isset($this->settings['template_attributes'])) { $this->settings['template_attributes'] = array(); } if (!isset($this->settings['template_attributes'][$target])) { $this->settings['template_attributes'][$target] = array(); } if (!isset($this->settings['template_attributes'][$target]['class'])) { $this->settings['template_attributes'][$target]['class'] = array(); } $this->settings['template_attributes'][$target]['class'] = array_merge(Utils::single_array($this->settings['template_attributes'][$target]['class']), explode(' ', $classes)); return $this; }
/** * Returns a named Theme descendant. * If no parameter is supplied, then * load the active theme from the database. * * If no theme option is set, a fatal error is thrown * * @param name ( optional ) override the default theme lookup * @param template_engine ( optional ) specify a template engine * @param theme_dir ( optional ) specify a theme directory **/ public static function create($name = null, $template_engine = null, $theme_dir = null) { static $bound = array(); $hash = md5(serialize(array($name, $template_engine, $theme_dir))); if (isset($bound[$hash])) { return $bound[$hash]; } // If the name is not supplied, load the active theme if (empty($name)) { $themedata = self::get_active(); if (empty($themedata)) { die(_t('Theme not installed.')); } } else { $themedata = self::get_by_name($name); } // If a theme wasn't found by name, create a blank object if (!$themedata) { $themedata = array(); $themedata['name'] = $name; $themedata['version'] = 0; } // If a specific template engine was supplied, use it if (!empty($template_engine)) { $themedata['template_engine'] = $template_engine; } // If a theme directory was supplied, use the directory that was supplied if (!empty($theme_dir)) { $themedata['theme_dir'] = $theme_dir; } // Set the default theme file $themefile = 'theme.php'; if (isset($themedata['info']->class['file']) && (string) $themedata['info']->class['file'] != '') { $themefile = (string) $themedata->xml->class['file']; } // Convert themedata to QueryRecord for legacy purposes // @todo: Potentially break themes by sending an array to the constructor instead of this QueryRecord $themedata = new QueryRecord($themedata); // Deal with parent themes if (isset($themedata->parent)) { // @todo If the parent theme doesn't exist, provide a useful error $parent_data = self::get_by_name($themedata->parent); $parent_themefile = 'theme.php'; if (isset($parent_data['info']->class['file']) && (string) $parent_data['info']->class['file'] != '') { $parent_themefile = (string) $parent_data['info']->class['file']; } include_once $parent_data['theme_dir'] . $parent_themefile; $themedata->parent_theme_dir = Utils::single_array($parent_data['theme_dir']); $themedata->theme_dir = array_merge(Utils::single_array($themedata->theme_dir), $themedata->parent_theme_dir); } $primary_theme_dir = $themedata->theme_dir; $primary_theme_dir = is_array($primary_theme_dir) ? reset($primary_theme_dir) : $primary_theme_dir; // Include the theme class file if (file_exists($primary_theme_dir . $themefile)) { include_once $primary_theme_dir . $themefile; } if (isset($themedata->class)) { $classname = $themedata->class; } else { $classname = self::class_from_filename($primary_theme_dir . $themefile); } // the final fallback, for the admin "theme" if ($classname == '') { $classname = 'Theme'; } $created_theme = new $classname($themedata); $created_theme->upgrade(); Plugins::act_id('init_theme', $created_theme->plugin_id(), $created_theme); Plugins::act('init_theme_any', $created_theme); $bound[$hash] = $created_theme; return $created_theme; }
/** * Applies a new set of specific tokens to a post * @param mixed $tokens A string token, or an array of tokens to apply to this post */ public function set_tokens( $tokens ) { $tokens = Utils::single_array( $tokens ); $new_tokens = array_map( array( 'ACL', 'token_id' ), $tokens ); $new_tokens = array_unique( $new_tokens ); DB::delete( '{post_tokens}', array( 'post_id' => $this->id ) ); foreach ( $new_tokens as $token_id ) { DB::insert( '{post_tokens}', array( 'post_id' => $this->id, 'token_id' => $token_id ) ); } $this->tokens = $new_tokens; }
/** * Handles AJAX from /admin/tags * Used to search for, delete and rename tags */ public function ajax_tags() { Utils::check_request_method(array('POST', 'HEAD')); $this->create_theme(); $params = $_POST['query']; // Get a usable array with filter parameters from the odd syntax we received from the faceted search $fetch_params = array(); if (isset($params)) { foreach ($params as $param) { $key = key($param); // Revert translation if ($key != 'text') { $key = self::$facets[$key]; } $value = current($param); if (array_key_exists($key, $fetch_params)) { $fetch_params[$key] = Utils::single_array($fetch_params[$key]); $fetch_params[$key][] = $value; } else { $fetch_params[$key] = $value; } } } // Grab facets / params $search = array_key_exists('text', $fetch_params) ? $fetch_params['text'] : null; $min = array_key_exists('morethan', $fetch_params) ? $fetch_params['morethan'] + 1 : 0; $max = array_key_exists('lessthan', $fetch_params) ? $fetch_params['lessthan'] - 1 : null; $orderby_code = array_key_exists('orderby', $fetch_params) ? $fetch_params['orderby'] : null; $orderby = isset($orderby_code) ? explode('_', self::$facet_values['orderby'][$orderby_code]) : ['alphabetical', 'asc']; $this->theme->tags = Tags::get_by_frequency(null, null, $min, $max, $search, self::$orderby_translate[$orderby[0]], $orderby[1] == 'asc'); // Create FormUI elements (list items) from the filtered tag list $this->theme->max = Tags::vocabulary()->max_count(); $this->theme->min = Tags::vocabulary()->min_count(); $output = ''; if (count($this->theme->tags) > 0) { $listitems = $this->get_tag_listitems(); // Get HTML from FormUI foreach ($listitems as $listitem) { $output .= $listitem->get($this->theme); } } $ar = new AjaxResponse(); $ar->html('#tag_collection', $output); $ar->out(); }
/** * Returns a post or posts based on supplied parameters. * <b>THIS CLASS SHOULD CACHE QUERY RESULTS!</b> * * @param array $paramarry An associated array of parameters, or a querystring * @return array An array of Post objects, or a single post object, depending on request */ public static function get($paramarray = array()) { $join_params = array(); $params = array(); $fns = array('get_results', 'get_row', 'get_value'); $select_ary = array(); // Default fields to select, everything by default foreach (Post::default_fields() as $field => $value) { $select_ary[$field] = "{posts}.{$field} AS {$field}"; } // Default parameters $orderby = 'pubdate DESC'; // If $paramarray is a querystring, convert it to an array $paramarray = Utils::get_params($paramarray); // Define the WHERE sets to process and OR in the final SQL statement if (isset($paramarray['where']) && is_array($paramarray['where'])) { $wheresets = $paramarray['where']; } else { $wheresets = array(array()); } /* Start building the WHERE clauses */ $wheres = array(); $joins = array(); // If the request as a textual WHERE clause, skip the processing of the $wheresets since it's empty if (isset($paramarray['where']) && is_string($paramarray['where'])) { $wheres[] = $paramarray['where']; } else { foreach ($wheresets as $paramset) { // Safety mechanism to prevent empty queries $where = array(); $paramset = array_merge((array) $paramarray, (array) $paramset); // $nots= preg_grep( '%^not:(\w+)$%iu', (array) $paramset ); if (isset($paramset['id'])) { if (is_array($paramset['id'])) { array_walk($paramset['id'], create_function('&$a,$b', '$a = intval($a);')); $where[] = "{posts}.id IN (" . implode(',', array_fill(0, count($paramset['id']), '?')) . ")"; $params = array_merge($params, $paramset['id']); } else { $where[] = "{posts}.id = ?"; $params[] = (int) $paramset['id']; } } if (isset($paramset['not:id'])) { if (is_array($paramset['not:id'])) { array_walk($paramset['not:id'], create_function('&$a,$b', '$a = intval($a);')); $where[] = "{posts}.id NOT IN (" . implode(',', array_fill(0, count($paramset['not:id']), '?')) . ")"; $params = array_merge($params, $paramset['not:id']); } else { $where[] = "{posts}.id != ?"; $params[] = (int) $paramset['not:id']; } } if (isset($paramset['status']) && $paramset['status'] != 'any' && 0 !== $paramset['status']) { if (is_array($paramset['status'])) { // remove 'any' from the list if we have an array $paramset['status'] = array_diff($paramset['status'], array('any')); array_walk($paramset['status'], create_function('&$a,$b', '$a = Post::status($a);')); $where[] = "{posts}.status IN (" . implode(',', array_fill(0, count($paramset['status']), '?')) . ")"; $params = array_merge($params, $paramset['status']); } else { $where[] = "{posts}.status = ?"; $params[] = (int) Post::status($paramset['status']); } } if (isset($paramset['content_type']) && $paramset['content_type'] != 'any' && 0 !== $paramset['content_type']) { if (is_array($paramset['content_type'])) { // remove 'any' from the list if we have an array $paramset['content_type'] = array_diff($paramset['content_type'], array('any')); array_walk($paramset['content_type'], create_function('&$a,$b', '$a = Post::type($a);')); $where[] = "{posts}.content_type IN (" . implode(',', array_fill(0, count($paramset['content_type']), '?')) . ")"; $params = array_merge($params, $paramset['content_type']); } else { $where[] = "{posts}.content_type = ?"; $params[] = (int) Post::type($paramset['content_type']); } } if (isset($paramset['not:content_type'])) { if (is_array($paramset['not:content_type'])) { array_walk($paramset['not:content_type'], create_function('&$a,$b', '$a = Post::type($a);')); $where[] = "{posts}.content_type NOT IN (" . implode(',', array_fill(0, count($paramset['not:content_type']), '?')) . ")"; $params = array_merge($params, $paramset['not:content_type']); } else { $where[] = "{posts}.content_type != ?"; $params[] = (int) Post::type($paramset['not:content_type']); } } if (isset($paramset['slug'])) { if (is_array($paramset['slug'])) { $where[] = "{posts}.slug IN (" . implode(',', array_fill(0, count($paramset['slug']), '?')) . ")"; $params = array_merge($params, $paramset['slug']); } else { $where[] = "{posts}.slug = ?"; $params[] = (string) $paramset['slug']; } } if (isset($paramset['user_id']) && 0 !== $paramset['user_id']) { if (is_array($paramset['user_id'])) { array_walk($paramset['user_id'], create_function('&$a,$b', '$a = intval($a);')); $where[] = "{posts}.user_id IN (" . implode(',', array_fill(0, count($paramset['user_id']), '?')) . ")"; $params = array_merge($params, $paramset['user_id']); } else { $where[] = "{posts}.user_id = ?"; $params[] = (int) $paramset['user_id']; } } if (isset($paramset['tag']) || isset($paramset['tag_slug'])) { $joins['tag2post_posts'] = ' JOIN {object_terms} ON {posts}.id = {object_terms}.object_id'; $joins['tags_tag2post'] = ' JOIN {terms} ON {object_terms}.term_id = {terms}.id'; if (isset($paramset['tag'])) { if (is_array($paramset['tag'])) { $where[] = "{terms}.term_display IN (" . implode(',', array_fill(0, count($paramset['tag']), '?')) . ")" . ' AND {object_terms}.object_type_id = ?'; $params = array_merge($params, $paramset['tag']); } else { $where[] = '{terms}.term_display = ? AND {object_terms}.object_type_id = ?'; $params[] = (string) $paramset['tag']; } } if (isset($paramset['tag_slug'])) { if (is_array($paramset['tag_slug'])) { $where[] = "{terms}.term IN (" . implode(',', array_fill(0, count($paramset['tag_slug']), '?')) . ")" . ' AND {object_terms}.object_type_id = ?'; $params = array_merge($params, $paramset['tag_slug']); } else { $where[] = '{terms}.term= ? AND {object_terms}.object_type_id = ?'; $params[] = (string) $paramset['tag_slug']; } } $params[] = Vocabulary::object_type_id(Tags::object_type()); } if (isset($paramset['all:tag'])) { $joins['tag2post_posts'] = ' JOIN {object_terms} ON {posts}.id = {object_terms}.object_id'; $joins['tags_tag2post'] = ' JOIN {terms} ON {object_terms}.term_id = {terms}.id'; if (is_array($paramset['all:tag'])) { $where[] = '{terms}.term_display IN (' . Utils::placeholder_string($paramset['all:tag']) . ')' . ' AND {object_terms}.object_type_id = ?'; $params = array_merge($params, $paramset['all:tag']); $groupby = '{posts}.id'; $having = 'count(*) = ' . count($paramset['all:tag']); } else { // this is actually the same as plain 'tag' for a single tag search - go with it $where[] = '{terms}.term_display = ? AND {object_terms}.object_type_id = ?'; $params[] = $paramset['all:tag']; } $params[] = Vocabulary::object_type_id(Tags::object_type()); } if (isset($paramset['all:tag_slug'])) { $joins['tag2post_posts'] = ' JOIN {object_terms} ON {posts}.id = {object_terms}.object_id'; $joins['tags_tag2post'] = ' JOIN {terms} ON {object_terms}.term_id = {terms}.id'; if (is_array($paramset['all:tag_slug'])) { $where[] = '{terms}.term IN (' . Utils::placeholder_string($paramset['all:tag_slug']) . ')' . ' AND {object_terms}.object_type_id = ?'; $params = array_merge($params, $paramset['all:tag_slug']); $groupby = '{posts}.id'; $having = 'count(*) = ' . count($paramset['all:tag_slug']); } else { // this is actually the same as plain 'tag' for a single tag search - go with it $where[] = '{terms}.term = ? AND {object_terms}.object_type_id = ?'; $params[] = $paramset['all:tag_slug']; } $params[] = Vocabulary::object_type_id(Tags::object_type()); } if (isset($paramset['not:tag'])) { $nottag = Utils::single_array($paramset['not:tag']); $where[] = 'NOT EXISTS (SELECT 1 FROM {object_terms} INNER JOIN {terms} ON {terms}.id = {object_terms}.term_id WHERE {terms}.term_display IN (' . Utils::placeholder_string($nottag) . ') AND {object_terms}.object_id = {posts}.id AND {object_terms}.object_type_id = ?) '; $params = array_merge($params, $nottag); $params[] = Vocabulary::object_type_id(Tags::object_type()); } if (isset($paramset['not:tag_slug'])) { $nottag = Utils::single_array($paramset['not:tag_slug']); $where[] = 'NOT EXISTS (SELECT 1 FROM {object_terms} INNER JOIN {terms} ON {terms}.id = {object_terms}.term_id WHERE {terms}.term_display IN (' . Utils::placeholder_string($nottag) . ') AND {object_terms}.object_id = {posts}.id AND {object_terms}.object_type_id = ?) '; $params = array_merge($params, $nottag); $params[] = Vocabulary::object_type_id(Tags::object_type()); } if (isset($paramset['criteria'])) { preg_match_all('/(?<=")([\\p{L}\\p{N}]+[^"]*)(?=")|([\\p{L}\\p{N}]+)/u', $paramset['criteria'], $matches); foreach ($matches[0] as $word) { $where[] .= "({posts}.title LIKE CONCAT('%',?,'%') OR {posts}.content LIKE CONCAT('%',?,'%'))"; $params[] = $word; $params[] = $word; // Not a typo (there are two ? in the above statement) } } if (isset($paramset['all:info']) || isset($paramset['info'])) { // merge the two possibile calls together $infos = array_merge(isset($paramset['all:info']) ? $paramset['all:info'] : array(), isset($paramset['info']) ? $paramset['info'] : array()); if (Utils::is_traversable($infos)) { $pi_count = 0; foreach ($infos as $info_key => $info_value) { $pi_count++; $joins['info_' . $info_key] = " LEFT JOIN {postinfo} ipi{$pi_count} ON {posts}.id = ipi{$pi_count}.post_id AND ipi{$pi_count}.name = ? AND ipi{$pi_count}.value = ?"; $join_params[] = $info_key; $join_params[] = $info_value; $where[] = "ipi{$pi_count}.name <> ''"; $select_ary["info_{$info_key}_value"] = "ipi{$pi_count}.value AS info_{$info_key}_value"; } } } if (isset($paramset['any:info'])) { if (Utils::is_traversable($paramset['any:info'])) { $pi_count = 0; $pi_where = array(); foreach ($paramset['any:info'] as $info_key => $info_value) { $pi_count++; $join_params[] = $info_key; if (is_array($info_value)) { $joins['any_info_' . $info_key] = " LEFT JOIN {postinfo} aipi{$pi_count} ON {posts}.id = aipi{$pi_count}.post_id AND aipi{$pi_count}.name = ? AND aipi{$pi_count}.value IN (" . Utils::placeholder_string(count($info_value)) . ")"; $join_params = array_merge($join_params, $info_value); } else { $joins['any_info_' . $info_key] = " LEFT JOIN {postinfo} aipi{$pi_count} ON {posts}.id = aipi{$pi_count}.post_id AND aipi{$pi_count}.name = ? AND aipi{$pi_count}.value = ?"; $join_params[] = $info_value; } $pi_where[] = "aipi{$pi_count}.name <> ''"; $select_ary["info_{$info_key}_value"] = "aipi{$pi_count}.value AS info_{$info_key}_value"; } $where[] = '(' . implode(' OR ', $pi_where) . ')'; } } if (isset($paramset['has:info'])) { $the_ins = array(); $has_info = Utils::single_array($paramset['has:info']); $pi_count = 0; $pi_where = array(); foreach ($has_info as $info_name) { $pi_count++; $joins['has_info_' . $info_name] = " LEFT JOIN {postinfo} hipi{$pi_count} ON {posts}.id = hipi{$pi_count}.post_id AND hipi{$pi_count}.name = ?"; $join_params[] = $info_name; $pi_where[] = "hipi{$pi_count}.name <> ''"; $select_ary["info_{$info_name}_value"] = "hipi{$pi_count}.value AS info_{$info_name}_value"; } $where[] = '(' . implode(' OR ', $pi_where) . ')'; } if (isset($paramset['not:all:info']) || isset($paramset['not:info'])) { // merge the two possible calls together $infos = array_merge(isset($paramset['not:all:info']) ? $paramset['not:all:info'] : array(), isset($paramset['not:info']) ? $paramset['not:info'] : array()); if (Utils::is_traversable($infos)) { $the_ins = array(); foreach ($infos as $info_key => $info_value) { $the_ins[] = ' ({postinfo}.name = ? AND {postinfo}.value = ? ) '; $params[] = $info_key; $params[] = $info_value; } $where[] = ' {posts}.id NOT IN ( SELECT post_id FROM {postinfo} WHERE ( ' . implode(' OR ', $the_ins) . ' ) GROUP BY post_id HAVING COUNT(*) = ' . count($infos) . ' ) '; // see that hard-coded number? sqlite wets itself if we use a bound parameter... don't change that } } if (isset($paramset['not:any:info'])) { if (Utils::is_traversable($paramset['not:any:info'])) { foreach ($paramset['not:any:info'] as $info_key => $info_value) { $the_ins[] = ' ({postinfo}.name = ? AND {postinfo}.value = ? ) '; $params[] = $info_key; $params[] = $info_value; } $where[] = ' {posts}.id NOT IN ( SELECT post_id FROM {postinfo} WHERE ( ' . implode(' OR ', $the_ins) . ' ) ) '; } } /** * Build the statement needed to filter by pubdate: * If we've got the day, then get the date; * If we've got the month, but no date, get the month; * If we've only got the year, get the whole year. */ if (isset($paramset['day']) && isset($paramset['month']) && isset($paramset['year'])) { $where[] = 'pubdate BETWEEN ? AND ?'; $startDate = sprintf('%d-%02d-%02d', $paramset['year'], $paramset['month'], $paramset['day']); $startDate = HabariDateTime::date_create($startDate); $params[] = $startDate->sql; $params[] = $startDate->modify('+1 day')->sql; //$params[] = date( 'Y-m-d H:i:s', mktime( 0, 0, 0, $paramset['month'], $paramset['day'], $paramset['year'] ) ); //$params[] = date( 'Y-m-d H:i:s', mktime( 23, 59, 59, $paramset['month'], $paramset['day'], $paramset['year'] ) ); } elseif (isset($paramset['month']) && isset($paramset['year'])) { $where[] = 'pubdate BETWEEN ? AND ?'; $startDate = sprintf('%d-%02d-%02d', $paramset['year'], $paramset['month'], 1); $startDate = HabariDateTime::date_create($startDate); $params[] = $startDate->sql; $params[] = $startDate->modify('+1 month')->sql; //$params[] = date( 'Y-m-d H:i:s', mktime( 0, 0, 0, $paramset['month'], 1, $paramset['year'] ) ); //$params[] = date( 'Y-m-d H:i:s', mktime( 23, 59, 59, $paramset['month'] + 1, 0, $paramset['year'] ) ); } elseif (isset($paramset['year'])) { $where[] = 'pubdate BETWEEN ? AND ?'; $startDate = sprintf('%d-%02d-%02d', $paramset['year'], 1, 1); $startDate = HabariDateTime::date_create($startDate); $params[] = $startDate->sql; $params[] = $startDate->modify('+1 year')->sql; //$params[] = date( 'Y-m-d H:i:s', mktime( 0, 0, 0, 1, 1, $paramset['year'] ) ); //$params[] = date( 'Y-m-d H:i:s', mktime( 0, 0, -1, 1, 1, $paramset['year'] + 1 ) ); } if (isset($paramset['after'])) { $where[] = 'pubdate > ?'; $params[] = HabariDateTime::date_create($paramset['after'])->sql; } if (isset($paramset['before'])) { $where[] = 'pubdate < ?'; $params[] = HabariDateTime::date_create($paramset['before'])->sql; } // Concatenate the WHERE clauses if (count($where) > 0) { $wheres[] = ' (' . implode(' AND ', $where) . ') '; } } } // Only show posts to which the current user has permission if (isset($paramset['ignore_permissions'])) { $master_perm_where = ''; } else { // This set of wheres will be used to generate a list of post_ids that this user can read $perm_where = array(); $perm_where_denied = array(); $params_where = array(); $where = array(); // Get the tokens that this user is granted or denied access to read $read_tokens = isset($paramset['read_tokens']) ? $paramset['read_tokens'] : ACL::user_tokens(User::identify(), 'read', true); $deny_tokens = isset($paramset['deny_tokens']) ? $paramset['deny_tokens'] : ACL::user_tokens(User::identify(), 'deny', true); // If a user can read his own posts, let him if (User::identify()->can('own_posts', 'read')) { $perm_where['own_posts_id'] = '{posts}.user_id = ?'; $params_where[] = User::identify()->id; } // If a user can read any post type, let him if (User::identify()->can('post_any', 'read')) { $perm_where = array('post_any' => '(1=1)'); $params_where = array(); } else { // If a user can read specific post types, let him $permitted_post_types = array(); foreach (Post::list_active_post_types() as $name => $posttype) { if (User::identify()->can('post_' . Utils::slugify($name), 'read')) { $permitted_post_types[] = $posttype; } } if (count($permitted_post_types) > 0) { $perm_where[] = '{posts}.content_type IN (' . implode(',', $permitted_post_types) . ')'; } // If a user can read posts with specific tokens, let him if (count($read_tokens) > 0) { $joins['post_tokens__allowed'] = ' LEFT JOIN {post_tokens} pt_allowed ON {posts}.id= pt_allowed.post_id AND pt_allowed.token_id IN (' . implode(',', $read_tokens) . ')'; $perm_where['perms_join_null'] = 'pt_allowed.post_id IS NOT NULL'; } } // If a user is denied access to all posts, do so if (User::identify()->cannot('post_any')) { $perm_where_denied = array('(1=0)'); } else { // If a user is denied read access to specific post types, deny him $denied_post_types = array(); foreach (Post::list_active_post_types() as $name => $posttype) { if (User::identify()->cannot('post_' . Utils::slugify($name))) { $denied_post_types[] = $posttype; } } if (count($denied_post_types) > 0) { $perm_where_denied[] = '{posts}.content_type NOT IN (' . implode(',', $denied_post_types) . ')'; } } // If there are granted permissions to check, add them to the where clause if (count($perm_where) == 0 && !isset($joins['post_tokens__allowed'])) { // You have no grants. You get no posts. $where['perms_granted'] = '(1=0)'; } elseif (count($perm_where) > 0) { $where['perms_granted'] = ' (' . implode(' OR ', $perm_where) . ') '; $params = array_merge($join_params, $params, $params_where); } if (count($deny_tokens) > 0) { $joins['post_tokens__denied'] = ' LEFT JOIN {post_tokens} pt_denied ON {posts}.id= pt_denied.post_id AND pt_denied.token_id IN (' . implode(',', $deny_tokens) . ')'; $perm_where_denied['perms_join_null'] = 'pt_denied.post_id IS NULL'; } // If there are denied permissions to check, add them to the where clause if (count($perm_where_denied) > 0) { $where['perms_denied'] = ' (' . implode(' AND ', $perm_where_denied) . ') '; } $master_perm_where = implode(' AND ', $where); } // Extract the remaining parameters which will be used onwards // For example: page number, fetch function, limit $paramarray = new SuperGlobal($paramarray); $extract = $paramarray->filter_keys('page', 'fetch_fn', 'count', 'orderby', 'groupby', 'limit', 'offset', 'nolimit', 'having'); foreach ($extract as $key => $value) { ${$key} = $value; } // Define the LIMIT if it does not exist, unless specific posts are requested if (!isset($limit) && !isset($paramset['id']) && !isset($paramset['slug'])) { $limit = Options::get('pagination') ? (int) Options::get('pagination') : 5; } elseif (!isset($limit)) { $selected_posts = 0; if (isset($paramset['id'])) { $selected_posts += count(Utils::single_array($paramset['id'])); } if (isset($paramset['slug'])) { $selected_posts += count(Utils::single_array($paramset['slug'])); } $limit = $selected_posts > 0 ? $selected_posts : ''; } // Calculate the OFFSET based on the page number if (isset($page) && is_numeric($page) && !isset($paramset['offset'])) { $offset = (intval($page) - 1) * intval($limit); } /** * Determine which fetch function to use: * If it is specified, make sure it is valid (based on the $fns array defined at the beginning of this function); * Else, use 'get_results' which will return a Posts array of Post objects. */ if (isset($fetch_fn)) { if (!in_array($fetch_fn, $fns)) { $fetch_fn = $fns[0]; } } else { $fetch_fn = $fns[0]; } /** * Turn the requested fields into a comma-separated SELECT field clause */ $select = implode(', ', $select_ary); /** * If a count is requested: * Replace the current fields to select with a COUNT(); * Change the fetch function to 'get_value'; * Remove the ORDER BY since it's useless. * Remove the GROUP BY (tag search added it) */ if (isset($count)) { $select = "COUNT({$count})"; $fetch_fn = 'get_value'; $orderby = ''; $groupby = ''; $having = ''; } // If the month counts are requested, replaced the select clause if (isset($paramset['month_cts'])) { if (isset($paramset['tag']) || isset($paramset['tag_slug'])) { $select = 'MONTH(FROM_UNIXTIME(pubdate)) AS month, YEAR(FROM_UNIXTIME(pubdate)) AS year, COUNT(DISTINCT {posts}.id) AS ct'; } else { $select = 'MONTH(FROM_UNIXTIME(pubdate)) AS month, YEAR(FROM_UNIXTIME(pubdate)) AS year, COUNT(*) AS ct'; } $groupby = 'year, month'; $orderby = 'year, month'; } // Remove the LIMIT if 'nolimit' or 'month_cts' is set // Doing this first should allow OFFSET to work if (isset($nolimit) || isset($paramset['month_cts'])) { $limit = ''; } // Define the LIMIT and add the OFFSET if it exists if (!empty($limit)) { $limit = " LIMIT {$limit}"; if (isset($offset)) { $limit .= " OFFSET {$offset}"; } } else { $limit = ''; } /* All SQL parts are constructed, on to real business! */ /** * Build the final SQL statement */ $query = ' SELECT DISTINCT ' . $select . ' FROM {posts} ' . implode(' ', $joins); if (count($wheres) > 0) { $query .= ' WHERE (' . implode(" \nOR\n ", $wheres) . ')'; $query .= $master_perm_where == '' ? '' : ' AND (' . $master_perm_where . ')'; } elseif ($master_perm_where != '') { $query .= ' WHERE (' . $master_perm_where . ')'; } $query .= !isset($groupby) || $groupby == '' ? '' : ' GROUP BY ' . $groupby; $query .= !isset($having) || $having == '' ? '' : ' HAVING ' . $having; $query .= ($orderby == '' ? '' : ' ORDER BY ' . $orderby) . $limit; /** * DEBUG: Uncomment the following line to display everything that happens in this function */ //print_R('<pre>'.$query.'</pre>'); //Utils::debug( $paramarray, $fetch_fn, $query, $params ); //Session::notice($query); /** * Execute the SQL statement using the PDO extension */ DB::set_fetch_mode(PDO::FETCH_CLASS); DB::set_fetch_class('Post'); $results = DB::$fetch_fn($query, $params, 'Post'); // Utils::debug( $paramarray, $fetch_fn, $query, $params, $results ); // var_dump( $query ); /** * Return the results */ if ('get_results' != $fetch_fn) { // Since a single result was requested, return a single Post object. return $results; } elseif (is_array($results)) { // With multiple results, return a Posts array of Post objects. $c = __CLASS__; $return_value = new $c($results); $return_value->get_param_cache = $paramarray; return $return_value; } }
/** * Handles AJAX requests from the manage posts page. */ public function ajax_posts() { Utils::check_request_method(array('POST', 'HEAD')); $this->create_theme(); $params = $_POST['query']; $fetch_params = array(); if (isset($params) && !empty($params)) { foreach ($params as $param) { $key = key($param); $value = current($param); if (isset($fetch_params[$key])) { $fetch_params[$key] = Utils::single_array($fetch_params[$key]); $fetch_params[$key][] = $value; } else { $fetch_params[$key] = $value; } } } $this->fetch_posts($fetch_params); $items = $this->theme->fetch('posts_items'); $timeline = $this->theme->fetch('timeline_items'); $item_ids = array(); foreach ($this->theme->posts as $post) { if (ACL::access_check($post->get_access(), 'delete')) { $item_ids['p' . $post->id] = 1; } } $ar = new AjaxResponse(); $ar->html('.posts', $items); $ar->data = array('items' => $items, 'item_ids' => $item_ids, 'timeline' => $timeline); $ar->out(); }