# HG changeset patch # User ymh # Date 1268237940 -3600 # Node ID 8f7f6284556267ae61825daad3844358e96af6ba # Parent cba6648bf1fedb54d0334d692f349c6c11edcf85 reorg for project and first link with solr diff -r cba6648bf1fe -r 8f7f62845562 .hgignore --- a/.hgignore Thu Oct 08 15:30:28 2009 +0200 +++ b/.hgignore Wed Mar 10 17:19:00 2010 +0100 @@ -1,11 +1,17 @@ syntax: regexp ^web/tagging/xxy\.f4v$ +^web/thdProject/web/videos/.+\..*$ ^web/thdProject/cache/.*$ ^web/thdProject/cache$ ^web/thdProject/web/phpinfo.php$ ^web/thdProject/log/.*$ +^web/thdProject/upload/.*$ +^web/thdProject/apps/frontend/configi/app.yml$ +^engine/solr/context.xml$ +^engine/solr/solr/data/.*$ syntax: glob .DS_Store *.swp + diff -r cba6648bf1fe -r 8f7f62845562 engine/solr/apache-solr-1.4.0.war Binary file engine/solr/apache-solr-1.4.0.war has changed diff -r cba6648bf1fe -r 8f7f62845562 engine/solr/context.xml.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/engine/solr/context.xml.tmpl Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,4 @@ + + + + diff -r cba6648bf1fe -r 8f7f62845562 engine/solr/solr/conf/schema.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/engine/solr/solr/conf/schema.xml Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uniqueid + + + all + + + + + + + + + + + diff -r cba6648bf1fe -r 8f7f62845562 engine/solr/solr/conf/solrconfig.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/engine/solr/solr/conf/solrconfig.xml Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,697 @@ + + + + + + ${solr.abortOnConfigurationError:true} + + + ${solr.data.dir:/Users/ymh/dev/workspace/mosatags/engine/solr/solr/data} + + + + false + + 10 + + + + 32 + 2147483647 + 10000 + 1000 + 10000 + + + + + + + + + + + single + + + + + false + 32 + 10 + + + 2147483647 + 10000 + + + false + + + + + + + + + + + + + + + + + + + + + + 1024 + + + + + + + + + + + + + true + + + + + + + + 50 + + + 200 + + + + + + + + + solr 0 10 + rocks 0 10 + static newSearcher warming query from solrconfig.xml + + + + + + + fast_warm 0 10 + static firstSearcher warming query from solrconfig.xml + + + + + false + + + 2 + + + + + + + + + + + + + + + + + + + + + + + explicit + + + + + + + + + dismax + explicit + 0.01 + + text^0.5 features^1.0 name^1.2 sku^1.5 id^10.0 manu^1.1 cat^1.4 + + + text^0.2 features^1.1 name^1.5 manu^1.4 manu_exact^1.9 + + + ord(popularity)^0.5 recip(rord(price),1,1000,1000)^0.3 + + + id,name,price,score + + + 2<-1 5<-2 6<90% + + 100 + *:* + + text features name + + 0 + + name + regex + + + + + + + dismax + explicit + text^0.5 features^1.0 name^1.2 sku^1.5 id^10.0 + 2<-1 5<-2 6<90% + + incubationdate_dt:[* TO NOW/DAY-1MONTH]^2.2 + + + + inStock:true + + + + cat + manu_exact + price:[* TO 500] + price:[500 TO *] + + + + + + + + + + textSpell + + + default + spell + ./spellchecker1 + + + + jarowinkler + spell + + org.apache.lucene.search.spell.JaroWinklerDistance + ./spellchecker2 + + + + + solr.FileBasedSpellChecker + file + spellings.txt + UTF-8 + ./spellcheckerFile + + + + + + + + false + + false + + 1 + + + spellcheck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + standard + solrpingquery + all + + + + + + + explicit + true + + + + + + + + + 100 + + + + + + + + 70 + + 0.5 + + [-\w ,/\n\"']{20,200} + + + + + + + ]]> + ]]> + + + + + + + + + + + + 5 + + + + + + + + + + solr + + + + + diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/apps/backend/config/app.yml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/apps/backend/config/app.yml Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,2 @@ +# default values +#all: diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/apps/backend/config/backendConfiguration.class.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/apps/backend/config/backendConfiguration.class.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,8 @@ + + web_debug: on + cache: off + no_script_name: off + etag: off + +test: + .settings: + error_reporting: + cache: off + web_debug: off + no_script_name: off + etag: off + +all: + .settings: + # Form security secret (CSRF protection) + csrf_secret: admin # Unique secret to enable CSRF protection or false to disable + + # Output escaping settings + escaping_strategy: true # Determines how variables are made available to templates. Accepted values: on, off. + escaping_method: ESC_SPECIALCHARS # Function or helper used for escaping. Accepted values: ESC_RAW, ESC_ENTITIES, ESC_JS, ESC_JS_NO_ENTITIES, and ESC_SPECIALCHARS. + + # Cache settings + lazy_cache_key: on # Delays creation of a cache key until after checking whether an action or partial is cacheable + +#all: +# .actions: +# error_404_module: default # To be called when a 404 error is raised +# error_404_action: error404 # Or when the requested URL doesn't match any route +# +# login_module: default # To be called when a non-authenticated user +# login_action: login # Tries to access a secure page +# +# secure_module: default # To be called when a user doesn't have +# secure_action: secure # The credentials required for an action +# +# module_disabled_module: default # To be called when a user requests +# module_disabled_action: disabled # A module disabled in the module.yml +# +# .settings: +# # Optional features. Deactivating unused features boots performance a bit. +# use_database: on # Enable database manager. Set to off if you don't use a database. +# i18n: off # Enable interface translation. Set to off if your application should not be translated. +# check_symfony_version: off # Enable check of symfony version for every request. Set to on to have symfony clear the cache automatically when the framework is upgraded. Set to off if you always clear the cache after an upgrade. +# compressed: off # Enable PHP response compression. Set to on to compress the outgoing HTML via the PHP handler. +# check_lock: off # Enable the application lock system triggered by the clear-cache and disable tasks. Set to on to have all requests to disabled applications redirected to the $sf_symfony_lib_dir/exception/data/unavailable.php page. +# +# # Routing settings +# no_script_name: off # Enable the front controller name in generated URLs +# +# # Validation settings, used for error generation by the Validation helper +# validation_error_prefix: ' ↓ ' +# validation_error_suffix: '  ↓' +# validation_error_class: form_error +# validation_error_id_prefix: error_for_ +# +# # Cache settings +# cache: off # Enable the template cache +# etag: on # Enable etag handling +# lazy_cache_key: off # Delays creation of a cache key until after checking whether an action or partial is cacheable (defaults to false for backward compatibility) +# +# # Logging and debugging settings +# web_debug: off # Enable the web debug toolbar +# error_reporting: # Determines which events are logged. +# +# # Assets paths +# rich_text_js_dir: js/tiny_mce +# admin_web_dir: /sf/sf_admin +# web_debug_web_dir: /sf/sf_web_debug +# calendar_web_dir: /sf/calendar +# +# # Helpers included in all templates by default +# standard_helpers: [Partial, Cache, Form] +# +# # Activated modules from plugins or from the symfony core +# enabled_modules: [default] +# +# # Charset used for the response +# charset: utf-8 +# +# # Miscellaneous +# strip_comments: on # Remove comments in core framework classes as defined in the core_compile.yml +# max_forwards: 5 +# +# # Logging +# logging_enabled: on +# +# # i18n +# default_culture: en # Default user culture diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/apps/backend/config/view.yml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/apps/backend/config/view.yml Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,17 @@ +default: + http_metas: + content-type: text/html + + metas: + #title: symfony project + #description: symfony project + #keywords: symfony, project + #language: en + #robots: index, follow + + stylesheets: [main.css] + + javascripts: [] + + has_layout: on + layout: layout diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/apps/backend/i18n/.keepme diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/apps/backend/lib/myUser.class.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/apps/backend/lib/myUser.class.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,5 @@ + + + + + + + + + + + + diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/apps/frontend/config/app.yml --- a/web/thdProject/apps/frontend/config/app.yml Thu Oct 08 15:30:28 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -# default values -all: - storage: - #segmentation files - uploads: "/Users/gautierthibault/Sites/thd/web/uploads/" - format: ".csv" - - player: - videoPath: "http://localhost/thd/web/videos/" - -#dev: diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/apps/frontend/config/app.yml.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/apps/frontend/config/app.yml.tmpl Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,11 @@ +# default values +all: + storage: + #segmentation files + uploads: "/Users/gautierthibault/Sites/thd/web/uploads/" + format: ".csv" + + player: + videoPath: "http://localhost/thd/web/videos/" + +#dev: diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/apps/frontend/i18n/.keepme diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/apps/frontend/modules/partials/templates/_header.php --- a/web/thdProject/apps/frontend/modules/partials/templates/_header.php Thu Oct 08 15:30:28 2009 +0200 +++ b/web/thdProject/apps/frontend/modules/partials/templates/_header.php Wed Mar 10 17:19:00 2010 +0100 @@ -1,6 +1,6 @@

UniversCiné

-
avec le concours de iri | Sony CSL | Cap Digital
+
avec le concours de iri | Sony CSL | Cap Digital
le site du cinéma indépendant
diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/cache/.keepme diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/config/doctrine/schema.yml --- a/web/thdProject/config/doctrine/schema.yml Thu Oct 08 15:30:28 2009 +0200 +++ b/web/thdProject/config/doctrine/schema.yml Wed Mar 10 17:19:00 2010 +0100 @@ -27,6 +27,13 @@ notnull: true original_title: string(255) production_year: integer(8) + uniqueid: + type: string(36) + notnull: true + indexes: + uniqueidindex: + fields: [uniqueid] + type: unique ThdImage: tableName: thd_image columns: @@ -59,7 +66,13 @@ autoincrement: true title: type: string(255) - notnull: true + notnull: false + tags: + type: string(1024) + notnull: false + desc: + type: string(2147483647) + notnull: false video_ref: type: integer(4) notnull: true @@ -75,6 +88,13 @@ creation_date: type: timestamp(25) notnull: true + uniqueid: + type: string(36) + notnull: true + indexes: + uniqueidindex: + fields: [uniqueid] + type: unique relations: ThdVideo: foreignAlias: segments @@ -105,4 +125,4 @@ local: film_ref foreign: ref type: one - foreignType: many \ No newline at end of file + foreignType: many diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/data/sql/schema.sql --- a/web/thdProject/data/sql/schema.sql Thu Oct 08 15:30:28 2009 +0200 +++ b/web/thdProject/data/sql/schema.sql Wed Mar 10 17:19:00 2010 +0100 @@ -1,6 +1,6 @@ -CREATE TABLE thd_film (id INT, ref INT NOT NULL, title VARCHAR(255) NOT NULL, pitch TEXT NOT NULL, duration INT NOT NULL, directors TEXT NOT NULL, actors TEXT NOT NULL, slug_url VARCHAR(255) NOT NULL, original_title VARCHAR(255), production_year BIGINT, PRIMARY KEY(id)) ENGINE = INNODB; +CREATE TABLE thd_film (id INT, ref INT NOT NULL, title VARCHAR(255) NOT NULL, pitch TEXT NOT NULL, duration INT NOT NULL, directors TEXT NOT NULL, actors TEXT NOT NULL, slug_url VARCHAR(255) NOT NULL, original_title VARCHAR(255), production_year BIGINT, uniqueid VARCHAR(36) NOT NULL, PRIMARY KEY(id)) ENGINE = INNODB; CREATE TABLE thd_image (id INT AUTO_INCREMENT, film_ref INT NOT NULL, type TINYINT NOT NULL, file VARCHAR(255) NOT NULL, INDEX film_ref_idx (film_ref), PRIMARY KEY(id)) ENGINE = INNODB; -CREATE TABLE thd_segment (id INT AUTO_INCREMENT, title VARCHAR(255) NOT NULL, video_ref INT NOT NULL, start DOUBLE NOT NULL, end DOUBLE NOT NULL, user_id INT NOT NULL, creation_date DATETIME NOT NULL, INDEX video_ref_idx (video_ref), PRIMARY KEY(id)) ENGINE = INNODB; +CREATE TABLE thd_segment (id INT AUTO_INCREMENT, title VARCHAR(255) NOT NULL, video_ref INT NOT NULL, start DOUBLE NOT NULL, end DOUBLE NOT NULL, user_id INT NOT NULL, creation_date DATETIME NOT NULL, uniqueid VARCHAR(36) NOT NULL, INDEX video_ref_idx (video_ref), PRIMARY KEY(id)) ENGINE = INNODB; CREATE TABLE thd_video (id INT AUTO_INCREMENT, ref INT NOT NULL, film_ref INT NOT NULL, file VARCHAR(255) NOT NULL, title VARCHAR(255), INDEX ref_idx (ref), INDEX film_ref_idx (film_ref), PRIMARY KEY(id)) ENGINE = INNODB; ALTER TABLE thd_image ADD FOREIGN KEY (film_ref) REFERENCES thd_film(ref); ALTER TABLE thd_segment ADD FOREIGN KEY (video_ref) REFERENCES thd_video(ref); diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/lib/form/doctrine/ThdFilmForm.class.php --- a/web/thdProject/lib/form/doctrine/ThdFilmForm.class.php Thu Oct 08 15:30:28 2009 +0200 +++ b/web/thdProject/lib/form/doctrine/ThdFilmForm.class.php Wed Mar 10 17:19:00 2010 +0100 @@ -11,5 +11,6 @@ { public function configure() { + $this->validatorSchema['uniqueid']->setOption('required', false); } -} \ No newline at end of file +} diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/lib/form/doctrine/ThdSegmentForm.class.php --- a/web/thdProject/lib/form/doctrine/ThdSegmentForm.class.php Thu Oct 08 15:30:28 2009 +0200 +++ b/web/thdProject/lib/form/doctrine/ThdSegmentForm.class.php Wed Mar 10 17:19:00 2010 +0100 @@ -11,5 +11,6 @@ { public function configure() { + $this->validatorSchema['uniqueid']->setOption('required', false); } -} \ No newline at end of file +} diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/lib/form/doctrine/base/BaseThdFilmForm.class.php --- a/web/thdProject/lib/form/doctrine/base/BaseThdFilmForm.class.php Thu Oct 08 15:30:28 2009 +0200 +++ b/web/thdProject/lib/form/doctrine/base/BaseThdFilmForm.class.php Wed Mar 10 17:19:00 2010 +0100 @@ -22,6 +22,7 @@ 'slug_url' => new sfWidgetFormInput(), 'original_title' => new sfWidgetFormInput(), 'production_year' => new sfWidgetFormInput(), + 'uniqueid' => new sfWidgetFormInput(), )); $this->setValidators(array( @@ -35,8 +36,13 @@ 'slug_url' => new sfValidatorString(array('max_length' => 255)), 'original_title' => new sfValidatorString(array('max_length' => 255, 'required' => false)), 'production_year' => new sfValidatorInteger(array('required' => false)), + 'uniqueid' => new sfValidatorString(array('max_length' => 36)), )); + $this->validatorSchema->setPostValidator( + new sfValidatorDoctrineUnique(array('model' => 'ThdFilm', 'column' => array('uniqueid'))) + ); + $this->widgetSchema->setNameFormat('thd_film[%s]'); $this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema); diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/lib/form/doctrine/base/BaseThdSegmentForm.class.php --- a/web/thdProject/lib/form/doctrine/base/BaseThdSegmentForm.class.php Thu Oct 08 15:30:28 2009 +0200 +++ b/web/thdProject/lib/form/doctrine/base/BaseThdSegmentForm.class.php Wed Mar 10 17:19:00 2010 +0100 @@ -14,23 +14,33 @@ $this->setWidgets(array( 'id' => new sfWidgetFormInputHidden(), 'title' => new sfWidgetFormInput(), + 'tags' => new sfWidgetFormTextarea(), + 'desc' => new sfWidgetFormTextarea(), 'video_ref' => new sfWidgetFormDoctrineChoice(array('model' => 'ThdVideo', 'add_empty' => false)), 'start' => new sfWidgetFormInput(), 'end' => new sfWidgetFormInput(), 'user_id' => new sfWidgetFormInput(), 'creation_date' => new sfWidgetFormDateTime(), + 'uniqueid' => new sfWidgetFormInput(), )); $this->setValidators(array( 'id' => new sfValidatorDoctrineChoice(array('model' => 'ThdSegment', 'column' => 'id', 'required' => false)), - 'title' => new sfValidatorString(array('max_length' => 255)), + 'title' => new sfValidatorString(array('max_length' => 255, 'required' => false)), + 'tags' => new sfValidatorString(array('max_length' => 1024, 'required' => false)), + 'desc' => new sfValidatorString(array('max_length' => 2147483647, 'required' => false)), 'video_ref' => new sfValidatorDoctrineChoice(array('model' => 'ThdVideo')), 'start' => new sfValidatorNumber(), 'end' => new sfValidatorNumber(), 'user_id' => new sfValidatorInteger(), 'creation_date' => new sfValidatorDateTime(), + 'uniqueid' => new sfValidatorString(array('max_length' => 36)), )); + $this->validatorSchema->setPostValidator( + new sfValidatorDoctrineUnique(array('model' => 'ThdSegment', 'column' => array('uniqueid'))) + ); + $this->widgetSchema->setNameFormat('thd_segment[%s]'); $this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema); diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/lib/model/doctrine/ThdFilm.class.php --- a/web/thdProject/lib/model/doctrine/ThdFilm.class.php Thu Oct 08 15:30:28 2009 +0200 +++ b/web/thdProject/lib/model/doctrine/ThdFilm.class.php Wed Mar 10 17:19:00 2010 +0100 @@ -6,4 +6,26 @@ class ThdFilm extends BaseThdFilm { -} \ No newline at end of file + public function getSolrDocumentFields() + { + // keys of this array are fields' name of solr's schema.xml + $type = "ThdFilm"; + $fields = array('type' => $type, + 'id' => $this->getId(), + 'title' => array('value' => $this->getTitle(), 'boost' => 1.0), + 'desc' => array('value' => $this->getPitch(), 'boost' => 1.0), + 'directors' => array('value' => $this->getDirectors(), 'boost' => 1.0), + 'actors' => array('value' => $this->getActors(), 'boost' => 1.0), + 'original_title' => array('value' => $this->getOriginal_title(), 'boost' => 1.0), + 'uniqueid' => array('value' => $this->getUniqueid(), 'boost' => 1.0), + ); + + return $fields; + } + + public function preInsert($event) + { + $this->uniqueid = UUID::generate(UUID::UUID_TIME, UUID::FMT_STRING, "mosatags"); + } + +} diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/lib/model/doctrine/ThdSegment.class.php --- a/web/thdProject/lib/model/doctrine/ThdSegment.class.php Thu Oct 08 15:30:28 2009 +0200 +++ b/web/thdProject/lib/model/doctrine/ThdSegment.class.php Wed Mar 10 17:19:00 2010 +0100 @@ -6,4 +6,24 @@ class ThdSegment extends BaseThdSegment { -} \ No newline at end of file + public function getSolrDocumentFields() + { // keys of this array are fields' name of solr's schema.xml + $type = "ThdFilm"; + $fields = array('type' => $type, + 'id' => $this->getId(), + 'title' => array('value' => $this->getTitle(), 'boost' => 1.0), + 'tags' => array('value' => $this->getTags(), 'boost' => 1.0), + 'desc' => array('value' => $this->getDesc(), 'boost' => 1.0), + 'uniqueid' => array('value' => $this->getUniqueid(), 'boost' => 1.0), + ); + + return $fields; + } + + + public function preInsert($event) + { + $this->uniqueid = UUID::generate(UUID::UUID_TIME, UUID::FMT_STRING, "mosatags"); + } + +} diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/lib/model/doctrine/base/BaseThdFilm.class.php --- a/web/thdProject/lib/model/doctrine/base/BaseThdFilm.class.php Thu Oct 08 15:30:28 2009 +0200 +++ b/web/thdProject/lib/model/doctrine/base/BaseThdFilm.class.php Wed Mar 10 17:19:00 2010 +0100 @@ -56,6 +56,20 @@ 'type' => 'integer', 'length' => '8', )); + $this->hasColumn('uniqueid', 'string', 36, array( + 'type' => 'string', + 'notnull' => true, + 'length' => '36', + )); + + + $this->index('uniqueidindex', array( + 'fields' => + array( + 0 => 'uniqueid', + ), + 'type' => 'unique', + )); } public function setUp() diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/lib/model/doctrine/base/BaseThdSegment.class.php --- a/web/thdProject/lib/model/doctrine/base/BaseThdSegment.class.php Thu Oct 08 15:30:28 2009 +0200 +++ b/web/thdProject/lib/model/doctrine/base/BaseThdSegment.class.php Wed Mar 10 17:19:00 2010 +0100 @@ -16,9 +16,16 @@ )); $this->hasColumn('title', 'string', 255, array( 'type' => 'string', - 'notnull' => true, 'length' => '255', )); + $this->hasColumn('tags', 'string', 1024, array( + 'type' => 'string', + 'length' => '1024', + )); + $this->hasColumn('desc', 'string', 2147483647, array( + 'type' => 'string', + 'length' => '2147483647', + )); $this->hasColumn('video_ref', 'integer', 4, array( 'type' => 'integer', 'notnull' => true, @@ -44,6 +51,20 @@ 'notnull' => true, 'length' => '25', )); + $this->hasColumn('uniqueid', 'string', 36, array( + 'type' => 'string', + 'notnull' => true, + 'length' => '36', + )); + + + $this->index('uniqueidindex', array( + 'fields' => + array( + 0 => 'uniqueid', + ), + 'type' => 'unique', + )); } public function setUp() diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/lib/vendor/shapeshifter/UUID.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/lib/vendor/shapeshifter/UUID.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,324 @@ + 0, /* 32-bit */ + 'time_mid' => 0, /* 16-bit */ + 'time_hi' => 0, /* 16-bit */ + 'clock_seq_hi' => 0, /* 8-bit */ + 'clock_seq_low' => 0, /* 8-bit */ + 'node' => array() /* 48-bit */ + ); + + static private $m_generate = array( + self::UUID_TIME => "generateTime", + self::UUID_RANDOM => "generateRandom", + self::UUID_NAME_MD5 => "generateNameMD5", + self::UUID_NAME_SHA1 => "generateNameSHA1" + ); + + static private $m_convert = array( + self::FMT_FIELD => array( + self::FMT_BYTE => "conv_field2byte", + self::FMT_STRING => "conv_field2string", + self::FMT_BINARY => "conv_field2binary" + ), + self::FMT_BYTE => array( + self::FMT_FIELD => "conv_byte2field", + self::FMT_STRING => "conv_byte2string", + self::FMT_BINARY => "conv_byte2binary" + ), + self::FMT_STRING => array( + self::FMT_BYTE => "conv_string2byte", + self::FMT_FIELD => "conv_string2field", + self::FMT_BINARY => "conv_string2binary" + ), + ); + + /* Swap byte order of a 32-bit number */ + static private function swap32($x) { + return (($x & 0x000000ff) << 24) | (($x & 0x0000ff00) << 8) | + (($x & 0x00ff0000) >> 8) | (($x & 0xff000000) >> 24); + } + + /* Swap byte order of a 16-bit number */ + static private function swap16($x) { + return (($x & 0x00ff) << 8) | (($x & 0xff00) >> 8); + } + + /* Auto-detect UUID format */ + static private function detectFormat($src) { + if (is_string($src)) + return self::FMT_STRING; + else if (is_array($src)) { + $len = count($src); + if ($len == 1 || ($len % 2) == 0) + return $len; + else + return (-1); + } + else + return self::FMT_BINARY; + } + + /* + * Public API, generate a UUID of 'type' in format 'fmt' for + * the given namespace 'ns' and node 'node' + */ + static public function generate($type, $fmt = self::FMT_BYTE, + $node = "", $ns = "") { + $func = self::$m_generate[$type]; + if (!isset($func)) + return null; + $conv = self::$m_convert[self::FMT_FIELD][$fmt]; + + $uuid = self::$func($ns, $node); + return self::$conv($uuid); + } + + /* + * Public API, convert a UUID from one format to another + */ + static public function convert($uuid, $from, $to) { + $conv = self::$m_convert[$from][$to]; + if (!isset($conv)) + return ($uuid); + + return (self::$conv($uuid)); + } + + /* + * Generate an UUID version 4 (pseudo random) + */ + static private function generateRandom($ns, $node) { + $uuid = self::$m_uuid_field; + + $uuid['time_hi'] = (4 << 12) | (mt_rand(0, 0x1000)); + $uuid['clock_seq_hi'] = (1 << 7) | mt_rand(0, 128); + $uuid['time_low'] = mt_rand(0, 0xffff) + (mt_rand(0, 0xffff) << 16); + $uuid['time_mid'] = mt_rand(0, 0xffff); + $uuid['clock_seq_low'] = mt_rand(0, 255); + for ($i = 0; $i < 6; $i++) + $uuid['node'][$i] = mt_rand(0, 255); + return ($uuid); + } + + /* + * Generate UUID version 3 and 5 (name based) + */ + static private function generateName($ns, $node, $hash, $version) { + $ns_fmt = self::detectFormat($ns); + $field = self::convert($ns, $ns_fmt, self::FMT_FIELD); + + /* Swap byte order to keep it in big endian on all platforms */ + $field['time_low'] = self::swap32($field['time_low']); + $field['time_mid'] = self::swap16($field['time_mid']); + $field['time_hi'] = self::swap16($field['time_hi']); + + /* Convert the namespace to binary and concatenate node */ + $raw = self::convert($field, self::FMT_FIELD, self::FMT_BINARY); + $raw .= $node; + + /* Hash the namespace and node and convert to a byte array */ + $val = $hash($raw, true); + $tmp = unpack('C16', $val); + foreach (array_keys($tmp) as $key) + $byte[$key - 1] = $tmp[$key]; + + /* Convert byte array to a field array */ + $field = self::conv_byte2field($byte); + + $field['time_low'] = self::swap32($field['time_low']); + $field['time_mid'] = self::swap16($field['time_mid']); + $field['time_hi'] = self::swap16($field['time_hi']); + + /* Apply version and constants */ + $field['clock_seq_hi'] &= 0x3f; + $field['clock_seq_hi'] |= (1 << 7); + $field['time_hi'] &= 0x0fff; + $field['time_hi'] |= ($version << 12); + + return ($field); + } + static private function generateNameMD5($ns, $node) { + return self::generateName($ns, $node, "md5", + self::UUID_NAME_MD5); + } + static private function generateNameSHA1($ns, $node) { + return self::generateName($ns, $node, "sha1", + self::UUID_NAME_SHA1); + } + + /* + * Generate UUID version 1 (time based) + */ + static private function generateTime($ns, $node) { + $uuid = self::$m_uuid_field; + + /* + * Get current time in 100 ns intervals. The magic value + * is the offset between UNIX epoch and the UUID UTC + * time base October 15, 1582. + */ + $tp = gettimeofday(); + $time = ($tp['sec'] * 10000000) + ($tp['usec'] * 10) + + 0x01B21DD213814000; + + $uuid['time_low'] = $time & 0xffffffff; + /* Work around PHP 32-bit bit-operation limits */ + $high = intval($time / 0xffffffff); + $uuid['time_mid'] = $high & 0xffff; + $uuid['time_hi'] = (($high >> 16) & 0xfff) | (self::UUID_TIME << 12); + + /* + * We don't support saved state information and generate + * a random clock sequence each time. + */ + $uuid['clock_seq_hi'] = 0x80 | mt_rand(0, 64); + $uuid['clock_seq_low'] = mt_rand(0, 255); + + /* + * Node should be set to the 48-bit IEEE node identifier, but + * we leave it for the user to supply the node. + */ + for ($i = 0; $i < 6; $i++) + $uuid['node'][$i] = ord(substr($node, $i, 1)); + + return ($uuid); + } + + /* Assumes correct byte order */ + static private function conv_field2byte($src) { + $uuid[0] = ($src['time_low'] & 0xff000000) >> 24; + $uuid[1] = ($src['time_low'] & 0x00ff0000) >> 16; + $uuid[2] = ($src['time_low'] & 0x0000ff00) >> 8; + $uuid[3] = ($src['time_low'] & 0x000000ff); + $uuid[4] = ($src['time_mid'] & 0xff00) >> 8; + $uuid[5] = ($src['time_mid'] & 0x00ff); + $uuid[6] = ($src['time_hi'] & 0xff00) >> 8; + $uuid[7] = ($src['time_hi'] & 0x00ff); + $uuid[8] = $src['clock_seq_hi']; + $uuid[9] = $src['clock_seq_low']; + + for ($i = 0; $i < 6; $i++) + $uuid[10+$i] = $src['node'][$i]; + + return ($uuid); + } + + static private function conv_field2string($src) { + $str = sprintf( + '%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x', + ($src['time_low']), ($src['time_mid']), ($src['time_hi']), + $src['clock_seq_hi'], $src['clock_seq_low'], + $src['node'][0], $src['node'][1], $src['node'][2], + $src['node'][3], $src['node'][4], $src['node'][5]); + return ($str); + } + + static private function conv_field2binary($src) { + $byte = self::conv_field2byte($src); + return self::conv_byte2binary($byte); + } + + static private function conv_byte2field($uuid) { + $field = self::$m_uuid_field; + $field['time_low'] = ($uuid[0] << 24) | ($uuid[1] << 16) | + ($uuid[2] << 8) | $uuid[3]; + $field['time_mid'] = ($uuid[4] << 8) | $uuid[5]; + $field['time_hi'] = ($uuid[6] << 8) | $uuid[7]; + $field['clock_seq_hi'] = $uuid[8]; + $field['clock_seq_low'] = $uuid[9]; + + for ($i = 0; $i < 6; $i++) + $field['node'][$i] = $uuid[10+$i]; + return ($field); + } + + static public function conv_byte2string($src) { + $field = self::conv_byte2field($src); + return self::conv_field2string($field); + } + + static private function conv_byte2binary($src) { + $raw = pack('C16', $src[0], $src[1], $src[2], $src[3], + $src[4], $src[5], $src[6], $src[7], $src[8], $src[9], + $src[10], $src[11], $src[12], $src[13], $src[14], $src[15]); + return ($raw); + } + + static private function conv_string2field($src) { + $parts = sscanf($src, '%x-%x-%x-%x-%02x%02x%02x%02x%02x%02x'); + $field = self::$m_uuid_field; + $field['time_low'] = ($parts[0]); + $field['time_mid'] = ($parts[1]); + $field['time_hi'] = ($parts[2]); + $field['clock_seq_hi'] = ($parts[3] & 0xff00) >> 8; + $field['clock_seq_low'] = $parts[3] & 0x00ff; + for ($i = 0; $i < 6; $i++) + $field['node'][$i] = $parts[4+$i]; + + return ($field); + } + + static private function conv_string2byte($src) { + $field = self::conv_string2field($src); + return self::conv_field2byte($field); + } + + static private function conv_string2binary($src) { + $byte = self::conv_string2byte($src); + return self::conv_byte2binary($byte); + } +} + +?> diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/plugins/uvmcSolrSearchPlugin/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/plugins/uvmcSolrSearchPlugin/LICENSE Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,5 @@ +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/plugins/uvmcSolrSearchPlugin/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/plugins/uvmcSolrSearchPlugin/README Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,146 @@ +# uvmcSolrSearchPlugin for symfony 1.2 # + +The `umvcSolrSearchPlugin` is a symfony plugin which permits you to index your models inside a solr service. +This readme assumes that you have already configured your solr service. If you want to learn how to setup a solr service, +you can read the [official solr tutorial](http://lucene.apache.org/solr/tutorial.html). + +As of now, please consider this plugin as an ALPHA release. +The plugin hasn't been fully tested. + +## Installation ## + + 1. Check out from svn + + svn co http://svn.symfony-project.org/plugins/uvmcSolrSearchPlugin/trunk uvmcSolrSearchPlugin + + 2. Clear your cache + + php symfony cc + +## Configuration ## + + 1. Configure solr.yml + + all: + enabled: on + servers: + master: + host: localhost + port: 8983 + path: "/solr" + + 2. Configure your solr installation to enable php serialiazed array writers + + In `your/install/of/solr/conf/solrconfig.xml`, uncomment those lines + + + + + 3. Add to the models you want to index the method `getSolrDocumentFields()` + + public function getSolrDocumentFields() + { + // keys of this array are fields' name of solr's schema.xml + $fields = array('id' => $this->getId(), + 'foo' => array('value' => $this->getFoo(), + 'boost' => 1.4); + + foreach($this->getBar() as $bar) + { + $fields['bar'][] = array('value' => $bar->getFoobar(), + 'boost' => 1.1); + } + + return $fields; + } + +## How to index/delete my model into solr? ## + +### In the admin generator + +All the models which have the method `getSolrDocumentFields()` will be automagically indexed/deleted upon save/deletion. + +### In my code + +Each time that you modify an indexable model, you have to notify the event dispatcher with the appropriate event. *Otherwise, it won't work*. + + // ... my super code ... + $myModel->save(); + $dispatcher = sfContext::getInstance()->getEventDispatcher(); + $dispatcher->notify(new sfEvent($mySubject, 'uvmc_solr.add_document', array('object' => $myModel, 'commit' => true))); + + // ... my ninja code ... + $dispatcher = sfContext::getInstance()->getEventDispatcher(); + $dispatcher->notify(new sfEvent($mySubject, 'uvmc_solr.delete_document', array('object' => $myModel))); + $myModel->delete(); + +## How to search? ## + +Let's say you configured solr to only give you back the primary keys of your models. + +### Add this in myModelTable.class.php ### + + public function findByScoredId($ids) + { + $query = $this->createQuery('p'); + $query->select('p.*') + ->whereIn('p.id', $ids) + // Keep scoring + // http://groups.google.com/group/symfony-users/browse_thread/thread/92adb0332dfe1065/ee7b8c0d27208368?lnk=gst&q=zend+search+sort#ee7b8c0d27208368 + ->addSelect('FIELD(p.id,'.implode(', ', $ids).') AS field') + ->orderBy('field'); + + return $query->execute(); + } + +### ...and this in your action! ### + + // Notify the dispatcher with the search event. + // $myQuery is a string containing your query + $event = $this->dispatcher->notify(new sfEvent($this, 'uvmc_solr.search', array('query' => $myQuery))); + $response = $event->getReturnValue(); + // solr is configured to give you back a serialized php array + $results = unserialize($response->getRawResponse()); + + $primaryKeys = array(); + foreach($results['response']['docs'] as $doc) + { + $primaryKeys[] = $doc['id']; + } + + if(!empty($primaryKeys)) + { + $this->results = Doctrine::getTable('myModel')->findByScoredId($primaryKeys); + } + else + { + $this->results = null; + } + +## Available events ## + + * uvmc_solr.search + * uvmc_solr.commit + * uvmc_solr.add_document + * uvmc_solr.update_document + * uvmc_solr.delete_document + +For more informations about those events and the required/optionnals parameters, please check _uvmcSolrEventListener.class.php_. + +## Available tasks ## + +Task namespace is uvmc-solr + + * reset-index. Reset the entire index of the solr service. + +## Known issues ## + +## Improvements ## + + * It would be great to manage multiple-servers + + * Write a task to re-index the entire site. + +## Credits ## + + * Kudos to [Miximum](http://www.miximum.fr/tutos/192-integrer-solr-a-symfony) (french) for the inspiration and code snippets :-) \ No newline at end of file diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/plugins/uvmcSolrSearchPlugin/config/solr.yml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/plugins/uvmcSolrSearchPlugin/config/solr.yml Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,12 @@ +# uvmcSolrSearchPlugin configuration file +# solr.yml can be configured at application level +# prefix: uvmc_solr_ +# +# + +all: + enabled: on + service: + host: localhost + port: 8080 + path: "/mosatags" \ No newline at end of file diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/plugins/uvmcSolrSearchPlugin/config/uvmcSolrSearchPluginConfiguration.class.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/plugins/uvmcSolrSearchPlugin/config/uvmcSolrSearchPluginConfiguration.class.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,44 @@ + + * @version $Id: uvmcSolrSearchPluginConfiguration.class.php 21181 2009-08-17 08:18:16Z futurecat $ + */ +class uvmcSolrSearchPluginConfiguration extends sfPluginConfiguration +{ + public function initialize() + { + if($this->configuration instanceof sfApplicationConfiguration) + { + $configCache = $this->configuration->getConfigCache(); + $configCache->registerConfigHandler('config/solr.yml', 'sfDefineEnvironmentConfigHandler', array('prefix' => 'uvmc_solr_')); + require_once($configCache->checkConfig('config/solr.yml')); + } + + $isEnabled = sfConfig::get('uvmc_solr_enabled', false); + $isEnabled = $isEnabled == true || $isEnabled == 'on' ? true : false; + + if ($isEnabled) + { + $this->connectEvents(); + } + } + + /** + * Connect events to listeners + */ + public function connectEvents() + { + $this->dispatcher->connect('admin.save_object', array('uvmcSolrEventListener', 'listenToAdminSaveObject')); + $this->dispatcher->connect('admin.delete_object', array('uvmcSolrEventListener', 'listenToAdminDeleteObject')); + $this->dispatcher->connect('uvmc_solr.search', array('uvmcSolrEventListener', 'listenToSearch')); + $this->dispatcher->connect('uvmc_solr.commit', array('uvmcSolrEventListener', 'listenToCommit')); + $this->dispatcher->connect('uvmc_solr.add_document', array('uvmcSolrEventListener', 'listenToAddDocument')); + $this->dispatcher->connect('uvmc_solr.update_document', array('uvmcSolrEventListener', 'listenToAddDocument')); + $this->dispatcher->connect('uvmc_solr.delete_document', array('uvmcSolrEventListener', 'listenToDeleteDocument')); + $this->dispatcher->connect('uvmc_solr.add_document_to_collection', array('uvmcSolrEventListener', 'listenToAddDocumentToCollection')); + $this->dispatcher->connect('uvmc_solr.add_collection', array('uvmcSolrEventListener', 'listenToAddCollection')); + } +} \ No newline at end of file diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/plugins/uvmcSolrSearchPlugin/lib/task/resetIndexTask.class.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/plugins/uvmcSolrSearchPlugin/lib/task/resetIndexTask.class.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,63 @@ + + * @version $Id: resetIndexTask.class.php 21094 2009-08-12 10:02:05Z futurecat $ + */ +class resetIndexTask extends sfBaseTask +{ + /** + * @see sfTask + */ + protected function configure() + { + // // add your own arguments here + $this->addArguments(array( + new sfCommandArgument('application', sfCommandArgument::REQUIRED, 'The application name'), + )); + + $this->addOptions(array( + // new sfCommandOption('application', null, sfCommandOption::PARAMETER_REQUIRED, 'The application name'), + new sfCommandOption('env', null, sfCommandOption::PARAMETER_REQUIRED, 'The environment', 'dev'), + new sfCommandOption('connection', null, sfCommandOption::PARAMETER_REQUIRED, 'The connection name', null), + // add your own options here + )); + + $this->namespace = 'uvmc-solr'; + $this->name = 'reset-index'; + $this->briefDescription = 'reset the solr index'; + $this->detailedDescription = <<askConfirmation(array(sprintf('resetIndex will DELETE the index of this service: http://%s:%s%s.', + sfConfig::get('uvmc_solr_service_host'), + sfConfig::get('uvmc_solr_service_port'), + sfConfig::get('uvmc_solr_service_path')), + 'Are you sure you want to proceed? (y/N)'), + 'QUESTION', + false); + if(!$confirm) + { + $this->logSection('uvmc-solr', 'task aborted'); + return 1; + } + + $solr = uvmcSolrServicesManager::getInstance()->getService(); + $solr->deleteByQuery('*:*'); + $this->logSection('uvmc-solr', 'Index has been deleted'); + } +} \ No newline at end of file diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/plugins/uvmcSolrSearchPlugin/lib/uvmcSolrEventListener.class.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/plugins/uvmcSolrSearchPlugin/lib/uvmcSolrEventListener.class.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,213 @@ + + * @version $Id: uvmcSolrEventListener.class.php 21181 2009-08-17 08:18:16Z futurecat $ + */ +class uvmcSolrEventListener +{ + static $documentCollection = array(); + + /** + * listen to symfony's admin generator "admin.save_object" event. + * If the model has a method 'getSolrDocumentFields', then the model will be indexed + * + * @param sfEvent $event + */ + static public function listenToAdminSaveObject(sfEvent $event) + { + $model = $event['object']; + + if (method_exists($model, 'getSolrDocumentFields')) + { + $docFields = $model->getSolrDocumentFields(); + $doc = uvmcSolrEventListener::transformArrayToSolrDocument($docFields); + + $solr = uvmcSolrServicesManager::getInstance()->getService(); + $solr->addDocument($doc); + $solr->commit(); + } + } + + + /** + * Listen to symfony's admin generator "admin.delete_object" event. + * + * @param sfEvent $event + */ + static function listentoAdminDeleteObject(sfEvent $event) + { + $model = $event['object']; + if (method_exists($model, 'getSolrDocumentFields')) + { + $docFields = $model->getSolrDocumentFields(); + $id = $docFieds['id']; + + $solr = uvmcSolrServicesManager::getInstance()->getService(); + $solr->deleteById($id); + } + } + + + /** + * Listen to uvmc_solr.delete_documment + * + * Parameters: + * - object (object, required) + * The object to delete from index. + * + * @param sfEvent $request + */ + static function listenToDeleteDocument(sfEvent $request) + { + $model = $event['object']; + + $docFields = $model->getSolrDocumentFields(); + $solr = uvmcSolrServicesManager::getInstance()->getService(); + $solr->deleteById($docFields['id']); + } + + /** + * Listen to uvmc_solr.add_document_to_collection + * Add a document to location collection but do not add it to solr + * + * Parameters: + * - object (object, required) + * The object to delete from index. + * + * @param sfEvent $event + */ + static function listenToAddDocumentToCollection(sfEvent $event) + { + $model = $event['object']; + + $docFields = $model->getSolrDocumentFields(); + $doc = uvmcSolrEventListener::transformArrayToSolrDocument($docFields); + + self::$documentCollection[] = $doc; + } + + /** + * Listen to uvmc_solr.add_collection + * Add the document collection to solr and resets it. + * + * @param sfEvent $event + */ + static function listenToAddCollection(sfEvent $event) + { + $solr = uvmcSolrServicesManager::getInstance()->getService(); + $solr->addDocuments(self::$documentCollection); + self::$documentCollection = array(); + } + + + /** + * Listen to uvmc_solr.add_document event + * Available parameters: + * - object (object, required) + * The object to index. + * + * - commit (bool, optional). + * false by default. + * set it to true to commit after the document has been added. + * @param sfEvent $event + */ + static public function listenToAddDocument(sfEvent $event) + { + $model = $event['object']; + + $docFields = $model->getSolrDocumentFields(); + $doc = uvmcSolrEventListener::transformArrayToSolrDocument($docFields); + + $solr = uvmcSolrServicesManager::getInstance()->getService(); + $solr->addDocument($doc); + + $commit = isset($event['commit']) ? $event['commit'] : false; + if ($commit) + { + $solr->commit(); + } + } + + + /** + * Commit all the document added to the master service + * + * @param sfEvent $event + */ + static public function listenToCommit(sfEvent $event) + { + $solr = uvmcSolrServicesManager::getInstance()->getService(); + $solr->commit(); + } + + + /** + * Search the Solr service + * Available parameters: + * - query (string, required) + * Search query to send to the solr service + * + * - offset (integer, optional) + * 0 by default. + * Offset of the first result to be returned. + * + * - maxhit (integer, optional) + * Maximum number of results to return. 10 by default + * + * @param sfEvent $event + */ + static public function listenToSearch(sfEvent $event) + { + if (!isset($event['query'])) + throw new sfException('Please specify a query.'); + + $query = $event['query']; + $offset = isset($event['offset']) ? $event['offset'] : 0; + $maxhit = isset($event['maxhit']) ? $event['maxhit'] : 10; + + $solr = uvmcSolrServicesManager::getInstance()->getService(); + $results = $solr->search($query, $offset, $maxhit); + + $event->setReturnValue($results); + } + + + /** + * Transform an array into a solr document + * @param array $docArray + * @return Apache_Solr_Document instance + */ + static public function transformArrayToSolrDocument($docArray) + { + $document = new Apache_Solr_Document(); + + foreach ($docArray as $fieldName => $fieldProperty) + { + if (!is_array($fieldProperty)) + { + $document->addField($fieldName, $fieldProperty); + } + else + { + if (isset($fieldProperty['value'])) + { + $boost = isset($fieldProperty['boost']) ? (float) $fieldProperty['boost'] : false; + $document->addField($fieldName, $fieldProperty['value'], $boost); + } + else + { + foreach ($fieldProperty as $property) + { + $boost = isset($property['boost']) ? (float) $property['boost'] : false; + $document->setMultiValue($fieldName, $property['value'], false); + } + } + } + } + + return $document; + } +} \ No newline at end of file diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/plugins/uvmcSolrSearchPlugin/lib/uvmcSolrServicesManager.class.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/plugins/uvmcSolrSearchPlugin/lib/uvmcSolrServicesManager.class.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,78 @@ + + * @version $Id: uvmcSolrServicesManager.class.php 21094 2009-08-12 10:02:05Z futurecat $ + */ +class uvmcSolrServicesManager +{ + static + $instance = null; + + protected + $service = null; + + /** + * Return the master Solr Service. + * @return Apache_Solr_Service + */ + public function getService() + { + if (is_null($this->service)) + { + $this->createService(); + } + if (!$this->service->ping()) + { + throw new sfException("Can't ping this Solr server"); + } + + return $this->service; + } + + /** + * Create the master Solr service + * + * @return Apache_Solr_service + */ + protected function createService() + { + $host = sfConfig::get('uvmc_solr_service_host', null); + $port = sfConfig::get('uvmc_solr_service_port', 8983); + $path = sfConfig::get('uvmc_solr_service_path', "/solr"); + + if (!is_null($host)) + { + $service = new Apache_Solr_Service($host, $port, $path); + if ($service->ping()) + { + $this->service = $service; + return $this->service; + } + } + + throw new sfException("Can't create an Apache_Solr_Service with this configuration."); + } + + /** + * @return uvmcSolrServicesManager instance + */ + static function getInstance() + { + if(!self::$instance instanceof uvmcSolrServicesManager) + { + self::createInstance(); + } + return self::$instance; + } + + static function createInstance() + { + self::$instance = new uvmcSolrServicesManager(); + } +} diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/plugins/uvmcSolrSearchPlugin/lib/vendor/solrphpclient/Document.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/plugins/uvmcSolrSearchPlugin/lib/vendor/solrphpclient/Document.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,362 @@ + + */ + +/** + * Holds Key / Value pairs that represent a Solr Document along with any associated boost + * values. Field values can be accessed by direct dereferencing such as: + * + * ... + * $document->title = 'Something'; + * echo $document->title; + * ... + * + * + * Additionally, the field values can be iterated with foreach + * + * + * foreach ($document as $fieldName => $fieldValue) + * { + * ... + * } + * + */ +class Apache_Solr_Document implements IteratorAggregate +{ + /** + * SVN Revision meta data for this class + */ + const SVN_REVISION = '$Revision: 21094 $'; + + /** + * SVN ID meta data for this class + */ + const SVN_ID = '$Id: Document.php 21094 2009-08-12 10:02:05Z futurecat $'; + + /** + * Document boost value + * + * @var float + */ + protected $_documentBoost = false; + + /** + * Document field values, indexed by name + * + * @var array + */ + protected $_fields = array(); + + /** + * Document field boost values, indexed by name + * + * @var array array of floats + */ + protected $_fieldBoosts = array(); + + /** + * Clear all boosts and fields from this document + */ + public function clear() + { + $this->_documentBoost = false; + + $this->_fields = array(); + $this->_fieldBoosts = array(); + } + + /** + * Get current document boost + * + * @return mixed will be false for default, or else a float + */ + public function getBoost() + { + return $this->_documentBoost; + } + + /** + * Set document boost factor + * + * @param mixed $boost Use false for default boost, else cast to float that should be > 0 or will be treated as false + */ + public function setBoost($boost) + { + $boost = (float) $boost; + + if ($boost > 0.0) + { + $this->_documentBoost = $boost; + } + else + { + $this->_documentBoost = false; + } + } + + /** + * Add a value to a multi-valued field + * + * NOTE: the solr XML format allows you to specify boosts + * PER value even though the underlying Lucene implementation + * only allows a boost per field. To remedy this, the final + * field boost value will be the product of all specified boosts + * on field values - this is similar to SolrJ's functionality. + * + * + * $doc = new Apache_Solr_Document(); + * + * $doc->addField('foo', 'bar', 2.0); + * $doc->addField('foo', 'baz', 3.0); + * + * // resultant field boost will be 6! + * echo $doc->getFieldBoost('foo'); + * + * + * @param string $key + * @param mixed $value + * @param mixed $boost Use false for default boost, else cast to float that should be > 0 or will be treated as false + */ + public function addField($key, $value, $boost = false) + { + if (!isset($this->_fields[$key])) + { + // create holding array if this is the first value + $this->_fields[$key] = array(); + } + else if (!is_array($this->_fields[$key])) + { + // move existing value into array if it is not already an array + $this->_fields[$key] = array($this->_fields[$key]); + } + + if ($this->getFieldBoost($key) === false) + { + // boost not already set, set it now + $this->setFieldBoost($key, $boost); + } + else if ((float) $boost > 0.0) + { + // multiply passed boost with current field boost - similar to SolrJ implementation + $this->_fieldBoosts[$key] *= (float) $boost; + } + + // add value to array + $this->_fields[$key][] = $value; + } + + /** + * Handle the array manipulation for a multi-valued field + * + * @param string $key + * @param string $value + * @param mixed $boost Use false for default boost, else cast to float that should be > 0 or will be treated as false + * + * @deprecated Use addField(...) instead + */ + public function setMultiValue($key, $value, $boost = false) + { + $this->addField($key, $value, $boost); + } + + /** + * Get field information + * + * @param string $key + * @return mixed associative array of info if field exists, false otherwise + */ + public function getField($key) + { + if (isset($this->_fields[$key])) + { + return array( + 'name' => $key, + 'value' => $this->_fields[$key], + 'boost' => $this->getFieldBoost($key) + ); + } + + return false; + } + + /** + * Set a field value. Multi-valued fields should be set as arrays + * or instead use the addField(...) function which will automatically + * make sure the field is an array. + * + * @param string $key + * @param mixed $value + * @param mixed $boost Use false for default boost, else cast to float that should be > 0 or will be treated as false + */ + public function setField($key, $value, $boost = false) + { + $this->_fields[$key] = $value; + $this->setFieldBoost($key, $boost); + } + + /** + * Get the currently set field boost for a document field + * + * @param string $key + * @return float currently set field boost, false if one is not set + */ + public function getFieldBoost($key) + { + return isset($this->_fieldBoosts[$key]) ? $this->_fieldBoosts[$key] : false; + } + + /** + * Set the field boost for a document field + * + * @param string $key field name for the boost + * @param mixed $boost Use false for default boost, else cast to float that should be > 0 or will be treated as false + */ + public function setFieldBoost($key, $boost) + { + $boost = (float) $boost; + + if ($boost > 0.0) + { + $this->_fieldBoosts[$key] = $boost; + } + else + { + $this->_fieldBoosts[$key] = false; + } + } + + /** + * Return current field boosts, indexed by field name + * + * @return array + */ + public function getFieldBoosts() + { + return $this->_fieldBoosts; + } + + /** + * Get the names of all fields in this document + * + * @return array + */ + public function getFieldNames() + { + return array_keys($this->_fields); + } + + /** + * Get the values of all fields in this document + * + * @return array + */ + public function getFieldValues() + { + return array_values($this->_fields); + } + + /** + * IteratorAggregate implementation function. Allows usage: + * + * + * foreach ($document as $key => $value) + * { + * ... + * } + * + */ + public function getIterator() + { + $arrayObject = new ArrayObject($this->_fields); + + return $arrayObject->getIterator(); + } + + /** + * Magic get for field values + * + * @param string $key + * @return mixed + */ + public function __get($key) + { + return $this->_fields[$key]; + } + + /** + * Magic set for field values. Multi-valued fields should be set as arrays + * or instead use the addField(...) function which will automatically + * make sure the field is an array. + * + * @param string $key + * @param mixed $value + */ + public function __set($key, $value) + { + $this->setField($key, $value); + } + + /** + * Magic isset for fields values. Do not call directly. Allows usage: + * + * + * isset($document->some_field); + * + * + * @param string $key + * @return boolean + */ + public function __isset($key) + { + return isset($this->_fields[$key]); + } + + /** + * Magic unset for field values. Do not call directly. Allows usage: + * + * + * unset($document->some_field); + * + * + * @param string $key + */ + public function __unset($key) + { + unset($this->_fields[$key]); + unset($this->_fieldBoosts[$key]); + } +} \ No newline at end of file diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/plugins/uvmcSolrSearchPlugin/lib/vendor/solrphpclient/Response.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/plugins/uvmcSolrSearchPlugin/lib/vendor/solrphpclient/Response.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,288 @@ + + */ + +/** + * Represents a Solr response. Parses the raw response into a set of stdClass objects + * and associative arrays for easy access. + * + * Currently requires json_decode which is bundled with PHP >= 5.2.0, Alternatively can be + * installed with PECL. Zend Framework also includes a purely PHP solution. + */ +class Apache_Solr_Response +{ + /** + * SVN Revision meta data for this class + */ + const SVN_REVISION = '$Revision: 21100 $'; + + /** + * SVN ID meta data for this class + */ + const SVN_ID = '$Id: Response.php 21100 2009-08-12 14:34:55Z futurecat $'; + + /** + * Holds the raw response used in construction + * + * @var string + */ + protected $_rawResponse; + + /** + * Parsed values from the passed in http headers + * + * @var string + */ + protected $_httpStatus, $_httpStatusMessage, $_type, $_encoding; + + /** + * Whether the raw response has been parsed + * + * @var boolean + */ + protected $_isParsed = false; + + /** + * Parsed representation of the data + * + * @var mixed + */ + protected $_parsedData; + + /** + * Data parsing flags. Determines what extra processing should be done + * after the data is initially converted to a data structure. + * + * @var boolean + */ + protected $_createDocuments = true, + $_collapseSingleValueArrays = true; + + /** + * Constructor. Takes the raw HTTP response body and the exploded HTTP headers + * + * @param string $rawResponse + * @param array $httpHeaders + * @param boolean $createDocuments Whether to convert the documents json_decoded as stdClass instances to Apache_Solr_Document instances + * @param boolean $collapseSingleValueArrays Whether to make multivalued fields appear as single values + */ + public function __construct($rawResponse, $httpHeaders = array(), $createDocuments = true, $collapseSingleValueArrays = true) + { + //Assume 0, 'Communication Error', utf-8, and text/plain + $status = 0; + $statusMessage = 'Communication Error'; + $type = 'text/plain'; + $encoding = 'UTF-8'; + + //iterate through headers for real status, type, and encoding + if (is_array($httpHeaders) && count($httpHeaders) > 0) + { + //look at the first headers for the HTTP status code + //and message (errors are usually returned this way) + // + //HTTP 100 Continue response can also be returned before + //the REAL status header, so we need look until we find + //the last header starting with HTTP + // + //the spec: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.1 + // + //Thanks to Daniel Andersson for pointing out this oversight + while (isset($httpHeaders[0]) && substr($httpHeaders[0], 0, 4) == 'HTTP') + { + $parts = explode(' ', substr($httpHeaders[0], 9), 2); + + $status = $parts[0]; + $statusMessage = trim($parts[1]); + + array_shift($httpHeaders); + } + + //Look for the Content-Type response header and determine type + //and encoding from it (if possible - such as 'Content-Type: text/plain; charset=UTF-8') + foreach ($httpHeaders as $header) + { + if (strncasecmp($header, 'Content-Type:', 13) == 0) + { + //split content type value into two parts if possible + $parts = explode(';', substr($header, 13), 2); + + $type = trim($parts[0]); + + if ($parts[1]) + { + //split the encoding section again to get the value + $parts = explode('=', $parts[1], 2); + + if ($parts[1]) + { + $encoding = trim($parts[1]); + } + } + + break; + } + } + } + + $this->_rawResponse = $rawResponse; + $this->_type = $type; + $this->_encoding = $encoding; + $this->_httpStatus = $status; + $this->_httpStatusMessage = $statusMessage; + $this->_createDocuments = (bool) $createDocuments; + $this->_collapseSingleValueArrays = (bool) $collapseSingleValueArrays; + } + + /** + * Get the HTTP status code + * + * @return integer + */ + public function getHttpStatus() + { + return $this->_httpStatus; + } + + /** + * Get the HTTP status message of the response + * + * @return string + */ + public function getHttpStatusMessage() + { + return $this->_httpStatusMessage; + } + + /** + * Get content type of this Solr response + * + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * Get character encoding of this response. Should usually be utf-8, but just in case + * + * @return string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Get the raw response as it was given to this object + * + * @return string + */ + public function getRawResponse() + { + return $this->_rawResponse; + } + + /** + * Magic get to expose the parsed data and to lazily load it + * + * @param unknown_type $key + * @return unknown + */ + public function __get($key) + { + if (!$this->_isParsed) + { + $this->_parseData(); + $this->_isParsed = true; + } + + if (isset($this->_parsedData->$key)) + { + return $this->_parsedData->$key; + } + + return null; + } + + /** + * Parse the raw response into the parsed_data array for access + */ + protected function _parseData() + { + //An alternative would be to use Zend_Json::decode(...) + $data = json_decode($this->_rawResponse); + + //if we're configured to collapse single valued arrays or to convert them to Apache_Solr_Document objects + //and we have response documents, then try to collapse the values and / or convert them now + if (($this->_createDocuments || $this->_collapseSingleValueArrays) && isset($data->response) && is_array($data->response->docs)) + { + $documents = array(); + + foreach ($data->response->docs as $originalDocument) + { + if ($this->_createDocuments) + { + $document = new Apache_Solr_Document(); + } + else + { + $document = $originalDocument; + } + + foreach ($originalDocument as $key => $value) + { + //If a result is an array with only a single + //value then its nice to be able to access + //it as if it were always a single value + if ($this->_collapseSingleValueArrays && is_array($value) && count($value) <= 1) + { + $value = array_shift($value); + } + + $document->$key = $value; + } + + $documents[] = $document; + } + + $data->response->docs = $documents; + } + + $this->_parsedData = $data; + } +} \ No newline at end of file diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/plugins/uvmcSolrSearchPlugin/lib/vendor/solrphpclient/Service.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/plugins/uvmcSolrSearchPlugin/lib/vendor/solrphpclient/Service.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,917 @@ + + */ + +// See Issue #1 (http://code.google.com/p/solr-php-client/issues/detail?id=1) +// Doesn't follow typical include path conventions, but is more convenient for users +require_once(dirname(__FILE__) . '/Document.php'); +require_once(dirname(__FILE__) . '/Response.php'); + +/** + * Starting point for the Solr API. Represents a Solr server resource and has + * methods for pinging, adding, deleting, committing, optimizing and searching. + * + * Example Usage: + * + * ... + * $solr = new Apache_Solr_Service(); //or explicitly new Apache_Solr_Service('localhost', 8180, '/solr') + * + * if ($solr->ping()) + * { + * $solr->deleteByQuery('*:*'); //deletes ALL documents - be careful :) + * + * $document = new Apache_Solr_Document(); + * $document->id = uniqid(); //or something else suitably unique + * + * $document->title = 'Some Title'; + * $document->content = 'Some content for this wonderful document. Blah blah blah.'; + * + * $solr->addDocument($document); //if you're going to be adding documents in bulk using addDocuments + * //with an array of documents is faster + * + * $solr->commit(); //commit to see the deletes and the document + * $solr->optimize(); //merges multiple segments into one + * + * //and the one we all care about, search! + * //any other common or custom parameters to the request handler can go in the + * //optional 4th array argument. + * $solr->search('content:blah', 0, 10, array('sort' => 'timestamp desc')); + * } + * ... + * + * + * @todo Investigate using other HTTP clients other than file_get_contents built-in handler. Could provide performance + * improvements when dealing with multiple requests by using HTTP's keep alive functionality + */ +class Apache_Solr_Service +{ + /** + * SVN Revision meta data for this class + */ + const SVN_REVISION = '$Revision: 21094 $'; + + /** + * SVN ID meta data for this class + */ + const SVN_ID = '$Id: Service.php 21094 2009-08-12 10:02:05Z futurecat $'; + + /** + * Response version we support + */ + const SOLR_VERSION = '1.3'; + + /** + * Response writer we'll request - JSON. See http://code.google.com/p/solr-php-client/issues/detail?id=6#c1 for reasoning + */ + const SOLR_WRITER = 'phps'; + + /** + * NamedList Treatment constants + */ + const NAMED_LIST_FLAT = 'flat'; + const NAMED_LIST_MAP = 'map'; + + /** + * Search HTTP Methods + */ + const METHOD_GET = 'GET'; + const METHOD_POST = 'POST'; + + /** + * Servlet mappings + */ + const PING_SERVLET = 'admin/ping'; + const UPDATE_SERVLET = 'update'; + const SEARCH_SERVLET = 'select'; + const THREADS_SERVLET = 'admin/threads'; + + /** + * Server identification strings + * + * @var string + */ + protected $_host, $_port, $_path; + + /** + * Whether {@link Apache_Solr_Response} objects should create {@link Apache_Solr_Document}s in + * the returned parsed data + * + * @var boolean + */ + protected $_createDocuments = true; + + /** + * Whether {@link Apache_Solr_Response} objects should have multivalue fields with only a single value + * collapsed to appear as a single value would. + * + * @var boolean + */ + protected $_collapseSingleValueArrays = true; + + /** + * How NamedLists should be formatted in the output. This specifically effects facet counts. Valid values + * are {@link Apache_Solr_Service::NAMED_LIST_MAP} (default) or {@link Apache_Solr_Service::NAMED_LIST_FLAT}. + * + * @var string + */ + protected $_namedListTreatment = self::NAMED_LIST_MAP; + + /** + * Query delimiters. Someone might want to be able to change + * these (to use & instead of & for example), so I've provided them. + * + * @var string + */ + protected $_queryDelimiter = '?', $_queryStringDelimiter = '&'; + + /** + * Constructed servlet full path URLs + * + * @var string + */ + protected $_pingUrl, $_updateUrl, $_searchUrl, $_threadsUrl; + + /** + * Keep track of whether our URLs have been constructed + * + * @var boolean + */ + protected $_urlsInited = false; + + /** + * Escape a value for special query characters such as ':', '(', ')', '*', '?', etc. + * + * NOTE: inside a phrase fewer characters need escaped, use {@link Apache_Solr_Service::escapePhrase()} instead + * + * @param string $value + * @return string + */ + static public function escape($value) + { + //list taken from http://lucene.apache.org/java/docs/queryparsersyntax.html#Escaping%20Special%20Characters + $pattern = '/(\+|-|&&|\|\||!|\(|\)|\{|}|\[|]|\^|"|~|\*|\?|:|\\\)/'; + $replace = '\\\$1'; + + return preg_replace($pattern, $replace, $value); + } + + /** + * Escape a value meant to be contained in a phrase for special query characters + * + * @param string $value + * @return string + */ + static public function escapePhrase($value) + { + $pattern = '/("|\\\)/'; + $replace = '\\\$1'; + + return preg_replace($pattern, $replace, $value); + } + + /** + * Convenience function for creating phrase syntax from a value + * + * @param string $value + * @return string + */ + static public function phrase($value) + { + return '"' . self::escapePhrase($value) . '"'; + } + + /** + * Constructor. All parameters are optional and will take on default values + * if not specified. + * + * @param string $host + * @param string $port + * @param string $path + */ + public function __construct($host = 'localhost', $port = 8180, $path = '/solr/') + { + $this->setHost($host); + $this->setPort($port); + $this->setPath($path); + + $this->_initUrls(); + } + + /** + * Return a valid http URL given this server's host, port and path and a provided servlet name + * + * @param string $servlet + * @return string + */ + protected function _constructUrl($servlet, $params = array()) + { + if (count($params)) + { + //escape all parameters appropriately for inclusion in the query string + $escapedParams = array(); + + foreach ($params as $key => $value) + { + $escapedParams[] = urlencode($key) . '=' . urlencode($value); + } + + $queryString = $this->_queryDelimiter . implode($this->_queryStringDelimiter, $escapedParams); + } + else + { + $queryString = ''; + } + + return 'http://' . $this->_host . ':' . $this->_port . $this->_path . $servlet . $queryString; + } + + /** + * Construct the Full URLs for the three servlets we reference + */ + protected function _initUrls() + { + //Initialize our full servlet URLs now that we have server information + $this->_pingUrl = $this->_constructUrl(self::PING_SERVLET); + $this->_updateUrl = $this->_constructUrl(self::UPDATE_SERVLET, array('wt' => self::SOLR_WRITER )); + $this->_searchUrl = $this->_constructUrl(self::SEARCH_SERVLET); + $this->_threadsUrl = $this->_constructUrl(self::THREADS_SERVLET, array('wt' => self::SOLR_WRITER )); + + $this->_urlsInited = true; + } + + /** + * Central method for making a get operation against this Solr Server + * + * @param string $url + * @param float $timeout Read timeout in seconds + * @return Apache_Solr_Response + * + * @throws Exception If a non 200 response status is returned + */ + protected function _sendRawGet($url, $timeout = FALSE) + { + //set up the stream context so we can control + // the timeout for file_get_contents + $context = stream_context_create(); + + // set the timeout if specified, without this I assume + // that the default_socket_timeout ini setting is used + if ($timeout !== FALSE && $timeout > 0.0) + { + // timeouts with file_get_contents seem to need + // to be halved to work as expected + $timeout = (float) $timeout / 2; + + stream_context_set_option($context, 'http', 'timeout', $timeout); + } + + //$http_response_header is set by file_get_contents + $response = new Apache_Solr_Response(@file_get_contents($url, false, $context), $http_response_header, $this->_createDocuments, $this->_collapseSingleValueArrays); + + if ($response->getHttpStatus() != 200) + { + throw new Exception('"' . $response->getHttpStatus() . '" Status: ' . $response->getHttpStatusMessage(), $response->getHttpStatus()); + } + + return $response; + } + + /** + * Central method for making a post operation against this Solr Server + * + * @param string $url + * @param string $rawPost + * @param float $timeout Read timeout in seconds + * @param string $contentType + * @return Apache_Solr_Response + * + * @throws Exception If a non 200 response status is returned + */ + protected function _sendRawPost($url, $rawPost, $timeout = FALSE, $contentType = 'text/xml; charset=UTF-8') + { + //set up the stream context for posting with file_get_contents + $context = stream_context_create( + array( + 'http' => array( + // set HTTP method + 'method' => 'POST', + + // Add our posted content type + 'header' => "Content-Type: $contentType", + + // the posted content + 'content' => $rawPost + ) + ) + ); + + // set the timeout if specified, without this I assume + // that the default_socket_timeout ini setting is used + if ($timeout !== FALSE && $timeout > 0.0) + { + // timeouts with file_get_contents seem to need + // to be halved to work as expected + $timeout = (float) $timeout / 2; + + stream_context_set_option($context, 'http', 'timeout', $timeout); + } + + //$http_response_header is set by file_get_contents + $response = new Apache_Solr_Response(@file_get_contents($url, false, $context), $http_response_header, $this->_createDocuments, $this->_collapseSingleValueArrays); + + if ($response->getHttpStatus() != 200) + { + throw new Exception('"' . $response->getHttpStatus() . '" Status: ' . $response->getHttpStatusMessage(), $response->getHttpStatus()); + } + + return $response; + } + + /** + * Returns the set host + * + * @return string + */ + public function getHost() + { + return $this->_host; + } + + /** + * Set the host used. If empty will fallback to constants + * + * @param string $host + */ + public function setHost($host) + { + //Use the provided host or use the default + if (empty($host)) + { + throw new Exception('Host parameter is empty'); + } + else + { + $this->_host = $host; + } + + if ($this->_urlsInited) + { + $this->_initUrls(); + } + } + + /** + * Get the set port + * + * @return integer + */ + public function getPort() + { + return $this->_port; + } + + /** + * Set the port used. If empty will fallback to constants + * + * @param integer $port + */ + public function setPort($port) + { + //Use the provided port or use the default + $port = (int) $port; + + if ($port <= 0) + { + throw new Exception('Port is not a valid port number'); + } + else + { + $this->_port = $port; + } + + if ($this->_urlsInited) + { + $this->_initUrls(); + } + } + + /** + * Get the set path. + * + * @return string + */ + public function getPath() + { + return $this->_path; + } + + /** + * Set the path used. If empty will fallback to constants + * + * @param string $path + */ + public function setPath($path) + { + $path = trim($path, '/'); + + $this->_path = '/' . $path . '/'; + + if ($this->_urlsInited) + { + $this->_initUrls(); + } + } + + /** + * Set the create documents flag. This determines whether {@link Apache_Solr_Response} objects will + * parse the response and create {@link Apache_Solr_Document} instances in place. + * + * @param unknown_type $createDocuments + */ + public function setCreateDocuments($createDocuments) + { + $this->_createDocuments = (bool) $createDocuments; + } + + /** + * Get the current state of teh create documents flag. + * + * @return boolean + */ + public function getCreateDocuments() + { + return $this->_createDocuments; + } + + /** + * Set the collapse single value arrays flag. + * + * @param boolean $collapseSingleValueArrays + */ + public function setCollapseSingleValueArrays($collapseSingleValueArrays) + { + $this->_collapseSingleValueArrays = (bool) $collapseSingleValueArrays; + } + + /** + * Get the current state of the collapse single value arrays flag. + * + * @return boolean + */ + public function getCollapseSingleValueArrays() + { + return $this->_collapseSingleValueArrays; + } + + /** + * Set how NamedLists should be formatted in the response data. This mainly effects + * the facet counts format. + * + * @param string $namedListTreatment + * @throws Exception If invalid option is set + */ + public function setNamedListTreatmet($namedListTreatment) + { + switch ((string) $namedListTreatment) + { + case Apache_Solr_Service::NAMED_LIST_FLAT: + $this->_namedListTreatment = Apache_Solr_Service::NAMED_LIST_FLAT; + break; + + case Apache_Solr_Service::NAMED_LIST_MAP: + $this->_namedListTreatment = Apache_Solr_Service::NAMED_LIST_MAP; + break; + + default: + throw new Exception('Not a valid named list treatement option'); + } + } + + /** + * Get the current setting for named list treatment. + * + * @return string + */ + public function getNamedListTreatment() + { + return $this->_namedListTreatment; + } + + + /** + * Set the string used to separate the path form the query string. + * Defaulted to '?' + * + * @param string $queryDelimiter + */ + public function setQueryDelimiter($queryDelimiter) + { + $this->_queryDelimiter = $queryDelimiter; + } + + /** + * Set the string used to separate the parameters in thequery string + * Defaulted to '&' + * + * @param string $queryStringDelimiter + */ + public function setQueryStringDelimiter($queryStringDelimiter) + { + $this->_queryStringDelimiter = $queryStringDelimiter; + } + + /** + * Call the /admin/ping servlet, can be used to quickly tell if a connection to the + * server is able to be made. + * + * @param float $timeout maximum time to wait for ping in seconds, -1 for unlimited (default is 2) + * @return float Actual time taken to ping the server, FALSE if timeout or HTTP error status occurs + */ + public function ping($timeout = 2) + { + $start = microtime(true); + + // when using timeout in context and file_get_contents + // it seems to take twice the timout value + $timeout = (float) $timeout / 2; + + if ($timeout <= 0.0) + { + $timeout = -1; + } + + $context = stream_context_create( + array( + 'http' => array( + 'method' => 'HEAD', + 'timeout' => $timeout + ) + ) + ); + + // attempt a HEAD request to the solr ping page + $ping = @file_get_contents($this->_pingUrl, false, $context); + + // result is false if there was a timeout + // or if the HTTP status was not 200 + if ($ping !== false) + { + return microtime(true) - $start; + } + else + { + return false; + } + } + + /** + * Call the /admin/threads servlet and retrieve information about all threads in the + * Solr servlet's thread group. Useful for diagnostics. + * + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function threads() + { + return $this->_sendRawGet($this->_threadsUrl); + } + + /** + * Raw Add Method. Takes a raw post body and sends it to the update service. Post body + * should be a complete and well formed "add" xml document. + * + * @param string $rawPost + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function add($rawPost) + { + return $this->_sendRawPost($this->_updateUrl, $rawPost); + } + + /** + * Add a Solr Document to the index + * + * @param Apache_Solr_Document $document + * @param boolean $allowDups + * @param boolean $overwritePending + * @param boolean $overwriteCommitted + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function addDocument(Apache_Solr_Document $document, $allowDups = false, $overwritePending = true, $overwriteCommitted = true) + { + $dupValue = $allowDups ? 'true' : 'false'; + $pendingValue = $overwritePending ? 'true' : 'false'; + $committedValue = $overwriteCommitted ? 'true' : 'false'; + + $rawPost = ''; + $rawPost .= $this->_documentToXmlFragment($document); + $rawPost .= ''; + + return $this->add($rawPost); + } + + /** + * Add an array of Solr Documents to the index all at once + * + * @param array $documents Should be an array of Apache_Solr_Document instances + * @param boolean $allowDups + * @param boolean $overwritePending + * @param boolean $overwriteCommitted + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function addDocuments($documents, $allowDups = false, $overwritePending = true, $overwriteCommitted = true) + { + $dupValue = $allowDups ? 'true' : 'false'; + $pendingValue = $overwritePending ? 'true' : 'false'; + $committedValue = $overwriteCommitted ? 'true' : 'false'; + + $rawPost = ''; + + foreach ($documents as $document) + { + if ($document instanceof Apache_Solr_Document) + { + $rawPost .= $this->_documentToXmlFragment($document); + } + } + + $rawPost .= ''; + + return $this->add($rawPost); + } + + /** + * Create an XML fragment from a {@link Apache_Solr_Document} instance appropriate for use inside a Solr add call + * + * @return string + */ + protected function _documentToXmlFragment(Apache_Solr_Document $document) + { + $xml = 'getBoost() !== false) + { + $xml .= ' boost="' . $document->getBoost() . '"'; + } + + $xml .= '>'; + + foreach ($document as $key => $value) + { + $key = htmlspecialchars($key, ENT_QUOTES, 'UTF-8'); + $fieldBoost = $document->getFieldBoost($key); + + if (is_array($value)) + { + foreach ($value as $multivalue) + { + $xml .= ''; + } + } + else + { + $xml .= ''; + } + } + + $xml .= ''; + + // replace any control characters to avoid Solr XML parser exception + return $this->_stripCtrlChars($xml); + } + + /** + * Replace control (non-printable) characters from string that are invalid to Solr's XML parser with a space. + * + * @param string $string + * @return string + */ + protected function _stripCtrlChars($string) + { + // See: http://w3.org/International/questions/qa-forms-utf-8.html + // Printable utf-8 does not include any of these chars below x7F + return preg_replace('@[\x00-\x08\x0B\x0C\x0E-\x1F]@', ' ', $string); + } + + /** + * Send a commit command. Will be synchronous unless both wait parameters are set to false. + * + * @param boolean $optimize Defaults to true + * @param boolean $waitFlush Defaults to true + * @param boolean $waitSearcher Defaults to true + * @param float $timeout Maximum expected duration (in seconds) of the commit operation on the server (otherwise, will throw a communication exception). Defaults to 1 hour + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function commit($optimize = true, $waitFlush = true, $waitSearcher = true, $timeout = 3600) + { + $optimizeValue = $optimize ? 'true' : 'false'; + $flushValue = $waitFlush ? 'true' : 'false'; + $searcherValue = $waitSearcher ? 'true' : 'false'; + + $rawPost = ''; + + return $this->_sendRawPost($this->_updateUrl, $rawPost, $timeout); + } + + /** + * Raw Delete Method. Takes a raw post body and sends it to the update service. Body should be + * a complete and well formed "delete" xml document + * + * @param string $rawPost Expected to be utf-8 encoded xml document + * @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception) + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function delete($rawPost, $timeout = 3600) + { + return $this->_sendRawPost($this->_updateUrl, $rawPost, $timeout); + } + + /** + * Create a delete document based on document ID + * + * @param string $id Expected to be utf-8 encoded + * @param boolean $fromPending + * @param boolean $fromCommitted + * @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception) + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function deleteById($id, $fromPending = true, $fromCommitted = true, $timeout = 3600) + { + $pendingValue = $fromPending ? 'true' : 'false'; + $committedValue = $fromCommitted ? 'true' : 'false'; + + //escape special xml characters + $id = htmlspecialchars($id, ENT_NOQUOTES, 'UTF-8'); + + $rawPost = '' . $id . ''; + + return $this->delete($rawPost, $timeout); + } + + /** + * Create a delete document based on a query and submit it + * + * @param string $rawQuery Expected to be utf-8 encoded + * @param boolean $fromPending + * @param boolean $fromCommitted + * @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception) + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function deleteByQuery($rawQuery, $fromPending = true, $fromCommitted = true, $timeout = 3600) + { + $pendingValue = $fromPending ? 'true' : 'false'; + $committedValue = $fromCommitted ? 'true' : 'false'; + + // escape special xml characters + $rawQuery = htmlspecialchars($rawQuery, ENT_NOQUOTES, 'UTF-8'); + + $rawPost = '' . $rawQuery . ''; + + return $this->delete($rawPost, $timeout); + } + + /** + * Send an optimize command. Will be synchronous unless both wait parameters are set + * to false. + * + * @param boolean $waitFlush + * @param boolean $waitSearcher + * @param float $timeout Maximum expected duration of the commit operation on the server (otherwise, will throw a communication exception) + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function optimize($waitFlush = true, $waitSearcher = true, $timeout = 3600) + { + $flushValue = $waitFlush ? 'true' : 'false'; + $searcherValue = $waitSearcher ? 'true' : 'false'; + + $rawPost = ''; + + return $this->_sendRawPost($this->_updateUrl, $rawPost, $timeout); + } + + /** + * Simple Search interface + * + * @param string $query The raw query string + * @param int $offset The starting offset for result documents + * @param int $limit The maximum number of result documents to return + * @param array $params key / value pairs for other query parameters (see Solr documentation), use arrays for parameter keys used more than once (e.g. facet.field) + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function search($query, $offset = 0, $limit = 10, $params = array(), $method = self::METHOD_GET) + { + if (!is_array($params)) + { + $params = array(); + } + + // construct our full parameters + // sending the version is important in case the format changes + $params['version'] = self::SOLR_VERSION; + + // common parameters in this interface + $params['wt'] = self::SOLR_WRITER; + $params['json.nl'] = $this->_namedListTreatment; + + $params['q'] = $query; + $params['start'] = $offset; + $params['rows'] = $limit; + + // use http_build_query to encode our arguments because its faster + // than urlencoding all the parts ourselves in a loop + $queryString = http_build_query($params, null, $this->_queryStringDelimiter); + + // because http_build_query treats arrays differently than we want to, correct the query + // string by changing foo[#]=bar (# being an actual number) parameter strings to just + // multiple foo=bar strings. This regex should always work since '=' will be urlencoded + // anywhere else the regex isn't expecting it + $queryString = preg_replace('/%5B(?:[0-9]|[1-9][0-9]+)%5D=/', '=', $queryString); + + if ($method == self::METHOD_GET) + { + return $this->_sendRawGet($this->_searchUrl . $this->_queryDelimiter . $queryString); + } + else if ($method == self::METHOD_POST) + { + return $this->_sendRawPost($this->_searchUrl, $queryString, FALSE, 'application/x-www-form-urlencoded'); + } + else + { + throw new Exception("Unsupported method '$method', please use the Apache_Solr_Service::METHOD_* constants"); + } + } +} \ No newline at end of file diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/plugins/uvmcSolrSearchPlugin/lib/vendor/solrphpclient/Service/Balancer.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/plugins/uvmcSolrSearchPlugin/lib/vendor/solrphpclient/Service/Balancer.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,774 @@ +, Dan Wolfe + */ + +// See Issue #1 (http://code.google.com/p/solr-php-client/issues/detail?id=1) +// Doesn't follow typical include path conventions, but is more convenient for users +require_once(dirname(dirname(__FILE__)) . '/Service.php'); + +/** + * Reference Implementation for using multiple Solr services in a distribution. Functionality + * includes: + * routing of read / write operations + * failover (on selection) for multiple read servers + */ +class Apache_Solr_Service_Balancer +{ + /** + * SVN Revision meta data for this class + */ + const SVN_REVISION = '$Revision: 21094 $'; + + /** + * SVN ID meta data for this class + */ + const SVN_ID = '$Id: Balancer.php 21094 2009-08-12 10:02:05Z futurecat $'; + + protected $_createDocuments = true; + + protected $_readableServices = array(); + protected $_writeableServices = array(); + + protected $_currentReadService = null; + protected $_currentWriteService = null; + + protected $_readPingTimeout = 2; + protected $_writePingTimeout = 4; + + // Configuration for server selection backoff intervals + protected $_useBackoff = false; // Set to true to use more resillient write server selection + protected $_backoffLimit = 600; // 10 minute default maximum + protected $_backoffEscalation = 2.0; // Rate at which to increase backoff period + protected $_defaultBackoff = 2.0; // Default backoff interval + + /** + * Escape a value for special query characters such as ':', '(', ')', '*', '?', etc. + * + * NOTE: inside a phrase fewer characters need escaped, use {@link Apache_Solr_Service::escapePhrase()} instead + * + * @param string $value + * @return string + */ + static public function escape($value) + { + return Apache_Solr_Service::escape($value); + } + + /** + * Escape a value meant to be contained in a phrase for special query characters + * + * @param string $value + * @return string + */ + static public function escapePhrase($value) + { + return Apache_Solr_Service::escapePhrase($value); + } + + /** + * Convenience function for creating phrase syntax from a value + * + * @param string $value + * @return string + */ + static public function phrase($value) + { + return Apache_Solr_Service::phrase($value); + } + + /** + * Constructor. Takes arrays of read and write service instances or descriptions + * + * @param array $readableServices + * @param array $writeableServices + */ + public function __construct($readableServices = array(), $writeableServices = array()) + { + //setup readable services + foreach ($readableServices as $service) + { + $this->addReadService($service); + } + + //setup writeable services + foreach ($writeableServices as $service) + { + $this->addWriteService($service); + } + } + + public function setReadPingTimeout($timeout) + { + $this->_readPingTimeout = $timeout; + } + + public function setWritePingTimeout($timeout) + { + $this->_writePingTimeout = $timeout; + } + + public function setUseBackoff($enable) + { + $this->_useBackoff = $enable; + } + + /** + * Generates a service ID + * + * @param string $host + * @param integer $port + * @param string $path + * @return string + */ + protected function _getServiceId($host, $port, $path) + { + return $host . ':' . $port . $path; + } + + /** + * Adds a service instance or service descriptor (if it is already + * not added) + * + * @param mixed $service + * + * @throws Exception If service descriptor is not valid + */ + public function addReadService($service) + { + if ($service instanceof Apache_Solr_Service) + { + $id = $this->_getServiceId($service->getHost(), $service->getPort(), $service->getPath()); + + $this->_readableServices[$id] = $service; + } + else if (is_array($service)) + { + if (isset($service['host']) && isset($service['port']) && isset($service['path'])) + { + $id = $this->_getServiceId((string)$service['host'], (int)$service['port'], (string)$service['path']); + + $this->_readableServices[$id] = $service; + } + else + { + throw new Exception('A Readable Service description array does not have all required elements of host, port, and path'); + } + } + } + + /** + * Removes a service instance or descriptor from the available services + * + * @param mixed $service + * + * @throws Exception If service descriptor is not valid + */ + public function removeReadService($service) + { + $id = ''; + + if ($service instanceof Apache_Solr_Service) + { + $id = $this->_getServiceId($service->getHost(), $service->getPort(), $service->getPath()); + } + else if (is_array($service)) + { + if (isset($service['host']) && isset($service['port']) && isset($service['path'])) + { + $id = $this->_getServiceId((string)$service['host'], (int)$service['port'], (string)$service['path']); + } + else + { + throw new Exception('A Readable Service description array does not have all required elements of host, port, and path'); + } + } + else if (is_string($service)) + { + $id = $service; + } + + if ($id && isset($this->_readableServices[$id])) + { + unset($this->_readableServices[$id]); + } + } + + /** + * Adds a service instance or service descriptor (if it is already + * not added) + * + * @param mixed $service + * + * @throws Exception If service descriptor is not valid + */ + public function addWriteService($service) + { + if ($service instanceof Apache_Solr_Service) + { + $id = $this->_getServiceId($service->getHost(), $service->getPort(), $service->getPath()); + + $this->_writeableServices[$id] = $service; + } + else if (is_array($service)) + { + if (isset($service['host']) && isset($service['port']) && isset($service['path'])) + { + $id = $this->_getServiceId((string)$service['host'], (int)$service['port'], (string)$service['path']); + + $this->_writeableServices[$id] = $service; + } + else + { + throw new Exception('A Writeable Service description array does not have all required elements of host, port, and path'); + } + } + } + + /** + * Removes a service instance or descriptor from the available services + * + * @param mixed $service + * + * @throws Exception If service descriptor is not valid + */ + public function removeWriteService($service) + { + $id = ''; + + if ($service instanceof Apache_Solr_Service) + { + $id = $this->_getServiceId($service->getHost(), $service->getPort(), $service->getPath()); + } + else if (is_array($service)) + { + if (isset($service['host']) && isset($service['port']) && isset($service['path'])) + { + $id = $this->_getServiceId((string)$service['host'], (int)$service['port'], (string)$service['path']); + } + else + { + throw new Exception('A Readable Service description array does not have all required elements of host, port, and path'); + } + } + else if (is_string($service)) + { + $id = $service; + } + + if ($id && isset($this->_writeableServices[$id])) + { + unset($this->_writeableServices[$id]); + } + } + + /** + * Iterate through available read services and select the first with a ping + * that satisfies configured timeout restrictions (or the default) + * + * @return Apache_Solr_Service + * + * @throws Exception If there are no read services that meet requirements + */ + protected function _selectReadService($forceSelect = false) + { + if (!$this->_currentReadService || !isset($this->_readableServices[$this->_currentReadService]) || $forceSelect) + { + if ($this->_currentReadService && isset($this->_readableServices[$this->_currentReadService]) && $forceSelect) + { + // we probably had a communication error, ping the current read service, remove it if it times out + if ($this->_readableServices[$this->_currentReadService]->ping($this->_readPingTimeout) === false) + { + $this->removeReadService($this->_currentReadService); + } + } + + if (count($this->_readableServices)) + { + // select one of the read services at random + $ids = array_keys($this->_readableServices); + + $id = $ids[rand(0, count($ids) - 1)]; + $service = $this->_readableServices[$id]; + + if (is_array($service)) + { + //convert the array definition to a client object + $service = new Apache_Solr_Service($service['host'], $service['port'], $service['path']); + $this->_readableServices[$id] = $service; + } + + $service->setCreateDocuments($this->_createDocuments); + $this->_currentReadService = $id; + } + else + { + throw new Exception('No read services were available'); + } + } + + return $this->_readableServices[$this->_currentReadService]; + } + + /** + * Iterate through available write services and select the first with a ping + * that satisfies configured timeout restrictions (or the default) + * + * @return Apache_Solr_Service + * + * @throws Exception If there are no write services that meet requirements + */ + protected function _selectWriteService($forceSelect = false) + { + if($this->_useBackoff) + { + return $this->_selectWriteServiceSafe($forceSelect); + } + + if (!$this->_currentWriteService || !isset($this->_writeableServices[$this->_currentWriteService]) || $forceSelect) + { + if ($this->_currentWriteService && isset($this->_writeableServices[$this->_currentWriteService]) && $forceSelect) + { + // we probably had a communication error, ping the current read service, remove it if it times out + if ($this->_writeableServices[$this->_currentWriteService]->ping($this->_writePingTimeout) === false) + { + $this->removeWriteService($this->_currentWriteService); + } + } + + if (count($this->_writeableServices)) + { + // select one of the read services at random + $ids = array_keys($this->_writeableServices); + + $id = $ids[rand(0, count($ids) - 1)]; + $service = $this->_writeableServices[$id]; + + if (is_array($service)) + { + //convert the array definition to a client object + $service = new Apache_Solr_Service($service['host'], $service['port'], $service['path']); + $this->_writeableServices[$id] = $service; + } + + $this->_currentWriteService = $id; + } + else + { + throw new Exception('No write services were available'); + } + } + + return $this->_writeableServices[$this->_currentWriteService]; + } + + /** + * Iterate through available write services and select the first with a ping + * that satisfies configured timeout restrictions (or the default). The + * timeout period will increase until a connection is made or the limit is + * reached. This will allow for increased reliability with heavily loaded + * server(s). + * + * @return Apache_Solr_Service + * + * @throws Exception If there are no write services that meet requirements + */ + + protected function _selectWriteServiceSafe($forceSelect = false) + { + if (!$this->_currentWriteService || !isset($this->_writeableServices[$this->_currentWriteService]) || $forceSelect) + { + if (count($this->_writeableServices)) + { + $backoff = $this->_defaultBackoff; + + do { + // select one of the read services at random + $ids = array_keys($this->_writeableServices); + + $id = $ids[rand(0, count($ids) - 1)]; + $service = $this->_writeableServices[$id]; + + if (is_array($service)) + { + //convert the array definition to a client object + $service = new Apache_Solr_Service($service['host'], $service['port'], $service['path']); + $this->_writeableServices[$id] = $service; + } + + $this->_currentWriteService = $id; + + $backoff *= $this->_backoffEscalation; + + if($backoff > $this->_backoffLimit) + { + throw new Exception('No write services were available. All timeouts exceeded.'); + } + + } while($this->_writeableServices[$this->_currentWriteService]->ping($backoff) === false); + } + else + { + throw new Exception('No write services were available'); + } + } + + return $this->_writeableServices[$this->_currentWriteService]; + } + + public function setCreateDocuments($createDocuments) + { + $this->_createDocuments = (bool) $createDocuments; + + if ($this->_currentReadService) + { + $service = $this->_selectReadService(); + $service->setCreateDocuments($createDocuments); + } + } + + public function getCreateDocuments() + { + return $this->_createDocuments; + } + + /** + * Raw Add Method. Takes a raw post body and sends it to the update service. Post body + * should be a complete and well formed "add" xml document. + * + * @param string $rawPost + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function add($rawPost) + { + $service = $this->_selectWriteService(); + + do + { + try + { + return $service->add($rawPost); + } + catch (Exception $e) + { + if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR + { + throw $e; + } + } + + $service = $this->_selectWriteService(true); + } while ($service); + + return false; + } + + /** + * Add a Solr Document to the index + * + * @param Apache_Solr_Document $document + * @param boolean $allowDups + * @param boolean $overwritePending + * @param boolean $overwriteCommitted + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function addDocument(Apache_Solr_Document $document, $allowDups = false, $overwritePending = true, $overwriteCommitted = true) + { + $service = $this->_selectWriteService(); + + do + { + try + { + return $service->addDocument($document, $allowDups, $overwritePending, $overwriteCommitted); + } + catch (Exception $e) + { + if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR + { + throw $e; + } + } + + $service = $this->_selectWriteService(true); + } while ($service); + + return false; + } + + /** + * Add an array of Solr Documents to the index all at once + * + * @param array $documents Should be an array of Apache_Solr_Document instances + * @param boolean $allowDups + * @param boolean $overwritePending + * @param boolean $overwriteCommitted + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function addDocuments($documents, $allowDups = false, $overwritePending = true, $overwriteCommitted = true) + { + $service = $this->_selectWriteService(); + + do + { + try + { + return $service->addDocuments($documents, $allowDups, $overwritePending, $overwriteCommitted); + } + catch (Exception $e) + { + if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR + { + throw $e; + } + } + + $service = $this->_selectWriteService(true); + } while ($service); + + return false; + } + + /** + * Send a commit command. Will be synchronous unless both wait parameters are set + * to false. + * + * @param boolean $waitFlush + * @param boolean $waitSearcher + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function commit($optimize = true, $waitFlush = true, $waitSearcher = true, $timeout = 3600) + { + $service = $this->_selectWriteService(); + + do + { + try + { + return $service->commit($optimize, $waitFlush, $waitSearcher, $timeout); + } + catch (Exception $e) + { + if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR + { + throw $e; + } + } + + $service = $this->_selectWriteService(true); + } while ($service); + + return false; + } + + /** + * Raw Delete Method. Takes a raw post body and sends it to the update service. Body should be + * a complete and well formed "delete" xml document + * + * @param string $rawPost + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function delete($rawPost) + { + $service = $this->_selectWriteService(); + + do + { + try + { + return $service->delete($rawPost); + } + catch (Exception $e) + { + if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR + { + throw $e; + } + } + + $service = $this->_selectWriteService(true); + } while ($service); + + return false; + } + + /** + * Create a delete document based on document ID + * + * @param string $id + * @param boolean $fromPending + * @param boolean $fromCommitted + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function deleteById($id, $fromPending = true, $fromCommitted = true) + { + $service = $this->_selectWriteService(); + + do + { + try + { + return $service->deleteById($id, $fromPending, $fromCommitted); + } + catch (Exception $e) + { + if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR + { + throw $e; + } + } + + $service = $this->_selectWriteService(true); + } while ($service); + + return false; + } + + /** + * Create a delete document based on a query and submit it + * + * @param string $rawQuery + * @param boolean $fromPending + * @param boolean $fromCommitted + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function deleteByQuery($rawQuery, $fromPending = true, $fromCommitted = true) + { + $service = $this->_selectWriteService(); + + do + { + try + { + return $service->deleteByQuery($rawQuery, $fromPending, $fromCommitted); + } + catch (Exception $e) + { + if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR + { + throw $e; + } + } + + $service = $this->_selectWriteService(true); + } while ($service); + + return false; + } + + /** + * Send an optimize command. Will be synchronous unless both wait parameters are set + * to false. + * + * @param boolean $waitFlush + * @param boolean $waitSearcher + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function optimize($waitFlush = true, $waitSearcher = true) + { + $service = $this->_selectWriteService(); + + do + { + try + { + return $service->optimize($waitFlush, $waitSearcher); + } + catch (Exception $e) + { + if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR + { + throw $e; + } + } + + $service = $this->_selectWriteService(true); + } while ($service); + + return false; + } + + /** + * Simple Search interface + * + * @param string $query The raw query string + * @param int $offset The starting offset for result documents + * @param int $limit The maximum number of result documents to return + * @param array $params key / value pairs for query parameters, use arrays for multivalued parameters + * @return Apache_Solr_Response + * + * @throws Exception If an error occurs during the service call + */ + public function search($query, $offset = 0, $limit = 10, $params = array()) + { + $service = $this->_selectReadService(); + + do + { + try + { + return $service->search($query, $offset, $limit, $params); + } + catch (Exception $e) + { + if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR + { + throw $e; + } + } + + $service = $this->_selectReadService(true); + } while ($service); + + return false; + } +} diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/test/functional/backend/filmActionsTest.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/test/functional/backend/filmActionsTest.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,19 @@ + + get('/film/index')-> + + with('request')->begin()-> + isParameter('module', 'film')-> + isParameter('action', 'index')-> + end()-> + + with('response')->begin()-> + isStatusCode(200)-> + checkElement('body', '!/This is a temporary page/')-> + end() +; diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/test/functional/backend/imageActionsTest.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/test/functional/backend/imageActionsTest.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,19 @@ + + get('/image/index')-> + + with('request')->begin()-> + isParameter('module', 'image')-> + isParameter('action', 'index')-> + end()-> + + with('response')->begin()-> + isStatusCode(200)-> + checkElement('body', '!/This is a temporary page/')-> + end() +; diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/test/functional/backend/segmentActionsTest.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/test/functional/backend/segmentActionsTest.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,19 @@ + + get('/segment/index')-> + + with('request')->begin()-> + isParameter('module', 'segment')-> + isParameter('action', 'index')-> + end()-> + + with('response')->begin()-> + isStatusCode(200)-> + checkElement('body', '!/This is a temporary page/')-> + end() +; diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/test/functional/backend/thd_segmentActionsTest.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/test/functional/backend/thd_segmentActionsTest.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,19 @@ + + get('/thd_segment/index')-> + + with('request')->begin()-> + isParameter('module', 'thd_segment')-> + isParameter('action', 'index')-> + end()-> + + with('response')->begin()-> + isStatusCode(200)-> + checkElement('body', '!/This is a temporary page/')-> + end() +; diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/test/functional/backend/videoActionsTest.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/test/functional/backend/videoActionsTest.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,19 @@ + + get('/video/index')-> + + with('request')->begin()-> + isParameter('module', 'video')-> + isParameter('action', 'index')-> + end()-> + + with('response')->begin()-> + isStatusCode(200)-> + checkElement('body', '!/This is a temporary page/')-> + end() +; diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/backend.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/web/backend.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,7 @@ +dispatch(); diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/backend_dev.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/web/backend_dev.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,13 @@ +dispatch(); diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/sfDoctrinePlugin/css/default.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/web/sfDoctrinePlugin/css/default.css Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,269 @@ +#sf_admin_container a +{ + color: #464646; + text-decoration: none; +} + +#sf_admin_container a:hover +{ + color: #000; + text-decoration: underline; +} + +#sf_admin_container h1 +{ + margin: 0; + padding: 0; + margin-bottom: 20px; +} + +#sf_admin_container th +{ + background-color: #e7eef6; + white-space: nowrap; +} + +#sf_admin_container td, #sf_admin_container th +{ + border: 0; + border-bottom: 1px solid #ddd; + border-top: 1px solid #ddd; + text-align: left; + vertical-align: top; +} + +#sf_admin_container tr +{ + background-color: #fff; + border-left: 1px solid #ddd; + border-right: 1px solid #ddd; +} + +#sf_admin_container ul.error_list +{ + margin: 0; + margin-bottom: 7px; + color: #d33; + border: none; + background-color: #f33; +} + +#sf_admin_container ul.error_list li +{ + padding: 4px; + padding-left: 25px; + list-style: none; + color: #fff; + background: url(../images/error.png) no-repeat 4px 4px; +} + +#sf_admin_container tr:hover +{ + background-color: #ffe; +} + +#sf_admin_container input, #sf_admin_container textarea +{ + width: auto; +} + +#sf_admin_container .radio_list, #sf_admin_container .checkbox_list +{ + margin: 0; +} + +#sf_admin_container .radio_list li, #sf_admin_container .checkbox_list li +{ + list-style: none; + display: inline; +} + +#sf_admin_container .double_list_select, #sf_admin_container .double_list_select-selected +{ + width: 12em; +} + +#sf_admin_container .double_list_label +{ + font-weight: bold; +} + +#sf_admin_container tfoot td +{ + margin: 0; + list-style: none; + text-align: right; +} + +#sf_admin_container thead img, #sf_admin_container tfoot img +{ + vertical-align: middle; +} + +#sf_admin_bar +{ + float: right; + margin-left: 20px; +} + +.sf_admin_pagination +{ + float: right; +} + +#sf_admin_container ul.sf_admin_td_actions +{ + margin: 0; + padding: 0; + list-style-type: none; +} + +#sf_admin_container ul.sf_admin_td_actions li +{ + list-style-type: none; + display: inline; + margin-right: 10px; + font-size: 90%; +} + +#sf_admin_container ul.sf_admin_actions +{ + margin: 10px 0; + list-style-type: none; +} + +#sf_admin_container ul.sf_admin_actions li +{ + list-style-type: none; + display: inline; + margin-right: 10px; +} + +#sf_admin_container ul li a +{ + padding-left: 20px; + background: url(../images/default.png) no-repeat 0 0; +} + +#sf_admin_container ul li.sf_admin_action_new a +{ + background: url(../images/new.png) no-repeat 0 0; +} + +#sf_admin_container ul li.sf_admin_action_delete a +{ + background: url(../images/delete.png) no-repeat 0 0; +} + +#sf_admin_container ul li.sf_admin_action_list a +{ + background: url(../images/list.png) no-repeat 0 0; +} + +#sf_admin_container ul li.sf_admin_action_edit a +{ + background: url(../images/edit.png) no-repeat 0 0; +} + +#sf_admin_container .notice +{ + margin: 4px 0; + padding: 4px 4px 4px 30px; + background: url(../images/tick.png) no-repeat 10px 4px; + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + background-color: #ffc; +} + +#sf_admin_container .error +{ + margin: 4px 0; + padding: 4px 4px 4px 30px; + background: url(../images/error.png) no-repeat 10px 4px; + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + background-color: #f33; + color: #fff; +} + +#sf_admin_container .sf_admin_row_0 td +{ +} + +#sf_admin_container .sf_admin_row_1 td +{ +/* background-color: #eee;*/ +} + +#sf_admin_container fieldset h2 +{ + padding: 3px; + color: #333; + background-color: #ccf; + font-size: 11px; +} + +#sf_admin_container fieldset +{ + margin-bottom: 3px; + border: 1px solid #ddd; + border-bottom: 0px; + background-color: #fff; +} + +#sf_admin_container fieldset.collapsed * { display:none; } +#sf_admin_container fieldset.collapsed h2, #sf_admin_container fieldset.collapsed { display:block !important; } +#sf_admin_container fieldset.collapsed .collapse-toggle { display: inline !important; } +#sf_admin_container fieldset.collapse h2 a.collapse-toggle { color:#ffc; } +#sf_admin_container fieldset.collapse h2 a.collapse-toggle:hover { text-decoration:underline; } + +#sf_admin_container label +{ + display: block; + padding: 0 1em 3px 0; + float: left; + text-align: left; + width: 8em; + color: #666; + font-weight: normal !important; +} + +#sf_admin_container ul label, #sf_admin_container td label +{ + display: inline; + float: none !important; +} + +#sf_admin_container .sf_admin_form_row +{ + clear: both; + padding: 10px; + border-bottom: 1px solid #ddd; +} + +#sf_admin_container .sf_admin_form_row .content +{ + padding-left: 9em; +} + +#sf_admin_container .help +{ + padding-left: 9em; + color: #aaa; +} + +#sf_admin_container td .help +{ + padding-left: 0; +} + +#sf_admin_container .errors input, #sf_admin_container .errors select +{ + border: 1px solid #f22; +} + +#sf_admin_container .sf_admin_list .sf_admin_boolean +{ + text-align: center; +} + diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/sfDoctrinePlugin/css/global.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/web/sfDoctrinePlugin/css/global.css Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,34 @@ +/* http://yui.yahooapis.com/2.6.0/build/reset/reset-min.css +Copyright (c) 2008, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.6.0 +*/ +html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:text-top;}sub{vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}input,textarea,select{*font-size:100%;}legend{color:#000;}del,ins{text-decoration:none;} + +/* http://yui.yahooapis.com/2.6.0/build/fonts/fonts-min.css +Copyright (c) 2008, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.6.0 +*/ +body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}select,input,button,textarea{font:99% arial,helvetica,clean,sans-serif;}table{font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;} + +/* http://yui.yahooapis.com/2.6.0/build/base/base-min.css +Copyright (c) 2008, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.6.0 +*/ +h1{font-size:138.5%;}h2{font-size:123.1%;}h3{font-size:108%;}h1,h2,h3{margin:1em 0;}h1,h2,h3,h4,h5,h6,strong{font-weight:bold;}abbr,acronym{border-bottom:1px dotted #000;cursor:help;} em{font-style:italic;}blockquote,ul,ol,dl{margin:1em;}ol,ul,dl{margin-left:2em;}ol li{list-style:decimal outside;}ul li{list-style:disc outside;}dl dd{margin-left:1em;}th,td{border:1px solid #000;padding:.5em;}th{font-weight:bold;text-align:center;}caption{margin-bottom:.5em;text-align:center;}p,fieldset,table,pre{margin-bottom:1em;}input[type=text],input[type=password],textarea{width:12.25em;*width:11.9em;} + +html +{ + background-color: #eee; +} + +body +{ + padding: 30px; + text-align: left; +} diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/sfDoctrinePlugin/images/asc.png Binary file web/thdProject/web/sfDoctrinePlugin/images/asc.png has changed diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/sfDoctrinePlugin/images/default.png Binary file web/thdProject/web/sfDoctrinePlugin/images/default.png has changed diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/sfDoctrinePlugin/images/delete.png Binary file web/thdProject/web/sfDoctrinePlugin/images/delete.png has changed diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/sfDoctrinePlugin/images/desc.png Binary file web/thdProject/web/sfDoctrinePlugin/images/desc.png has changed diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/sfDoctrinePlugin/images/edit.png Binary file web/thdProject/web/sfDoctrinePlugin/images/edit.png has changed diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/sfDoctrinePlugin/images/error.png Binary file web/thdProject/web/sfDoctrinePlugin/images/error.png has changed diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/sfDoctrinePlugin/images/first.png Binary file web/thdProject/web/sfDoctrinePlugin/images/first.png has changed diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/sfDoctrinePlugin/images/last.png Binary file web/thdProject/web/sfDoctrinePlugin/images/last.png has changed diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/sfDoctrinePlugin/images/list.png Binary file web/thdProject/web/sfDoctrinePlugin/images/list.png has changed diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/sfDoctrinePlugin/images/new.png Binary file web/thdProject/web/sfDoctrinePlugin/images/new.png has changed diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/sfDoctrinePlugin/images/next.png Binary file web/thdProject/web/sfDoctrinePlugin/images/next.png has changed diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/sfDoctrinePlugin/images/previous.png Binary file web/thdProject/web/sfDoctrinePlugin/images/previous.png has changed diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/sfDoctrinePlugin/images/tick.png Binary file web/thdProject/web/sfDoctrinePlugin/images/tick.png has changed diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/uploads/.keepme diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/uploads/tags.csv diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/uuid.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/thdProject/web/uuid.php Wed Mar 10 17:19:00 2010 +0100 @@ -0,0 +1,6 @@ +v1(); + +?> diff -r cba6648bf1fe -r 8f7f62845562 web/thdProject/web/videos/.keepme