/**
  * Wraps the countwrapper query so that a join can be done to the table(s) that hold the name
  * and other text fields which provide data for the node labels. We can't put the text
  * fields into the countwrapper because Oracle won't have any of it.
  *
  * @static
  * @param $countwrapperquery
  * @param $filters
  * @return block_ajax_marking_query_base
  */
 private static function get_display_query($countwrapperquery, $filters)
 {
     // The outermost query just joins the already counted nodes with their display data e.g. we
     // already have a count for each courseid, now we want course name and course description
     // but we don't do this in the counting bit so as to avoid weird issues with group by on
     // Oracle.
     $displayquery = new block_ajax_marking_query_base();
     $modulename = null;
     if (!empty($filters['coursemoduleid']) && is_numeric($filters['coursemoduleid'])) {
         $moduleobject = self::get_module_object_from_cmid($filters['coursemoduleid']);
         if ($moduleobject) {
             $modulename = $moduleobject->get_module_name();
         }
     }
     $nextnodefilter = block_ajax_marking_get_nextnodefilter_from_params($filters);
     $displayquery->add_select(array('table' => 'countwrapperquery', 'column' => 'id', 'alias' => $nextnodefilter));
     $displayquery->add_select(array('table' => 'countwrapperquery', 'column' => 'itemcount'));
     $displayquery->add_select(array('table' => 'countwrapperquery', 'column' => 'timestamp'));
     $displayquery->add_select(array('table' => 'countwrapperquery', 'column' => 'recentcount'));
     $displayquery->add_select(array('table' => 'countwrapperquery', 'column' => 'mediumcount'));
     $displayquery->add_select(array('table' => 'countwrapperquery', 'column' => 'overduecount'));
     $havecoursemodulefilter = array_key_exists('coursemoduleid', $filters);
     if ($havecoursemodulefilter) {
         // Need to have this pass through in case we have a mixture.
         $displayquery->add_select(array('table' => 'countwrapperquery', 'column' => 'modulename'));
     }
     $displayquery->add_from(array('table' => $countwrapperquery, 'alias' => 'countwrapperquery', 'subquery' => true));
     reset($filters);
     foreach ($filters as $filtername => $filtervalue) {
         if ($filtervalue == 'nextnodefilter') {
             // This will attach an id to the query, to either be retrieved directly from the moduleunion,
             // or added via a join of some sort.
             self::add_query_filter($displayquery, $filtername, 'current', null, $modulename);
             // If this one needs it, we add the decorator that gets the config settings.
             // TODO this is not a very elegant way of determining this.
             // Currently, we use the same wrapper for the display query, no matter what the mechanism
             // for getting the settings into the countwrapper query is, because they will just have standard
             // aliases. We don't always need it though.
             if (in_array($filtername, array('courseid', 'coursemoduleid'))) {
                 self::add_query_filter($displayquery, 'core', 'select_config_display_displayquery');
             }
         }
     }
     return $displayquery;
 }
 /**
  * Sometimes there will need to be extra processing of the nodes that is specific to this module
  * e.g. the title to be displayed for submissions needs to be formatted with firstname and
  * lastname in the way that makes sense for the user's chosen language.
  *
  * @param array $nodes Array of objects
  * @param array $filters as sent via $_POST
  * @internal param string $nodetype the name of the filter that provides the SELECT statements
  * for the query
  * @return array of objects - the altered nodes
  */
 public function postprocess_nodes_hook($nodes, $filters)
 {
     foreach ($nodes as &$node) {
         // Just so we know (for styling and accessing js in the client).
         $node->modulename = $this->modulename;
         $nextnodefilter = block_ajax_marking_get_nextnodefilter_from_params($filters);
         switch ($nextnodefilter) {
             case 'discussionid':
                 if (self::forum_is_eachuser($filters['coursemoduleid'])) {
                     $node->name = fullname($node);
                 } else {
                     $node->name = $node->label;
                 }
                 break;
             default:
                 break;
         }
     }
     return $nodes;
 }
 /**
  * Sometimes there will need to be extra processing of the nodes that is specific to this module
  * e.g. the title to be displayed for submissions needs to be formatted with firstname and
  * lastname in the way that makes sense for the user's chosen language.
  *
  * This function provides a default that can be overridden by the subclasses.
  *
  * @param array $nodes Array of objects
  * @param array $filters as sent via $_POST
  * @internal param string $nodetype the name of the filter that provides the SELECT statements
  * for the query
  * @return array of objects - the altered nodes
  */
 public function postprocess_nodes_hook($nodes, $filters)
 {
     foreach ($nodes as &$node) {
         // Just so we know (for styling and accessing js in the client).
         $node->modulename = $this->modulename;
         $nextnodefilter = block_ajax_marking_get_nextnodefilter_from_params($filters);
         switch ($nextnodefilter) {
             case 'userid':
                 // Sort out the firstname/lastname thing.
                 $node->name = fullname($node);
                 unset($node->firstname, $node->lastname);
                 $node->tooltip = userdate($node->tooltip);
                 break;
             default:
                 break;
         }
     }
     return $nodes;
 }
require_once $CFG->dirroot . '/blocks/ajax_marking/classes/module_base.class.php';
require_once $CFG->dirroot . '/blocks/ajax_marking/classes/nodes_builder.class.php';
block_ajax_marking_login_error();
require_login(0, false);
// Still need this to set stuff up.
// TODO might be in a course.
$PAGE->set_context(context_system::instance());
// Each ajax request will have different stuff that we want to pass to the callback function. Using
// required_param() means hard-coding them.
$params = array();
// Need to get the filters in the right order so that the query receives them in the right order.
foreach ($_POST as $name => $value) {
    $params[$name] = clean_param($value, PARAM_ALPHANUMEXT);
}
if (isset($params['config'])) {
    $nodes = block_ajax_marking_nodes_builder::get_config_nodes($params);
} else {
    $nodes = block_ajax_marking_nodes_builder::unmarked_nodes($params);
}
$nextnodefilter = block_ajax_marking_get_nextnodefilter_from_params($params);
foreach ($nodes as &$node) {
    block_ajax_marking_format_node($node, $nextnodefilter);
}
// Reindex array so we pick it up in js as an array and can find the length. Associative arrays
// with strings for keys are automatically sent as objects.
$nodes = array_values($nodes);
$data = array('nodes' => $nodes);
if (isset($params['nodeindex'])) {
    $data['nodeindex'] = $params['nodeindex'];
}
echo json_encode($data);