66class RemoteDatasource extends DataSource implements iDatasource
77{
88
9+ private static $ transformer = null ;
910 private static $ url_result = null ;
10-
1111 private static $ cacheable = null ;
1212
1313 public static function getName ()
@@ -71,6 +71,19 @@ public function exposeData(&$data)
7171
7272 }
7373
74+ /**
75+ * This method is called when their is an http error
76+ * or when content type is unsupported
77+ *
78+ * @since Remote Datasource 2.0
79+ * @param array $info
80+ * info of the http request
81+ */
82+ public function httpError (&$ info )
83+ {
84+
85+ }
86+
7487/*-------------------------------------------------------------------------
7588 Utilities
7689-------------------------------------------------------------------------*/
@@ -119,23 +132,7 @@ public static function isValidURL($url, $timeout = 6, $format = 'xml', $fetch_UR
119132 if (trim ($ url ) == '' ) {
120133 return __ ('This is a required field ' );
121134 } elseif ($ fetch_URL === true ) {
122- $ gateway = new Gateway ;
123- $ gateway ->init ($ url );
124- $ gateway ->setopt ('TIMEOUT ' , $ timeout );
125-
126- // Set the approtiate Accept: headers depending on the format of the URL.
127- if ($ format == 'xml ' ) {
128- $ gateway ->setopt ('HTTPHEADER ' , array ('Accept: text/xml, */* ' ));
129- } elseif ($ format == 'json ' ) {
130- $ gateway ->setopt ('HTTPHEADER ' , array ('Accept: application/json, */* ' ));
131- } elseif ($ format == 'csv ' ) {
132- $ gateway ->setopt ('HTTPHEADER ' , array ('Accept: text/csv, */* ' ));
133- }
134-
135- self ::prepareGateway ($ gateway );
136-
137- $ data = $ gateway ->exec ();
138- $ info = $ gateway ->getInfoLast ();
135+ list ($ data , $ info ) = self ::fetch ($ url , $ format , $ timeout );
139136
140137 // 28 is CURLE_OPERATION_TIMEOUTED
141138 if (isset ($ info ['curl_error ' ]) && $ info ['curl_error ' ] == 28 ) {
@@ -226,7 +223,7 @@ public static function buildCacheID($settings)
226223 */
227224 public static function buildCacheInformation (XMLElement $ wrapper , Cacheable $ cache , $ cache_id )
228225 {
229- $ cachedData = $ cache ->check ($ cache_id );
226+ $ cachedData = $ cache ->read ($ cache_id );
230227
231228 if (is_array ($ cachedData ) && !empty ($ cachedData ) && (time () < $ cachedData ['expiry ' ])) {
232229 $ a = Widget::Anchor (__ ('Clear now ' ), SYMPHONY_URL . getCurrentPage () . 'clear_cache/ ' );
@@ -256,7 +253,7 @@ public static function buildEditor(XMLElement $wrapper, array &$errors = array()
256253
257254 // If `clear_cache` is set, clear it..
258255 if (isset ($ cache_id ) && in_array ('clear_cache ' , Administration::instance ()->Page ->getContext ())) {
259- $ cache ->forceExpiry ($ cache_id );
256+ $ cache ->delete ($ cache_id );
260257 Administration::instance ()->Page ->pageAlert (
261258 __ ('Data source cache cleared at %s. ' , array (Widget::Time ()->generate ()))
262259 . '<a href=" ' . SYMPHONY_URL . '/blueprints/datasources/" accesskey="a"> '
@@ -565,7 +562,8 @@ public static function prepare(array $settings, array $params, $template)
565562 $ settings ['namespaces ' ] = $ namespaces ;
566563 $ cache = Symphony::ExtensionManager ()->getCacheProvider ('remotedatasource ' );
567564 $ cache_id = self ::buildCacheID ($ settings );
568- $ cache ->write ($ cache_id , self ::$ url_result , $ settings ['cache ' ]);
565+ $ data = self ::transformResult (self ::$ url_result , $ settings ['format ' ]);
566+ $ cache ->write ($ cache_id , $ data , $ settings ['cache ' ]);
569567 }
570568
571569 return sprintf (
@@ -639,7 +637,7 @@ public function execute(array &$param_pool = null)
639637 // Check for an existing Cache for this Datasource
640638 $ cache_id = self ::buildCacheID ($ this );
641639 $ cache = Symphony::ExtensionManager ()->getCacheProvider ('remotedatasource ' );
642- $ cachedData = $ cache ->check ($ cache_id );
640+ $ cachedData = $ cache ->read ($ cache_id );
643641 $ writeToCache = null ;
644642 $ isCacheValid = true ;
645643 $ creation = DateTimeObj::get ('c ' );
@@ -650,34 +648,16 @@ public function execute(array &$param_pool = null)
650648 || (time () - $ cachedData ['creation ' ]) > ($ this ->dsParamCACHE * 60 ) // The cache is old.
651649 ) {
652650 if (Mutex::acquire ($ cache_id , $ this ->dsParamTIMEOUT , TMP )) {
653- $ ch = new Gateway ;
654- $ ch ->init ($ this ->dsParamURL );
655- $ ch ->setopt ('TIMEOUT ' , $ this ->dsParamTIMEOUT );
656-
657- // Set the approtiate Accept: headers depending on the format of the URL.
658- if ($ this ->dsParamFORMAT == 'xml ' ) {
659- $ ch ->setopt ('HTTPHEADER ' , array ('Accept: text/xml, */* ' ));
660- } elseif ($ this ->dsParamFORMAT == 'json ' ) {
661- $ ch ->setopt ('HTTPHEADER ' , array ('Accept: application/json, */* ' ));
662- } elseif ($ this ->dsParamFORMAT == 'csv ' ) {
663- $ ch ->setopt ('HTTPHEADER ' , array ('Accept: text/csv, */* ' ));
664- }
665-
666- self ::prepareGateway ($ ch );
667-
668- $ data = $ ch ->exec ();
669- $ info = $ ch ->getInfoLast ();
670-
651+ list ($ data , $ info ) = self ::fetch ($ this ->dsParamURL , $ this ->dsParamFORMAT , $ this ->dsParamTIMEOUT );
671652 Mutex::release ($ cache_id , TMP );
672-
673- $ data = trim ($ data );
674653 $ writeToCache = true ;
675654
676655 // Handle any response that is not a 200, or the content type does not include XML, JSON, plain or text
677656 if ((int ) $ info ['http_code ' ] != 200 || !preg_match ('/(xml|json|csv|plain|text)/i ' , $ info ['content_type ' ])) {
678657 $ writeToCache = false ;
679658
680659 $ result ->setAttribute ('valid ' , 'false ' );
660+ $ this ->httpError ($ info );
681661
682662 // 28 is CURLE_OPERATION_TIMEOUTED
683663 if ($ info ['curl_error ' ] == 28 ) {
@@ -697,76 +677,47 @@ public function execute(array &$param_pool = null)
697677 }
698678
699679 return $ result ;
700- } else if (strlen ($ data ) > 0 ) {
701680
702- // Handle where there is `$data`
703-
704- // If it's JSON, convert it to XML
705- if ($ this ->dsParamFORMAT == 'json ' ) {
706- try {
707- require_once TOOLKIT . '/class.json.php ' ;
708- $ data = JSON ::convertToXML ($ data );
709- } catch (Exception $ ex ) {
710- $ writeToCache = false ;
711- $ errors = array (
712- array ('message ' => $ ex ->getMessage ())
713- );
714- }
715- } elseif ($ this ->dsParamFORMAT == 'csv ' ) {
716- try {
717- require_once EXTENSIONS . '/remote_datasource/lib/class.csv.php ' ;
718- $ data = CSV ::convertToXML ($ data );
719- } catch (Exception $ ex ) {
720- $ writeToCache = false ;
721- $ errors = array (
722- array ('message ' => $ ex ->getMessage ())
723- );
724- }
725- } elseif ($ this ->dsParamFORMAT == 'txt ' ) {
726- $ txtElement = new XMLElement ('entry ' );
727- $ txtElement ->setValue (General::wrapInCDATA ($ data ));
728- $ data = $ txtElement ->generate ();
729- $ txtElement = null ;
730- }
731- else if (!General::validateXML ($ data , $ errors , false , new XsltProcess )) {
732- // If the XML doesn't validate..
733- $ writeToCache = false ;
681+ // Handle where there is `$data`
682+ } else if (strlen ($ data ) > 0 ) {
683+ try {
684+ $ data = self ::transformResult ($ data , $ this ->dsParamFORMAT );
734685 }
735-
736686 // If the `$data` is invalid, return a result explaining why
737- if ($ writeToCache === false ) {
687+ catch (TransformException $ ex ) {
688+ $ writeToCache = false ;
738689 $ error = new XMLElement ('errors ' );
739690 $ error ->setAttribute ('valid ' , 'false ' );
740691
741692 $ error ->appendChild (new XMLElement ('error ' , __ ('Data returned is invalid. ' )));
742693
743- foreach ($ errors as $ e ) {
694+ foreach ($ ex -> getErrors () as $ e ) {
744695 if (strlen (trim ($ e ['message ' ])) == 0 ) {
745696 continue ;
746697 }
747-
698+
748699 $ error ->appendChild (new XMLElement ('item ' , General::sanitize ($ e ['message ' ])));
749700 }
750701
751702 $ result ->appendChild ($ error );
752703
753704 return $ result ;
754705 }
706+
707+ // If `$data` is empty, set the `force_empty_result` to true.
755708 } elseif (strlen ($ data ) == 0 ) {
756-
757- // If `$data` is empty, set the `force_empty_result` to true.
758709 $ this ->_force_empty_result = true ;
759710 }
711+
712+ // Failed to acquire a lock
760713 } else {
761-
762- // Failed to acquire a lock
763714 $ result ->appendChild (
764715 new XMLElement ('error ' , __ ('The %s class failed to acquire a lock. ' , array ('<code>Mutex</code> ' )))
765716 );
766717 }
718+
719+ // The cache is good, use it!
767720 } else {
768-
769- // The cache is good, use it!
770721 $ data = trim ($ cachedData ['data ' ]);
771722 $ creation = DateTimeObj::get ('c ' , $ cachedData ['creation ' ]);
772723 }
@@ -832,6 +783,75 @@ public function execute(array &$param_pool = null)
832783
833784 return $ result ;
834785 }
786+
787+ /**
788+ * Given a URL, Format and Timeout, this function will initalise
789+ * Symphony's Gateway class to retrieve the contents of the URL.
790+ *
791+ * @param string $url
792+ * @param string $format
793+ * @param integer $timeout
794+ * @return array
795+ */
796+ public static function fetch ($ url , $ format , $ timeout )
797+ {
798+ $ ch = new Gateway ;
799+ $ ch ->init ($ url );
800+ $ ch ->setopt ('TIMEOUT ' , $ timeout );
801+
802+ // Set the approtiate Accept: headers depending on the format of the URL.
803+ if ($ transformer = self ::getTransformer ($ format )) {
804+ $ accepts = $ transformer ->accepts ();
805+ $ ch ->setopt ('HTTPHEADER ' , array ('Accept: ' . $ accepts ));
806+ }
807+
808+ self ::prepareGateway ($ ch );
809+
810+ return array (
811+ trim ($ ch ->exec ()),
812+ $ ch ->getInfoLast ()
813+ );
814+ }
815+
816+ /**
817+ * Given the result (a string), and a desired format, this
818+ * function will transform it to the desired format and return
819+ * it.
820+ * @param string $data
821+ * @param string $format
822+ * @return string
823+ */
824+ public static function transformResult ($ data , $ format )
825+ {
826+ if ($ transformer = self ::getTransformer ($ format )) {
827+ $ data = $ transformer ->transform ($ data );
828+ } else {
829+ $ data = '' ;
830+ }
831+
832+ return $ data ;
833+ }
834+
835+ /**
836+ * Given the format, this function will look for the file
837+ * and create a new transformer.
838+ *
839+ * @param string $format
840+ * @return Transformer
841+ */
842+ public static function getTransformer ($ format )
843+ {
844+ $ transformer = EXTENSIONS . '/remote_datasource/lib/class. ' . strtolower ($ format ) . '.php ' ;
845+
846+ if (!isset (self ::$ transformer )) {
847+ if (file_exists ($ transformer )) {
848+ $ classname = require_once $ transformer ;
849+ self ::$ transformer = new $ classname ;
850+ }
851+ }
852+
853+ return self ::$ transformer ;
854+ }
835855}
836856
837857return 'RemoteDatasource ' ;
0 commit comments