/** * Get a collection of the laws most similar to the present law. */ function get_related() { /* * The number of results to return. The default is 5. */ if (!isset($this->num_results)) { $this->num_results = 5; } /* * Intialize Solarium. */ $client = new Solarium_Client($GLOBALS['solr_config']); if ($client === FALSE) { return FALSE; } /* * Create a MoreLikeThis query instance. */ $query = $client->createMoreLikeThis(); /* * Note that we have to escape colons in this query. */ $query->setQuery('section:' . str_replace(':', '\\:', $this->section_number)); $query->setMltFields('text,tags,catch_line'); $query->setMatchInclude(TRUE); $query->setStart(0)->setRows($this->num_results); /* * Execute the query and return the result. */ $results = $client->select($query); /* * If our query fails. */ if ($results === FALSE) { return FALSE; } /* * Create a new, blank object to store our related sections. */ $related = new StdClass(); /* * Iterate through the returned documents */ $i = 0; foreach ($results as $document) { $law = new Law(); $law->law_id = $document->id; $law->get_law(); $related->{$i} = $law; $i++; } return TRUE; }
* If we have a list of related laws, list them. * Note that Solr < 4.6 will probably die horribly trying this. * We catch any exceptions as a result and go about our business. */ try { $search_client = new SearchIndex(array('config' => json_decode(SEARCH_CONFIG, TRUE))); $related_laws = $search_client->find_related($law, 3); if ($related_laws && count($related_laws->get_results()) > 0) { $sidebar .= ' <section class="related-group grid-box" id="related-links"> <h1>Related Laws</h1> <ul id="related">'; $related_law = new Law(); foreach ($related_laws->get_results() as $result) { $related_law->law_id = $result->law_id; $related_law->get_law(); $related_law->permalink = $related_law->get_url($result->law_id); $sidebar .= '<li>' . SECTION_SYMBOL . ' <a href="' . $related_law->permalink->url . '">' . $related_law->section_number . '</a> ' . $related_law->catch_line . '</li>'; } $sidebar .= ' </ul> </section>'; } } catch (Exception $exception) { // Do nothing. } /* * If we have citation data and it's formatted properly, display it. */ if (isset($law->citation) && is_object($law->citation)) { $sidebar .= '<section class="related-group grid-box" id="cite-as">
/** * Get the definition for a given term for a given section of code. */ function define_term() { /* * We're going to need access to the database connection throughout this class. */ global $db; /* * If no term has been defined, there is nothing to be done. */ if (!isset($this->term)) { return FALSE; } /* * Determine the structural heritage of the provided section number and store it in an * array. */ if (isset($this->section_number) || isset($this->law_id)) { $heritage = new Law(); $heritage->config = new stdClass(); $heritage->config->get_structure = TRUE; if (isset($this->section_number)) { $heritage->section_number = $this->section_number; } elseif (isset($this->law_id)) { $heritage->law_id = $this->law_id; } if (isset($this->edition_id)) { $heritage->edition_id = $this->edition_id; } $law = $heritage->get_law(); $ancestry = array(); foreach ($law->ancestry as $tmp) { $ancestry[] = $tmp->id; } } /* * We want to check if the term is in all caps. If it is, then we want to keep it in * all caps to query the database. Otherwise, we lowercase it. That is, "Board" should be looked * up as "board," but "NAIC" should be looked up as "NAIC." */ for ($i = 0; $i < strlen($this->term); $i++) { /* * If there are any uppercase characters, then make this PCRE string case * sensitive. */ if (ord($this->term[$i]) >= 97 && ord($this->term[$i]) <= 122) { $lowercase = TRUE; break; } } if ($lowercase === TRUE) { $this->term = strtolower($this->term); } /* * If the last character in this word is an "s," then it might be a plural, in which * case we need to search for this and without its plural version. */ if (substr($this->term, -1) == 's') { $plural = TRUE; } /* * This is a tortured assembly of a query. The idea is to provide flexibility on a pair of * axes. The first is to support both plural and singular terms. The second is to support * queries with and without section numbers, to provide either the one true definition for * a term within a given scope or all definitions in the whole code. */ $sql = 'SELECT dictionary.term, dictionary.definition, dictionary.scope, laws.section AS section_number, laws.id AS law_id, permalinks.url AS url FROM dictionary LEFT JOIN laws ON dictionary.law_id=laws.id LEFT JOIN permalinks ON permalinks.relational_id=laws.id AND permalinks.object_type = :object_type AND permalinks.preferred=1 WHERE (dictionary.term = :term'; $sql_args = array(':term' => $this->term, ':object_type' => 'law'); if ($plural === TRUE) { $sql .= ' OR dictionary.term = :term_single'; $sql_args[':term_single'] = substr($this->term, 0, -1); } $sql .= ') '; if (isset($this->section_number) || isset($this->law_id)) { $sql .= 'AND ('; $ancestor_count = count($ancestry); for ($i = 0; $i < $ancestor_count; $i++) { $sql .= "(dictionary.structure_id = :structure_id{$i}) OR "; $sql_args[":structure_id{$i}"] = $ancestry[$i]; } $sql .= ' (dictionary.scope = :scope) OR '; if (isset($this->section_number)) { $sql .= '(laws.section = :section_number)'; $sql_args[':section_number'] = $this->section_number; } else { $sql .= '(laws.id = :law_id)'; $sql_args[':law_id'] = $this->law_id; } $sql .= ') AND dictionary.edition_id = :edition_id '; $sql_args[':scope'] = 'global'; $sql_args[':edition_id'] = $this->edition_id; } $sql .= 'ORDER BY dictionary.scope_specificity '; if (isset($this->section_number) || isset($this->law_id)) { $sql .= 'LIMIT 1'; } $statement = $db->prepare($sql); $result = $statement->execute($sql_args); /* * If the query succeeds, great, retrieve it. */ if ($result !== FALSE && $statement->rowCount() > 0) { /* * Get all results. */ $dictionary = new stdClass(); $i = 0; while ($term = $statement->fetch(PDO::FETCH_OBJ)) { $term->formatted = wptexturize($term->definition) . ' (<a href="' . $term->url . '">' . $term->section_number . '</a>)'; $dictionary->{$i} = $term; $i++; } } else { /* * Assemble the SQL. */ $sql = 'SELECT term, definition, source, source_url AS url FROM dictionary_general WHERE term = :term'; $sql_args = array(':term' => $this->term); if ($plural === TRUE) { $sql .= ' OR term = :term_single'; $sql_args[':term_single'] = substr($this->term, 0, -1); } $sql .= ' LIMIT 1'; $statement = $db->prepare($sql); $result = $statement->execute($sql_args); /* * If the query fails, or if no results are found, return false -- we have no terms for * this structural unit. */ if ($result === FALSE || $statement->rowCount() < 1) { return FALSE; } /* * Get the first result. Assemble a slightly different response than for a custom term. * We assign this to the first element of an object because that is the format that the * API expects to receive a list of terms in. In this case, we have just one term. */ $dictionary->{0} = $statement->fetch(PDO::FETCH_OBJ); $dictionary->{0}->formatted = wptexturize($dictionary->{0}->definition) . ' (<a href="' . $dictionary->{0}->url . '">' . $dictionary->{0}->source . '</a>)'; } return $dictionary; }
/** * Create and save a sitemap.xml * * List every law in this legal code and create an XML file with an entry for every one of them. */ function generate_sitemap() { $this->logger->message('Generating sitemap.xml', 3); /* * The sitemap.xml file must be kept in the site root, as per the standard. */ $sitemap_file = WEB_ROOT . '/sitemap.xml'; if (!is_writable($sitemap_file)) { $this->logger->message('Do not have permissions to write to sitemap.xml', 3); return FALSE; } /* * List the ID of every law in the current edition. We cut it off at 50,000 laws because * that is the sitemap.xml limit. */ $sql = 'SELECT id FROM laws WHERE edition_id = :edition_id LIMIT 50000'; $sql_args = array(':edition_id' => EDITION_ID); $statement = $this->db->prepare($sql); $result = $statement->execute($sql_args); if ($result === FALSE || $statement->rowCount() == 0) { $this->logger->message('No laws could be found to export to the sitemap', 3); return FALSE; } /* * Create a new XML file, using the sitemap.xml schema. */ $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" />'); /* * Create a new instance of the class that handles information about individual laws. */ $laws = new Law(); /* * Iterate through every section ID. */ while ($section = $statement->fetch(PDO::FETCH_OBJ)) { /* * Instruct the Law class on what, specifically, it should retrieve. (Very little.) */ $laws->config->get_all = FALSE; $laws->config->get_text = FALSE; $laws->config->get_structure = FALSE; $laws->config->get_amendment_attempts = FALSE; $laws->config->get_court_decisions = FALSE; $laws->config->get_metadata = FALSE; $laws->config->get_references = FALSE; $laws->config->get_related_laws = FALSE; $laws->config->render_html = FALSE; /* * Get the law in question. */ $laws->law_id = $section->id; $law = $laws->get_law(); /* * Add a record of this law to the XML. */ $url = $xml->addChild('url'); $url->addchild('loc', $law->url); $url->addchild('changefreq', 'monthly'); } /* * Save the resulting file. */ file_put_contents($sitemap_file, $xml->asXML()); return TRUE; }
function handle($args) { /* * Create a new instance of the class that handles information about individual laws. */ $laws = new Law(); /* * Instruct the Law class on what, specifically, it should retrieve. */ $laws->config->get_text = TRUE; $laws->config->get_structure = TRUE; $laws->config->get_amendment_attempts = FALSE; $laws->config->get_court_decisions = TRUE; $laws->config->get_metadata = TRUE; $laws->config->get_references = TRUE; $laws->config->get_related_laws = TRUE; /* * Pass the requested section number to Law. */ $laws->section_number = $args['identifier']; $laws->law_id = $args['relational_id']; /* * Get a list of all of the basic information that we have about this section. */ $response = $laws->get_law(); /* * If, for whatever reason, this section is not found, return an error. */ if ($response === false) { $this->handleNotFound(); } else { /* * Eliminate the listing of all other sections in the chapter that contains this section. That's * returned by our internal API by default, but it's not liable to be useful to folks receiving * this data. */ unset($response->chapter_contents); } /* * If the request contains a specific list of fields to be returned. */ if (isset($_GET['fields'])) { /* * Turn that list into an array. */ $returned_fields = explode(',', urldecode($_GET['fields'])); foreach ($returned_fields as &$field) { $field = trim($field); } /* * It's essential to unset $field at the conclusion of the prior loop. */ unset($field); /* * Step through our response fields and eliminate those that aren't in the requested list. */ foreach ($response as $field => &$value) { if (in_array($field, $returned_fields) === false) { unset($response->{$field}); } } } $this->render($response, 'OK'); }
* @link http://www.statedecoded.com/ * @since 0.1 */ /* * Create a new instance of Law. */ $laws = new Law(); /* * Use the ID passed to look up the law. */ if (isset($args['relational_id'])) { $laws->law_id = filter_var($args['relational_id'], FILTER_SANITIZE_STRING); /* * Retrieve a copy of the law. */ $law = $laws->get_law(); } if (!isset($law) || $law === FALSE) { send_404(); } /* * Store a record that this section was viewed. */ $laws->record_view(); /* * If this is a request for a plain text version of this law, simply display that and exit. */ if (isset($_GET['plain_text'])) { /* * Instruct the browser that this is plain text. */
public function index_laws($args) { if (!isset($this->edition)) { $edition_obj = new Edition(array('db' => $this->db)); $this->edition = $edition_obj->current(); } if (!isset($this->edition)) { throw new Exception('No edition, cannot index laws.'); } if ($this->edition->current != '1') { $this->logger->message('The edition is not current, skipping the update of the search ' . ' index', 9); return; } if (!defined('SEARCH_CONFIG')) { $this->logger->message('Solr is not in use, skipping index', 9); return; } else { /* * Index the laws. */ $this->logger->message('Updating search index', 5); $this->logger->message('Indexing laws', 6); $search_index = new SearchIndex(array('config' => json_decode(SEARCH_CONFIG, TRUE))); $law_obj = new Law(array('db' => $this->db)); $result = $law_obj->get_all_laws($this->edition->id, true); $search_index->start_update(); while ($law = $result->fetch()) { // Get the full data of the actual law. $document = new Law(array('db' => $this->db)); $document->law_id = $law['id']; $document->config->get_all = TRUE; $document->get_law(); // Bring over our edition info. $document->edition = $this->edition; try { $search_index->add_document($document); } catch (Exception $error) { $this->logger->message('Search index error "' . $error->getStatusMessage() . '"', 10); return FALSE; } } $search_index->commit(); // $this->logger->message('Indexing structures', 6); ### TODO: Index structures $this->logger->message('Laws were indexed', 5); return TRUE; } }
function handle($args) { /* * If we have received neither a term nor a section, we can't do anything. */ if (empty($args['term']) && empty($_GET['section'])) { json_error('Neither a dictionary term nor a section number have been provided.'); die; } /* * Clean up the term. */ $term = filter_var($args['term'], FILTER_SANITIZE_STRING); /* * If a section has been specified, then clean that up. */ if (isset($_GET['section'])) { $section = filter_input(INPUT_GET, 'section', FILTER_SANITIZE_STRING); } $dict = new Dictionary(); /* * Get the definitions for the requested term, if a term has been requested. */ if (!empty($args['term'])) { if (isset($section)) { $dict->section_number = $section; } $dict->term = $term; $dictionary = $dict->define_term(); /* * If, for whatever reason, this term is not found, return an error. */ if ($dictionary === FALSE) { $response = array('definition' => 'Definition not available.'); } else { /* * Uppercase the first letter of the first (quoted) word. We perform this twice because * some egal codes begin the definition with a quotation mark and some do not. (That is, * some write '"Whale" is a large sea-going mammal' and some write 'Whale is a large * sea-going mammal.") */ if (preg_match('/[A-Za-z]/', $dictionary->definition[0]) === 1) { $dictionary->definition[0] = strtoupper($dictionary->definition[0]); } elseif (preg_match('/[A-Za-z]/', $dictionary->definition[1]) === 1) { $dictionary->definition[1] = strtoupper($dictionary->definition[1]); } /* * If the request contains a specific list of fields to be returned. */ if (isset($_GET['fields'])) { /* * Turn that list into an array. */ $returned_fields = explode(',', urldecode($_GET['fields'])); foreach ($returned_fields as &$field) { $field = trim($field); } /* * It's essential to unset $field at the conclusion of the prior loop. */ unset($field); foreach ($dictionary as &$term) { /* * Step through our response fields and eliminate those that aren't in the * requested list. */ foreach ($term as $field => &$value) { if (in_array($field, $returned_fields) === FALSE) { unset($term->{$field}); } } } } /* * If a section has been specified, then simplify this response by returning just a * single definition. */ if (isset($section)) { $dictionary = $dictionary->{0}; } /* * Rename this variable to use the expected name. */ $response = $dictionary; } // end else if term is found } elseif (!empty($_GET['section'])) { /* * Get the structural ID of the container for this section. */ $law = new Law(); $law->section_number = $section; $law->config = FALSE; $result = $law->get_law(); if ($result == FALSE) { $response = array('terms' => 'Term list not available.'); } else { /* * Now get the term list. */ $dict->section_id = $law->section_id; $dict->structure_id = $law->structure_id; $response = $dict->term_list(); if ($response == FALSE) { $response = array('terms' => 'Term list not available.'); } } } // end elseif (!empty($args['section'])) $this->render($response, 'OK', $_REQUEST['callback']); }
function handle($args) { /* * Make sure we have a search term. */ if (!isset($args['term']) || empty($args['term'])) { json_error('Search term not provided.'); die; } /* * Clean up the search term. */ $term = filter_var($args['term'], FILTER_SANITIZE_STRING); /* * Determine if the search results should display detailed information about each law. */ if (!isset($_GET['detailed']) || empty($_GET['detailed'])) { $detailed = FALSE; } else { $detailed = filter_var($_GET['detailed'], FILTER_SANITIZE_STRING); if ($detailed == "true") { $detailed = TRUE; } elseif ($detailed != "false") { $detailed = FALSE; } else { $detailed = FALSE; } } /* * Intialize Solarium. */ $client = new Solarium_Client($GLOBALS['solr_config']); /* * Set up our query. */ $query = $client->createSelect(); $query->setQuery($term); /* * We want the most useful bits extracted as search results snippets. */ $hl = $query->getHighlighting(); $hl->setFields('catch_line, text'); /* * Specify that we want the first 100 results. */ $query->setStart(0)->setRows(100); /* * Execute the query. */ $search_results = $client->select($query); /* * Display uses of the search terms in a preview of the result. */ $highlighted = $search_results->getHighlighting(); /* * If there are no results. */ if (count($search_results) == 0) { $response->records = 0; $response->total_records = 0; } /* * If we have results. */ /* * Instantiate the Law class. */ $law = new Law(); /* * Save an array of the legal code's structure, which we'll use to properly identify the structural * data returned by Solr. We hack off the last element of the array, since that identifies the laws * themselves, not a structural unit. */ $code_structures = array_slice(explode(',', STRUCTURE), 0, -1); $i = 0; foreach ($search_results as $document) { /* * Attempt to display a snippet of the indexed law. */ $snippet = $highlighted->getResult($document->id); if ($snippet != FALSE) { /* * Build the snippet up from the snippet object. */ foreach ($snippet as $field => $highlight) { $response->results->{$i}->excerpt .= strip_tags(implode(' ... ', $highlight)) . ' ... '; } /* * Use an appropriate closing ellipsis. */ if (substr($response->results->{$i}->excerpt, -6) == '. ... ') { $response->results->{$i}->excerpt = substr($response->results->{$i}->excerpt, 0, -6) . '....'; } $response->results->{$i}->excerpt = trim($response->results->{$i}->excerpt); } /* * At the default level of verbosity, just give the data indexed by Solr, plus the URL. */ if ($detailed === FALSE) { /* * Store the relevant fields within the response we'll send. */ $response->results->{$i}->section_number = $document->section; $response->results->{$i}->catch_line = $document->catch_line; $response->results->{$i}->text = $document->text; $response->results->{$i}->url = $law->get_url($document->section); $response->results->{$i}->score = $document->score; $response->results->{$i}->ancestry = (object) array_combine($code_structures, explode('/', $document->structure)); } else { $law->section_number = $document->section; $response->results->{$i} = $law->get_law(); $response->results->{$i}->score = $document->score; } $i++; } /* * Provide the total number of available documents, beyond the number returned by or available * via the API. */ $response->total_records = $search_results->getNumFound(); /* * If the request contains a specific list of fields to be returned. */ if (isset($args['fields'])) { /* * Turn that list into an array. */ $returned_fields = explode(',', urldecode(filter_var($args['fields'], FILTER_SANITIZE_STRING))); foreach ($returned_fields as &$field) { $field = trim($field); } /* * It's essential to unset $field at the conclusion of the prior loop. */ unset($field); /* * Step through our response fields and eliminate those that aren't in the requested list. */ foreach ($response as $field => &$value) { if (in_array($field, $returned_fields) === false) { unset($response->{$field}); } } } $this->render($response, 'OK'); }
} else { /* * Start the DIV that stores all of the search results. */ $body .= ' <div class="search-results"> <p>' . number_format($results->get_count()) . ' results found.</p> <ul>'; /* * Iterate through the results. */ global $db; $law = new Law(array('db' => $db)); foreach ($results->get_results() as $result) { $law->law_id = $result->law_id; $law->get_law(); $url = $law->get_url($result->law_id); $url_string = $url->url; if (strpos($url, '?') !== FALSE) { $url_string .= '?'; } else { $url_string .= '*'; } $url_string .= 'q=' . urlencode($q); $body .= '<li><div class="result">'; $body .= '<h1><a href="' . $url_string . '">'; if (strlen($result->catch_line)) { $body .= $result->catch_line; } else { $body .= $law->catch_line; }