Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Anatomy of a 5000 hour project

069965463531f082c67fa8087eff0b05?s=47 BoldMinded
October 16, 2012

The Anatomy of a 5000 hour project

#eeciconf2012

069965463531f082c67fa8087eff0b05?s=128

BoldMinded

October 16, 2012
Tweet

More Decks by BoldMinded

Other Decks in Technology

Transcript

  1. 1

  2. HELLO! SENIOR DEVELOPER AT - MAY RECOGNIZE ME AS &

    - @LITZINGER, @BOLDMINDED 2
  3. THE ANATOMY OF A 5000 HOUR PROJECT 3

  4. 4

  5. 5

  6. ORIGINAL ESTIMATE = 4600 HOURS OUR LARGEST PROJECT (GO EE!)

    THE SALE 6
  7. “ENTERPRISE” 7

  8. AVOID VENDOR LOCK-IN DON’T RE-INVENT THE WHEEL WHY YOU NO

    WANT CUSTOM? 8
  9. IT WASN’T ME! 9

  10. LEVERAGE EXISTING ADD-ONS BUILD NEW ONES TO FILL GAPS OFF

    THE SHELF WHY EE? 10
  11. SO MANY SALES MEETINGS... THE MEETINGS BUT WE UNDERSTOOD WHY.

    WE ASKED THEM TO JUMP SHIP. 11
  12. FINAL NUMBERS 12

  13. TEAM JASON DICKS HTML/CSS/EE PHILIP BRAND LEAD DEV JONNY BRANUM

    SOLR GURU JOSH ANDERSON EE BRIAN LITZINGER ADD-ONS ISAAC RAWAY ADD-ONS 13
  14. DEMO 14

  15. 30 CHANNELS 203 CUSTOM FIELDS 165 TEMPLATES 7,144 ENTRIES 15

  16. MULTILINGUAL/DRAFTS TRANSLATION IMPORT/EXPORT ROBUST SEARCH ZIP FILE GENERATION USER DOWNLOAD

    HISTORY CUSTOM FORM BUILDER KEY FEATURES UHURA UHURA SOLR PLAYA/CUSTOM ASSETS PLUS PROFORM HOURS 350 200 250 200 125 0 1125 16
  17. TRANSCRIBE & BETTER WORKFLOW DID NOT EXIST HAD A GREAT

    IDEA TURNS OUT IT WAS A TERRIBLE IDEA (100 FIELDS X 12) X 2 = 2400 COLUMNS MULTILINGUAL/DRAFTS 17
  18. USE CUSTOM TABLE BUILD FIELDTYPE TO HOUSE OTHER FIELDTYPES WORKED!

    BUT JAVASCRIPT EVENTS WERE FLAKY AND WOULDN’T SUPPORT MATRIX MULTILINGUAL TAKE 2! 18
  19. HAD TO BE A BETTER WAY MULTILINGUAL TAKE 3! $this->api_channel_fields->apply('display_publish_field',

    array($field_value)); $this->EE->api_channel_fields->apply('save', array($data[$field_name])); $this->EE->api_channel_fields->apply('replace_tag', array('data' => $data, 'params' => $params, 'tagdata' => $tagdata)); 19
  20. JACKPOT! function apply($method, $parameters = array()) { $_ft_path = $this->ft_paths[$this->field_type];

    $this->EE->load->add_package_path($_ft_path, FALSE); $res = call_user_func_array(array(&$this->field_types[$this->field_type], $method), $parameters); $this->EE->load->remove_package_path($_ft_path); return $res; } 20
  21. JACKPOT! function apply($method, $parameters = array()) { $_ft_path = $this->ft_paths[$this->field_type];

    $this->EE->load->add_package_path($_ft_path, FALSE); require PATH_THIRD .'/uhura/libraries/uhura.php'; $res = call_user_func_array(array(&$this->field_types[$this->field_type], $method), $parameters); $this->EE->load->remove_package_path($_ft_path); return $res; } 21
  22. function apply($method, $parameters = array()) { $_ft_path = $this->ft_paths[$this->field_type]; $this->EE->load->add_package_path($_ft_path,

    FALSE); if(array_key_exists('uhura', $this->EE->addons->get_installed())) { if(isset($this->EE->form_validation->_error_array) AND count($this->EE->form_validation->_error_array) > 0) { // Do nothing. } else { require_once 'Uhura_Api_channel_fields.php'; $uhura = new Uhura_Api_channel_fields($this); $parameters = $uhura->apply($method, $this->field_type, $parameters); } } $res = call_user_func_array(array(&$this->field_types[$this->field_type], $method), $parameters); $this->EE->load->remove_package_path($_ft_path); return $res; } 22
  23. QUESTIONS? 23

  24. SCOPED TO USE SOLR CAN WE USE A 3RD PARTY

    SEARCH MODULE INSTEAD? SERIOUSLY THOUGHT ABOUT IT FOR A WEEK STUCK WITH SOLR. GLAD WE DID. (EVEN THOUGH IT WAS AN EPIC P.I.T.A.) SEARCH 24
  25. SEARCH RELEVANCY WEIGHTING/BOOST FAST. FREAKING FAST. DEMO SEARCH BENEFITS OF

    SOLR 25
  26. <schema name="VictaulicSearch" version="1.4"> <types> <fieldtype name="text_en_US" class="solr.TextField"> <analyzer> <tokenizer class="solr.StandardTokenizerFactory"/>

    <filter class="solr.StandardFilterFactory"/> <filter class="solr.ISOLatin1AccentFilterFactory"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.SnowballPorterFilterFactory" language="English"/> </analyzer> </fieldtype> ... 26
  27. <!-- title of entry [one per language] --> <field name="title_en_US"

    type="string" indexed="true" stored="true" /> <field name="title_es_ES" type="string" indexed="true" stored="true" /> <field name="title_es_MX" type="string" indexed="true" stored="true" /> ... <!-- text searched actual content [one per language] --> <field name="content_en_US" type="text_en_US" indexed="true" stored="true" /> <field name="content_es_ES" type="text_es_ES" indexed="true" stored="true" /> <field name="content_es_MX" type="text_es_MX" indexed="true" stored="true" /> ... <!-- facet search options based on entry categories or relationships --> <!-- Relationships (Playa) --> <field name="systemType" type="int" indexed="true" multiValued="true" stored="true" /> <field name="productCategory" type="int" indexed="true" multiValued="true" stored="true" /> <field name="productBrand" type="int" indexed="true" multiValued="true" stored="true" /> <field name="productSubcategory" type="int" indexed="true" multiValued="true" stored="true" /> <field name="productSystem" type="int" indexed="true" multiValued="true" stored="true" /> ... <!-- Categories --> <field name="business" type="int" indexed="true" multiValued="true" stored="true" /> <field name="businessApplication" type="int" indexed="true" multiValued="true" stored="true" /> <field name="region" type="int" indexed="true" multiValued="true" stored="true" /> <field name="facilityType" type="int" indexed="true" multiValued="true" stored="true" /> <field name="howDoI" type="int" indexed="true" multiValued="true" stored="true" /> ... 27
  28. $config['solr']['requiredFields'] = array( "id", "entryDate", "urlSlug", "channelId", "title", "content" );

    // Mapping Playa or category fields to facets $config['solr']['relationshipMappings'] = array( 'productBrand' => array( 'literature_rel_product_brands', 'product_parent_brand' ), 'productCategory' => array( 'product_category', 'literature_rel_product_cat' ), 'business' => array( 'calendar_rel_businesses', 'contact_rel_businesses', 'literature_rel_businesses', 'news_rel_businesses', 'product_rel_businesses', 'study_rel_businesses', 'video_rel_businesses' ), 'businessApplication' => array( 'business_rel_applications', 'product_rel_applications' ) ); 28
  29. // Fields used for the facets. The sidebar facet list

    renders in this order. $config['solr']['multiValueFields'] = array( 'channelId', 'facilityType', 'systemType', 'howDoI', 'eventType', 'literatureType', 'newsCategory', 'productCategory', 'productSubcategory', 'productBrand', 'joiningSystem', 'pipeMaterialCategory', 'pipeSchedule', 'productSizeRangeInches', 'productSizeRangeMetric', 'deflector', 'response', 'productKFactorImperial', 'productKFactorSi', 'productOrificeInches', 'productOrificeMetric', 'business', 'businessApplication', 'productSystem', 'videoCategory', 'facilityType', 'discontinued', 'region' ); 29
  30. // Set search boost to a higher priority, if not

    set here, then it gets a 1 $config['solr']['boost'] = array( // channel_id => boost value 5 => 9, // products 19 => 2, // videos 15 => 2, // literature, 14 => 2 // solutions ); 30
  31. // entry_submit_absolute_end() $facets['businessGroup'][] = $playa_id; $facets['businessGroup'][] = $cat_id; $facets['content_'.$language] =

    trim(strip_tags(implode(' ', $content_fields))); $facets['snippet_'.$language] = trim(strip_tags(implode(' ', $snippet_fields))); // Assemble our output to send to Solr $out = array( 'id' => $entry_id, 'entry_id' => $entry_id, 'entryDate' => ((isset($meta['entry_date']) AND $meta['entry_date'] != "" AND $meta['entry_date'] != "0") ? $meta['entry_date'] : $this->EE->localize->now), 'editDate' => ((isset($meta['edit_date']) AND $meta['edit_date'] != "") ? strtotime($meta['edit_date']) : $meta['entry_date']), 'urlSlug' => ((isset($data['structure__uri']) AND $data['structure__uri'] != '') ? $data['structure__uri'] : $this->_generate_url_slug($meta, $entry_id)), 'imageUrl_'. $language => $image, 'imageUrl' => $image, 'channelId' => $meta['channel_id'], 'title_'. $language => $title, 'title' => $title ); 31
  32. $out = array_merge($out, $stored_fields, $facets, $date_fields); $solr->addDocumentByLanguage($out, $addedLanguages); $solr->commit(); 32

  33. CAD PACKAGES SOFTWARE MODULES CAD FILES PAC-SERIES 745 DELUGE.RFA PAC-SERIES

    745 DRY.RFA PAC-SERIES 745 PRE.RFA FIRE PROTECTION AUTO-DESK REVIT 33
  34. CHANNEL: CAD FILES CHANNEL: CAD MODULES CHANNEL: CAD SOFTWARE 34

  35. GO OUTSIDE YOUR SAFE ZONE. SLOW DOWN. PLAN YOUR CODE.

    EE CAN HANDLE JUST ABOUT ANYTHING. MORAL OF THE STORY 35
  36. QUESTIONS? Pssst!