]> gitweb.fluxo.info Git - lorea/elgg.git/commitdiff
Pulling out entity views in search.
authorbrettp <brettp@36083f99-b078-4883-b0ff-0f9b5a30f544>
Mon, 11 Jan 2010 22:58:55 +0000 (22:58 +0000)
committerbrettp <brettp@36083f99-b078-4883-b0ff-0f9b5a30f544>
Mon, 11 Jan 2010 22:58:55 +0000 (22:58 +0000)
Adding dev documentation.

git-svn-id: http://code.elgg.org/elgg/trunk@3795 36083f99-b078-4883-b0ff-0f9b5a30f544

mod/search/README.txt [new file with mode: 0644]
mod/search/index.php
mod/search/start.php
mod/search/views/default/search/comments/entity.php [new file with mode: 0644]
mod/search/views/default/search/comments/listing.php [deleted file]
mod/search/views/default/search/entity.php [new file with mode: 0644]
mod/search/views/default/search/listing.php

diff --git a/mod/search/README.txt b/mod/search/README.txt
new file mode 100644 (file)
index 0000000..047ba10
--- /dev/null
@@ -0,0 +1,185 @@
+Full text search dev reference.
+
+1.  OVERVIEW
+
+       * All entities are searched through title and description using
+       MySQL's native fulltext search when possible, and LIKE %...% when not.
+       This can be overriden on a type/subtype basis.
+       
+       * Entities are displayed in a standard list view consisting of a 
+       title, blurb, and icon of the owning entity.  This can be overriden 
+       on a type/subtype basis.
+       
+       * Search is separated based upon types/subtypes pairs and any 
+       registered custom search.
+       
+       * METADATA, ANNOTATIONS, AND PRIVATE DATA ARE NOT SEARCHED.  
+       These are used in a variety of ways by plugin authors and generally 
+       should not be displayed.  There are exceptions (profile fields and 
+       comments) but if a plugin needs to match against metadata, 
+       annotations, or private data it must register a search hook itself.
+
+
+2.  SEARCH AND YOUR PLUGIN
+
+       * To appear in search you must register your entity type and subtype
+       by saying in your plugin's init function:
+       
+               register_entity_type($type, $subtype);
+       
+       If you are extending ElggObject with your own class, it is also advised 
+       to add a subtype in your plugin's run_once function by saying:
+       
+               add_subtype($type, $subtype, $class);
+
+       * If your plugin uses ElggEntity's standard title and description, 
+       and you don't need a custom display, there is nothing else you need 
+       to do for your results to appear in search.  If you would like more
+       granular control of search, continue below.
+       
+       
+3.1  CONTROLLING SEARCH -- ENTITIES
+
+       * You can override the default search by responding to the search/type
+       or search/type:subtype hook.  Generally, you will be replying to 
+       search/object:subtype.
+
+       * Search will first trigger a hook for search/type:subtype.  If no 
+       results are returned (but not FALSE, see below) a hook for search/type 
+       will be triggered.  
+       
+       * FALSE returned for any search hook will halt results for that type/subtype.
+       
+       * Register plugin hooks like this:
+       
+               register_plugin_hook('search', 'object:my_subtype', 'my_subtype_search_hook');
+       
+       * The hooked function is provided with details about the search query in $param.
+       These include:
+               query
+               offset
+               limit
+               search_type
+               type - Entity type. (Not applicable for custom searches)
+               subtype - Entity subtype.  (Not applicable for custom searches)
+               owner_guid
+               friends - Should only entities by friends of the logged in 
+                       user be searched? (@todo)
+               pagination - Show pagination?
+       
+       * The hooked function should respond to search triggers with the 
+       following:
+               array(
+                       'count' => A count of ALL entities found,
+                       'entities' => An array of entities.
+               )
+       
+       This information is passed directly to the search view, so if you are 
+       registering your own custom hook, you can provide more 
+       information to display in your custom view. 
+       
+       * For each entity in the returned array, search expects two pieces of
+       volatile data: search_matched_title and search_matched_description.
+       Set these by saying:
+       
+               $entity->setVolatileData('data_name', 'data_value');
+               
+       Again, if you are customizing your search views, you can add anything
+       you need.
+
+
+3.2  CONTROLLING SEARCH - ENTITY VIEWS
+
+       * The default view for entities is search/entity.
+
+       * Search views are separate from the object/entity views because
+       view types might not match entity types.
+       
+       * The default search listing view interates through each entity
+       found and passes to the entity view.  See 3.3 for more information
+       about listing views.
+       
+       * Views are discovered in the following order.  The first search view 
+       found is used.
+               search/type/subtype/entity (For entity-based searches only)
+               search/type/entity
+               search/entity
+               
+       * The following parameters are passed in $vars to the entity view by 
+       the default listing view:
+               entity => The current returned entity
+               params =>
+               results
+               
+       * Example: To create an entity view for an ElggObject of subtype blog,
+       create a file called:
+               views/default/search/object/blog/entity.php
+               
+       To create an entity view for a custom search mysearch, create a file
+       called:
+               views/default/search/mysearch/entity.php
+       
+       
+3.3  CONTROLLING SEARCH - LISTING VIEWS
+
+       * The default search view is search/listing.
+       
+       * For each entity in the returned array, search expects two pieces of
+       volatile data: search_matched_title and search_matched_description.
+       
+       * Views are discovered in the following order.  The first search view 
+       found is used.
+               search/type/subtype/listing (For entity-based searches only)
+               search/type/listing
+               search/listing
+               
+       * The view is called with the following in $vars:
+               results => The results from the search/type:subtype hook
+               params => The params passed to the search/type:subtype hook
+               
+       * Example: To create a listing view for ElggObjects with the subtype 
+       of blog, create a file called:
+               views/default/search/object/blog/listing.php
+               
+       To create a listing view for the custom search mysearch, create a file
+       called:
+               views/default/search/mysearch/listing.php
+
+
+3.4  CONTROLLING SEARCH - CUSTOM SEARCH
+       
+       * Non-entities, including information from 3rd party applications,
+       can easily be included in search by registering a custom search hook
+       that responds to the search_types/get_types trigger:
+       
+               register_plugin_hook('search_types', 'get_types', 'my_custom_search_hook_function');
+       
+       In this function, append to the array sent in $value with the name of 
+       your custom search:
+       
+               function my_custom_search_hook_function($hook, $type, $value, $params) {
+                       $value[] = 'my_custom_search';
+                       return $value;
+               }
+       
+       Search will trigger a hook for search/my_custom_search, which your 
+       plugin should respond to as detailed in section 3.1 above.
+
+
+4.  HINTS
+
+       * Use search_get_relevant_substring() to extract and highlight 
+       relevant substrings for the search_match_title and description.
+       
+       * If searching in 3rd party applications, create a temporary 
+       ElggObject to hold the results.  No need to save it since search 
+       uses volatile data.
+               $entity = new ElggObject();
+               $entity->owner_guid = use_magic_to_match_to_a_real_user();
+               $entity->setVolatileData('search_matched_title', '3rd Party Integration');
+               $entity->setVolatileData('search_matched_description', 'Searching is fun!');
+               
+               return array(
+                       'count' => $count,
+                       'entities' => array($entity)
+               );
\ No newline at end of file
index e7081ecb57333a50033e1e7a5abf9f4246a139e2..adf514cafc9878682814457921bcfc8bac4dc05e 100644 (file)
@@ -152,7 +152,9 @@ if ($search_type == 'all' || $search_type == 'entities') {
                                }
 
                                if (is_array($results['entities']) && $results['count']) {
-                                       $results_html .= search_get_listing_html($results['entities'], $results['count'], $params);
+                                       if ($view = search_get_search_view($params, 'listing')) {
+                                               $results_html .= elgg_view($view, array('results' => $results, 'params' => $params));
+                                       }
                                }
                        }
                }
@@ -169,23 +171,23 @@ if ($search_type == 'all' || $search_type == 'entities') {
                }
 
                if (is_array($results['entities']) && $results['count']) {
-                       $results_html .= search_get_listing_html($results['entities'], $results['count'], $params);
+                       if ($view = search_get_search_view($params, 'listing')) {
+                               $results_html .= elgg_view($view, array('results' => $results, 'params' => $params));
+                       }
                }
        }
 }
 
 // call custom searches
 if ($search_type != 'entities' || $search_type == 'all') {
-       // get custom search types
-       $types = trigger_plugin_hook('search_types', 'get_types', $params, array());
-
-       if (is_array($types)) {
-               foreach ($types as $type) {
+       if (is_array($custom_types)) {
+               foreach ($custom_types as $type) {
                        if ($search_type != 'all' && $search_type != $type) {
                                continue;
                        }
 
                        $params['search_type'] = $type;
+                       // custom search types have no subtype.
                        unset($params['subtype']);
 
                        $results = trigger_plugin_hook('search', $type, $params, array());
@@ -196,7 +198,9 @@ if ($search_type != 'entities' || $search_type == 'all') {
                        }
 
                        if (is_array($results['entities']) && $results['count']) {
-                               $results_html .= search_get_listing_html($results['entities'], $results['count'], $params);
+                               if ($view = search_get_search_view($params, 'listing')) {
+                                       $results_html .= elgg_view($view, array('results' => $results, 'params' => $params));
+                               }
                        }
                }
        }
index 92d5c65b6eb5854dd3321190ee802d07afebaad1..c54072b915106f97155abe32a1801391d0b39789 100644 (file)
@@ -316,48 +316,41 @@ function search_remove_ignored_words($query, $format = 'array') {
 
 
 /**
- * Passes entities, count, and original params to the view functions for
+ * Passes results, and original params to the view functions for
  * search type.
  *
- * @param array $entities
- * @param int $count
+ * @param array $results
  * @param array $params
+ * @param string $view_type = listing || entity
  * @return string
  */
-function search_get_listing_html($entities, $count, $params) {
-       if (!is_array($entities) || !$count) {
+function search_get_search_view($params, $view_type) {
+       if ($view_type != 'listing' && $view_type != 'entity') {
                return FALSE;
        }
-
        $view_order = array();
 
-       // check if there's a special search view for this type:subtype
+       // check if there's a special search listing view for this type:subtype
        if (isset($params['type']) && $params['type'] && isset($params['subtype']) && $params['subtype']) {
-               $view_order[] = "search/{$params['type']}/{$params['subtype']}/listing";
+               $view_order[] = "search/{$params['type']}/{$params['subtype']}/$view_type";
        }
 
        // also check for the default type
        if (isset($params['type']) && $params['type']) {
-               $view_order[] = "search/{$params['type']}/listing";
+               $view_order[] = "search/{$params['type']}/$view_type";
        }
 
        // check search types
        if (isset($params['search_type']) && $params['search_type']) {
-               $view_order[] = "search/{$params['search_type']}/listing";
+               $view_order[] = "search/{$params['search_type']}/$view_type";
        }
 
        // finally default to a search listing default
-       $view_order[] = "search/listing";
-
-       $vars = array(
-               'entities' => $entities,
-               'count' => $count,
-               'params' => $params
-       );
+       $view_order[] = "search/$view_type";
 
        foreach ($view_order as $view) {
                if (elgg_view_exists($view)) {
-                       return elgg_view($view, $vars);
+                       return $view;
                }
        }
 
diff --git a/mod/search/views/default/search/comments/entity.php b/mod/search/views/default/search/comments/entity.php
new file mode 100644 (file)
index 0000000..8b4d286
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Elgg search entity
+ *
+ * @package Elgg
+ * @subpackage Core
+ * @author Curverider Ltd
+ * @link http://elgg.org/
+ */
+$entity = $vars['entity'];
+
+$owner = get_entity($entity->getVolatileData('search_matched_comment_owner_guid'));
+
+if ($owner instanceof ElggUser) {
+       $icon = elgg_view('profile/icon', array('entity' => $owner, 'size' => 'small'));
+} else {
+       $icon = '';
+}
+
+// @todo Sometimes we find comments on entities we can't display...
+if ($entity->getVolatileData('search_unavailable_entity')) {
+       $title = sprintf(elgg_echo('search:comment_on'), elgg_echo('search:unavailable_entity'));
+       // keep anchor for formatting.
+       $title = "<a>$title</a>";
+} else {
+       if ($entity->getType() == 'object') {
+               $title = $entity->title;
+       } else {
+               $title = $entity->name;
+       }
+
+       if (!$title) {
+               $title = elgg_echo('item:' . $entity->getType() . ':' . $entity->getSubtype());
+       }
+
+       if (!$title) {
+               $title = elgg_echo('item:' . $entity->getType());
+       }
+
+       $title = sprintf(elgg_echo('search:comment_on'), $title);
+       $url = $entity->getURL() . '#annotation-' . $entity->getVolatileData('search_match_annotation_id');
+       $title = "<a href=\"$url\">$title</a>";
+}
+
+$description = $entity->getVolatileData('search_matched_comment');
+$tc = $entity->getVolatileData('search_matched_comment_time_created');;
+$time = friendly_time($tc);
+
+echo <<<___END
+       <div class="search_listing">
+               <div class="search_listing_icon">$icon</div>
+               <div class="search_listing_info">
+                       <p class="ItemTitle">$title</p>$description
+                       <p class="ItemTimestamp">$time</p>
+               </div>
+       </div>
+___END;
+
+?>
\ No newline at end of file
diff --git a/mod/search/views/default/search/comments/listing.php b/mod/search/views/default/search/comments/listing.php
deleted file mode 100644 (file)
index 34456bd..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-<?php
-/**
- * Elgg comments search listing
- *
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
- */
-
-if (!is_array($vars['entities']) || !count($vars['entities'])) {
-       return FALSE;
-}
-
-$title_str = elgg_echo('comments');
-
-$query = htmlspecialchars(http_build_query(
-       array(
-               'q' => $vars['params']['query'],
-               'entity_type' => $vars['params']['type'],
-               'entity_subtype' => $vars['params']['subtype'],
-               'limit' => get_input('limit', 10),
-               'offset' => get_input('offset', 0),
-               'search_type' => 'comments',
-       )
-));
-
-$url = "{$vars['url']}pg/search?$query";
-
-// get pagination
-if (array_key_exists('pagination', $vars) && $vars['pagination']) {
-       $nav .= elgg_view('navigation/pagination',array(
-               'baseurl' => $url,
-               'offset' => $vars['params']['offset'],
-               'count' => $vars['count'],
-               'limit' => $vars['params']['limit'],
-       ));
-} else {
-       $nav = '';
-}
-
-// get more links
-$more_check = $vars['count'] - ($vars['params']['offset'] + $vars['params']['limit']);
-$more = ($more_check > 0) ? $more_check : 0;
-
-if ($more) {
-       $title_key = ($more == 1) ? 'comment' : 'comments';
-       $more_str = sprintf(elgg_echo('search:more'), $vars['count'], elgg_echo($title_key));
-       $more_link = "<div class='search_listing'><a href=\"$url\">$more_str</a></div>";
-} else {
-       $more_link = '';
-}
-
-$body = elgg_view_title($title_str);
-
-foreach ($vars['entities'] as $entity) {
-       $owner = get_entity($entity->getVolatileData('search_matched_comment_owner_guid'));
-
-       if ($owner instanceof ElggUser) {
-               $icon = elgg_view('profile/icon', array('entity' => $owner, 'size' => 'small'));
-       } else {
-               $icon = '';
-       }
-
-       // @todo Sometimes we find comments on entities we can't display...
-       if ($entity->getVolatileData('search_unavailable_entity')) {
-               $title = sprintf(elgg_echo('search:comment_on'), elgg_echo('search:unavailable_entity'));
-               // keep anchor for formatting.
-               $title = "<a>$title</a>";
-       } else {
-               if ($entity->getType() == 'object') {
-                       $title = $entity->title;
-               } else {
-                       $title = $entity->name;
-               }
-
-               if (!$title) {
-                       $title = elgg_echo('item:' . $entity->getType() . ':' . $entity->getSubtype());
-               }
-
-               if (!$title) {
-                       $title = elgg_echo('item:' . $entity->getType());
-               }
-
-               $title = sprintf(elgg_echo('search:comment_on'), $title);
-               $url = $entity->getURL() . '#annotation-' . $entity->getVolatileData('search_match_annotation_id');
-               $title = "<a href=\"$url\">$title</a>";
-       }
-
-       $description = $entity->getVolatileData('search_matched_comment');
-       $tc = $entity->getVolatileData('search_matched_comment_time_created');;
-       $time = friendly_time($tc);
-
-       $body .= <<<___END
-       <div class="search_listing">
-               <div class="search_listing_icon">$icon</div>
-               <div class="search_listing_info">
-                       <p class="ItemTitle">$title</p>$description
-                       <p class="ItemTimestamp">$time</p>
-               </div>
-       </div>
-___END;
-}
-
-echo $body;
-echo $more_link;
-echo $nav;
diff --git a/mod/search/views/default/search/entity.php b/mod/search/views/default/search/entity.php
new file mode 100644 (file)
index 0000000..06dd54f
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Elgg search entity
+ *
+ * @package Elgg
+ * @subpackage Core
+ * @author Curverider Ltd
+ * @link http://elgg.org/
+ */
+
+$entity = $vars['entity'];
+
+if ($owner = $entity->getOwnerEntity()) {
+       $icon = elgg_view('profile/icon', array('entity' => $owner, 'size' => 'small'));
+} elseif ($entity instanceof ElggUser) {
+       $icon = elgg_view('profile/icon', array('entity' => $entity, 'size' => 'small'));
+} else {
+       $icon = '';
+}
+
+$title = $entity->getVolatileData('search_matched_title');
+$description = $entity->getVolatileData('search_matched_description');
+$extra_info = $entity->getVolatileData('search_matched_extra');
+$url = $entity->getURL();
+$title = "<a href=\"$url\">$title</a>";
+$tc = $entity->time_created;
+$tu = $entity->time_updated;
+$time = friendly_time(($tu > $tc) ? $tu : $tc);
+
+echo <<<___END
+       <div class="search_listing">
+               <div class="search_listing_icon">$icon</div>
+               <div class="search_listing_info">
+                       <p class="ItemTitle">$title</p>$description
+                       <p class="ItemTimestamp">$time $extra_info</p>
+               </div>
+       </div>
+___END;
+
+// php bug. must have close tag after heredocs
+?>
\ No newline at end of file
index 867523d65d82ddd640c03f511b5eed0e9baa07a6..36032940dea9057b5397d49836c9433e377defe1 100644 (file)
@@ -8,11 +8,10 @@
  * @link http://elgg.org/
  */
 
+$entities = $vars['results']['entities'];
+$count = $vars['results']['count'] - count($entities);
 
-$entities = $vars['entities'];
-$count = $vars['count'] - count($vars['entities']);
-
-if (!is_array($vars['entities']) || !count($vars['entities'])) {
+if (!is_array($entities) || !count($entities)) {
        return FALSE;
 }
 
@@ -34,7 +33,7 @@ if (array_key_exists('pagination', $vars) && $vars['pagination']) {
        $nav .= elgg_view('navigation/pagination',array(
                'baseurl' => $url,
                'offset' => $vars['params']['offset'],
-               'count' => $vars['count'],
+               'count' => $vars['results']['count'],
                'limit' => $vars['params']['limit'],
        ));
 } else {
@@ -84,7 +83,7 @@ if (array_key_exists('pagination', $vars['params']) && $vars['params']['paginati
        $nav .= elgg_view('navigation/pagination',array(
                'baseurl' => $url,
                'offset' => $vars['params']['offset'],
-               'count' => $vars['count'],
+               'count' => $vars['results']['count'],
                'limit' => $vars['params']['limit'],
        ));
 } else {
@@ -92,7 +91,7 @@ if (array_key_exists('pagination', $vars['params']) && $vars['params']['paginati
 }
 
 // get any more links.
-$more_check = $vars['count'] - ($vars['params']['offset'] + $vars['params']['limit']);
+$more_check = $vars['results']['count'] - ($vars['params']['offset'] + $vars['params']['limit']);
 $more = ($more_check > 0) ? $more_check : 0;
 
 if ($more) {
@@ -106,31 +105,13 @@ if ($more) {
 $body = elgg_view_title($type_str);
 
 foreach ($entities as $entity) {
-       if ($owner = $entity->getOwnerEntity()) {
-               $icon = elgg_view('profile/icon', array('entity' => $owner, 'size' => 'small'));
-       } elseif ($entity instanceof ElggUser) {
-               $icon = elgg_view('profile/icon', array('entity' => $entity, 'size' => 'small'));
-       } else {
-               $icon = '';
+       if ($view = search_get_search_view($vars['params'], 'entity')) {
+               $body .= elgg_view($view, array(
+                       'entity' => $entity,
+                       'params' => $vars['params'],
+                       'results' => $vars['results']
+               ));
        }
-       $title = $entity->getVolatileData('search_matched_title');
-       $description = $entity->getVolatileData('search_matched_description');
-       $extra_info = $entity->getVolatileData('search_matched_extra');
-       $url = $entity->getURL();
-       $title = "<a href=\"$url\">$title</a>";
-       $tc = $entity->time_created;
-       $tu = $entity->time_updated;
-       $time = friendly_time(($tu > $tc) ? $tu : $tc);
-
-       $body .= <<<___END
-       <div class="search_listing">
-               <div class="search_listing_icon">$icon</div>
-               <div class="search_listing_info">
-                       <p class="ItemTitle">$title</p>$description
-                       <p class="ItemTimestamp">$time $extra_info</p>
-               </div>
-       </div>
-___END;
 }
 echo $body;
 echo $more_link;