Plugin Directory

Changeset 918102


Ignore:
Timestamp:
05/20/2014 06:37:29 PM (12 years ago)
Author:
mustela
Message:

Release 0.2

Location:
maven-algolia/trunk
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • maven-algolia/trunk/admin/controllers/indexer.php

    r915533 r918102  
    1414     */
    1515    public function __construct ( ) {
    16         // Delete the post in the index when it was deleted in the site
    17         add_action( 'deleted_post', array( &$this, 'postDeleted' ) );
    18         // Delete the post in the index when it was unpublished
    19         add_action( 'transition_post_status', array( &$this, 'postUnpublished' ), 10, 3 );
    20         // Update the post in the index when it was updated
    21         // JUST WHEN IT IS publish
    22         add_action( 'save_post', array( &$this, 'postUpdated' ), 11, 3 );
     16       
     17        if( Registry::instance()->isEnabled() ){
     18            // Delete the post in the index when it was deleted in the site
     19            add_action( 'deleted_post', array( &$this, 'postDeleted' ) );
     20            // Delete the post in the index when it was unpublished
     21            add_action( 'transition_post_status', array( &$this, 'postUnpublished' ), 10, 3 );
     22            // Update the post in the index when it was updated
     23            // JUST WHEN IT IS publish
     24            add_action( 'save_post', array( &$this, 'postUpdated' ), 11, 3 );
     25
     26            // Update the term in the index when the counter was updated in WP
     27            add_action( "edited_term_taxonomy", array( &$this, 'termTaxonomyUpdated' ), 10, 2 );
     28            // Insert the term in the index when it was created
     29            add_action( "created_term", array( &$this, 'termCreated' ), 10, 3 );
     30            // Delete the term in the index when it was deleted in the site
     31            add_action( 'delete_term', array( &$this, 'termDeleted' ), 10, 4 );
     32        }
    2333    }
    2434   
     
    4555        if ( isset( $postTypesToIndex[$post->post_type] ) && $old_status == 'publish' && $new_status != 'publish' && !empty( $post->ID ) ) {
    4656            // Post is unpublished so remove from index
    47             // Init the index
    48             $indexer = new Core\Indexer( Registry::instance()->getAppId(), Registry::instance()->getApiKey() );
    49             // TODO: remember to add the index by post type when we have it implemented
    50             $indexer->removeObject( Registry::instance()->getDefaultIndex(), $post->ID );
     57            try {
     58                // Init the index
     59                $indexer = new Core\Indexer( Registry::instance()->getAppId(), Registry::instance()->getApiKey() );
     60                // TODO: remember to add the index by post type when we have it implemented
     61                $indexer->deleteObject( Registry::instance()->getDefaultIndex(), $post->ID );
     62            } catch ( Exception $exc ) {
     63               
     64            }
    5165        }
    5266    }
     
    6882        $postTypesToIndex = Core\FieldsHelper::getPostTypesObject();
    6983        if ( !isset( $postTypesToIndex[$post->post_type] ) ) { return $postID; }
    70         // Init the index
    71         $indexer = new Core\Indexer( Registry::instance()->getAppId(), Registry::instance()->getApiKey() );
    72         $objectToIndex = $indexer->postToAlgoliaObject( $post,$postTypesToIndex[$post->post_type] );
    73         if( $objectToIndex ){
    74             // TODO: remember to add the index by post type when we have it implemented
    75             $indexer->indexObject( Registry::instance()->getDefaultIndex(), $objectToIndex );
     84        try {
     85            // Init the index
     86            $indexer = new Core\Indexer( Registry::instance()->getAppId(), Registry::instance()->getApiKey() );
     87            $objectToIndex = $indexer->postToAlgoliaObject( $post, $postTypesToIndex[$post->post_type] );
     88            if( $objectToIndex ){
     89                // TODO: remember to add the index by post type when we have it implemented
     90                $indexer->indexObject( Registry::instance()->getDefaultIndex(), $objectToIndex );
     91            }
     92        } catch ( Exception $exc ) {
     93
    7694        }
    7795    }
     
    8098     * Remove the post from the index when it was deleted in WP
    8199     * Called from deleted_post action
    82      * @param int $postid
     100     * @param int $postId
    83101     */
    84     public function postDeleted( $postid ) {
    85         if ( !empty( $postid ) ) {
    86             // Post is unpublished so remove from index
     102    public function postDeleted( $postId ) {
     103        if ( !empty( $postId ) ) {
     104            try {
     105                // Post is unpublished so remove from index
     106                $indexer = new Core\Indexer( Registry::instance()->getAppId(), Registry::instance()->getApiKey() );
     107                // TODO: remember to add the index by post type when we have it implemented
     108                $indexer->deleteObject( Registry::instance()->getDefaultIndex(), $postId );
     109            } catch ( Exception $exc ) {
     110
     111            }
     112        }
     113    }
     114   
     115    /**
     116     * Update term in the index when it was unpdated in WP
     117     * Called from edited_term and created_term actions
     118     * @param integer $ttId
     119     * @param object $taxonomy
     120     */
     121    public function termTaxonomyUpdated( $ttId, $taxonomy ) {
     122        if( empty( $taxonomy->name ) ){ return $ttId; }
     123       
     124        $taxonomyToIndex = Core\FieldsHelper::getTaxonomyObjectByType( $taxonomy->name );
     125       
     126        if ( empty( $taxonomyToIndex ) || ! $taxonomyToIndex->getIndexName() ) { return $ttId; }
     127       
     128        // Get the object before deletion so we can pass to actions below
     129        $termUpdated = get_term_by( 'term_taxonomy_id', $ttId, $taxonomy->name );
     130        if( !is_wp_error( $termUpdated ) && $termUpdated ){
     131            try {
     132                // Init the index
     133                $indexer = new Core\Indexer( Registry::instance()->getAppId(), Registry::instance()->getApiKey() );
     134                // Convert the term in a algolia object
     135                $objectToIndex = $indexer->termToAlgoliaObject( $termUpdated, $taxonomyToIndex );
     136                if( $objectToIndex ){
     137                    $indexer->indexObject( $taxonomyToIndex->getIndexName(), $objectToIndex );
     138                }
     139            } catch ( Exception $exc ) {
     140
     141            }
     142        }
     143    }
     144   
     145    /**
     146     * Update term in the index when it was unpdated in WP
     147     * Called from edited_term and created_term actions
     148     * @param integer $termId
     149     * @param integer $ttId
     150     * @param string $taxonomy
     151     */
     152    public function termCreated( $termId, $ttId, $taxonomy ) {
     153        $taxonomyToIndex = Core\FieldsHelper::getTaxonomyObjectByType( $taxonomy );
     154        if ( empty( $taxonomyToIndex ) || ! $taxonomyToIndex->getIndexName() ) { return $termId; }
     155       
     156        // Get the object before deletion so we can pass to actions below
     157        $termUpdated = get_term( $termId, $taxonomy );
     158        if( !is_wp_error( $termUpdated ) && $termUpdated ){
     159            try {
     160                // Init the index
     161                $indexer = new Core\Indexer( Registry::instance()->getAppId(), Registry::instance()->getApiKey() );
     162                // Convert the term in a algolia object
     163                $objectToIndex = $indexer->termToAlgoliaObject( $termUpdated, $taxonomyToIndex );
     164                if( $objectToIndex ){
     165                    $indexer->indexObject( $taxonomyToIndex->getIndexName(), $objectToIndex );
     166                }
     167            } catch ( Exception $exc ) {
     168
     169            }
     170        }
     171    }
     172   
     173    /**
     174     * Remove the term from the index when it was deleted in WP
     175     * Called from delete_term action
     176     * @param integer $termId
     177     * @param integer $ttId
     178     * @param string $taxonomy
     179     * @param object $deleted_term
     180     */
     181    public function termDeleted( $termId, $ttId, $taxonomy, $deleted_term ) {
     182        $taxonomyToIndex = Core\FieldsHelper::getTaxonomyObjectByType( $taxonomy );
     183        if ( empty( $ttId ) || empty( $taxonomyToIndex ) || ! $taxonomyToIndex->getIndexName() ) { return $termId; }
     184        try {
     185                // Term was removed so remove it from index
    87186            $indexer = new Core\Indexer( Registry::instance()->getAppId(), Registry::instance()->getApiKey() );
    88             // TODO: remember to add the index by post type when we have it implemented
    89             $indexer->removeObject( Registry::instance()->getDefaultIndex(), $postid );
     187            $indexer->deleteObject( $taxonomyToIndex->getIndexName(), $ttId );
     188        } catch ( Exception $exc ) {
     189
    90190        }
    91191    }
  • maven-algolia/trunk/admin/controllers/settings.php

    r915533 r918102  
    185185                $offset = !empty( $_POST['queryOffset'] ) ? (int)$_POST['queryOffset'] : 0;
    186186
    187                 // Init the index
    188                 $indexer = new Core\Indexer( Registry::instance()->getAppId(), Registry::instance()->getApiKey() );
    189187
    190188               
     
    194192                        $postType = $postTypesToIndex[$indexPostType];
    195193                        try {
     194                            // Init the index
     195                            $indexer = new Core\Indexer( Registry::instance()->getAppId(), Registry::instance()->getApiKey() );
    196196                            // indexing in a tmp index to avoid breaking something in the current site functionality
    197197                            // Then it will be moved to the correct name with the new info
     
    234234                $indexTaxonomyType = !empty( $_POST['indexTaxonomyType'] ) ? sanitize_text_field( $_POST['indexTaxonomyType'] ) : 0;
    235235                $offset = !empty( $_POST['queryOffset'] ) ? (int)$_POST['queryOffset'] : 0;
    236 
    237                 // Init the index
    238                 $indexer = new Core\Indexer( Registry::instance()->getAppId(), Registry::instance()->getApiKey() );
    239 
    240                
     236       
    241237                $taxonomyTypeToIndex = Core\FieldsHelper::getTaxonomyObjectByType( $indexTaxonomyType );
    242238//              var_dump($taxonomyTypeToIndex);
     
    244240                if( $taxonomyTypeToIndex && $taxonomyTypeToIndex->getIndexName() ){
    245241                        try {
     242                            // Init the index
     243                            $indexer = new Core\Indexer( Registry::instance()->getAppId(), Registry::instance()->getApiKey() );
    246244                            // indexing in a tmp index to avoid breaking something in the current site functionality
    247245                            // Then it will be moved to the correct name with the new info
     
    357355            $offset = !empty( $_POST['queryOffset'] ) ? (int)$_POST['queryOffset'] : 0;
    358356           
    359             // Init the index
    360             $indexer = new Core\Indexer( Registry::instance()->getAppId(), Registry::instance()->getApiKey() );
    361357           
    362358            $errorMessage = '';
     
    366362            if( $postTypesToIndex && is_array( $postTypesToIndex ) ){
    367363                    try {
     364                        // Init the index
     365                        $indexer = new Core\Indexer( Registry::instance()->getAppId(), Registry::instance()->getApiKey() );
    368366                        $totalRemoved = $indexer->removeIndexData( Registry::instance()->getDefaultIndex(), $postTypesToIndex, $this->postsPerPageToRemove, $offset );
    369367                    } catch ( Exception $exc ) {
     
    389387        if( !empty( $_POST['runMoveIndex'] ) &&  Registry::instance()->isValidApp() )
    390388        {
    391             // Init the index
    392             $indexer = new Core\Indexer( Registry::instance()->getAppId(), Registry::instance()->getApiKey() );
    393389           
    394390            $errorMessage = '';
     
    397393            if( $postTypesToIndex && is_array( $postTypesToIndex ) ){
    398394                    try {
     395                        // Init the index
     396                        $indexer = new Core\Indexer( Registry::instance()->getAppId(), Registry::instance()->getApiKey() );
    399397                        $indexName = Registry::instance()->getDefaultIndex();
    400398                        $tmpIndexName = sprintf( '%s_tmp', $indexName );
  • maven-algolia/trunk/admin/views/settings.php

    r915533 r918102  
    1111        <input type="hidden" value="<?php echo Settings::updateAction; ?>" name="mvnAlg_action">
    1212        <?php wp_nonce_field( Settings::updateAction ); ?>
    13         <table class="widefat" style="width: 75%">
    14             <thead>
    15                 <tr>
    16                     <th class="row-title" colspan="2"><strong><?php esc_html_e( 'Configure your App Credentials', $langDomain ); ?></strong></th>
    17                 </tr>
    18             </thead>
    19             <tbody>
    20                 <tr valign="top">
    21                     <th scope="row"><label for="mvnAlg_appId"><?php esc_html_e( 'APP ID', $langDomain ); ?></label></th>
    22                     <td><input type="text" class="regular-text" value="<?php echo esc_attr(  $registry->getAppId() ); ?>" id="mvnAlg_appId" name="<?php echo Settings::settingsField; ?>[appId]"></td>
    23                 </tr>
    24                 <tr valign="top">
    25                     <th scope="row"><label for="mvnAlg_apiKey"><?php esc_html_e( 'API Key', $langDomain ); ?></label></th>
    26                     <td><input type="text" class="regular-text" value="<?php echo esc_attr(  $registry->getApiKey() ); ?>" id="mvnAlg_apiKey" name="<?php echo Settings::settingsField; ?>[apiKey]"></td>
    27                 </tr>
    28                 <tr valign="top">
    29                     <th scope="row"><label for="mvnAlg_apiKeySearch"><?php esc_html_e( 'API Key for Search Only', $langDomain ); ?></label></th>
    30                     <td><input type="text" class="regular-text" value="<?php echo esc_attr(  $registry->getApiKeySearch() ); ?>" id="mvnAlg_apiKeySearch" name="<?php echo Settings::settingsField; ?>[apiKeySearch]"></td>
    31                 </tr>
    32                 <tr>
    33                     <td>
    34                         <p class="submit"><input type="submit" value="<?php esc_attr_e( 'Save Changes', $langDomain ); ?>" class="button button-primary" id="submit" name="submit"></p>
    35                     </td>
    36                 </tr>
    37             </tbody>
     13        <table style="width: 100%">
     14            <tr>
     15                <td style="width:45%; vertical-align: top;">
     16                    <table class="widefat">
     17                        <thead>
     18                            <tr>
     19                                <th class="row-title" colspan="2"><strong><?php esc_html_e( 'Configure your App Credentials', $langDomain ); ?></strong></th>
     20                            </tr>
     21                        </thead>
     22                        <tbody>
     23                            <tr valign="top">
     24                                <th scope="row"><label for="mvnAlg_appId"><?php esc_html_e( 'APP ID', $langDomain ); ?></label></th>
     25                                <td><input type="text" class="regular-text" value="<?php echo esc_attr(  $registry->getAppId() ); ?>" id="mvnAlg_appId" name="<?php echo Settings::settingsField; ?>[appId]"></td>
     26                            </tr>
     27                            <tr valign="top">
     28                                <th scope="row"><label for="mvnAlg_apiKey"><?php esc_html_e( 'API Key', $langDomain ); ?></label></th>
     29                                <td><input type="text" class="regular-text" value="<?php echo esc_attr(  $registry->getApiKey() ); ?>" id="mvnAlg_apiKey" name="<?php echo Settings::settingsField; ?>[apiKey]"></td>
     30                            </tr>
     31                            <tr valign="top">
     32                                <th scope="row"><label for="mvnAlg_apiKeySearch"><?php esc_html_e( 'API Key for Search Only', $langDomain ); ?></label></th>
     33                                <td><input type="text" class="regular-text" value="<?php echo esc_attr(  $registry->getApiKeySearch() ); ?>" id="mvnAlg_apiKeySearch" name="<?php echo Settings::settingsField; ?>[apiKeySearch]"></td>
     34                            </tr>
     35                            <tr>
     36                                <td>
     37                                    <p class="submit"><input type="submit" value="<?php esc_attr_e( 'Save Changes', $langDomain ); ?>" class="button button-primary" id="submit" name="submit"></p>
     38                                </td>
     39                            </tr>
     40                        </tbody>
     41                    </table>
     42
     43                    <?php if ( Core\UtilsAlgolia::readyToIndex() ): ?>
     44                    <table class="widefat" style="margin-top: 30px; ">
     45                        <thead>
     46                            <tr>
     47                                <th class="row-title" colspan="2"><strong><?php esc_html_e( 'Index Content', $langDomain ); ?></strong></th>
     48                            </tr>
     49                        </thead>
     50                        <tbody>
     51                            <tr valign="top">
     52                                <th scope="row"><label for="mvnAlg_defaultIndex"><?php esc_html_e( 'Index Name', $langDomain ); ?></label></th>
     53                                <td><input type="text" class="regular-text" value="<?php echo esc_attr(  $registry->getDefaultIndex() ); ?>" id="mvnAlg_defaultIndex" name="<?php echo Settings::settingsField; ?>[defaultIndex]"></td>
     54                            </tr>
     55                            <?php if ( $registry->getDefaultIndex() ): ?>
     56
     57                                <tr valign="top" class="index-action-row index-action-button">
     58                                    <th scope="row"><label for="mvnAlg_index"><?php esc_html_e( 'Click to index content', $langDomain ); ?></label></th>
     59                                    <td>
     60                                        <div class="algolia-action-button" style="width:50%;">
     61                                            <button type="button" class="button button-secondary"  id="mvnAlg_index" name="mvnAlg_index"><?php esc_html_e( 'Index Content', $langDomain ); ?></button>
     62                                            <span class="spinner algolia-index-spinner"></span>
     63                                        </div>
     64                                    </td>
     65                                </tr>
     66                                <tr class="index-action-row index-messages">
     67                                    <th>&nbsp;</th>
     68                                    <td>
     69                                        <div class="success"><ul id="mvn-alg-index-result"></ul></div>
     70                                        <div class="error error-message" style="display: none;"><p id="mvn-alg-index-error" ></p></div>
     71                                    </td>
     72                                </tr>
     73                            <?php else: ?>
     74                                <tr>
     75                                    <td colspan="2">
     76                                        <p><?php _e( 'Please set an "Index Name" and then update the settings to start indexing content.', $langDomain ) ?></p>
     77                                    </td>
     78                                </tr>
     79                            <?php endif; ?>
     80                                <tr>
     81                                    <td>
     82                                        <p class="submit"><input type="submit" value="<?php esc_attr_e( 'Save Changes', $langDomain ); ?>" class="button button-primary" id="submit" name="submit"></p>
     83                                    </td>
     84                                </tr>
     85                        </tbody>
     86                    </table>
     87                    <?php endif; ?>
     88                </td>
     89                <td style="width: 45%; vertical-align: top;">
     90                    <table class="widefat">
     91                        <thead>
     92                            <tr>
     93                                <th class="row-title" colspan="2"><strong><?php esc_html_e( 'Customization', $langDomain ); ?></strong></th>
     94                            </tr>
     95                        </thead>
     96                        <tbody>
     97                            <tr valign="top">
     98                                <td>
     99                                    <label for="mvnAlg_indexTaxonomies"><?php esc_html_e( 'Check if you want to index taxonomies', $langDomain ); ?></label>
     100                                    <input type="hidden" value="0" name="<?php echo Settings::settingsField; ?>[indexTaxonomies]">
     101                                    <input type="checkbox" class="checkbox" <?php checked( $registry->indexTaxonomies() ); ?> value="1" id="mvnAlg_indexTaxonomies" name="<?php echo Settings::settingsField; ?>[indexTaxonomies]">
     102                                </td>
     103                            </tr>
     104                            <tr valign="top">
     105                                <th scope="row">
     106                                    <?php esc_html_e( 'This is the list of Taxonomies that would be indexed, please remember that each taxonomy will have its own index name and they will appear separately in the "suggestions search" popup.', $langDomain ); ?><br>
     107                                    <ul><?php
     108                                    $taxonomiesToIndex = Core\FieldsHelper::getTaxonomyObjects();
     109                                    if( $taxonomiesToIndex ):
     110                                        $taxonomiesLabels = Core\FieldsHelper::getTaxonomyLabels();
     111                                        foreach ( $taxonomiesToIndex as $taxKey => $tax ) :
     112                                    ?>
     113                                        <li><?php echo sprintf( '<strong>%s</strong>: %s <br> <strong>%s</strong>: %s', __('Taxonomy'), $taxonomiesLabels[$taxKey], __('Index Name'), $tax->getIndexName() ); ?></li>
     114                                    <?php
     115                                        endforeach;
     116                                    endif;
     117                                    ?>
     118                                    </ul>
     119                                </td>
     120                            </tr>
     121                            <tr>
     122                                <td>
     123                                    <p class="submit"><input type="submit" value="<?php esc_attr_e( 'Save Changes', $langDomain ); ?>" class="button button-primary" id="submit" name="submit"></p>
     124                                </td>
     125                            </tr>
     126                        </tbody>
     127                    </table>
     128                </td>
     129            </tr>
    38130        </table>
    39131       
    40         <?php if ( Core\UtilsAlgolia::readyToIndex() ): ?>
    41         <table class="widefat" style="width: 75%; margin-top: 30px; ">
    42             <thead>
    43                 <tr>
    44                     <th class="row-title" colspan="2"><strong><?php esc_html_e( 'Index Content', $langDomain ); ?></strong></th>
    45                 </tr>
    46             </thead>
    47             <tbody>
    48                 <tr valign="top">
    49                     <th scope="row"><label for="mvnAlg_defaultIndex"><?php esc_html_e( 'Index Name', $langDomain ); ?></label></th>
    50                     <td><input type="text" class="regular-text" value="<?php echo esc_attr(  $registry->getDefaultIndex() ); ?>" id="mvnAlg_defaultIndex" name="<?php echo Settings::settingsField; ?>[defaultIndex]"></td>
    51                 </tr>
    52                 <?php if ( $registry->getDefaultIndex() ): ?>
    53 
    54                     <tr valign="top" class="index-action-row index-action-button">
    55                         <th scope="row"><label for="mvnAlg_index"><?php esc_html_e( 'Click to index content', $langDomain ); ?></label></th>
    56                         <td>
    57                             <div class="algolia-action-button" style="width:50%;">
    58                                 <button type="button" class="button button-secondary"  id="mvnAlg_index" name="mvnAlg_index"><?php esc_html_e( 'Index Content', $langDomain ); ?></button>
    59                                 <span class="spinner algolia-index-spinner"></span>
    60                             </div>
    61                         </td>
    62                     </tr>
    63                     <tr class="index-action-row index-messages">
    64                         <th>&nbsp;</th>
    65                         <td>
    66                             <div class="success"><ul id="mvn-alg-index-result"></ul></div>
    67                             <div class="error error-message" style="display: none;"><p id="mvn-alg-index-error" ></p></div>
    68                         </td>
    69                     </tr>
    70                 <?php else: ?>
    71                     <tr>
    72                         <td colspan="2">
    73                             <p><?php _e( 'Please set an "Index Name" and then update the settings to start indexing content.', $langDomain ) ?></p>
    74                         </td>
    75                     </tr>
    76                 <?php endif; ?>
    77                     <tr>
    78                         <td>
    79                             <p class="submit"><input type="submit" value="<?php esc_attr_e( 'Save Changes', $langDomain ); ?>" class="button button-primary" id="submit" name="submit"></p>
    80                         </td>
    81                     </tr>
    82             </tbody>
    83         </table>
    84         <?php endif; ?>
    85132        </form>
    86133</div>
  • maven-algolia/trunk/core/fields-helper.php

    r915533 r918102  
    101101                                            'taxonomies' => array(
    102102                                                                'category' => array( 'algoliaName' => 'category', 'isTag' => FALSE, 'forFaceting' => TRUE ),
    103                                                                 'tag' => array( 'algoliaName' => 'tag', 'isTag' => TRUE, 'forFaceting' => FALSE ),
     103                                                                'post_tag' => array( 'algoliaName' => '_tags', 'isTag' => TRUE, 'forFaceting' => FALSE ),
    104104                                                            ),
    105105                                            //'metas' =>    array( '{{META_KEY}}' =>  array( 'algoliaName' => '{{FIELD_NAME_IN_ALGOLIA}}', 'isSingle' => TRUE, 'type' => '{{FIELD_TYPE}}' ) )
     
    180180        $fieldsNames = array(
    181181                'term_taxonomy_id'  => array ( 'label' => "objectID", 'type' => 'integer' ),
    182                 'term_id'           => array ( 'label' => "termId", 'type' => 'integer' ), 
     182                'term_id'           => array ( 'label' => "termId", 'type' => 'integer' ),
    183183                'name'              => array ( 'label' => "title", 'type' => 'string' ),
    184184                'slug'              => array ( 'label' => "slug", 'type' => 'string' ),
     
    186186                'parent'            => array ( 'label' => "parent", 'type' => 'integer' ),
    187187                'count'             => array ( 'label' => "postsRelated", 'type' => 'integer' ),
     188                'taxonomy'          => array ( 'label' => "taxonomy", 'type' => 'string' ),
    188189            );
    189190       
     
    218219   
    219220   
    220    
     221    /**
     222     *
     223     * @param object $term
     224     * @param string $field
     225     * @param mixed $value
     226     * @return mixed
     227     */
    221228    public static function getTaxCompoundFieldValue( $term, $field, $value = '' ) {
    222229        switch ( $field ) {
     
    231238    }
    232239   
     240    /**
     241     * Get the domain name
     242     * @return string
     243     */
     244    public static function getDomainName ( ) {
     245        $host =  parse_url ( site_url(), PHP_URL_HOST );
     246        $domainName = array_shift( explode( '.', str_replace( 'www.', '', $host ) ) );
     247        return ( $domainName ) ? $domainName : '' ;
     248    }
     249
     250
     251    /**
     252     * Return the array of taxonomies to index with their fields
     253     * @return array
     254     */
    233255    public static function getTaxonomiesToIndex(){
     256        $indexPrefix = self::getDomainName();
     257        if( !empty( $indexPrefix ) ){
     258            $indexPrefix = sprintf( '%s-', $indexPrefix );
     259        }
    234260       
    235261        $defaultTaxonomies =  array(
    236262                                'category' => array(
    237                                             'indexName' => 'WP-Categories',
     263                                            'indexName' => sprintf( '%sWP-Categories', $indexPrefix ),
    238264                                            //'metas' =>    array( '{{META_KEY}}' =>  array( 'algoliaName' => '{{FIELD_NAME_IN_ALGOLIA}}', 'isSingle' => TRUE, 'type' => '{{FIELD_TYPE}}' ) )
    239265                                            ),
    240266                                'post_tag' => array(
    241                                             'indexName' => 'WP-Tags',
     267                                            'indexName' => sprintf( '%sWP-Tags', $indexPrefix ),
    242268                                            //'metas' =>    array( '{{META_KEY}}' =>  array( 'algoliaName' => '{{FIELD_NAME_IN_ALGOLIA}}', 'isSingle' => TRUE, 'type' => '{{FIELD_TYPE}}' ) )
    243269                                            ),
    244270                                );
    245         return apply_filters( 'mvnAlgTaxonomiesToIndex', $defaultTaxonomies );
    246     }
    247    
     271        return apply_filters( 'mvnAlgTaxonomiesToIndex', $defaultTaxonomies, $indexPrefix );
     272    }
     273   
     274    /**
     275     *
     276     * @return array
     277     */
    248278    public static function getTaxonomyObjects( ){
    249279        $taxonomyObjects = array();
    250         $taxonomies = self::getPostTypesToIndex();
     280        $taxonomies = self::getTaxonomiesToIndex();
    251281        foreach ( $taxonomies as $taxonomyType => $fields ) {
    252282            $taxonomyObjects[$taxonomyType] = self::getTaxonomyObject( $taxonomyType, $fields );
     
    256286    }
    257287   
     288    /**
     289     *
     290     * @param string $taxonomyType
     291     * @return \MavenAlgolia\Core\Domain\Taxonomy|null
     292     */
    258293    public static function getTaxonomyObjectByType( $taxonomyType ){
    259294        $taxonomies = self::getTaxonomiesToIndex();
     
    264299    }
    265300   
     301    /**
     302     *
     303     * @param strings $taxonomyType
     304     * @param array $fields
     305     * @return \MavenAlgolia\Core\Domain\Taxonomy
     306     */
    266307    public static function getTaxonomyObject( $taxonomyType, $fields ){
    267308        $taxObj = new Domain\Taxonomy();
  • maven-algolia/trunk/core/indexer.php

    r915533 r918102  
    512512     */
    513513    public function termToAlgoliaObject( $term, $taxonomy = null ) {
    514         global $wpdb;
    515514       
    516515        if( empty( $taxonomy ) && !empty( $term->taxonomy ) ){
  • maven-algolia/trunk/core/initializer.php

    r915533 r918102  
    2828            $adminUrl = admin_url();
    2929            $homeUrl = set_url_scheme( home_url() );
    30            
    3130            // Front js script
    3231            $settings = array(
     
    3635                    'apiKeySearch' => Registry::instance()->getApiKeySearch(),
    3736                    'indexName' => Registry::instance()->getDefaultIndex(),
    38                     'showExcerpt' => FALSE,
     37                    'showExcerpt' => 0, // Should be an Integer 0 | 1
     38                    'indexTaxonomies' => (int)Registry::instance()->indexTaxonomies(), // Should be an Integer 0 | 1
     39                    'taxonomiesToIndex' => (Registry::instance()->indexTaxonomies()) ? FieldsHelper::getTaxonomiesToIndex() : array(),
     40                    'labels' => array( 'taxonomies' => FieldsHelper::getTaxonomyLabels(), 'posts' => __('Posts') )
    3941                );
    4042            wp_localize_script( 'mvnAlgoliaSearch', 'mvnAlgSettings', $settings, Registry::instance()->getPluginVersion() );
     
    4850                    'inputSearchName' => 's',
    4951                    'containerId' => 'mvn-alg-predictions',
    50                     'showExcerpt' => FALSE,
    5152                    'postsPerPage' => 5,
    5253//                  'labels' => array(
    53 //                                      'indexationError' => 'There was an error trying to run indexation, please contact to the support team.',
    54 //                                      'starting' => 'Starting...',
    55 //                                      'indexing' => 'Indexing ',
    56 //                                      'complete' => 'Complete!',
    57 //                                      'running' => 'Indexation is running as background process, it could take several minutes.',
    58 //                                      'removing' => 'Removing unpublish posts from the index',
    59 //                                      'postsLabels' => $postLabels,
    6054//                                      ),
    6155                );
  • maven-algolia/trunk/core/registry.php

    r915533 r918102  
    3737                'appValid' => '0',
    3838                'appSearchValid' => '0',
     39                'indexTaxonomies' => '0',
    3940            );
    4041           
     
    274275    }
    275276   
     277    public function indexTaxonomies( ) {
     278        return (bool)$this->getValue('indexTaxonomies');
     279    }
     280   
    276281}
  • maven-algolia/trunk/front/assets/scripts/predictions.js

    r915533 r918102  
    22    var algolia;
    33    var that;
     4    var algoliaQueries = [];
    45    var self = {
    56        initialize: function() {
     
    1213            algolia = new AlgoliaSearch( mvnAlgSettings.appId, mvnAlgSettings.apiKeySearch ); // public credentials
    1314        },
     15        indexTaxonomies: function() {
     16            if( typeof mvnAlgSettings.indexTaxonomies !== 'undefined'
     17                    && parseInt( mvnAlgSettings.indexTaxonomies ) === 1
     18                    && typeof mvnAlgSettings.taxonomiesToIndex !== 'undefined'
     19                    && mvnAlgSettings.taxonomiesToIndex ){
     20                return true;
     21            }
     22            return false;
     23        },
    1424        searchCallback: function(success, content, response) {
    15             if ( success && content.results.length > 0 && that.lastQuery === content.results[0].query ) { // do not consider outdated answers
    16           var data = [];
    17                 var posts = content.results[0];
     25            var data = [];
     26            var resultIndex = jQuery.inArray( 'posts', algoliaQueries );
     27            if ( success && content.results.length > 0 && that.lastQuery === content.results[resultIndex].query ) { // do not consider outdated answers
     28                var posts = content.results[resultIndex];
    1829                if( posts.hits.length > 0 ){
    1930                    for (var i = 0; i < posts.hits.length; ++i) {
    2031                        var hit = posts.hits[i];
    21                         data[i] = {
     32                        var hitInfo = {
    2233                                    label: hit.title,
    2334                                    value: hit.title,
     
    2940                                    description: (hit._highlightResult.content && hit._highlightResult.content.value) || hit.content,
    3041                                    date: hit.date,
    31                                     featuredImage: hit.featuredImage
     42                                    featuredImage: hit.featuredImage,
     43                                    category: (mvnAlgSettings.labels.posts) ? mvnAlgSettings.labels.posts : ''   // Posts LABEL
    3244                                    };
     45                        data.push( hitInfo );
    3346                    }
    3447                }
    35         response(data);
    3648            }
     49            if( self.indexTaxonomies() ){
     50                jQuery.each(mvnAlgSettings.taxonomiesToIndex, function(index, element){
     51                    resultIndex = jQuery.inArray( index, algoliaQueries );
     52                    var terms = content.results[resultIndex];
     53                    if( terms.hits.length > 0 ){
     54                        for (var i = 0; i < terms.hits.length; ++i) {
     55                            var hit = terms.hits[i];
     56                            var hitInfo = {
     57                                        label: hit.title,
     58                                        value: hit.objectID,
     59                                        title: (hit._highlightResult.title && hit._highlightResult.title.value) || hit.title,
     60                                        permalink: hit.permalink,
     61                                        featuredImage: hit.image,                                   
     62                                        termId: hit.termId,
     63                                        parent: hit.parent,
     64                                        postsRelated: hit.postsRelated,
     65                                        taxonomy: hit.taxonomy,
     66                                        category: (mvnAlgSettings.labels.taxonomies[index]) ? mvnAlgSettings.labels.taxonomies[index] : ''   // TAXONOMY LABEL
     67                                        };
     68                            data.push( hitInfo );
     69                        }
     70                    }
     71                });
     72            }
     73            response(data);
    3774        },
    3875        getDisplayPost: function( hit ) {
     
    4784                htmlPost += '           <br /><span class="mvn-alg-ls-item-cats">' + hit.categories.join() + '</span>';
    4885            }
    49             if( mvnAlgSearchVars.showExcerpt && typeof hit.excerpt !== 'undefined' && hit.excerpt ){
     86            if( mvnAlgSettings.showExcerpt && typeof hit.excerpt !== 'undefined' && hit.excerpt ){
    5087                htmlPost += '           <br /><span class="mvn-alg-ls-item-desc">' + hit.excerpt + '</span>';
    5188            }
     
    5390            return htmlPost;
    5491        },
     92        getDisplayTerm: function( hit ) {
     93            var html = '';
     94            html += '<a href="' + hit.permalink + '" class="mvn-alg-ls-item-title">';
     95            if( typeof hit.featuredImage !== 'undefined' && hit.featuredImage ){
     96                html += '   <img src="'+hit.featuredImage+'" width="40" height="60" />';
     97            }
     98            html += '       <strong>' + hit.title + '</strong>';
     99            html += '</a>';
     100            return html;
     101        },
    55102        search: function( request, response ) {
    56103            if( typeof algolia !== 'undefined' ){
     104                algoliaQueries = [];
    57105                algolia.startQueriesBatch();
     106               
    58107                algolia.addQueryInBatch( mvnAlgSettings.indexName, request.term, {
    59108                    attributesToRetrieve: ['objectID', 'title', 'permalink', 'excerpt', 'content', 'date', 'featuredImage' , 'category', '_tags'],
    60109                    hitsPerPage: mvnAlgSearchVars.postsPerPage
    61110                });
     111                algoliaQueries.push( 'posts' );
     112               
     113                if( self.indexTaxonomies() ){
     114                    jQuery.each(mvnAlgSettings.taxonomiesToIndex, function(index, element){
     115                        if( typeof element.indexName !== 'undefined' && element.indexName ){
     116                            algolia.addQueryInBatch( element.indexName, request.term, {
     117                                hitsPerPage: mvnAlgSearchVars.postsPerPage
     118                            });
     119                            algoliaQueries.push( index );
     120                        }
     121                    });
     122                }
     123               
    62124                algolia.sendQueriesBatch(function(success, content) {
    63125                    // forward 'response' to Algolia's callback in order to call it with up-to-date results
     
    73135jQuery(document).ready(function($) {
    74136    mvnAlgoliaPrediction.initialize();
    75    
    76137    // The autocomplete function is called on the input textbox with id input_element
    77138    $("input[name='" + mvnAlgSearchVars.inputSearchName + "']").each(function(index){
     
    87148              $(this).val(ui.item.label);
    88149              return false;
    89             },
    90             // This function is executed when the users focuses on a item with the mouse
    91             // or keyboard
    92             focus: function(event, ui) {
    93               // Sets the text of the input textbox to the title of the object referenced
    94               // by the focused list item
    95               $(this).val(ui.item.label);
    96               return false;
    97150            }
    98151          // Here we alter the standard behavior when rendering items in the list
    99           }).data("ui-autocomplete")._renderItem = function(ul, item) {
     152          });
     153        $(this).autocomplete().data("ui-autocomplete")._renderItem = function(ul, item) {
    100154            // ul is the unordered suggestion list
    101155            // item is a object in the data object that was send to the response function
    102156            // after the JSON request
    103157            // We append a custom formatted list item to the suggestion list
    104             return $("<li></li>").data("item.autocomplete", item).append(mvnAlgoliaPrediction.getDisplayPost(item)).appendTo(ul);
    105           };
     158            var itemHtml = '';
     159            if( typeof item.taxonomy !== 'undefined' ){
     160                itemHtml = mvnAlgoliaPrediction.getDisplayTerm(item);
     161            }else{
     162                itemHtml = mvnAlgoliaPrediction.getDisplayPost(item);
     163            }
     164            return $("<li></li>").data("item.autocomplete", item).append(itemHtml).appendTo(ul);
     165        };
     166        // Render menu just if index taxonomies is enabled
     167        if( typeof mvnAlgSettings.indexTaxonomies !== 'undefined' && mvnAlgSettings.indexTaxonomies > 0 && typeof mvnAlgSettings.taxonomiesToIndex !== 'undefined' ){
     168           
     169            $(this).autocomplete().data("ui-autocomplete")._renderMenu = function(ul, items) {
     170                var that = this,
     171                currentCategory = "";
     172                $.each(items, function(index, item) {
     173                    if ( item.category && item.category !== currentCategory) {
     174                        ul.append("<li class='ui-autocomplete-category'><span>" + item.category + "</span></li>");
     175                        currentCategory = item.category;
     176                    }
     177                    that._renderItemData(ul, item);
     178                });
     179            };
     180        }
    106181    });
    107182});
  • maven-algolia/trunk/lib/algoliasearch.min.js

    r915533 r918102  
    11/*!
    2  * algoliasearch 2.4.6
     2 * algoliasearch 2.5.1
    33 * https://github.com/algolia/algoliasearch-client-js
    44 * Copyright 2014 Algolia SAS; Licensed MIT
    55 */
    66
    7 function AlgoliaExplainResults(a,b,c){function d(a,b){var c=[];if("object"==typeof a&&"matchedWords"in a&&"value"in a){for(var e=!1,f=0;f<a.matchedWords.length;++f){var g=a.matchedWords[f];g in b||(b[g]=1,e=!0)}e&&c.push(a.value)}else if("[object Array]"===Object.prototype.toString.call(a))for(var h=0;h<a.length;++h){var i=d(a[h],b);c=c.concat(i)}else if("object"==typeof a)for(var j in a)a.hasOwnProperty(j)&&(c=c.concat(d(a[j],b)));return c}function e(a,b,c){var f=a._highlightResult||a;if(-1===c.indexOf("."))return c in f?d(f[c],b):[];for(var g=c.split("."),h=f,i=0;i<g.length;++i){if("[object Array]"===Object.prototype.toString.call(h)){for(var j=[],k=0;k<h.length;++k)j=j.concat(e(h[k],b,g.slice(i).join(".")));return j}if(!(g[i]in h))return[];h=h[g[i]]}return d(h,b)}var f={},g={},h=e(a,g,b);if(f.title=h.length>0?h[0]:"",f.subtitles=[],"undefined"!=typeof c)for(var i=0;i<c.length;++i)for(var j=e(a,g,c[i]),k=0;k<j.length;++k)f.subtitles.push({attr:c[i],value:j[k]});return f}var ALGOLIA_VERSION="2.4.6",AlgoliaSearch=function(a,b,c,d,e){this.applicationID=a,this.apiKey=b,this._isUndefined(e)&&(e=[a+"-1.algolia.io",a+"-2.algolia.io",a+"-3.algolia.io"]),this.hosts=[];for(var f=0;f<e.length;++f)Math.random()>.5&&this.hosts.reverse(),this._isUndefined(c)||null==c?this.hosts.push(("https:"==document.location.protocol?"https":"http")+"://"+e[f]):"https"===c||"HTTPS"===c?this.hosts.push("https://"+e[f]):this.hosts.push("http://"+e[f]);Math.random()>.5&&this.hosts.reverse(),(this._isUndefined(d)||d)&&this._jsonRequest({method:"GET",url:"/1/isalive"}),this.extraHeaders=[]};AlgoliaSearch.prototype={deleteIndex:function(a,b){this._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(a),callback:b})},moveIndex:function(a,b,c){var d={operation:"move",destination:b};this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(a)+"/operation",body:d,callback:c})},copyIndex:function(a,b,c){var d={operation:"copy",destination:b};this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(a)+"/operation",body:d,callback:c})},getLogs:function(a,b,c){this._isUndefined(b)&&(b=0),this._isUndefined(c)&&(c=10),this._jsonRequest({method:"GET",url:"/1/logs?offset="+b+"&length="+c,callback:a})},listIndexes:function(a){this._jsonRequest({method:"GET",url:"/1/indexes/",callback:a})},initIndex:function(a){return new this.Index(this,a)},listUserKeys:function(a){this._jsonRequest({method:"GET",url:"/1/keys",callback:a})},getUserKeyACL:function(a,b){this._jsonRequest({method:"GET",url:"/1/keys/"+a,callback:b})},deleteUserKey:function(a,b){this._jsonRequest({method:"DELETE",url:"/1/keys/"+a,callback:b})},addUserKey:function(a,b){var c={};c.acl=a,this._jsonRequest({method:"POST",url:"/1/keys",body:c,callback:b})},addUserKeyWithValidity:function(a,b,c,d,e){var f=this,g={};g.acl=a,g.validity=b,g.maxQueriesPerIPPerHour=c,g.maxHitsPerQuery=d,this._jsonRequest({method:"POST",url:"/1/indexes/"+f.indexName+"/keys",body:g,callback:e})},setSecurityTags:function(a){if("[object Array]"===Object.prototype.toString.call(a)){for(var b=[],c=0;c<a.length;++c)if("[object Array]"===Object.prototype.toString.call(a[c])){for(var d=[],e=0;e<a[c].length;++e)d.push(a[c][e]);b.push("("+d.join(",")+")")}else b.push(a[c]);a=b.join(",")}this.tagFilters=a},setUserToken:function(a){this.userToken=a},startQueriesBatch:function(){this.batch=[]},addQueryInBatch:function(a,b,c){var d="query="+encodeURIComponent(b);this._isUndefined(c)||null==c||(d=this._getSearchParams(c,d)),this.batch.push({indexName:a,params:d})},clearCache:function(){this.cache={}},sendQueriesBatch:function(a,b){var c=this,d={requests:[],apiKey:this.apiKey,appID:this.applicationID};this.userToken&&(d["X-Algolia-UserToken"]=this.userToken),this.tagFilters&&(d["X-Algolia-TagFilters"]=this.tagFilters);for(var e=0;e<c.batch.length;++e)d.requests.push(c.batch[e]);if(window.clearTimeout(c.onDelayTrigger),!this._isUndefined(b)&&null!=b&&b>0){var f=window.setTimeout(function(){c._sendQueriesBatch(d,a)},b);c.onDelayTrigger=f}else this._sendQueriesBatch(d,a)},Index:function(a,b){this.indexName=b,this.as=a,this.typeAheadArgs=null,this.typeAheadValueOption=null},setExtraHeader:function(a,b){this.extraHeaders.push({key:a,value:b})},_sendQueriesBatch:function(a,b){this._jsonRequest({cache:this.cache,method:"POST",url:"/1/indexes/*/queries",body:a,callback:b})},_jsonRequest:function(a){var b=this,c=a.callback,d=null,e=a.url;if(this._isUndefined(a.body)||(e=a.url+"_body_"+JSON.stringify(a.body)),!this._isUndefined(a.cache)&&(d=a.cache,!this._isUndefined(d[e])))return this._isUndefined(c)||c(!0,d[e]),void 0;var f=function(g){var h=0;return b._isUndefined(g)||(h=g),b.hosts.length<=h?(b._isUndefined(c)||c(!1,{message:"Cannot contact server"}),void 0):(a.callback=function(g,i,j,k){i||b._isUndefined(k)||console.log("Error: "+k.message),i&&!b._isUndefined(a.cache)&&(d[e]=k),!i&&g&&h+1<b.hosts.length?f(h+1):b._isUndefined(c)||c(i,k)},a.hostname=b.hosts[h],b._jsonRequestByHost(a),void 0)};f()},_jsonRequestByHost:function(a){var b=null,c=this;this._isUndefined(a.body)||(b=JSON.stringify(a.body));var d=a.hostname+a.url,e=null;if(e=new XMLHttpRequest,"withCredentials"in e){e.open(a.method,d,!0),e.setRequestHeader("X-Algolia-API-Key",this.apiKey),e.setRequestHeader("X-Algolia-Application-Id",this.applicationID);for(var f=0;f<this.extraHeaders.length;++f)e.setRequestHeader(this.extraHeaders[f].key,this.extraHeaders[f].value);null!=b&&e.setRequestHeader("Content-type","application/json")}else"undefined"!=typeof XDomainRequest?(e=new XDomainRequest,e.open(a.method,d)):console.log("your browser is too old to support CORS requests");e.send(b),e.onload=function(b){if(c._isUndefined(b)||null==b.target)a.callback(!1,!0,b,JSON.parse(e.responseText));else{var d=0===b.target.status||503===b.target.status,f=200===b.target.status||201===b.target.status;a.callback(d,f,b.target,null!=b.target.response?JSON.parse(b.target.response):null)}},e.onerror=function(){a.callback(!0,!1,null,{message:"Could not connect to Host"})}},_getSearchParams:function(a,b){if(this._isUndefined(a)||null==a)return b;for(var c in a)null!=c&&a.hasOwnProperty(c)&&(b+=0===b.length?"?":"&",b+=c+"="+encodeURIComponent("[object Array]"===Object.prototype.toString.call(a[c])?JSON.stringify(a[c]):a[c]));return b},_isUndefined:function(a){return void 0===a},applicationID:null,apiKey:null,tagFilters:null,userToken:null,hosts:[],cache:{},extraHeaders:[]},AlgoliaSearch.prototype.Index.prototype={clearCache:function(){this.cache={}},addObject:function(a,b,c){var d=this;this.as._isUndefined(c)?this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(d.indexName),body:a,callback:b}):this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(d.indexName)+"/"+encodeURIComponent(c),body:a,callback:b})},addObjects:function(a,b){for(var c=this,d={requests:[]},e=0;e<a.length;++e){var f={action:"addObject",body:a[e]};d.requests.push(f)}this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/batch",body:d,callback:b})},getObject:function(a,b,c){var d=this,e="";if(!this.as._isUndefined(c)){e="?attributes=";for(var f=0;f<c.length;++f)0!==f&&(e+=","),e+=c[f]}this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(d.indexName)+"/"+encodeURIComponent(a)+e,callback:b})},partialUpdateObject:function(a,b){var c=this;this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/"+encodeURIComponent(a.objectID)+"/partial",body:a,callback:b})},partialUpdateObjects:function(a,b){for(var c=this,d={requests:[]},e=0;e<a.length;++e){var f={action:"partialUpdateObject",objectID:a[e].objectID,body:a[e]};d.requests.push(f)}this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/batch",body:d,callback:b})},saveObject:function(a,b){var c=this;this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/"+encodeURIComponent(a.objectID),body:a,callback:b})},saveObjects:function(a,b){for(var c=this,d={requests:[]},e=0;e<a.length;++e){var f={action:"updateObject",objectID:a[e].objectID,body:a[e]};d.requests.push(f)}this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/batch",body:d,callback:b})},deleteObject:function(a,b){if(null==a||0===a.length)return b(!1,{message:"empty objectID"}),void 0;var c=this;this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/"+encodeURIComponent(a),callback:b})},search:function(a,b,c,d){var e=this,f="query="+encodeURIComponent(a);if(this.as._isUndefined(c)||null==c||(f=this.as._getSearchParams(c,f)),window.clearTimeout(e.onDelayTrigger),!this.as._isUndefined(d)&&null!=d&&d>0){var g=window.setTimeout(function(){e._search(f,b)},d);e.onDelayTrigger=g}else this._search(f,b)},browse:function(a,b,c){var d=this,e="?page="+a;_.isUndefined(c)||(e+="&hitsPerPage="+c),this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(d.indexName)+"/browse"+e,callback:b})},ttAdapter:function(a){var b=this;return function(c,d){b.search(c,function(a,b){a&&d(b.hits)},a)}},waitTask:function(a,b){var c=this;this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/task/"+a,callback:function(d,e){d?"published"===e.status?b(!0,e):setTimeout(function(){c.waitTask(a,b)},100):b(!1,e)}})},clearIndex:function(a){var b=this;this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(b.indexName)+"/clear",callback:a})},getSettings:function(a){var b=this;this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(b.indexName)+"/settings",callback:a})},setSettings:function(a,b){var c=this;this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/settings",body:a,callback:b})},listUserKeys:function(a){var b=this;this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(b.indexName)+"/keys",callback:a})},getUserKeyACL:function(a,b){var c=this;this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/keys/"+a,callback:b})},deleteUserKey:function(a,b){var c=this;this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/keys/"+a,callback:b})},addUserKey:function(a,b){var c=this,d={};d.acl=a,this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/keys",body:d,callback:b})},addUserKeyWithValidity:function(a,b,c,d,e){var f=this,g={};g.acl=a,g.validity=b,g.maxQueriesPerIPPerHour=c,g.maxHitsPerQuery=d,this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(f.indexName)+"/keys",body:g,callback:e})},_search:function(a,b){var c={params:a,apiKey:this.as.apiKey,appID:this.as.applicationID};this.as.tagFilters&&(c["X-Algolia-TagFilters"]=this.as.tagFilters),this.as.userToken&&(c["X-Algolia-UserToken"]=this.as.userToken),this.as._jsonRequest({cache:this.cache,method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/query",body:c,callback:b})},as:null,indexName:null,cache:{},typeAheadArgs:null,typeAheadValueOption:null,emptyConstructor:function(){}},function(){var a,b=function(a){a=a||{};for(var b=1;b<arguments.length;b++)if(arguments[b])for(var c in arguments[b])arguments[b].hasOwnProperty(c)&&(a[c]=arguments[b][c]);return a};window.AlgoliaSearchHelper=function(c,d,e){var f={facets:[],disjunctiveFacets:[],hitsPerPage:20};this.init(c,d,b({},f,e)),a=this},AlgoliaSearchHelper.prototype={init:function(a,b,c){this.client=a,this.index=b,this.options=c,this.page=0,this.refinements={},this.disjunctiveRefinements={}},search:function(a,b,c){this.q=a,this.searchCallback=b,this.searchParams=c||{},this.page=this.page||0,this.refinements=this.refinements||{},this.disjunctiveRefinements=this.disjunctiveRefinements||{},this._search()},toggleRefine:function(a,b){for(var c=0;c<this.options.facets.length;++c)if(this.options.facets[c]==a){var d=a+":"+b;return this.refinements[d]=!this.refinements[d],this.page=0,this._search(),!0}this.disjunctiveRefinements[a]=this.disjunctiveRefinements[a]||{};for(var e=0;e<this.options.disjunctiveFacets.length;++e)if(this.options.disjunctiveFacets[e]==a)return this.disjunctiveRefinements[a][b]=!this.disjunctiveRefinements[a][b],this.page=0,this._search(),!0;return!1},isRefined:function(a,b){var c=a+":"+b;return this.refinements[c]?!0:this.disjunctiveRefinements[a]&&this.disjunctiveRefinements[a][b]?!0:!1},nextPage:function(){this._gotoPage(this.page+1)},previousPage:function(){this.page>0&&this._gotoPage(this.page-1)},_gotoPage:function(a){this.page=a,this._search()},_search:function(){this.client.startQueriesBatch(),this.client.addQueryInBatch(this.index,this.q,this._getHitsSearchParams());for(var b=0;b<this.options.disjunctiveFacets.length;++b)this.client.addQueryInBatch(this.index,this.q,this._getDisjunctiveFacetSearchParams(this.options.disjunctiveFacets[b]));this.client.sendQueriesBatch(function(b,c){if(!b)return a.searchCallback(!1,c),void 0;var d=c.results[0];d.disjunctiveFacets={};for(var e=1;e<c.results.length;++e)for(var f in c.results[e].facets)if(d.disjunctiveFacets[f]=c.results[e].facets[f],a.disjunctiveRefinements[f])for(var g in a.disjunctiveRefinements[f])!d.disjunctiveFacets[f][g]&&a.disjunctiveRefinements[f][g]&&(d.disjunctiveFacets[f][g]=0);a.searchCallback(!0,d)})},_getHitsSearchParams:function(){return b({},this.searchParams,{hitsPerPage:this.options.hitsPerPage,page:this.page,facets:this.options.facets,facetFilters:this._getFacetFilters()})},_getDisjunctiveFacetSearchParams:function(a){return b({},this.searchParams,{hitsPerPage:1,page:0,facets:a,facetFilters:this._getFacetFilters(a)})},_getFacetFilters:function(a){var b=[];for(var c in this.refinements)this.refinements[c]&&b.push(c);for(var d in this.disjunctiveRefinements)if(d!=a){var e=[];for(var f in this.disjunctiveRefinements[d])this.disjunctiveRefinements[d][f]&&e.push(d+":"+f);e.length>0&&b.push(e)}return b}}}();
     7function AlgoliaExplainResults(a,b,c){function d(a,b){var c=[];if("object"==typeof a&&"matchedWords"in a&&"value"in a){for(var e=!1,f=0;f<a.matchedWords.length;++f){var g=a.matchedWords[f];g in b||(b[g]=1,e=!0)}e&&c.push(a.value)}else if("[object Array]"===Object.prototype.toString.call(a))for(var h=0;h<a.length;++h){var i=d(a[h],b);c=c.concat(i)}else if("object"==typeof a)for(var j in a)a.hasOwnProperty(j)&&(c=c.concat(d(a[j],b)));return c}function e(a,b,c){var f=a._highlightResult||a;if(-1===c.indexOf("."))return c in f?d(f[c],b):[];for(var g=c.split("."),h=f,i=0;i<g.length;++i){if("[object Array]"===Object.prototype.toString.call(h)){for(var j=[],k=0;k<h.length;++k)j=j.concat(e(h[k],b,g.slice(i).join(".")));return j}if(!(g[i]in h))return[];h=h[g[i]]}return d(h,b)}var f={},g={},h=e(a,g,b);if(f.title=h.length>0?h[0]:"",f.subtitles=[],"undefined"!=typeof c)for(var i=0;i<c.length;++i)for(var j=e(a,g,c[i]),k=0;k<j.length;++k)f.subtitles.push({attr:c[i],value:j[k]});return f}var ALGOLIA_VERSION="2.5.1",AlgoliaSearch=function(a,b,c,d,e){var f=this;this.applicationID=a,this.apiKey=b,this._isUndefined(e)&&(e=[a+"-1.algolia.io",a+"-2.algolia.io",a+"-3.algolia.io"]),this.hosts=[];for(var g=0;g<e.length;++g)Math.random()>.5&&this.hosts.reverse(),this._isUndefined(c)||null==c?this.hosts.push(("https:"==document.location.protocol?"https":"http")+"://"+e[g]):"https"===c||"HTTPS"===c?this.hosts.push("https://"+e[g]):this.hosts.push("http://"+e[g]);Math.random()>.5&&this.hosts.reverse(),this.jsonp=null,this.jsonpWait=0,this._jsonRequest({method:"GET",url:"/1/isalive",callback:function(a){f.jsonp=!a}}),this.extraHeaders=[]};AlgoliaSearch.prototype={deleteIndex:function(a,b){this._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(a),callback:b})},moveIndex:function(a,b,c){var d={operation:"move",destination:b};this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(a)+"/operation",body:d,callback:c})},copyIndex:function(a,b,c){var d={operation:"copy",destination:b};this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(a)+"/operation",body:d,callback:c})},getLogs:function(a,b,c){this._isUndefined(b)&&(b=0),this._isUndefined(c)&&(c=10),this._jsonRequest({method:"GET",url:"/1/logs?offset="+b+"&length="+c,callback:a})},listIndexes:function(a){this._jsonRequest({method:"GET",url:"/1/indexes",callback:a})},initIndex:function(a){return new this.Index(this,a)},listUserKeys:function(a){this._jsonRequest({method:"GET",url:"/1/keys",callback:a})},getUserKeyACL:function(a,b){this._jsonRequest({method:"GET",url:"/1/keys/"+a,callback:b})},deleteUserKey:function(a,b){this._jsonRequest({method:"DELETE",url:"/1/keys/"+a,callback:b})},addUserKey:function(a,b){var c={};c.acl=a,this._jsonRequest({method:"POST",url:"/1/keys",body:c,callback:b})},addUserKeyWithValidity:function(a,b,c,d,e){var f=this,g={};g.acl=a,g.validity=b,g.maxQueriesPerIPPerHour=c,g.maxHitsPerQuery=d,this._jsonRequest({method:"POST",url:"/1/indexes/"+f.indexName+"/keys",body:g,callback:e})},setSecurityTags:function(a){if("[object Array]"===Object.prototype.toString.call(a)){for(var b=[],c=0;c<a.length;++c)if("[object Array]"===Object.prototype.toString.call(a[c])){for(var d=[],e=0;e<a[c].length;++e)d.push(a[c][e]);b.push("("+d.join(",")+")")}else b.push(a[c]);a=b.join(",")}this.tagFilters=a},setUserToken:function(a){this.userToken=a},startQueriesBatch:function(){this.batch=[]},addQueryInBatch:function(a,b,c){var d="query="+encodeURIComponent(b);this._isUndefined(c)||null==c||(d=this._getSearchParams(c,d)),this.batch.push({indexName:a,params:d})},clearCache:function(){this.cache={}},sendQueriesBatch:function(a,b){var c=this,d={requests:[],apiKey:this.apiKey,appID:this.applicationID};this.userToken&&(d["X-Algolia-UserToken"]=this.userToken),this.tagFilters&&(d["X-Algolia-TagFilters"]=this.tagFilters);for(var e=0;e<c.batch.length;++e)d.requests.push(c.batch[e]);if(window.clearTimeout(c.onDelayTrigger),!this._isUndefined(b)&&null!=b&&b>0){var f=window.setTimeout(function(){c._sendQueriesBatch(d,a)},b);c.onDelayTrigger=f}else this._sendQueriesBatch(d,a)},Index:function(a,b){this.indexName=b,this.as=a,this.typeAheadArgs=null,this.typeAheadValueOption=null},setExtraHeader:function(a,b){this.extraHeaders.push({key:a,value:b})},_sendQueriesBatch:function(a,b){if(null==this.jsonp){var c=this;return this._waitReady(function(){c._sendQueriesBatch(a,b)}),void 0}if(this.jsonp){for(var d="",e=0;e<a.requests.length;++e){var f="/1/indexes/"+encodeURIComponent(a.requests[e].indexName)+"?"+a.requests[e].params;d+=e+"="+encodeURIComponent(f)+"&"}this._jsonRequest({cache:this.cache,method:"GET",jsonp:!0,url:"/1/indexes/*",body:{params:d},callback:b})}else this._jsonRequest({cache:this.cache,method:"POST",url:"/1/indexes/*/queries",body:a,callback:b})},_jsonRequest:function(a){var b=this,c=a.callback,d=null,e=a.url;if(this._isUndefined(a.body)||(e=a.url+"_body_"+JSON.stringify(a.body)),!this._isUndefined(a.cache)&&(d=a.cache,!this._isUndefined(d[e])))return this._isUndefined(c)||c(!0,d[e]),void 0;var f=function(g){var h=0;return b._isUndefined(g)||(h=g),b.hosts.length<=h?(b._isUndefined(c)||c(!1,{message:"Cannot contact server"}),void 0):(a.callback=function(g,i,j,k){i||b._isUndefined(k)||window.console&&console.log("Error: "+k.message),i&&!b._isUndefined(a.cache)&&(d[e]=k),!i&&g&&h+1<b.hosts.length?f(h+1):b._isUndefined(c)||c(i,k)},a.hostname=b.hosts[h],b._jsonRequestByHost(a),void 0)};f()},_jsonRequestByHost:function(a){var b=this,c=a.hostname+a.url;if(this.jsonp){if(!a.jsonp)return a.callback(!0,!1,null,{message:"Method "+a.method+" "+c+" is not supported by JSONP."}),void 0;this.jsonpCounter=this.jsonpCounter||0,this.jsonpCounter+=1;var d="algoliaJSONP_"+this.jsonpCounter;window[d]=function(b){a.callback(!1,!0,null,b);try{delete window[d]}catch(c){window[d]=void 0}};var e=document.createElement("script");e.type="text/javascript",e.src=c+"?callback="+d+","+this.applicationID+","+this.apiKey,a["X-Algolia-TagFilters"]&&(e.src+="&X-Algolia-TagFilters="+a["X-Algolia-TagFilters"]),a["X-Algolia-UserToken"]&&(e.src+="&X-Algolia-UserToken="+a["X-Algolia-UserToken"]),a.body&&a.body.params&&(e.src+="&"+a.body.params);var f=document.getElementsByTagName("head")[0];e.onerror=function(){a.callback(!0,!1,null,{message:"Failed to load JSONP script."}),f.removeChild(e);try{delete window[d]}catch(b){window[d]=void 0}};var g=!1;e.onload=e.onreadystatechange=function(){if(!(g||this.readyState&&"loaded"!=this.readyState&&"complete"!=this.readyState)){if(g=!0,"undefined"==typeof window[d+"_loaded"]){a.callback(!0,!1,null,{message:"Failed to load JSONP script."});try{delete window[d]}catch(b){window[d]=void 0}}else try{delete window[d+"_loaded"]}catch(b){window[d+"_loaded"]=void 0}e.onload=e.onreadystatechange=null,f.removeChild(e)}},f.appendChild(e)}else{var h=null;this._isUndefined(a.body)||(h=JSON.stringify(a.body));var i=window.XMLHttpRequest?new XMLHttpRequest:{};if("withCredentials"in i){i.open(a.method,c,!0),i.setRequestHeader("X-Algolia-API-Key",this.apiKey),i.setRequestHeader("X-Algolia-Application-Id",this.applicationID);for(var j=0;j<this.extraHeaders.length;++j)i.setRequestHeader(this.extraHeaders[j].key,this.extraHeaders[j].value);null!=h&&i.setRequestHeader("Content-type","application/json")}else{if("undefined"==typeof XDomainRequest)return window.console&&console.log("Your browser is too old to support CORS requests"),a.callback(!1,!1,null,{message:"CORS not supported"}),void 0;i=new XDomainRequest,i.open(a.method,c)}i.send(h),i.onload=function(c){if(b._isUndefined(c)||null==c.target)a.callback(!1,!0,c,JSON.parse(i.responseText));else{var d=0===c.target.status||503===c.target.status,e=200===c.target.status||201===c.target.status;a.callback(d,e,c.target,null!=c.target.response?JSON.parse(c.target.response):null)}},i.onerror=function(b){a.callback(!0,!1,null,{message:"Could not connect to host",error:b})}}},_waitReady:function(a){null==this.jsonp&&(this.jsonpWait+=100,this.jsonpWait>2e3&&(this.jsonp=!0),setTimeout(a,100))},_getSearchParams:function(a,b){if(this._isUndefined(a)||null==a)return b;for(var c in a)null!=c&&a.hasOwnProperty(c)&&(b+=0===b.length?"?":"&",b+=c+"="+encodeURIComponent("[object Array]"===Object.prototype.toString.call(a[c])?JSON.stringify(a[c]):a[c]));return b},_isUndefined:function(a){return void 0===a},applicationID:null,apiKey:null,tagFilters:null,userToken:null,hosts:[],cache:{},extraHeaders:[]},AlgoliaSearch.prototype.Index.prototype={clearCache:function(){this.cache={}},addObject:function(a,b,c){var d=this;this.as._isUndefined(c)?this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(d.indexName),body:a,callback:b}):this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(d.indexName)+"/"+encodeURIComponent(c),body:a,callback:b})},addObjects:function(a,b){for(var c=this,d={requests:[]},e=0;e<a.length;++e){var f={action:"addObject",body:a[e]};d.requests.push(f)}this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/batch",body:d,callback:b})},getObject:function(a,b,c){if(null==this.as.jsonp){var d=this;return this.as._waitReady(function(){d.getObject(a,b,c)}),void 0}var e=this,f="";if(!this.as._isUndefined(c)){f="?attributes=";for(var g=0;g<c.length;++g)0!==g&&(f+=","),f+=c[g]}this.as._jsonRequest({method:"GET",jsonp:!0,url:"/1/indexes/"+encodeURIComponent(e.indexName)+"/"+encodeURIComponent(a)+f,callback:b})},partialUpdateObject:function(a,b){var c=this;this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/"+encodeURIComponent(a.objectID)+"/partial",body:a,callback:b})},partialUpdateObjects:function(a,b){for(var c=this,d={requests:[]},e=0;e<a.length;++e){var f={action:"partialUpdateObject",objectID:a[e].objectID,body:a[e]};d.requests.push(f)}this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/batch",body:d,callback:b})},saveObject:function(a,b){var c=this;this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/"+encodeURIComponent(a.objectID),body:a,callback:b})},saveObjects:function(a,b){for(var c=this,d={requests:[]},e=0;e<a.length;++e){var f={action:"updateObject",objectID:a[e].objectID,body:a[e]};d.requests.push(f)}this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/batch",body:d,callback:b})},deleteObject:function(a,b){if(null==a||0===a.length)return b(!1,{message:"empty objectID"}),void 0;var c=this;this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/"+encodeURIComponent(a),callback:b})},search:function(a,b,c,d){var e=this,f="query="+encodeURIComponent(a);if(this.as._isUndefined(c)||null==c||(f=this.as._getSearchParams(c,f)),window.clearTimeout(e.onDelayTrigger),!this.as._isUndefined(d)&&null!=d&&d>0){var g=window.setTimeout(function(){e._search(f,b)},d);e.onDelayTrigger=g}else this._search(f,b)},browse:function(a,b,c){var d=this,e="?page="+a;_.isUndefined(c)||(e+="&hitsPerPage="+c),this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(d.indexName)+"/browse"+e,callback:b})},ttAdapter:function(a){var b=this;return function(c,d){b.search(c,function(a,b){a&&d(b.hits)},a)}},waitTask:function(a,b){var c=this;this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/task/"+a,callback:function(d,e){d?"published"===e.status?b(!0,e):setTimeout(function(){c.waitTask(a,b)},100):b(!1,e)}})},clearIndex:function(a){var b=this;this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(b.indexName)+"/clear",callback:a})},getSettings:function(a){var b=this;this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(b.indexName)+"/settings",callback:a})},setSettings:function(a,b){var c=this;this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/settings",body:a,callback:b})},listUserKeys:function(a){var b=this;this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(b.indexName)+"/keys",callback:a})},getUserKeyACL:function(a,b){var c=this;this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/keys/"+a,callback:b})},deleteUserKey:function(a,b){var c=this;this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/keys/"+a,callback:b})},addUserKey:function(a,b){var c=this,d={};d.acl=a,this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/keys",body:d,callback:b})},addUserKeyWithValidity:function(a,b,c,d,e){var f=this,g={};g.acl=a,g.validity=b,g.maxQueriesPerIPPerHour=c,g.maxHitsPerQuery=d,this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(f.indexName)+"/keys",body:g,callback:e})},_search:function(a,b){if(null==this.as.jsonp){var c=this;return this.as._waitReady(function(){c._search(a,b)}),void 0}var d={params:a,apiKey:this.as.apiKey,appID:this.as.applicationID};this.as.tagFilters&&(d["X-Algolia-TagFilters"]=this.as.tagFilters),this.as.userToken&&(d["X-Algolia-UserToken"]=this.as.userToken),this.as.jsonp?this.as._jsonRequest({cache:this.cache,method:"GET",jsonp:!0,url:"/1/indexes/"+encodeURIComponent(this.indexName),body:d,callback:b}):this.as._jsonRequest({cache:this.cache,method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/query",body:d,callback:b})},as:null,indexName:null,cache:{},typeAheadArgs:null,typeAheadValueOption:null,emptyConstructor:function(){}},function(){var a=function(a){a=a||{};for(var b=1;b<arguments.length;b++)if(arguments[b])for(var c in arguments[b])arguments[b].hasOwnProperty(c)&&(a[c]=arguments[b][c]);return a};window.AlgoliaSearchHelper=function(b,c,d){var e={facets:[],disjunctiveFacets:[],hitsPerPage:20};this.init(b,c,a({},e,d))},AlgoliaSearchHelper.prototype={init:function(a,b,c){this.client=a,this.index=b,this.options=c,this.page=0,this.refinements={},this.disjunctiveRefinements={}},search:function(a,b,c){this.q=a,this.searchCallback=b,this.searchParams=c||{},this.page=this.page||0,this.refinements=this.refinements||{},this.disjunctiveRefinements=this.disjunctiveRefinements||{},this._search()},toggleRefine:function(a,b){for(var c=0;c<this.options.facets.length;++c)if(this.options.facets[c]==a){var d=a+":"+b;return this.refinements[d]=!this.refinements[d],this.page=0,this._search(),!0}this.disjunctiveRefinements[a]=this.disjunctiveRefinements[a]||{};for(var e=0;e<this.options.disjunctiveFacets.length;++e)if(this.options.disjunctiveFacets[e]==a)return this.disjunctiveRefinements[a][b]=!this.disjunctiveRefinements[a][b],this.page=0,this._search(),!0;return!1},isRefined:function(a,b){var c=a+":"+b;return this.refinements[c]?!0:this.disjunctiveRefinements[a]&&this.disjunctiveRefinements[a][b]?!0:!1},nextPage:function(){this._gotoPage(this.page+1)},previousPage:function(){this.page>0&&this._gotoPage(this.page-1)},_gotoPage:function(a){this.page=a,this._search()},_search:function(){this.client.startQueriesBatch(),this.client.addQueryInBatch(this.index,this.q,this._getHitsSearchParams());for(var a=0;a<this.options.disjunctiveFacets.length;++a)this.client.addQueryInBatch(this.index,this.q,this._getDisjunctiveFacetSearchParams(this.options.disjunctiveFacets[a]));var b=this;this.client.sendQueriesBatch(function(a,c){if(!a)return b.searchCallback(!1,c),void 0;var d=c.results[0];d.disjunctiveFacets={};for(var e=1;e<c.results.length;++e)for(var f in c.results[e].facets)if(d.disjunctiveFacets[f]=c.results[e].facets[f],b.disjunctiveRefinements[f])for(var g in b.disjunctiveRefinements[f])!d.disjunctiveFacets[f][g]&&b.disjunctiveRefinements[f][g]&&(d.disjunctiveFacets[f][g]=0);b.searchCallback(!0,d)})},_getHitsSearchParams:function(){return a({},this.searchParams,{hitsPerPage:this.options.hitsPerPage,page:this.page,facets:this.options.facets,facetFilters:this._getFacetFilters()})},_getDisjunctiveFacetSearchParams:function(b){return a({},this.searchParams,{hitsPerPage:1,page:0,facets:b,facetFilters:this._getFacetFilters(b)})},_getFacetFilters:function(a){var b=[];for(var c in this.refinements)this.refinements[c]&&b.push(c);for(var d in this.disjunctiveRefinements)if(d!=a){var e=[];for(var f in this.disjunctiveRefinements[d])this.disjunctiveRefinements[d][f]&&e.push(d+":"+f);e.length>0&&b.push(e)}return b}}}(),"object"!=typeof JSON&&(JSON={}),function(){"use strict";function f(a){return 10>a?"0"+a:a}function quote(a){return escapable.lastIndex=0,escapable.test(a)?'"'+a.replace(escapable,function(a){var b=meta[a];return"string"==typeof b?b:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function str(a,b){var c,d,e,f,g,h=gap,i=b[a];switch(i&&"object"==typeof i&&"function"==typeof i.toJSON&&(i=i.toJSON(a)),"function"==typeof rep&&(i=rep.call(b,a,i)),typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";if(gap+=indent,g=[],"[object Array]"===Object.prototype.toString.apply(i)){for(f=i.length,c=0;f>c;c+=1)g[c]=str(c,i)||"null";return e=0===g.length?"[]":gap?"[\n"+gap+g.join(",\n"+gap)+"\n"+h+"]":"["+g.join(",")+"]",gap=h,e}if(rep&&"object"==typeof rep)for(f=rep.length,c=0;f>c;c+=1)"string"==typeof rep[c]&&(d=rep[c],e=str(d,i),e&&g.push(quote(d)+(gap?": ":":")+e));else for(d in i)Object.prototype.hasOwnProperty.call(i,d)&&(e=str(d,i),e&&g.push(quote(d)+(gap?": ":":")+e));return e=0===g.length?"{}":gap?"{\n"+gap+g.join(",\n"+gap)+"\n"+h+"}":"{"+g.join(",")+"}",gap=h,e}}"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()});var cx,escapable,gap,indent,meta,rep;"function"!=typeof JSON.stringify&&(escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,meta={"\b":"\\b","    ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},JSON.stringify=function(a,b,c){var d;if(gap="",indent="","number"==typeof c)for(d=0;c>d;d+=1)indent+=" ";else"string"==typeof c&&(indent=c);if(rep=b,b&&"function"!=typeof b&&("object"!=typeof b||"number"!=typeof b.length))throw new Error("JSON.stringify");return str("",{"":a})}),"function"!=typeof JSON.parse&&(cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,JSON.parse=function(text,reviver){function walk(a,b){var c,d,e=a[b];if(e&&"object"==typeof e)for(c in e)Object.prototype.hasOwnProperty.call(e,c)&&(d=walk(e,c),void 0!==d?e[c]=d:delete e[c]);return reviver.call(a,b,e)}var j;if(text=String(text),cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})),/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return j=eval("("+text+")"),"function"==typeof reviver?walk({"":j},""):j;throw new SyntaxError("JSON.parse")})}();
  • maven-algolia/trunk/lib/algoliasearch.php

    r915533 r918102  
    2323 *
    2424 *
    25  * VERSION 1.1.8
     25 * VERSION 1.1.9
    2626 *
    2727 */
     
    2929
    3030class AlgoliaException extends \Exception { }
     31
     32class ClientContext {
     33    function __construct($applicationID, $apiKey, $hostsArray) {
     34        $this->applicationID = $applicationID;
     35        $this->apiKey = $apiKey;
     36        $this->hostsArray = $hostsArray;
     37
     38        if ($this->applicationID == null || mb_strlen($this->applicationID) == 0) {
     39            throw new \Exception('AlgoliaSearch requires an applicationID.');
     40        }
     41        if ($this->apiKey == null || mb_strlen($this->apiKey) == 0) {
     42            throw new \Exception('AlgoliaSearch requires an apiKey.');
     43        }
     44        if ($this->hostsArray == null || count($this->hostsArray) == 0) {
     45            throw new \Exception('AlgoliaSearch requires a list of hostnames.');
     46        } else {
     47            // randomize elements of hostsArray (act as a kind of load-balancer)
     48            shuffle($this->hostsArray);
     49        }
     50
     51        $this->curlMHandle = NULL;
     52        $this->adminAPIKey = NULL;
     53        $this->endUserIP = NULL;
     54        $this->rateLimitAPIKey = NULL;
     55    }
     56
     57    function __destruct() {
     58        if ($this->curlMHandle != null) {
     59            curl_multi_close($this->curlMHandle);
     60        }
     61    }
     62
     63    public function getMHandle($curlHandle) {
     64        if ($this->curlMHandle == null) {
     65            $this->curlMHandle = curl_multi_init();
     66        }
     67        curl_multi_add_handle($this->curlMHandle, $curlHandle);
     68
     69        return $this->curlMHandle;
     70    }
     71
     72    public function releaseMHandle($curlHandle) {
     73        curl_multi_remove_handle($this->curlMHandle, $curlHandle);
     74    }
     75   
     76    public function setRateLimit($adminAPIKey, $endUserIP, $rateLimitAPIKey) {
     77        $this->adminAPIKey = $adminAPIKey;
     78        $this->endUserIP = $endUserIP;
     79        $this->rateLimitAPIKey = $rateLimitAPIKey;
     80    }
     81
     82    public function disableRateLimit() {
     83        $this->adminAPIKey = NULL;
     84        $this->endUserIP = NULL;
     85        $this->rateLimitAPIKey = NULL;
     86
     87    }
     88
     89    public $applicationID;
     90    public $apiKey;
     91    public $hostsArray;
     92    public $curlMHandle;
     93    public $adminAPIKey;
     94}
    3195
    3296/**
     
    42106     * @param hostsArray the list of hosts that you have received for the service
    43107     */
    44     public function __construct($applicationID, $apiKey, $hostsArray = null) {
    45         $this->applicationID = $applicationID;
    46         $this->apiKey = $apiKey;
     108    function __construct($applicationID, $apiKey, $hostsArray = null) {
    47109        if ($hostsArray == null) {
    48             $this->hostsArray = array($applicationID . "-1.algolia.io", $applicationID . "-2.algolia.io", $applicationID . "-3.algolia.io");
     110            $this->context = new ClientContext($applicationID, $apiKey, array($applicationID . "-1.algolia.io", $applicationID . "-2.algolia.io", $applicationID . "-3.algolia.io"));
    49111        } else {
    50             $this->hostsArray = $hostsArray;
    51         }
    52 
     112            $this->context = new ClientContext($applicationID, $apiKey, $hostsArray);
     113        }
    53114        if(!function_exists('curl_init')){
    54115            throw new \Exception('AlgoliaSearch requires the CURL PHP extension.');
    55116        }
    56 
    57117        if(!function_exists('json_decode')){
    58118            throw new \Exception('AlgoliaSearch requires the JSON PHP extension.');
    59119        }
    60         if ($this->applicationID == null || mb_strlen($this->applicationID) == 0) {
    61             throw new \Exception('AlgoliaSearch requires an applicationID.');
    62         }
    63         if ($this->apiKey == null || mb_strlen($this->apiKey) == 0) {
    64             throw new \Exception('AlgoliaSearch requires an apiKey.');
    65         }
    66         if ($this->hostsArray == null || count($this->hostsArray) == 0) {
    67             throw new \Exception('AlgoliaSearch requires a list of hostnames.');
    68         } else {
    69             // randomize elements of hostsArray (act as a kind of load-balancer)
    70             shuffle($this->hostsArray);
    71         }
    72 
    73         // initialize curl library
    74         $this->curlHandle = curl_init();
    75         curl_setopt($this->curlHandle, CURLOPT_HTTPHEADER, array(
    76                     'X-Algolia-Application-Id: ' . $this->applicationID,
    77                     'X-Algolia-API-Key: ' . $this->apiKey,
    78                     'Content-type: application/json'
    79                     ));
    80         curl_setopt($this->curlHandle, CURLOPT_USERAGENT, "Algolia for PHP 1.1.8");
    81         //Return the output instead of printing it
    82         curl_setopt($this->curlHandle, CURLOPT_RETURNTRANSFER, true);
    83         curl_setopt($this->curlHandle, CURLOPT_FAILONERROR, true);
    84         curl_setopt($this->curlHandle, CURLOPT_ENCODING, '');
    85         curl_setopt($this->curlHandle, CURLOPT_SSL_VERIFYPEER, true);
    86         curl_setopt($this->curlHandle, CURLOPT_SSL_VERIFYHOST, 2);
    87         curl_setopt($this->curlHandle, CURLOPT_CAINFO, __DIR__ . '/resources/ca-bundle.crt');
     120    }
     121
     122    /*
     123     * Release curl handle
     124     */
     125    function __destruct() {
    88126    }
    89127
     
    96134     */
    97135    public function enableRateLimitForward($adminAPIKey, $endUserIP, $rateLimitAPIKey) {
    98          curl_setopt($this->curlHandle, CURLOPT_HTTPHEADER, array(
    99                     'X-Algolia-Application-Id: ' . $this->applicationID,
    100                     'X-Algolia-API-Key: ' . $adminAPIKey,
    101                     'X-Forwarded-For: ' . $endUserIP,
    102                     'X-Forwarded-API-Key: ' . $rateLimitAPIKey,
    103                     'Content-type: application/json'
    104                     ));
     136        $this->context->setRateLimit($adminAPIKey, $endUserIP, $rateLimitAPIKey);
    105137    }
    106138
     
    109141     */
    110142    public function disableRateLimitForward() {
    111         curl_setopt($this->curlHandle, CURLOPT_HTTPHEADER, array(
    112                     'X-Algolia-Application-Id: ' . $this->applicationID,
    113                     'X-Algolia-API-Key: ' . $this->apiKey,
    114                     'Content-type: application/json'
    115                     ));
     143        $this->context->disableRateLimit();
    116144    }
    117145
     
    135163            array_push($requests, $req);
    136164        }
    137         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "POST", "/1/indexes/*/queries", array(), array("requests" => $requests));
     165        return AlgoliaUtils_request($this->context, "POST", "/1/indexes/*/queries", array(), array("requests" => $requests));
    138166    }
    139167
     
    147175     */
    148176    public function listIndexes() {
    149         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "GET", "/1/indexes/");
     177        return AlgoliaUtils_request($this->context, "GET", "/1/indexes/");
    150178    }
    151179
     
    157185     */
    158186    public function deleteIndex($indexName) {
    159         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "DELETE", "/1/indexes/" . urlencode($indexName));
     187        return AlgoliaUtils_request($this->context, "DELETE", "/1/indexes/" . urlencode($indexName));
    160188    }
    161189
     
    167195    public function moveIndex($srcIndexName, $dstIndexName) {
    168196        $request = array("operation" => "move", "destination" => $dstIndexName);
    169         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "POST", "/1/indexes/" . urlencode($srcIndexName) . "/operation", array(), $request);
     197        return AlgoliaUtils_request($this->context, "POST", "/1/indexes/" . urlencode($srcIndexName) . "/operation", array(), $request);
    170198    }
    171199
     
    177205    public function copyIndex($srcIndexName, $dstIndexName) {
    178206        $request = array("operation" => "copy", "destination" => $dstIndexName);
    179         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "POST", "/1/indexes/" . urlencode($srcIndexName) . "/operation", array(), $request);
     207        return AlgoliaUtils_request($this->context, "POST", "/1/indexes/" . urlencode($srcIndexName) . "/operation", array(), $request);
    180208    }
    181209
     
    186214     */
    187215    public function getLogs($offset = 0, $length = 10, $onlyErrors = false) {
    188         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "GET", "/1/logs?offset=" . $offset . "&length=" . $length . "&onlyErrors=" . $onlyErrors);
     216        return AlgoliaUtils_request($this->context, "GET", "/1/logs?offset=" . $offset . "&length=" . $length . "&onlyErrors=" . $onlyErrors);
    189217    }
    190218
     
    195223     */
    196224    public function initIndex($indexName) {
    197         return new Index($this->curlHandle, $this->hostsArray, $indexName);
     225        return new Index($this->context, $indexName);
    198226    }
    199227
     
    203231     */
    204232    public function listUserKeys() {
    205         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "GET", "/1/keys");
     233        return AlgoliaUtils_request($this->context, "GET", "/1/keys");
    206234    }
    207235
     
    211239     */
    212240    public function getUserKeyACL($key) {
    213         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "GET", "/1/keys/" . $key);
     241        return AlgoliaUtils_request($this->context, "GET", "/1/keys/" . $key);
    214242    }
    215243
     
    219247     */
    220248    public function deleteUserKey($key) {
    221         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "DELETE", "/1/keys/" . $key);
     249        return AlgoliaUtils_request($this->context, "DELETE", "/1/keys/" . $key);
    222250    }
    223251
     
    254282            $params['indexes'] = $indexes;
    255283        }
    256         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "POST", "/1/keys", array(), $params);
     284        return AlgoliaUtils_request($this->context, "POST", "/1/keys", array(), $params);
    257285    }
    258286
     
    285313    }
    286314
    287     protected $applicationID;
    288     protected $apiKey;
    289     protected $hostsArray;
    290     protected $curlHandle;
     315    protected $context;
    291316}
    292317
     
    299324     * Index initialization (You should not call this initialized yourself)
    300325     */
    301     public function __construct($curlHandle, $hostsArray, $indexName) {
    302         $this->curlHandle = $curlHandle;
    303         $this->hostsArray = $hostsArray;
     326    public function __construct($context, $indexName) {
     327        $this->context = $context;
    304328        $this->indexName = $indexName;
    305329        $this->urlIndexName = urlencode($indexName);
     
    348372
    349373        if ($objectID === null) {
    350             return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "POST", "/1/indexes/" . $this->urlIndexName, array(), $content);
     374            return AlgoliaUtils_request($this->context, "POST", "/1/indexes/" . $this->urlIndexName, array(), $content);
    351375        } else {
    352             return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "PUT", "/1/indexes/" . $this->urlIndexName . "/" . urlencode($objectID), array(), $content);
     376            return AlgoliaUtils_request($this->context, "PUT", "/1/indexes/" . $this->urlIndexName . "/" . urlencode($objectID), array(), $content);
    353377        }
    354378    }
     
    373397        $id = urlencode($objectID);
    374398        if ($attributesToRetrieve === null)
    375             return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "GET", "/1/indexes/" . $this->urlIndexName . "/" . $id);
     399            return AlgoliaUtils_request($this->context, "GET", "/1/indexes/" . $this->urlIndexName . "/" . $id);
    376400        else
    377             return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "GET", "/1/indexes/" . $this->urlIndexName . "/" . $id, array("attributes" => $attributesToRetrieve));
     401            return AlgoliaUtils_request($this->context, "GET", "/1/indexes/" . $this->urlIndexName . "/" . $id, array("attributes" => $attributesToRetrieve));
    378402    }
    379403
     
    385409     */
    386410    public function partialUpdateObject($partialObject) {
    387         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "POST", "/1/indexes/" . $this->urlIndexName . "/" . urlencode($partialObject["objectID"]) . "/partial", array(), $partialObject);
     411        return AlgoliaUtils_request($this->context, "POST", "/1/indexes/" . $this->urlIndexName . "/" . urlencode($partialObject["objectID"]) . "/partial", array(), $partialObject);
    388412    }
    389413
     
    404428     */
    405429    public function saveObject($object) {
    406         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "PUT", "/1/indexes/" . $this->urlIndexName . "/" . urlencode($object["objectID"]), array(), $object);
     430        return AlgoliaUtils_request($this->context, "PUT", "/1/indexes/" . $this->urlIndexName . "/" . urlencode($object["objectID"]), array(), $object);
    407431    }
    408432
     
    426450            throw new \Exception('objectID is mandatory');
    427451        }
    428         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "DELETE", "/1/indexes/" . $this->urlIndexName . "/" . urlencode($objectID));
     452        return AlgoliaUtils_request($this->context, "DELETE", "/1/indexes/" . $this->urlIndexName . "/" . urlencode($objectID));
    429453    }
    430454
     
    511535        }
    512536        $args["query"] = $query;
    513         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "GET", "/1/indexes/" . $this->urlIndexName, $args);
     537        return AlgoliaUtils_request($this->context, "GET", "/1/indexes/" . $this->urlIndexName, $args);
    514538    }
    515539
     
    522546     */
    523547    public function browse($page = 0, $hitsPerPage = 1000) {
    524         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "GET", "/1/indexes/" . $this->urlIndexName . "/browse",
     548        return AlgoliaUtils_request($this->context, "GET", "/1/indexes/" . $this->urlIndexName . "/browse",
    525549                                    array("page" => $page, "hitsPerPage" => $hitsPerPage));
    526550    }
     
    535559    public function waitTask($taskID, $timeBeforeRetry = 100) {
    536560        while (true) {
    537             $res = AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "GET", "/1/indexes/" . $this->urlIndexName . "/task/" . $taskID);
     561            $res = AlgoliaUtils_request($this->context, "GET", "/1/indexes/" . $this->urlIndexName . "/task/" . $taskID);
    538562            if ($res["status"] === "published")
    539563                return $res;
     
    547571     */
    548572    public function getSettings() {
    549         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "GET", "/1/indexes/" . $this->urlIndexName . "/settings");
     573        return AlgoliaUtils_request($this->context, "GET", "/1/indexes/" . $this->urlIndexName . "/settings");
    550574    }
    551575
     
    554578     */
    555579    public function clearIndex() {
    556         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "POST", "/1/indexes/" . $this->urlIndexName . "/clear");
     580        return AlgoliaUtils_request($this->context, "POST", "/1/indexes/" . $this->urlIndexName . "/clear");
    557581    }
    558582
     
    609633     */
    610634    public function setSettings($settings) {
    611         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "PUT", "/1/indexes/" . $this->urlIndexName . "/settings", array(), $settings);
     635        return AlgoliaUtils_request($this->context, "PUT", "/1/indexes/" . $this->urlIndexName . "/settings", array(), $settings);
    612636    }
    613637
     
    617641     */
    618642    public function listUserKeys() {
    619         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "GET", "/1/indexes/" . $this->urlIndexName . "/keys");
     643        return AlgoliaUtils_request($this->context, "GET", "/1/indexes/" . $this->urlIndexName . "/keys");
    620644    }
    621645
     
    625649     */
    626650    public function getUserKeyACL($key) {
    627         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "GET", "/1/indexes/" . $this->urlIndexName . "/keys/" . $key);
     651        return AlgoliaUtils_request($this->context, "GET", "/1/indexes/" . $this->urlIndexName . "/keys/" . $key);
    628652    }
    629653
     
    633657     */
    634658    public function deleteUserKey($key) {
    635         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "DELETE", "/1/indexes/" . $this->urlIndexName . "/keys/" . $key);
     659        return AlgoliaUtils_request($this->context, "DELETE", "/1/indexes/" . $this->urlIndexName . "/keys/" . $key);
    636660    }
    637661
     
    652676     */
    653677    public function addUserKey($acls, $validity = 0, $maxQueriesPerIPPerHour = 0, $maxHitsPerQuery = 0) {
    654         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "POST", "/1/indexes/" . $this->urlIndexName . "/keys", array(),
     678        return AlgoliaUtils_request($this->context, "POST", "/1/indexes/" . $this->urlIndexName . "/keys", array(),
    655679            array("acl" => $acls, "validity" => $validity, "maxQueriesPerIPPerHour" => $maxQueriesPerIPPerHour, "maxHitsPerQuery" => $maxHitsPerQuery));
    656680    }
     
    661685     */
    662686    public function batch($requests) {
    663         return AlgoliaUtils_request($this->curlHandle, $this->hostsArray, "POST", "/1/indexes/" . $this->urlIndexName . "/batch", array(), $requests);
     687        return AlgoliaUtils_request($this->context, "POST", "/1/indexes/" . $this->urlIndexName . "/batch", array(), $requests);
    664688    }
    665689
     
    689713}
    690714
    691 function AlgoliaUtils_request($curlHandle, $hostsArray, $method, $path, $params = array(), $data = array()) {
     715function AlgoliaUtils_request($context, $method, $path, $params = array(), $data = array()) {
    692716    $exception = null;
    693     foreach ($hostsArray as &$host) {
     717    foreach ($context->hostsArray as &$host) {
    694718        try {
    695             $res = AlgoliaUtils_requestHost($curlHandle, $method, $host, $path, $params, $data);
     719            $res = AlgoliaUtils_requestHost($context, $method, $host, $path, $params, $data);
    696720            if ($res !== null)
    697721                return $res;
     
    708732}
    709733
    710 function AlgoliaUtils_requestHost($curlHandle, $method, $host, $path, $params, $data) {
     734function AlgoliaUtils_requestHost($context, $method, $host, $path, $params, $data) {
    711735    $url = "https://" . $host . $path;
    712 
     736//echo $url;
    713737    if ($params != null && count($params) > 0) {
    714738        $params2 = array();
     
    721745        }
    722746        $url .= "?" . http_build_query($params2);
    723     }
    724 
     747       
     748    }
     749//echo $url;
     750    // initialize curl library
     751    $curlHandle = curl_init();
     752    //curl_setopt($curlHandle, CURLOPT_VERBOSE, true);
     753    if ($context->adminAPIKey == null) {
     754        curl_setopt($curlHandle, CURLOPT_HTTPHEADER, array(
     755                    'X-Algolia-Application-Id: ' . $context->applicationID,
     756                    'X-Algolia-API-Key: ' . $context->apiKey,
     757                    'Content-type: application/json'
     758                    ));
     759    } else {
     760         curl_setopt($curlHandle, CURLOPT_HTTPHEADER, array(
     761                'X-Algolia-Application-Id: ' . $context->applicationID,
     762                'X-Algolia-API-Key: ' . $context->adminAPIKey,
     763                'X-Forwarded-For: ' . $context->endUserIP,
     764                'X-Forwarded-API-Key: ' . $context->rateLimitAPIKey,
     765                'Content-type: application/json'
     766                ));
     767    }
     768    curl_setopt($curlHandle, CURLOPT_USERAGENT, "Algolia for PHP 1.1.9");
     769    //Return the output instead of printing it
     770    curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, true);
     771    curl_setopt($curlHandle, CURLOPT_FAILONERROR, true);
     772    curl_setopt($curlHandle, CURLOPT_ENCODING, '');
     773    curl_setopt($curlHandle, CURLOPT_SSL_VERIFYPEER, true);
     774    curl_setopt($curlHandle, CURLOPT_SSL_VERIFYHOST, 2);
     775    curl_setopt($curlHandle, CURLOPT_CAINFO, __DIR__ . '/resources/ca-bundle.crt');
     776   
    725777    curl_setopt($curlHandle, CURLOPT_URL, $url);
    726778    curl_setopt($curlHandle, CURLOPT_CONNECTTIMEOUT, 30);
     779    curl_setopt($curlHandle, CURLOPT_NOSIGNAL, 1); # The problem is that on (Li|U)nix, when libcurl uses the standard name resolver, a SIGALRM is raised during name resolution which libcurl thinks is the timeout alarm.
    727780    curl_setopt($curlHandle, CURLOPT_FAILONERROR, false);
    728781
     
    745798        curl_setopt($curlHandle, CURLOPT_POST, true);
    746799    }
    747     $response = curl_exec($curlHandle);
     800    $mhandle = $context->getMHandle($curlHandle);
     801
     802    $response = NULL;
     803    // Do all the processing.
     804    $active = NULL;
     805
     806    $mrc = curl_multi_exec($mhandle, $active);
     807    while ($mrc == CURLM_CALL_MULTI_PERFORM) {
     808        usleep(100);
     809        $mrc = curl_multi_exec($mhandle, $active);
     810    }
     811    while ($active && $mrc == CURLM_OK) {
     812        $select = curl_multi_select($mhandle);
     813        if ($select != -1 || $select != 0) {
     814            do {
     815                $mrc = curl_multi_exec($mhandle, $active);
     816            } while ($mrc == CURLM_CALL_MULTI_PERFORM);
     817        } elseif ($select == 0) { //Nothing to do stop
     818            break;
     819        }
     820        usleep(100);
     821    }
     822
     823
    748824    if ($response === false) {
    749825        throw new \Exception(curl_error($curlHandle));
     
    755831        return null;
    756832    }
     833    $response = curl_multi_getcontent($curlHandle);
    757834    $answer = json_decode($response, true);
     835    $context->releaseMHandle($curlHandle);
     836    curl_close($curlHandle);
    758837
    759838    if ($http_status == 400) {
     
    783862            $errorMsg = 'JSON parsing error: underflow or the modes mismatch';
    784863            break;
    785         case (defined(JSON_ERROR_UTF8) ? JSON_ERROR_UTF8 : -1): // PHP 5.3 less than 5.3.3 (Ubuntu 10.04 LTS)
     864        case (defined('JSON_ERROR_UTF8') ? JSON_ERROR_UTF8 : -1): // PHP 5.3 less than 5.3.3 (Ubuntu 10.04 LTS)
    786865            $errorMsg = 'JSON parsing error: malformed UTF-8 characters, possibly incorrectly encoded';
    787866            break;
     
    791870            break;
    792871    }
    793     if ($errorMsg !== null)
     872    if ($errorMsg !== null) 
    794873        throw new AlgoliaException($errorMsg);
    795874
  • maven-algolia/trunk/maven-algolia.php

    r915533 r918102  
    55  Plugin URI:
    66  Description: Fully customise WordPress search implementing algolia API
    7   Version: 0.1
     7  Version: 0.2
    88  Author: gtenaschuk, mustela
    9   Author URI: http:www.sitemavens.com
     9  Author URI: http://www.sitemavens.com
    1010  Copyright: sitemavens.com
    1111 */
     
    2424$registry->setPluginDir( plugin_dir_path( __FILE__ ) );
    2525$registry->setPluginUrl( defined( 'DEV_ENV' ) && DEV_ENV ? WP_PLUGIN_URL . "/maven-algolia/" : plugin_dir_url( __FILE__ )  );
    26 $registry->setPluginVersion( "0.1" );
     26$registry->setPluginVersion( "0.2" );
    2727$registry->setPluginName( 'Maven Algolia' );
    2828$registry->setPluginShortName( 'mvnAlg' );
Note: See TracChangeset for help on using the changeset viewer.