--- 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
+
Binary file engine/solr/apache-solr-1.4.0.war has changed
--- /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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Context docBase="<path_to_mosatags>/engine/solr/apache-solr-1.3.0.war" debug="0" crossContext="true">
+ <Environment name="solr/home" type="java.lang.String" value="<path_to_mosatags>/engine/solr" override="true"/>
+</Context>
--- /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 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!--
+ This is the Solr schema file. This file should be named "schema.xml" and
+ should be in the conf directory under the solr home
+ (i.e. ./solr/conf/schema.xml by default)
+ or located where the classloader for the Solr webapp can find it.
+
+ This example schema is the recommended starting point for users.
+ It should be kept correct and concise, usable out-of-the-box.
+
+ For more information, on how to customize this file, please see
+ http://wiki.apache.org/solr/SchemaXml
+-->
+
+<schema name="mosatags" version="1.1">
+
+ <types>
+
+ <fieldType name="type" class="solr.StrField" sortMissingLast="true" omitNorms="true" />
+ <fieldType name="id" class="solr.IntField" omitNorms="true" />
+ <fieldType name="uniqueId" class="solr.StrField" sortMissingLast="true" omitNorms="true" />
+ <fieldType name="title" class="solr.TextField" sortMissingLast="true" omitNorms="true" >
+ <analyzer>
+ <tokenizer class="solr.WhitespaceTokenizerFactory"/>
+ <filter class="solr.LowerCaseFilterFactory"/>
+ </analyzer>
+ </fieldType>
+ <fieldType name="textdata" class="solr.TextField" sortMissingLast="true" omitNorms="true" >
+ <analyzer>
+ <tokenizer class="solr.WhitespaceTokenizerFactory"/>
+ <filter class="solr.SnowballPorterFilterFactory" language="French" />
+ </analyzer>
+ </fieldType>
+ <fieldType name="tags" class="solr.TextField" sortMissingLast="true" omitNorms="true" >
+ <analyzer>
+ <tokenizer class="solr.PatternTokenizerFactory" pattern="; *" />
+ <filter class="solr.LowerCaseFilterFactory"/>
+ <filter class="solr.TrimFilterFactory" />
+ <filter class="solr.SnowballPorterFilterFactory" language="French" />
+ </analyzer>
+ </fieldType>
+ <fieldType name="personsList" class="solr.TextField" sortMissingLast="true" omitNorms="true" >
+ <analyzer>
+ <tokenizer class="solr.PatternTokenizerFactory" pattern="; *" />
+ <filter class="solr.LowerCaseFilterFactory"/>
+ <filter class="solr.TrimFilterFactory" />
+ </analyzer>
+ </fieldType>
+
+ </types>
+
+
+ <fields>
+ <!-- Valid attributes for fields:
+ name: mandatory - the name for the field
+ type: mandatory - the name of a previously defined type from the <types> section
+ indexed: true if this field should be indexed (searchable or sortable)
+ stored: true if this field should be retrievable
+ compressed: [false] if this field should be stored using gzip compression
+ (this will only apply if the field type is compressable; among
+ the standard field types, only TextField and StrField are)
+ multiValued: true if this field may contain multiple values per document
+ omitNorms: (expert) set to true to omit the norms associated with
+ this field (this disables length normalization and index-time
+ boosting for the field, and saves some memory). Only full-text
+ fields or fields that need an index-time boost need norms.
+ termVectors: [false] set to true to store the term vector for a given field.
+ When using MoreLikeThis, fields used for similarity should be stored for
+ best performance.
+ -->
+
+ <field name="type" type="type" indexed="true" stored="true" required="true" />
+ <field name="id" type="id" indexed="no" stored="true" required="true" />
+ <field name="uniqueid" type="uniqueId" indexed="true" stored="true" required="true" />
+ <field name="title" type="title" indexed="true" stored="false" required="false" />
+ <field name="original_title" type="title" indexed="true" stored="false" required="false" />
+ <field name="desc" type="textdata" indexed="true" stored="false" required="false" />
+ <field name="tags" type="tags" indexed="true" stored="false" required="false" />
+ <field name="directors" type="personsList" indexed="true" stored="false" required="false" />
+ <field name="actors" type="personsList" indexed="true" stored="false" required="false" />
+ <field name="all" type="textdata" indexed="true" stored="false" required="false" multiValued="true" />
+
+ </fields>
+
+ <!-- Field to use to determine and enforce document uniqueness.
+ Unless this field is marked with required="false", it will be a required field
+ -->
+ <uniqueKey>uniqueid</uniqueKey>
+
+ <!-- field for the QueryParser to use when an explicit fieldname is absent -->
+ <defaultSearchField>all</defaultSearchField>
+
+ <!-- SolrQueryParser configuration: defaultOperator="AND|OR" -->
+ <solrQueryParser defaultOperator="OR"/>
+
+ <copyField source="title" dest="all"/>
+ <copyField source="desc" dest="all"/>
+ <copyField source="tags" dest="all"/>
+ <copyField source="directors" dest="all"/>
+ <copyField source="actors" dest="all"/>
+
+</schema>
--- /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 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<config>
+ <!-- Set this to 'false' if you want solr to continue working after it has
+ encountered an severe configuration error. In a production environment,
+ you may want solr to keep working even if one handler is mis-configured.
+
+ You may also set this to false using by setting the system property:
+ -Dsolr.abortOnConfigurationError=false
+ -->
+ <abortOnConfigurationError>${solr.abortOnConfigurationError:true}</abortOnConfigurationError>
+
+ <!-- Used to specify an alternate directory to hold all index data
+ other than the default ./data under the Solr home.
+ If replication is in use, this should match the replication configuration. -->
+ <dataDir>${solr.data.dir:/Users/ymh/dev/workspace/mosatags/engine/solr/solr/data}</dataDir>
+
+ <indexDefaults>
+ <!-- Values here affect all index writers and act as a default unless overridden. -->
+ <useCompoundFile>false</useCompoundFile>
+
+ <mergeFactor>10</mergeFactor>
+ <!--
+ If both ramBufferSizeMB and maxBufferedDocs is set, then Lucene will flush based on whichever limit is hit first.
+
+ -->
+ <!--<maxBufferedDocs>1000</maxBufferedDocs>-->
+ <!-- Tell Lucene when to flush documents to disk.
+ Giving Lucene more memory for indexing means faster indexing at the cost of more RAM
+
+ If both ramBufferSizeMB and maxBufferedDocs is set, then Lucene will flush based on whichever limit is hit first.
+
+ -->
+ <ramBufferSizeMB>32</ramBufferSizeMB>
+ <maxMergeDocs>2147483647</maxMergeDocs>
+ <maxFieldLength>10000</maxFieldLength>
+ <writeLockTimeout>1000</writeLockTimeout>
+ <commitLockTimeout>10000</commitLockTimeout>
+
+ <!--
+ Expert: Turn on Lucene's auto commit capability.
+ This causes intermediate segment flushes to write a new lucene
+ index descriptor, enabling it to be opened by an external
+ IndexReader.
+ NOTE: Despite the name, this value does not have any relation to Solr's autoCommit functionality
+ -->
+ <!--<luceneAutoCommit>false</luceneAutoCommit>-->
+ <!--
+ Expert:
+ The Merge Policy in Lucene controls how merging is handled by Lucene. The default in 2.3 is the LogByteSizeMergePolicy, previous
+ versions used LogDocMergePolicy.
+
+ LogByteSizeMergePolicy chooses segments to merge based on their size. The Lucene 2.2 default, LogDocMergePolicy chose when
+ to merge based on number of documents
+
+ Other implementations of MergePolicy must have a no-argument constructor
+ -->
+ <!--<mergePolicy>org.apache.lucene.index.LogByteSizeMergePolicy</mergePolicy>-->
+
+ <!--
+ Expert:
+ The Merge Scheduler in Lucene controls how merges are performed. The ConcurrentMergeScheduler (Lucene 2.3 default)
+ can perform merges in the background using separate threads. The SerialMergeScheduler (Lucene 2.2 default) does not.
+ -->
+ <!--<mergeScheduler>org.apache.lucene.index.ConcurrentMergeScheduler</mergeScheduler>-->
+
+ <!--
+ This option specifies which Lucene LockFactory implementation to use.
+
+ single = SingleInstanceLockFactory - suggested for a read-only index
+ or when there is no possibility of another process trying
+ to modify the index.
+ native = NativeFSLockFactory
+ simple = SimpleFSLockFactory
+
+ (For backwards compatibility with Solr 1.2, 'simple' is the default
+ if not specified.)
+ -->
+ <lockType>single</lockType>
+ </indexDefaults>
+
+ <mainIndex>
+ <!-- options specific to the main on-disk lucene index -->
+ <useCompoundFile>false</useCompoundFile>
+ <ramBufferSizeMB>32</ramBufferSizeMB>
+ <mergeFactor>10</mergeFactor>
+ <!-- Deprecated -->
+ <!--<maxBufferedDocs>1000</maxBufferedDocs>-->
+ <maxMergeDocs>2147483647</maxMergeDocs>
+ <maxFieldLength>10000</maxFieldLength>
+
+ <!-- If true, unlock any held write or commit locks on startup.
+ This defeats the locking mechanism that allows multiple
+ processes to safely access a lucene index, and should be
+ used with care.
+ This is not needed if lock type is 'none' or 'single'
+ -->
+ <unlockOnStartup>false</unlockOnStartup>
+ </mainIndex>
+
+ <!-- Enables JMX if and only if an existing MBeanServer is found, use
+ this if you want to configure JMX through JVM parameters. Remove
+ this to disable exposing Solr configuration and statistics to JMX.
+
+ If you want to connect to a particular server, specify the agentId
+ e.g. <jmx agentId="myAgent" />
+
+ If you want to start a new MBeanServer, specify the serviceUrl
+ e.g <jmx serviceurl="service:jmx:rmi:///jndi/rmi://localhost:9999/solr" />
+
+ For more details see http://wiki.apache.org/solr/SolrJmx
+ -->
+ <jmx />
+
+ <!-- the default high-performance update handler -->
+ <updateHandler class="solr.DirectUpdateHandler2">
+
+ <!-- A prefix of "solr." for class names is an alias that
+ causes solr to search appropriate packages, including
+ org.apache.solr.(search|update|request|core|analysis)
+ -->
+
+ <!-- Perform a <commit/> automatically under certain conditions:
+ maxDocs - number of updates since last commit is greater than this
+ maxTime - oldest uncommited update (in ms) is this long ago
+ <autoCommit>
+ <maxDocs>10000</maxDocs>
+ <maxTime>1000</maxTime>
+ </autoCommit>
+ -->
+
+ <!-- The RunExecutableListener executes an external command.
+ exe - the name of the executable to run
+ dir - dir to use as the current working directory. default="."
+ wait - the calling thread waits until the executable returns. default="true"
+ args - the arguments to pass to the program. default=nothing
+ env - environment variables to set. default=nothing
+ -->
+ <!-- A postCommit event is fired after every commit or optimize command
+ <listener event="postCommit" class="solr.RunExecutableListener">
+ <str name="exe">solr/bin/snapshooter</str>
+ <str name="dir">.</str>
+ <bool name="wait">true</bool>
+ <arr name="args"> <str>arg1</str> <str>arg2</str> </arr>
+ <arr name="env"> <str>MYVAR=val1</str> </arr>
+ </listener>
+ -->
+ <!-- A postOptimize event is fired only after every optimize command, useful
+ in conjunction with index distribution to only distribute optimized indicies
+ <listener event="postOptimize" class="solr.RunExecutableListener">
+ <str name="exe">snapshooter</str>
+ <str name="dir">solr/bin</str>
+ <bool name="wait">true</bool>
+ </listener>
+ -->
+
+ </updateHandler>
+
+
+ <query>
+ <!-- Maximum number of clauses in a boolean query... can affect
+ range or prefix queries that expand to big boolean
+ queries. An exception is thrown if exceeded. -->
+ <maxBooleanClauses>1024</maxBooleanClauses>
+
+
+ <!-- Cache used by SolrIndexSearcher for filters (DocSets),
+ unordered sets of *all* documents that match a query.
+ When a new searcher is opened, its caches may be prepopulated
+ or "autowarmed" using data from caches in the old searcher.
+ autowarmCount is the number of items to prepopulate. For LRUCache,
+ the autowarmed items will be the most recently accessed items.
+ Parameters:
+ class - the SolrCache implementation (currently only LRUCache)
+ size - the maximum number of entries in the cache
+ initialSize - the initial capacity (number of entries) of
+ the cache. (seel java.util.HashMap)
+ autowarmCount - the number of entries to prepopulate from
+ and old cache.
+ -->
+ <filterCache
+ class="solr.LRUCache"
+ size="512"
+ initialSize="512"
+ autowarmCount="128"/>
+
+ <!-- queryResultCache caches results of searches - ordered lists of
+ document ids (DocList) based on a query, a sort, and the range
+ of documents requested. -->
+ <queryResultCache
+ class="solr.LRUCache"
+ size="512"
+ initialSize="512"
+ autowarmCount="32"/>
+
+ <!-- documentCache caches Lucene Document objects (the stored fields for each document).
+ Since Lucene internal document ids are transient, this cache will not be autowarmed. -->
+ <documentCache
+ class="solr.LRUCache"
+ size="512"
+ initialSize="512"
+ autowarmCount="0"/>
+
+ <!-- If true, stored fields that are not requested will be loaded lazily.
+
+ This can result in a significant speed improvement if the usual case is to
+ not load all stored fields, especially if the skipped fields are large compressed
+ text fields.
+ -->
+ <enableLazyFieldLoading>true</enableLazyFieldLoading>
+
+ <!-- Example of a generic cache. These caches may be accessed by name
+ through SolrIndexSearcher.getCache(),cacheLookup(), and cacheInsert().
+ The purpose is to enable easy caching of user/application level data.
+ The regenerator argument should be specified as an implementation
+ of solr.search.CacheRegenerator if autowarming is desired. -->
+ <!--
+ <cache name="myUserCache"
+ class="solr.LRUCache"
+ size="4096"
+ initialSize="1024"
+ autowarmCount="1024"
+ regenerator="org.mycompany.mypackage.MyRegenerator"
+ />
+ -->
+
+ <!-- An optimization that attempts to use a filter to satisfy a search.
+ If the requested sort does not include score, then the filterCache
+ will be checked for a filter matching the query. If found, the filter
+ will be used as the source of document ids, and then the sort will be
+ applied to that.
+ <useFilterForSortedQuery>true</useFilterForSortedQuery>
+ -->
+
+ <!-- An optimization for use with the queryResultCache. When a search
+ is requested, a superset of the requested number of document ids
+ are collected. For example, if a search for a particular query
+ requests matching documents 10 through 19, and queryWindowSize is 50,
+ then documents 0 through 49 will be collected and cached. Any further
+ requests in that range can be satisfied via the cache. -->
+ <queryResultWindowSize>50</queryResultWindowSize>
+
+ <!-- Maximum number of documents to cache for any entry in the
+ queryResultCache. -->
+ <queryResultMaxDocsCached>200</queryResultMaxDocsCached>
+
+ <!-- This entry enables an int hash representation for filters (DocSets)
+ when the number of items in the set is less than maxSize. For smaller
+ sets, this representation is more memory efficient, more efficient to
+ iterate over, and faster to take intersections. -->
+ <HashDocSet maxSize="3000" loadFactor="0.75"/>
+
+ <!-- a newSearcher event is fired whenever a new searcher is being prepared
+ and there is a current searcher handling requests (aka registered). -->
+ <!-- QuerySenderListener takes an array of NamedList and executes a
+ local query request for each NamedList in sequence. -->
+ <listener event="newSearcher" class="solr.QuerySenderListener">
+ <arr name="queries">
+ <lst> <str name="q">solr</str> <str name="start">0</str> <str name="rows">10</str> </lst>
+ <lst> <str name="q">rocks</str> <str name="start">0</str> <str name="rows">10</str> </lst>
+ <lst><str name="q">static newSearcher warming query from solrconfig.xml</str></lst>
+ </arr>
+ </listener>
+
+ <!-- a firstSearcher event is fired whenever a new searcher is being
+ prepared but there is no current registered searcher to handle
+ requests or to gain autowarming data from. -->
+ <listener event="firstSearcher" class="solr.QuerySenderListener">
+ <arr name="queries">
+ <lst> <str name="q">fast_warm</str> <str name="start">0</str> <str name="rows">10</str> </lst>
+ <lst><str name="q">static firstSearcher warming query from solrconfig.xml</str></lst>
+ </arr>
+ </listener>
+
+ <!-- If a search request comes in and there is no current registered searcher,
+ then immediately register the still warming searcher and use it. If
+ "false" then all requests will block until the first searcher is done
+ warming. -->
+ <useColdSearcher>false</useColdSearcher>
+
+ <!-- Maximum number of searchers that may be warming in the background
+ concurrently. An error is returned if this limit is exceeded. Recommend
+ 1-2 for read-only slaves, higher for masters w/o cache warming. -->
+ <maxWarmingSearchers>2</maxWarmingSearchers>
+
+ </query>
+
+ <!--
+ Let the dispatch filter handler /select?qt=XXX
+ handleSelect=true will use consistent error handling for /select and /update
+ handleSelect=false will use solr1.1 style error formatting
+ -->
+ <requestDispatcher handleSelect="true" >
+ <!--Make sure your system has some authentication before enabling remote streaming! -->
+ <requestParsers enableRemoteStreaming="false" multipartUploadLimitInKB="2048" />
+
+ <!-- Set HTTP caching related parameters (for proxy caches and clients).
+
+ To get the behaviour of Solr 1.2 (ie: no caching related headers)
+ use the never304="true" option and do not specify a value for
+ <cacheControl>
+ -->
+ <!-- <httpCaching never304="true"> -->
+ <httpCaching lastModifiedFrom="openTime"
+ etagSeed="Solr">
+ <!-- lastModFrom="openTime" is the default, the Last-Modified value
+ (and validation against If-Modified-Since requests) will all be
+ relative to when the current Searcher was opened.
+ You can change it to lastModFrom="dirLastMod" if you want the
+ value to exactly corrispond to when the physical index was last
+ modified.
+
+ etagSeed="..." is an option you can change to force the ETag
+ header (and validation against If-None-Match requests) to be
+ differnet even if the index has not changed (ie: when making
+ significant changes to your config file)
+
+ lastModifiedFrom and etagSeed are both ignored if you use the
+ never304="true" option.
+ -->
+ <!-- If you include a <cacheControl> directive, it will be used to
+ generate a Cache-Control header, as well as an Expires header
+ if the value contains "max-age="
+
+ By default, no Cache-Control header is generated.
+
+ You can use the <cacheControl> option even if you have set
+ never304="true"
+ -->
+ <!-- <cacheControl>max-age=30, public</cacheControl> -->
+ </httpCaching>
+ </requestDispatcher>
+
+
+ <!-- requestHandler plugins... incoming queries will be dispatched to the
+ correct handler based on the path or the qt (query type) param.
+ Names starting with a '/' are accessed with the a path equal to the
+ registered name. Names without a leading '/' are accessed with:
+ http://host/app/select?qt=name
+ If no qt is defined, the requestHandler that declares default="true"
+ will be used.
+ -->
+ <requestHandler name="standard" class="solr.SearchHandler" default="true">
+ <!-- default values for query parameters -->
+ <lst name="defaults">
+ <str name="echoParams">explicit</str>
+ <!--
+ <int name="rows">10</int>
+ <str name="fl">*</str>
+ <str name="version">2.1</str>
+ -->
+ </lst>
+ </requestHandler>
+
+
+ <!-- DisMaxRequestHandler allows easy searching across multiple fields
+ for simple user-entered phrases. It's implementation is now
+ just the standard SearchHandler with a default query type
+ of "dismax".
+ see http://wiki.apache.org/solr/DisMaxRequestHandler
+ -->
+ <requestHandler name="dismax" class="solr.SearchHandler" >
+ <lst name="defaults">
+ <str name="defType">dismax</str>
+ <str name="echoParams">explicit</str>
+ <float name="tie">0.01</float>
+ <str name="qf">
+ text^0.5 features^1.0 name^1.2 sku^1.5 id^10.0 manu^1.1 cat^1.4
+ </str>
+ <str name="pf">
+ text^0.2 features^1.1 name^1.5 manu^1.4 manu_exact^1.9
+ </str>
+ <str name="bf">
+ ord(popularity)^0.5 recip(rord(price),1,1000,1000)^0.3
+ </str>
+ <str name="fl">
+ id,name,price,score
+ </str>
+ <str name="mm">
+ 2<-1 5<-2 6<90%
+ </str>
+ <int name="ps">100</int>
+ <str name="q.alt">*:*</str>
+ <!-- example highlighter config, enable per-query with hl=true -->
+ <str name="hl.fl">text features name</str>
+ <!-- for this field, we want no fragmenting, just highlighting -->
+ <str name="f.name.hl.fragsize">0</str>
+ <!-- instructs Solr to return the field itself if no query terms are
+ found -->
+ <str name="f.name.hl.alternateField">name</str>
+ <str name="f.text.hl.fragmenter">regex</str> <!-- defined below -->
+ </lst>
+ </requestHandler>
+
+ <!-- Note how you can register the same handler multiple times with
+ different names (and different init parameters)
+ -->
+ <requestHandler name="partitioned" class="solr.SearchHandler" >
+ <lst name="defaults">
+ <str name="defType">dismax</str>
+ <str name="echoParams">explicit</str>
+ <str name="qf">text^0.5 features^1.0 name^1.2 sku^1.5 id^10.0</str>
+ <str name="mm">2<-1 5<-2 6<90%</str>
+ <!-- This is an example of using Date Math to specify a constantly
+ moving date range in a config...
+ -->
+ <str name="bq">incubationdate_dt:[* TO NOW/DAY-1MONTH]^2.2</str>
+ </lst>
+ <!-- In addition to defaults, "appends" params can be specified
+ to identify values which should be appended to the list of
+ multi-val params from the query (or the existing "defaults").
+
+ In this example, the param "fq=instock:true" will be appended to
+ any query time fq params the user may specify, as a mechanism for
+ partitioning the index, independent of any user selected filtering
+ that may also be desired (perhaps as a result of faceted searching).
+
+ NOTE: there is *absolutely* nothing a client can do to prevent these
+ "appends" values from being used, so don't use this mechanism
+ unless you are sure you always want it.
+ -->
+ <lst name="appends">
+ <str name="fq">inStock:true</str>
+ </lst>
+ <!-- "invariants" are a way of letting the Solr maintainer lock down
+ the options available to Solr clients. Any params values
+ specified here are used regardless of what values may be specified
+ in either the query, the "defaults", or the "appends" params.
+
+ In this example, the facet.field and facet.query params are fixed,
+ limiting the facets clients can use. Faceting is not turned on by
+ default - but if the client does specify facet=true in the request,
+ these are the only facets they will be able to see counts for;
+ regardless of what other facet.field or facet.query params they
+ may specify.
+
+ NOTE: there is *absolutely* nothing a client can do to prevent these
+ "invariants" values from being used, so don't use this mechanism
+ unless you are sure you always want it.
+ -->
+ <lst name="invariants">
+ <str name="facet.field">cat</str>
+ <str name="facet.field">manu_exact</str>
+ <str name="facet.query">price:[* TO 500]</str>
+ <str name="facet.query">price:[500 TO *]</str>
+ </lst>
+ </requestHandler>
+
+
+ <!--
+ Search components are registered to SolrCore and used by Search Handlers
+
+ By default, the following components are avaliable:
+
+ <searchComponent name="query" class="org.apache.solr.handler.component.QueryComponent" />
+ <searchComponent name="facet" class="org.apache.solr.handler.component.FacetComponent" />
+ <searchComponent name="mlt" class="org.apache.solr.handler.component.MoreLikeThisComponent" />
+ <searchComponent name="highlight" class="org.apache.solr.handler.component.HighlightComponent" />
+ <searchComponent name="debug" class="org.apache.solr.handler.component.DebugComponent" />
+
+ Default configuration in a requestHandler would look like:
+ <arr name="components">
+ <str>query</str>
+ <str>facet</str>
+ <str>mlt</str>
+ <str>highlight</str>
+ <str>debug</str>
+ </arr>
+
+ If you register a searchComponent to one of the standard names, that will be used instead.
+ To insert handlers before or after the 'standard' components, use:
+
+ <arr name="first-components">
+ <str>myFirstComponentName</str>
+ </arr>
+
+ <arr name="last-components">
+ <str>myLastComponentName</str>
+ </arr>
+ -->
+
+ <!-- The spell check component can return a list of alternative spelling
+ suggestions. -->
+ <searchComponent name="spellcheck" class="solr.SpellCheckComponent">
+
+ <str name="queryAnalyzerFieldType">textSpell</str>
+
+ <lst name="spellchecker">
+ <str name="name">default</str>
+ <str name="field">spell</str>
+ <str name="spellcheckIndexDir">./spellchecker1</str>
+
+ </lst>
+ <lst name="spellchecker">
+ <str name="name">jarowinkler</str>
+ <str name="field">spell</str>
+ <!-- Use a different Distance Measure -->
+ <str name="distanceMeasure">org.apache.lucene.search.spell.JaroWinklerDistance</str>
+ <str name="spellcheckIndexDir">./spellchecker2</str>
+
+ </lst>
+
+ <lst name="spellchecker">
+ <str name="classname">solr.FileBasedSpellChecker</str>
+ <str name="name">file</str>
+ <str name="sourceLocation">spellings.txt</str>
+ <str name="characterEncoding">UTF-8</str>
+ <str name="spellcheckIndexDir">./spellcheckerFile</str>
+ </lst>
+ </searchComponent>
+
+ <!-- a request handler utilizing the spellcheck component -->
+ <requestHandler name="/spellCheckCompRH" class="solr.SearchHandler">
+ <lst name="defaults">
+ <!-- omp = Only More Popular -->
+ <str name="spellcheck.onlyMorePopular">false</str>
+ <!-- exr = Extended Results -->
+ <str name="spellcheck.extendedResults">false</str>
+ <!-- The number of suggestions to return -->
+ <str name="spellcheck.count">1</str>
+ </lst>
+ <arr name="last-components">
+ <str>spellcheck</str>
+ </arr>
+ </requestHandler>
+
+ <!-- a search component that enables you to configure the top results for
+ a given query regardless of the normal lucene scoring.-->
+ <!--searchComponent name="elevator" class="solr.QueryElevationComponent" -->
+ <!-- pick a fieldType to analyze queries -->
+ <!--str name="queryFieldType">string</str>
+ <str name="config-file">elevate.xml</str>
+ </searchComponent-->
+
+ <!-- a request handler utilizing the elevator component -->
+ <!--requestHandler name="/elevate" class="solr.SearchHandler" startup="lazy">
+ <lst name="defaults">
+ <str name="echoParams">explicit</str>
+ </lst>
+ <arr name="last-components">
+ <str>elevator</str>
+ </arr>
+ </requestHandler-->
+
+
+ <!-- Update request handler.
+
+ Note: Since solr1.1 requestHandlers requires a valid content type header if posted in
+ the body. For example, curl now requires: -H 'Content-type:text/xml; charset=utf-8'
+ The response format differs from solr1.1 formatting and returns a standard error code.
+
+ To enable solr1.1 behavior, remove the /update handler or change its path
+ -->
+ <requestHandler name="/update" class="solr.XmlUpdateRequestHandler" />
+
+ <!--
+ Analysis request handler. Since Solr 1.3. Use to returnhow a document is analyzed. Useful
+ for debugging and as a token server for other types of applications
+ -->
+ <requestHandler name="/analysis" class="solr.AnalysisRequestHandler" />
+
+
+ <!-- CSV update handler, loaded on demand -->
+ <requestHandler name="/update/csv" class="solr.CSVRequestHandler" startup="lazy" />
+
+
+ <!--
+ Admin Handlers - This will register all the standard admin RequestHandlers. Adding
+ this single handler is equivolent to registering:
+
+ <requestHandler name="/admin/luke" class="org.apache.solr.handler.admin.LukeRequestHandler" />
+ <requestHandler name="/admin/system" class="org.apache.solr.handler.admin.SystemInfoHandler" />
+ <requestHandler name="/admin/plugins" class="org.apache.solr.handler.admin.PluginInfoHandler" />
+ <requestHandler name="/admin/threads" class="org.apache.solr.handler.admin.ThreadDumpHandler" />
+ <requestHandler name="/admin/properties" class="org.apache.solr.handler.admin.PropertiesRequestHandler" />
+ <requestHandler name="/admin/file" class="org.apache.solr.handler.admin.ShowFileRequestHandler" >
+
+ If you wish to hide files under ${solr.home}/conf, explicitly register the ShowFileRequestHandler using:
+ <requestHandler name="/admin/file" class="org.apache.solr.handler.admin.ShowFileRequestHandler" >
+ <lst name="invariants">
+ <str name="hidden">synonyms.txt</str>
+ <str name="hidden">anotherfile.txt</str>
+ </lst>
+ </requestHandler>
+ -->
+ <requestHandler name="/admin/" class="org.apache.solr.handler.admin.AdminHandlers" />
+
+ <!-- ping/healthcheck -->
+ <requestHandler name="/admin/ping" class="PingRequestHandler">
+ <lst name="defaults">
+ <str name="qt">standard</str>
+ <str name="q">solrpingquery</str>
+ <str name="echoParams">all</str>
+ </lst>
+ </requestHandler>
+
+ <!-- Echo the request contents back to the client -->
+ <requestHandler name="/debug/dump" class="solr.DumpRequestHandler" >
+ <lst name="defaults">
+ <str name="echoParams">explicit</str> <!-- for all params (including the default etc) use: 'all' -->
+ <str name="echoHandler">true</str>
+ </lst>
+ </requestHandler>
+
+ <highlighting>
+ <!-- Configure the standard fragmenter -->
+ <!-- This could most likely be commented out in the "default" case -->
+ <fragmenter name="gap" class="org.apache.solr.highlight.GapFragmenter" default="true">
+ <lst name="defaults">
+ <int name="hl.fragsize">100</int>
+ </lst>
+ </fragmenter>
+
+ <!-- A regular-expression-based fragmenter (f.i., for sentence extraction) -->
+ <fragmenter name="regex" class="org.apache.solr.highlight.RegexFragmenter">
+ <lst name="defaults">
+ <!-- slightly smaller fragsizes work better because of slop -->
+ <int name="hl.fragsize">70</int>
+ <!-- allow 50% slop on fragment sizes -->
+ <float name="hl.regex.slop">0.5</float>
+ <!-- a basic sentence pattern -->
+ <str name="hl.regex.pattern">[-\w ,/\n\"']{20,200}</str>
+ </lst>
+ </fragmenter>
+
+ <!-- Configure the standard formatter -->
+ <formatter name="html" class="org.apache.solr.highlight.HtmlFormatter" default="true">
+ <lst name="defaults">
+ <str name="hl.simple.pre"><![CDATA[<em>]]></str>
+ <str name="hl.simple.post"><![CDATA[</em>]]></str>
+ </lst>
+ </formatter>
+ </highlighting>
+
+
+ <!-- queryResponseWriter plugins... query responses will be written using the
+ writer specified by the 'wt' request parameter matching the name of a registered
+ writer.
+ The "default" writer is the default and will be used if 'wt' is not specified
+ in the request. XMLResponseWriter will be used if nothing is specified here.
+ The json, python, and ruby writers are also available by default.
+
+ <queryResponseWriter name="xml" class="org.apache.solr.request.XMLResponseWriter" default="true"/>
+ <queryResponseWriter name="json" class="org.apache.solr.request.JSONResponseWriter"/>
+ <queryResponseWriter name="python" class="org.apache.solr.request.PythonResponseWriter"/>
+ <queryResponseWriter name="ruby" class="org.apache.solr.request.RubyResponseWriter"/>
+ <queryResponseWriter name="php" class="org.apache.solr.request.PHPResponseWriter"/>
+ <queryResponseWriter name="phps" class="org.apache.solr.request.PHPSerializedResponseWriter"/>
+
+ <queryResponseWriter name="custom" class="com.example.MyResponseWriter"/>
+ -->
+ <queryResponseWriter name="php" class="org.apache.solr.request.PHPResponseWriter"/>
+ <queryResponseWriter name="phps" class="org.apache.solr.request.PHPSerializedResponseWriter"/>
+
+ <!-- XSLT response writer transforms the XML output by any xslt file found
+ in Solr's conf/xslt directory. Changes to xslt files are checked for
+ every xsltCacheLifetimeSeconds.
+ -->
+ <queryResponseWriter name="xslt" class="org.apache.solr.request.XSLTResponseWriter">
+ <int name="xsltCacheLifetimeSeconds">5</int>
+ </queryResponseWriter>
+
+
+ <!-- example of registering a query parser
+ <queryParser name="lucene" class="org.apache.solr.search.LuceneQParserPlugin"/>
+ -->
+
+ <!-- example of registering a custom function parser
+ <valueSourceParser name="myfunc" class="com.mycompany.MyValueSourceParser" />
+ -->
+
+ <!-- config for the admin interface -->
+ <admin>
+ <defaultQuery>solr</defaultQuery>
+
+ <!-- configure a healthcheck file for servers behind a loadbalancer
+ <healthcheck type="file">server-enabled</healthcheck>
+ -->
+ </admin>
+
+</config>
--- /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:
--- /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 @@
+<?php
+
+class backendConfiguration extends sfApplicationConfiguration
+{
+ public function configure()
+ {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/config/cache.yml Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,4 @@
+default:
+ enabled: off
+ with_layout: false
+ lifetime: 86400
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/config/factories.yml Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,132 @@
+prod:
+ logger:
+ class: sfNoLogger
+ param:
+ level: err
+ loggers: ~
+
+cli:
+ controller:
+ class: sfConsoleController
+ request:
+ class: sfConsoleRequest
+ response:
+ class: sfConsoleResponse
+
+test:
+ storage:
+ class: sfSessionTestStorage
+ param:
+ session_path: %SF_TEST_CACHE_DIR%/sessions
+
+ response:
+ class: sfWebResponse
+ param:
+ send_http_headers: false
+
+all:
+ routing:
+ class: sfPatternRouting
+ param:
+ generate_shortest_url: true
+ extra_parameters_as_query_string: true
+
+#all:
+# controller:
+# class: sfFrontWebController
+#
+# request:
+# class: sfWebRequest
+# param:
+# logging: %SF_LOGGING_ENABLED%
+# path_info_array: SERVER
+# path_info_key: PATH_INFO
+# relative_url_root: ~
+# formats:
+# txt: text/plain
+# js: [application/javascript, application/x-javascript, text/javascript]
+# css: text/css
+# json: [application/json, application/x-json]
+# xml: [text/xml, application/xml, application/x-xml]
+# rdf: application/rdf+xml
+# atom: application/atom+xml
+#
+# response:
+# class: sfWebResponse
+# param:
+# logging: %SF_LOGGING_ENABLED%
+# charset: %SF_CHARSET%
+# send_http_headers: true
+#
+# user:
+# class: myUser
+# param:
+# timeout: 1800
+# logging: %SF_LOGGING_ENABLED%
+# use_flash: true
+# default_culture: %SF_DEFAULT_CULTURE%
+#
+# storage:
+# class: sfSessionStorage
+# param:
+# session_name: symfony
+#
+# view_cache:
+# class: sfFileCache
+# param:
+# automatic_cleaning_factor: 0
+# cache_dir: %SF_TEMPLATE_CACHE_DIR%
+# lifetime: 86400
+# prefix: %SF_APP_DIR%/template
+#
+# i18n:
+# class: sfI18N
+# param:
+# source: XLIFF
+# debug: off
+# untranslated_prefix: "[T]"
+# untranslated_suffix: "[/T]"
+# cache:
+# class: sfFileCache
+# param:
+# automatic_cleaning_factor: 0
+# cache_dir: %SF_I18N_CACHE_DIR%
+# lifetime: 31556926
+# prefix: %SF_APP_DIR%/i18n
+#
+# routing:
+# class: sfPatternRouting
+# param:
+# load_configuration: true
+# suffix: ''
+# default_module: default
+# default_action: index
+# debug: %SF_DEBUG%
+# logging: %SF_LOGGING_ENABLED%
+# generate_shortest_url: false
+# extra_parameters_as_query_string: false
+# cache:
+# class: sfFileCache
+# param:
+# automatic_cleaning_factor: 0
+# cache_dir: %SF_CONFIG_CACHE_DIR%/routing
+# lifetime: 31556926
+# prefix: %SF_APP_DIR%/routing
+#
+# logger:
+# class: sfAggregateLogger
+# param:
+# level: debug
+# loggers:
+# sf_web_debug:
+# class: sfWebDebugLogger
+# param:
+# level: debug
+# condition: %SF_WEB_DEBUG%
+# xdebug_logging: true
+# web_debug_class: sfWebDebug
+# sf_file_debug:
+# class: sfFileLogger
+# param:
+# level: debug
+# file: %SF_LOG_DIR%/%SF_APP%_%SF_ENVIRONMENT%.log
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/config/filters.yml Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,8 @@
+rendering: ~
+security: ~
+
+# insert your own filters here
+
+cache: ~
+common: ~
+execution: ~
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/config/routing.yml Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,56 @@
+thd_image_image:
+ class: sfDoctrineRouteCollection
+ options:
+ model: ThdImage
+ module: image
+ prefix_path: image
+ column: id
+ with_wildcard_routes: true
+
+thd_video_video:
+ class: sfDoctrineRouteCollection
+ options:
+ model: ThdVideo
+ module: video
+ prefix_path: video
+ column: id
+ with_wildcard_routes: true
+
+thd_film_film:
+ class: sfDoctrineRouteCollection
+ options:
+ model: ThdFilm
+ module: film
+ prefix_path: film
+ column: id
+ with_wildcard_routes: true
+
+thd_segment_segment:
+ class: sfDoctrineRouteCollection
+ options:
+ model: ThdSegment
+ module: segment
+ prefix_path: segment
+ column: id
+ with_wildcard_routes: true
+
+thd_segment:
+ class: sfDoctrineRouteCollection
+ options:
+ model: ThdSegment
+ module: thd_segment
+ prefix_path: thd_segment
+ column: id
+ with_wildcard_routes: true
+
+# default rules
+homepage:
+ url: /
+ param: { module: default, action: index }
+
+default_index:
+ url: /:module
+ param: { action: index }
+
+default:
+ url: /:module/:action/*
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/config/security.yml Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,2 @@
+default:
+ is_secure: off
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/config/settings.yml Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,97 @@
+prod:
+ .settings:
+ no_script_name: off
+ logging_enabled: off
+
+dev:
+ .settings:
+ error_reporting: <?php echo (E_ALL | E_STRICT)."\n" ?>
+ web_debug: on
+ cache: off
+ no_script_name: off
+ etag: off
+
+test:
+ .settings:
+ error_reporting: <?php echo ((E_ALL | E_STRICT) ^ E_NOTICE)."\n" ?>
+ 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: <?php echo (E_PARSE | E_COMPILE_ERROR | E_ERROR | E_CORE_ERROR | E_USER_ERROR)."\n" ?> # 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
--- /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
--- /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 @@
+<?php
+
+class myUser extends sfBasicSecurityUser
+{
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/modules/film/actions/actions.class.php Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,16 @@
+<?php
+
+require_once dirname(__FILE__).'/../lib/filmGeneratorConfiguration.class.php';
+require_once dirname(__FILE__).'/../lib/filmGeneratorHelper.class.php';
+
+/**
+ * film actions.
+ *
+ * @package thd
+ * @subpackage film
+ * @author Your name here
+ * @version SVN: $Id: actions.class.php 12474 2008-10-31 10:41:27Z fabien $
+ */
+class filmActions extends autoFilmActions
+{
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/modules/film/config/generator.yml Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,20 @@
+generator:
+ class: sfDoctrineGenerator
+ param:
+ model_class: ThdFilm
+ theme: admin
+ non_verbose_templates: true
+ with_show: false
+ singular: ~
+ plural: ~
+ route_prefix: thd_film_film
+ with_doctrine_route: 1
+
+ config:
+ actions: ~
+ fields: ~
+ list: ~
+ filter: ~
+ form: ~
+ edit: ~
+ new: ~
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/modules/film/lib/filmGeneratorConfiguration.class.php Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * film module configuration.
+ *
+ * @package thd
+ * @subpackage film
+ * @author Your name here
+ * @version SVN: $Id: configuration.php 12474 2008-10-31 10:41:27Z fabien $
+ */
+class filmGeneratorConfiguration extends BaseFilmGeneratorConfiguration
+{
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/modules/film/lib/filmGeneratorHelper.class.php Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * film module helper.
+ *
+ * @package thd
+ * @subpackage film
+ * @author Your name here
+ * @version SVN: $Id: helper.php 12474 2008-10-31 10:41:27Z fabien $
+ */
+class filmGeneratorHelper extends BaseFilmGeneratorHelper
+{
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/modules/image/actions/actions.class.php Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,16 @@
+<?php
+
+require_once dirname(__FILE__).'/../lib/imageGeneratorConfiguration.class.php';
+require_once dirname(__FILE__).'/../lib/imageGeneratorHelper.class.php';
+
+/**
+ * image actions.
+ *
+ * @package thd
+ * @subpackage image
+ * @author Your name here
+ * @version SVN: $Id: actions.class.php 12474 2008-10-31 10:41:27Z fabien $
+ */
+class imageActions extends autoImageActions
+{
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/modules/image/config/generator.yml Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,20 @@
+generator:
+ class: sfDoctrineGenerator
+ param:
+ model_class: ThdImage
+ theme: admin
+ non_verbose_templates: true
+ with_show: false
+ singular: ~
+ plural: ~
+ route_prefix: thd_image_image
+ with_doctrine_route: 1
+
+ config:
+ actions: ~
+ fields: ~
+ list: ~
+ filter: ~
+ form: ~
+ edit: ~
+ new: ~
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/modules/image/lib/imageGeneratorConfiguration.class.php Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * image module configuration.
+ *
+ * @package thd
+ * @subpackage image
+ * @author Your name here
+ * @version SVN: $Id: configuration.php 12474 2008-10-31 10:41:27Z fabien $
+ */
+class imageGeneratorConfiguration extends BaseImageGeneratorConfiguration
+{
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/modules/image/lib/imageGeneratorHelper.class.php Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * image module helper.
+ *
+ * @package thd
+ * @subpackage image
+ * @author Your name here
+ * @version SVN: $Id: helper.php 12474 2008-10-31 10:41:27Z fabien $
+ */
+class imageGeneratorHelper extends BaseImageGeneratorHelper
+{
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/modules/segment/actions/actions.class.php Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,16 @@
+<?php
+
+require_once dirname(__FILE__).'/../lib/segmentGeneratorConfiguration.class.php';
+require_once dirname(__FILE__).'/../lib/segmentGeneratorHelper.class.php';
+
+/**
+ * segment actions.
+ *
+ * @package thd
+ * @subpackage segment
+ * @author Your name here
+ * @version SVN: $Id: actions.class.php 12474 2008-10-31 10:41:27Z fabien $
+ */
+class segmentActions extends autoSegmentActions
+{
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/modules/segment/config/generator.yml Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,20 @@
+generator:
+ class: sfDoctrineGenerator
+ param:
+ model_class: ThdSegment
+ theme: admin
+ non_verbose_templates: true
+ with_show: false
+ singular: ~
+ plural: ~
+ route_prefix: thd_segment_segment
+ with_doctrine_route: 1
+
+ config:
+ actions: ~
+ fields: ~
+ list: ~
+ filter: ~
+ form: ~
+ edit: ~
+ new: ~
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/modules/segment/lib/segmentGeneratorConfiguration.class.php Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * segment module configuration.
+ *
+ * @package thd
+ * @subpackage segment
+ * @author Your name here
+ * @version SVN: $Id: configuration.php 12474 2008-10-31 10:41:27Z fabien $
+ */
+class segmentGeneratorConfiguration extends BaseSegmentGeneratorConfiguration
+{
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/modules/segment/lib/segmentGeneratorHelper.class.php Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * segment module helper.
+ *
+ * @package thd
+ * @subpackage segment
+ * @author Your name here
+ * @version SVN: $Id: helper.php 12474 2008-10-31 10:41:27Z fabien $
+ */
+class segmentGeneratorHelper extends BaseSegmentGeneratorHelper
+{
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/modules/video/actions/actions.class.php Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,16 @@
+<?php
+
+require_once dirname(__FILE__).'/../lib/videoGeneratorConfiguration.class.php';
+require_once dirname(__FILE__).'/../lib/videoGeneratorHelper.class.php';
+
+/**
+ * video actions.
+ *
+ * @package thd
+ * @subpackage video
+ * @author Your name here
+ * @version SVN: $Id: actions.class.php 12474 2008-10-31 10:41:27Z fabien $
+ */
+class videoActions extends autoVideoActions
+{
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/modules/video/config/generator.yml Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,20 @@
+generator:
+ class: sfDoctrineGenerator
+ param:
+ model_class: ThdVideo
+ theme: admin
+ non_verbose_templates: true
+ with_show: false
+ singular: ~
+ plural: ~
+ route_prefix: thd_video_video
+ with_doctrine_route: 1
+
+ config:
+ actions: ~
+ fields: ~
+ list: ~
+ filter: ~
+ form: ~
+ edit: ~
+ new: ~
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/modules/video/lib/videoGeneratorConfiguration.class.php Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * video module configuration.
+ *
+ * @package thd
+ * @subpackage video
+ * @author Your name here
+ * @version SVN: $Id: configuration.php 12474 2008-10-31 10:41:27Z fabien $
+ */
+class videoGeneratorConfiguration extends BaseVideoGeneratorConfiguration
+{
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/modules/video/lib/videoGeneratorHelper.class.php Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * video module helper.
+ *
+ * @package thd
+ * @subpackage video
+ * @author Your name here
+ * @version SVN: $Id: helper.php 12474 2008-10-31 10:41:27Z fabien $
+ */
+class videoGeneratorHelper extends BaseVideoGeneratorHelper
+{
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/backend/templates/layout.php Wed Mar 10 17:19:00 2010 +0100
@@ -0,0 +1,12 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <?php include_http_metas() ?>
+ <?php include_metas() ?>
+ <?php include_title() ?>
+ <link rel="shortcut icon" href="/favicon.ico" />
+ </head>
+ <body>
+ <?php echo $sf_content ?>
+ </body>
+</html>
--- 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:
--- /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:
--- 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 @@
<div id="universcinethd">
<h1 id="logo"><a href="" title="UniversCiné">UniversCiné</a></h1>
</div>
-<div id="partners"> avec le concours de <a class="logo-partner">iri</a> <a class="logo-partner">| Sony CSL</a> <a class="logo-partner">| Cap Digital</a></div>
+<div id="partners"> avec le concours de <a class="logo-partner" href="http://www.iri.centrepompidou.fr">iri</a> <a class="logo-partner">| Sony CSL</a> <a class="logo-partner">| Cap Digital</a></div>
<div id="baseline"><cite>le site du cinéma indépendant</cite></div>
--- 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
--- 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);
--- 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
+}
--- 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
+}
--- 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);
--- 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);
--- 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");
+ }
+
+}
--- 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");
+ }
+
+}
--- 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()
--- 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()
--- /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 @@
+<?php
+/*-
+ * Copyright (c) 2008 Fredrik Lindberg - http://www.shapeshifter.se
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * UUID (RFC4122) Generator
+ * http://tools.ietf.org/html/rfc4122
+ *
+ * Implements version 1, 3, 4 and 5
+ */
+class UUID {
+ /* UUID versions */
+ const UUID_TIME = 1; /* Time based UUID */
+ const UUID_NAME_MD5 = 3; /* Name based (MD5) UUID */
+ const UUID_RANDOM = 4; /* Random UUID */
+ const UUID_NAME_SHA1 = 5; /* Name based (SHA1) UUID */
+
+ /* UUID formats */
+ const FMT_FIELD = 100;
+ const FMT_STRING = 101;
+ const FMT_BINARY = 102;
+ const FMT_QWORD = 1; /* Quad-word, 128-bit (not impl.) */
+ const FMT_DWORD = 2; /* Double-word, 64-bit (not impl.) */
+ const FMT_WORD = 4; /* Word, 32-bit (not impl.) */
+ const FMT_SHORT = 8; /* Short (not impl.) */
+ const FMT_BYTE = 16; /* Byte */
+ const FMT_DEFAULT = 16;
+
+ /* Field UUID representation */
+ static private $m_uuid_field = array(
+ 'time_low' => 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);
+ }
+}
+
+?>
--- /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.
--- /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
+
+ <queryResponseWriter name="php" class="org.apache.solr.request.PHPResponseWriter"/>
+ <queryResponseWriter name="phps" class="org.apache.solr.request.PHPSerializedResponseWriter"/>
+
+ 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
--- /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
--- /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 @@
+<?php
+
+/**
+ * @package uvmcSolrSearchPlugin
+ * @subpackage configuration
+ * @author Marc Weistroff <mweistroff@uneviemoinschere.com>
+ * @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
--- /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 @@
+<?php
+
+/**
+ * Reset the index of solr.
+ *
+ * @package uvmcSolrSearchPlugin
+ * @subpackage task
+ * @author Marc Weistroff <mweistroff@uneviemoinschere.com>
+ * @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 = <<<EOF
+The [reset-index|INFO] deletes the entire solr index.
+Call it with:
+
+ [php symfony uvmc-solr:reset-index application|INFO]
+EOF;
+ }
+
+ /**
+ * @see sfTask
+ */
+ protected function execute($arguments = array(), $options = array())
+ {
+ $confirm = $this->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
--- /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 @@
+<?php
+
+/**
+ * @package uvmcSolrSearchPlugin
+ * @subpackage event
+ * @author Marc Weistroff <mweistroff@uneviemoinschere.com>
+ * @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
--- /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 @@
+<?php
+
+/**
+ * uvmcSolrServicesManager implements the singleton design pattern.
+ * This class is used to manage a solr service.
+ *
+ * @package uvmcSolrSearchPlugin
+ * @subpackage listener
+ * @author Marc Weistroff <mweistroff@uneviemoinschere.com>
+ * @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();
+ }
+}
--- /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 @@
+<?php
+/**
+ * Copyright (c) 2007-2009, Conduit Internet Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of Conduit Internet Technologies, Inc. nor the names of
+ * its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @copyright Copyright 2007-2009 Conduit Internet Technologies, Inc. (http://conduit-it.com)
+ * @license New BSD (http://solr-php-client.googlecode.com/svn/trunk/COPYING)
+ * @version $Id: Document.php 21094 2009-08-12 10:02:05Z futurecat $
+ *
+ * @package Apache
+ * @subpackage Solr
+ * @author Donovan Jimenez <djimenez@conduit-it.com>
+ */
+
+/**
+ * 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:
+ * <code>
+ * ...
+ * $document->title = 'Something';
+ * echo $document->title;
+ * ...
+ * </code>
+ *
+ * Additionally, the field values can be iterated with foreach
+ *
+ * <code>
+ * foreach ($document as $fieldName => $fieldValue)
+ * {
+ * ...
+ * }
+ * </code>
+ */
+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.
+ *
+ * <code>
+ * $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');
+ * </code>
+ *
+ * @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:
+ *
+ * <code>
+ * foreach ($document as $key => $value)
+ * {
+ * ...
+ * }
+ * </code>
+ */
+ 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:
+ *
+ * <code>
+ * isset($document->some_field);
+ * </code>
+ *
+ * @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:
+ *
+ * <code>
+ * unset($document->some_field);
+ * </code>
+ *
+ * @param string $key
+ */
+ public function __unset($key)
+ {
+ unset($this->_fields[$key]);
+ unset($this->_fieldBoosts[$key]);
+ }
+}
\ No newline at end of file
--- /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 @@
+<?php
+/**
+ * Copyright (c) 2007-2009, Conduit Internet Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of Conduit Internet Technologies, Inc. nor the names of
+ * its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @copyright Copyright 2007-2009 Conduit Internet Technologies, Inc. (http://conduit-it.com)
+ * @license New BSD (http://solr-php-client.googlecode.com/svn/trunk/COPYING)
+ * @version $Id: Response.php 21100 2009-08-12 14:34:55Z futurecat $
+ *
+ * @package Apache
+ * @subpackage Solr
+ * @author Donovan Jimenez <djimenez@conduit-it.com>
+ */
+
+/**
+ * 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
--- /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 @@
+<?php
+/**
+ * Copyright (c) 2007-2009, Conduit Internet Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of Conduit Internet Technologies, Inc. nor the names of
+ * its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @copyright Copyright 2007-2009 Conduit Internet Technologies, Inc. (http://conduit-it.com)
+ * @license New BSD (http://solr-php-client.googlecode.com/svn/trunk/COPYING)
+ * @version $Id: Service.php 21094 2009-08-12 10:02:05Z futurecat $
+ *
+ * @package Apache
+ * @subpackage Solr
+ * @author Donovan Jimenez <djimenez@conduit-it.com>
+ */
+
+// 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:
+ * <code>
+ * ...
+ * $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'));
+ * }
+ * ...
+ * </code>
+ *
+ * @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 = '<add allowDups="' . $dupValue . '" overwritePending="' . $pendingValue . '" overwriteCommitted="' . $committedValue . '">';
+ $rawPost .= $this->_documentToXmlFragment($document);
+ $rawPost .= '</add>';
+
+ 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 = '<add allowDups="' . $dupValue . '" overwritePending="' . $pendingValue . '" overwriteCommitted="' . $committedValue . '">';
+
+ foreach ($documents as $document)
+ {
+ if ($document instanceof Apache_Solr_Document)
+ {
+ $rawPost .= $this->_documentToXmlFragment($document);
+ }
+ }
+
+ $rawPost .= '</add>';
+
+ 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 = '<doc';
+
+ if ($document->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 .= '<field name="' . $key . '"';
+
+ if ($fieldBoost !== false)
+ {
+ $xml .= ' boost="' . $fieldBoost . '"';
+
+ // only set the boost for the first field in the set
+ $fieldBoost = false;
+ }
+
+ $multivalue = htmlspecialchars($multivalue, ENT_NOQUOTES, 'UTF-8');
+
+ $xml .= '>' . $multivalue . '</field>';
+ }
+ }
+ else
+ {
+ $xml .= '<field name="' . $key . '"';
+
+ if ($fieldBoost !== false)
+ {
+ $xml .= ' boost="' . $fieldBoost . '"';
+ }
+
+ $value = htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8');
+
+ $xml .= '>' . $value . '</field>';
+ }
+ }
+
+ $xml .= '</doc>';
+
+ // 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 = '<commit optimize="' . $optimizeValue . '" waitFlush="' . $flushValue . '" waitSearcher="' . $searcherValue . '" />';
+
+ 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 = '<delete fromPending="' . $pendingValue . '" fromCommitted="' . $committedValue . '"><id>' . $id . '</id></delete>';
+
+ 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 = '<delete fromPending="' . $pendingValue . '" fromCommitted="' . $committedValue . '"><query>' . $rawQuery . '</query></delete>';
+
+ 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 = '<optimize waitFlush="' . $flushValue . '" waitSearcher="' . $searcherValue . '" />';
+
+ 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
--- /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 @@
+<?php
+/**
+ * Copyright (c) 2007-2009, Conduit Internet Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of Conduit Internet Technologies, Inc. nor the names of
+ * its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @copyright Copyright 2007-2009 Conduit Internet Technologies, Inc. (http://conduit-it.com)
+ * @license New BSD (http://solr-php-client.googlecode.com/svn/trunk/COPYING)
+ * @version $Id: Balancer.php 21094 2009-08-12 10:02:05Z futurecat $
+ *
+ * @package Apache
+ * @subpackage Solr
+ * @author Donovan Jimenez <djimenez@conduit-it.com>, 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;
+ }
+}
--- /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 @@
+<?php
+
+include(dirname(__FILE__).'/../../bootstrap/functional.php');
+
+$browser = new sfTestFunctional(new sfBrowser());
+
+$browser->
+ 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()
+;
--- /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 @@
+<?php
+
+include(dirname(__FILE__).'/../../bootstrap/functional.php');
+
+$browser = new sfTestFunctional(new sfBrowser());
+
+$browser->
+ 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()
+;
--- /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 @@
+<?php
+
+include(dirname(__FILE__).'/../../bootstrap/functional.php');
+
+$browser = new sfTestFunctional(new sfBrowser());
+
+$browser->
+ 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()
+;
--- /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 @@
+<?php
+
+include(dirname(__FILE__).'/../../bootstrap/functional.php');
+
+$browser = new sfTestFunctional(new sfBrowser());
+
+$browser->
+ 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()
+;
--- /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 @@
+<?php
+
+include(dirname(__FILE__).'/../../bootstrap/functional.php');
+
+$browser = new sfTestFunctional(new sfBrowser());
+
+$browser->
+ 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()
+;
--- /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 @@
+<?php
+
+
+require_once(dirname(__FILE__).'/../config/ProjectConfiguration.class.php');
+
+$configuration = ProjectConfiguration::getApplicationConfiguration('backend', 'prod', false);
+sfContext::createInstance($configuration)->dispatch();
--- /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 @@
+<?php
+
+// this check prevents access to debug front controllers that are deployed by accident to production servers.
+// feel free to remove this, extend it or make something more sophisticated.
+if (!in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1')))
+{
+ die('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
+}
+
+require_once(dirname(__FILE__).'/../config/ProjectConfiguration.class.php');
+
+$configuration = ProjectConfiguration::getApplicationConfiguration('backend', 'dev', true);
+sfContext::createInstance($configuration)->dispatch();
--- /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;
+}
+
--- /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;
+}
Binary file web/thdProject/web/sfDoctrinePlugin/images/asc.png has changed
Binary file web/thdProject/web/sfDoctrinePlugin/images/default.png has changed
Binary file web/thdProject/web/sfDoctrinePlugin/images/delete.png has changed
Binary file web/thdProject/web/sfDoctrinePlugin/images/desc.png has changed
Binary file web/thdProject/web/sfDoctrinePlugin/images/edit.png has changed
Binary file web/thdProject/web/sfDoctrinePlugin/images/error.png has changed
Binary file web/thdProject/web/sfDoctrinePlugin/images/first.png has changed
Binary file web/thdProject/web/sfDoctrinePlugin/images/last.png has changed
Binary file web/thdProject/web/sfDoctrinePlugin/images/list.png has changed
Binary file web/thdProject/web/sfDoctrinePlugin/images/new.png has changed
Binary file web/thdProject/web/sfDoctrinePlugin/images/next.png has changed
Binary file web/thdProject/web/sfDoctrinePlugin/images/previous.png has changed
Binary file web/thdProject/web/sfDoctrinePlugin/images/tick.png has changed
--- /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 @@
+<?php
+
+$uuid = new uuid();
+echo $uuid->v1();
+
+?>