├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── RoboFile.php ├── build.properties.dist ├── build.xml ├── cli └── joomla.php ├── codeception.yml ├── component ├── admin │ ├── Webservices │ │ ├── Controller │ │ │ ├── AddController.php │ │ │ ├── AjaxController.php │ │ │ ├── ApplyController.php │ │ │ ├── CancelController.php │ │ │ ├── DisplayController.php │ │ │ ├── EditController.php │ │ │ ├── InstallController.php │ │ │ ├── PublishController.php │ │ │ ├── SaveController.php │ │ │ └── UnpublishController.php │ │ ├── Helper.php │ │ ├── Layout │ │ │ ├── fields.php │ │ │ ├── fields │ │ │ │ └── field.php │ │ │ ├── operation.php │ │ │ ├── operation │ │ │ │ └── attributes.php │ │ │ ├── resources.php │ │ │ ├── resources │ │ │ │ └── resource.php │ │ │ └── scopes.php │ │ ├── Model │ │ │ ├── Fields │ │ │ │ ├── componentlist.php │ │ │ │ ├── tablelist.php │ │ │ │ ├── webservicelist.php │ │ │ │ ├── webservicepaths.php │ │ │ │ └── webservicescopes.php │ │ │ ├── FormModel.php │ │ │ ├── Forms │ │ │ │ ├── filter_webservices.xml │ │ │ │ ├── webservice.xml │ │ │ │ ├── webservice_defaults.xml │ │ │ │ └── webservice_operation.xml │ │ │ ├── WebserviceModel.php │ │ │ └── WebservicesModel.php │ │ ├── Table │ │ │ └── WebserviceTable.php │ │ └── View │ │ │ ├── DefaultHtmlView.php │ │ │ ├── Webservice │ │ │ ├── WebserviceHtmlView.php │ │ │ └── tmpl │ │ │ │ ├── default.php │ │ │ │ ├── default_create.php │ │ │ │ ├── default_delete.php │ │ │ │ ├── default_documentation.php │ │ │ │ ├── default_main.php │ │ │ │ ├── default_read.php │ │ │ │ ├── default_task.php │ │ │ │ └── default_update.php │ │ │ └── Webservices │ │ │ ├── WebservicesHtmlView.php │ │ │ └── tmpl │ │ │ └── default.php │ ├── access.xml │ ├── config.xml │ ├── language │ │ └── en-GB │ │ │ ├── en-GB.com_webservices.ini │ │ │ └── en-GB.com_webservices.sys.ini │ ├── sql │ │ ├── install │ │ │ └── mysql │ │ │ │ ├── install.sql │ │ │ │ └── uninstall.sql │ │ └── updates │ │ │ └── mysql │ │ │ └── 1.0.0.sql │ └── webservices.php ├── media │ └── webservices │ │ └── js │ │ ├── component.js │ │ └── component.min.js └── webservices.xml ├── composer.json ├── composer.lock ├── config.dist.json ├── extension_packager.xml ├── layouts └── webservice │ ├── documentation.php │ ├── documentationoperation.php │ └── documentationoperation │ └── example.php ├── plugins └── authentication │ └── redcore_oauth2 │ ├── language │ └── en-GB │ │ ├── en-GB.plg_authentication_redcore_oauth2.ini │ │ └── en-GB.plg_authentication_redcore_oauth2.sys.ini │ ├── redcore_oauth2.php │ └── redcore_oauth2.xml ├── routes.json ├── src ├── Api │ ├── ApiBase.php │ ├── ApiInterface.php │ ├── Rest │ │ └── Rest.php │ └── Soap │ │ ├── Operation │ │ └── Operation.php │ │ ├── Soap.php │ │ ├── SoapHelper.php │ │ ├── Transform │ │ ├── TransformArray.php │ │ ├── TransformArrayDefined.php │ │ ├── TransformArrayRequired.php │ │ ├── TransformBase.php │ │ ├── TransformBoolean.php │ │ ├── TransformDatetime.php │ │ ├── TransformFloat.php │ │ ├── TransformInt.php │ │ └── TransformInterface.php │ │ └── Wsdl.php ├── CliApplication.php ├── Integrations │ ├── AuthorisationInterface.php │ ├── IntegrationInterface.php │ └── Joomla │ │ ├── Authorisation │ │ └── Authorise.php │ │ ├── Joomla.php │ │ ├── Model │ │ ├── Item.php │ │ └── Jlist.php │ │ ├── Strategy │ │ └── Joomla.php │ │ ├── Table │ │ └── Table.php │ │ └── defines.php ├── Layout │ ├── Base.php │ ├── File.php │ ├── Layout.php │ └── LayoutHelper.php ├── Renderer │ ├── Application │ │ ├── Haljson.php │ │ ├── Halxml.php │ │ ├── Json.php │ │ ├── Soapxml.php │ │ └── Xml.php │ ├── Renderer.php │ └── RendererInterface.php ├── Resource │ ├── Resource.php │ ├── ResourceHome.php │ ├── ResourceItem.php │ ├── ResourceLink.php │ └── ResourceList.php ├── Service │ ├── ConfigurationProvider.php │ ├── DatabaseProvider.php │ ├── EventProvider.php │ └── RendererProvider.php ├── Type │ ├── AbstractType.php │ ├── TypeArray.php │ ├── TypeBoolean.php │ ├── TypeDatetime.php │ ├── TypeFile.php │ ├── TypeFloat.php │ ├── TypeFloating.php │ ├── TypeInteger.php │ ├── TypeInterface.php │ ├── TypeJson.php │ ├── TypeNone.php │ ├── TypePosition.php │ ├── TypeState.php │ ├── TypeString.php │ ├── TypeTarget.php │ ├── TypeUrn.php │ └── TypeYnglobal.php ├── Uri │ └── Uri.php ├── WebApplication.php ├── Webservices │ ├── ConfigurationHelper.php │ ├── Create.php │ ├── Delete.php │ ├── Exception │ │ ├── ConfigurationException.php │ │ └── KeyNotFoundException.php │ ├── Factory.php │ ├── Profile.php │ ├── Read.php │ ├── Update.php │ ├── Webservice.php │ ├── WebserviceBase.php │ └── WebserviceHelper.php ├── Xml │ └── XmlHelper.php └── language │ └── en-GB │ └── en-GB.lib_webservices.ini ├── tests ├── _bootstrap.php ├── _data │ └── dump.sql ├── _support │ └── Helper │ │ ├── Acceptance.php │ │ ├── Api.php │ │ ├── Functional.php │ │ └── Unit.php ├── acceptance.suite.dist.yml ├── acceptance │ ├── _bootstrap.php │ ├── administrator │ │ └── ActivateContactWebserviceCept.php │ ├── install │ │ ├── 01-InstallJoomlaCept.php │ │ └── 02-InstallExtensionCept.php │ └── uninstall │ │ └── ZZ-UninstallExtensionCept.php ├── api.suite.dist.yml ├── api │ ├── _bootstrap.php │ └── administrator.contact.1.0.0.Cest.php ├── functional │ └── _bootstrap.php ├── travis-ci-apache.conf └── unit │ └── _bootstrap.php ├── webservices_copy_mandatory.xml └── www ├── htaccess.txt ├── index.php └── media └── webservices └── webservices ├── index.html ├── joomla ├── administrator.contact.1.0.0.php ├── administrator.contact.1.0.0.xml ├── index.html ├── site.categories.1.0.0.php ├── site.categories.1.0.0.xml ├── site.contacts.1.0.0.php ├── site.contacts.1.0.0.xml ├── site.contents.1.0.0.xml ├── site.users.1.0.0.php └── site.users.1.0.0.xml └── upload └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | config.json 2 | 3 | # OSX 4 | .DS_Store 5 | ._* 6 | .Spotlight-V100 7 | .Trashes 8 | 9 | # Windows 10 | Thumbs.db 11 | Desktop.ini 12 | 13 | # PHPStorm 14 | .idea/ 15 | 16 | # Sublime Text 17 | *.sublime* 18 | 19 | # Eclipse 20 | .buildpath 21 | .project 22 | .settings 23 | 24 | # Temp files 25 | *.tmp 26 | *.bak 27 | *.swp 28 | *~.nib 29 | *~ 30 | 31 | # Phing 32 | build.properties 33 | phing-latest.phar 34 | .dist 35 | 36 | # composer 37 | composer.phar 38 | vendor/* 39 | 40 | # Robo 41 | robo.phar 42 | 43 | # Test related files 44 | tests/acceptance.suite.yml 45 | tests/functional.suite.yml 46 | tests/unit.suite.yml 47 | tests/api.suite.yml 48 | tests/*/*Tester.php 49 | tests/joomla-cms3* 50 | tests/_output 51 | selenium-server-standalone.jar 52 | codecept.phar 53 | selenium.log 54 | selenium-errors.log 55 | tests/_support/_generated/* 56 | tests/_output/* 57 | 58 | # Never ignore 59 | !.gitignore 60 | !index.html 61 | !index.php 62 | 63 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | env: TRAVIS_PUBLIC_REPOSITORY=true 3 | php: 4 | - 5.5 5 | - 5.6 6 | - 7.0 7 | matrix: 8 | allow_failures: 9 | - php: 5.6 10 | - php: 7.0 11 | before_script: 12 | - sudo apt-get update -qq 13 | - sudo apt-get install -y --force-yes apache2 libapache2-mod-fastcgi php5-curl php5-mysql php5-intl php5-gd > /dev/null 14 | - sudo mkdir $(pwd)/.run 15 | - sudo cp ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf.default ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf 16 | - sudo sed -e "s,listen = 127.0.0.1:9000,listen = /tmp/php5-fpm.sock,g" --in-place ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf 17 | - sudo sed -e "s,;listen.owner = nobody,listen.owner = $USER,g" --in-place ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf 18 | - sudo sed -e "s,;listen.group = nobody,listen.group = $USER,g" --in-place ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf 19 | - sudo sed -e "s,;listen.mode = 0660,listen.mode = 0666,g" --in-place ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf 20 | - sudo sed -e "s,user = nobody,;user = $USER,g" --in-place ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf 21 | - sudo sed -e "s,group = nobody,;group = $USER,g" --in-place ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf 22 | - cat ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf 23 | - sudo a2enmod rewrite actions fastcgi alias 24 | - echo "cgi.fix_pathinfo = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini 25 | - ~/.phpenv/versions/$(phpenv version-name)/sbin/php-fpm 26 | - sudo cp -f tests/travis-ci-apache.conf /etc/apache2/sites-available/default 27 | - sudo sed -e "s?%TRAVIS_BUILD_DIR%?$(pwd)?g" --in-place /etc/apache2/sites-available/default 28 | - git submodule update --init --recursive 29 | - sudo service apache2 restart 30 | - "export DISPLAY=:99.0" 31 | - "sh -e /etc/init.d/xvfb start" 32 | - sleep 3 # give xvfb some time to start 33 | - sudo apt-get install fluxbox -y --force-yes 34 | - fluxbox & 35 | - sleep 3 # give fluxbox some time to start 36 | - composer install --prefer-dist 37 | 38 | script: 39 | - mv tests/acceptance.suite.dist.yml tests/acceptance.suite.yml 40 | - mv tests/api.suite.dist.yml tests/api.suite.yml 41 | - vendor/bin/robo run:tests 1 42 | -------------------------------------------------------------------------------- /build.properties.dist: -------------------------------------------------------------------------------- 1 | # Properties files are configuration files used by PHING scripts containing: 2 | # key=value 3 | # more info at: https://redweb.atlassian.net/wiki/display/Devportal/Using+PHING+for+packaging+and+testing+an+extension 4 | 5 | # Extension details: 6 | comp.name=webservices 7 | 8 | # Folder to create the extension .zip build package used by extension_packager.xml 9 | package.dir= 10 | 11 | # Testing Joomla site at a localhost folder. Only needed when using build.xml 12 | www.dir= 13 | 14 | # For unit testing. Only needed when using build.xml 15 | www.dirtest= 16 | -------------------------------------------------------------------------------- /cli/joomla.php: -------------------------------------------------------------------------------- 1 | registerServiceProvider(new Joomla\Webservices\Service\ConfigurationProvider) 31 | ->registerServiceProvider(new Joomla\Webservices\Service\DatabaseProvider) 32 | ->registerServiceProvider(new Joomla\Language\Service\LanguageFactoryProvider) 33 | ->registerServiceProvider(new Joomla\Webservices\Service\EventProvider); 34 | 35 | // Set error reporting based on config 36 | $errorReporting = (int) $container->get('config')->get('errorReporting', 0); 37 | error_reporting($errorReporting); 38 | } 39 | catch (\Exception $e) 40 | { 41 | echo 'An error occurred while booting the application: ' . $e->getMessage() . "\n"; 42 | 43 | exit; 44 | } 45 | 46 | // Execute the application 47 | try 48 | { 49 | (new Joomla\Webservices\CliApplication($container))->execute(); 50 | } 51 | catch (\Exception $e) 52 | { 53 | echo 'An error occurred while executing the application: ' . $e->getMessage() . "\n"; 54 | 55 | exit; 56 | } 57 | 58 | -------------------------------------------------------------------------------- /codeception.yml: -------------------------------------------------------------------------------- 1 | actor: Tester 2 | paths: 3 | tests: tests 4 | log: tests/_output 5 | data: tests/_data 6 | support: tests/_support 7 | settings: 8 | bootstrap: _bootstrap.php 9 | colors: true 10 | memory_limit: 1024M 11 | extensions: 12 | enabled: 13 | - Codeception\Extension\RunFailed 14 | -------------------------------------------------------------------------------- /component/admin/Webservices/Controller/AddController.php: -------------------------------------------------------------------------------- 1 | context = \JApplicationHelper::getComponentName() . '.' . $this->getInput()->getCmd('view', $this->defaultView); 45 | } 46 | 47 | /** 48 | * Execute the controller. 49 | * 50 | * @return boolean True on success 51 | * 52 | * @since 2.0 53 | * @throws \RuntimeException 54 | */ 55 | public function execute() 56 | { 57 | // Set up variables to build our classes 58 | $view = $this->defaultView; 59 | $format = $this->getInput()->getCmd('format', 'html'); 60 | 61 | // Register the layout paths for the view 62 | $paths = new \SplPriorityQueue; 63 | 64 | // Add the path for template overrides 65 | $paths->insert(JPATH_THEMES . '/' . $this->getApplication()->getTemplate() . '/html/' . \JApplicationHelper::getComponentName() . '/' . $view, 2); 66 | 67 | // Add the path for the default layouts 68 | $paths->insert(JPATH_BASE . '/components/' . \JApplicationHelper::getComponentName() . '/Webservices/View/' . ucfirst($view) . '/tmpl', 1); 69 | 70 | // Build the class names for the model and view 71 | $viewClass = '\\Webservices\\View\\' . ucfirst($view) . '\\' . ucfirst($view) . ucfirst($format) . 'View'; 72 | $modelClass = '\\Webservices\\Model\\' . ucfirst($view) . 'Model'; 73 | 74 | // Sanity check - Ensure our classes exist 75 | if (!class_exists($viewClass)) 76 | { 77 | // Try to use a default view 78 | $viewClass = '\\Webservices\\View\\Default' . ucfirst($format) . 'View'; 79 | 80 | if (!class_exists($viewClass)) 81 | { 82 | throw new \RuntimeException( 83 | sprintf('The view class for the %1$s view in the %2$s format was not found.', $view, $format), 500 84 | ); 85 | } 86 | } 87 | 88 | if (!class_exists($modelClass)) 89 | { 90 | throw new \RuntimeException(sprintf('The model class for the %s view was not found.', $view), 500); 91 | } 92 | 93 | // Initialize the model class now; need to do it before setting the state to get required data from it 94 | $model = new $modelClass($this->context, null, Helper::createDbo()); 95 | 96 | // Initialize the state for the model 97 | //$model->setState($this->initializeState($model)); 98 | 99 | // Initialize the view class now 100 | $view = new $viewClass($model, $paths); 101 | 102 | // Echo the rendered view for the application 103 | echo $view->render(); 104 | 105 | // Finished! 106 | return true; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /component/admin/Webservices/Controller/ApplyController.php: -------------------------------------------------------------------------------- 1 | setState($this->initializeState($model)); 38 | 39 | $id = $this->getInput()->getUint('id'); 40 | 41 | $data = $this->getInput()->getArray()['jform']; 42 | 43 | if ($model->save($data)) 44 | { 45 | $msg = \JText::_('COM_WEBSERVICES_APPLY_OK'); 46 | } 47 | else 48 | { 49 | $msg = \JText::_('COM_WEBSERVICES_APPLY_ERROR'); 50 | } 51 | 52 | $type = 'message'; 53 | $url = 'index.php?option=com_webservices&task=edit&id=' . $id; 54 | } 55 | catch (\Exception $e) 56 | { 57 | $msg = $e->getMessage(); 58 | $type = 'error'; 59 | } 60 | 61 | $url = isset($this->returnurl) ? $this->returnurl : $url; 62 | 63 | $this->getApplication()->enqueueMessage($msg, $type); 64 | $this->getApplication()->redirect(\JRoute::_($url, false)); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /component/admin/Webservices/Controller/CancelController.php: -------------------------------------------------------------------------------- 1 | getApplication()->enqueueMessage($msg, $type); 33 | $this->getApplication()->redirect(\JRoute::_('index.php?option=com_webservices', false)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /component/admin/Webservices/Controller/EditController.php: -------------------------------------------------------------------------------- 1 | returnurl = 'index.php?option=com_webservices&view=webservices'; 33 | parent::execute(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /component/admin/Webservices/Controller/InstallController.php: -------------------------------------------------------------------------------- 1 | returnurl = 'index.php?option=com_webservices'; 37 | 38 | // Initialize the state for the model 39 | $model->setState($this->initializeState($model)); 40 | 41 | $input = $this->getInput(); 42 | 43 | $webservice = $input->getString('webservice'); 44 | $version = $input->getString('version'); 45 | $folder = $input->getString('folder'); 46 | $client = $input->getString('client'); 47 | 48 | $msg = \JText::_('COM_WEBSERVICES_WEBSERVICES_INSTALLED_WEBSERVICES'); 49 | $type = 'message'; 50 | 51 | try 52 | { 53 | if ($webservice == 'all') 54 | { 55 | // @@ TODO: Fix this 56 | //$this->batchWebservices('install'); 57 | throw new \Exception('Batch installation not implemented yet. Install services one at a time.'); 58 | } 59 | else 60 | { 61 | if ($model->installWebservice($client, $webservice, $version, $folder)) 62 | { 63 | $msg = \JText::_('COM_WEBSERVICES_WEBSERVICES_WEBSERVICE_INSTALLED'); 64 | } 65 | } 66 | } 67 | catch (\Exception $e) 68 | { 69 | $msg = $e->getMessage(); 70 | $type = 'error'; 71 | } 72 | 73 | $this->getApplication()->enqueueMessage($msg, $type); 74 | $this->getApplication()->redirect(\JRoute::_($this->returnurl, false)); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /component/admin/Webservices/Controller/PublishController.php: -------------------------------------------------------------------------------- 1 | input; 37 | 38 | // Get the values 39 | $cid = $input->get('cid', array(), 'array'); 40 | $data = array('publish' => 1, 'unpublish' => 0, 'archive' => 2, 'trash' => -2, 'report' => -3); 41 | $task = $input->get('task'); 42 | $value = \JArrayHelper::getValue($data, $task, 0, 'int'); 43 | 44 | if (empty($cid)) 45 | { 46 | \JLog::add(\JText::_('COM_WEBSERVICES_NO_ITEM_SELECTED'), \JLog::WARNING, 'jerror'); 47 | } 48 | else 49 | { 50 | // Get and initialize the state for the model 51 | $model = new WebserviceModel; 52 | $model->setState($this->initializeState($model)); 53 | 54 | $table = $model->getTable(); 55 | 56 | // Make sure the item ids are integers 57 | \JArrayHelper::toInteger($cid); 58 | 59 | // Publish the items. 60 | try 61 | { 62 | $table->publish($cid, $value, \JFactory::getUser()->id); 63 | 64 | if ($value == 1) 65 | { 66 | $ntext = \JText::plural('COM_WEBSERVICES_N_ITEMS_PUBLISHED', count($cid)); 67 | } 68 | elseif ($value == 0) 69 | { 70 | $ntext = \JText::plural('COM_WEBSERVICES_N_ITEMS_UNPUBLISHED', count($cid)); 71 | } 72 | elseif ($value == 2) 73 | { 74 | $ntext = \JText::plural('COM_WEBSERVICES_N_ITEMS_ARCHIVED', count($cid)); 75 | } 76 | else 77 | { 78 | $ntext = \JText::plural('COM_WEBSERVICES_N_ITEMS_TRASHED', count($cid)); 79 | } 80 | 81 | $type = 'message'; 82 | } 83 | catch (\Exception $e) 84 | { 85 | $type = 'error'; 86 | } 87 | } 88 | 89 | $this->getApplication()->enqueueMessage($ntext, $type); 90 | 91 | $this->returnurl = 'index.php?option=com_webservices&view=webservices'; 92 | parent::execute(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /component/admin/Webservices/Controller/SaveController.php: -------------------------------------------------------------------------------- 1 | returnurl = 'index.php?option=com_webservices&view=webservices'; 33 | parent::execute(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /component/admin/Webservices/Controller/UnpublishController.php: -------------------------------------------------------------------------------- 1 | returnurl = 'index.php?option=com_webservices&view=webservices'; 33 | parent::execute(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /component/admin/Webservices/Layout/operation.php: -------------------------------------------------------------------------------- 1 | 19 |
20 |
21 | sublayout('attributes', $displayData); ?> 22 |
23 | $view, 28 | 'options' => array( 29 | 'operation' => $operation, 30 | 'fieldList' => $fieldList, 31 | 'form' => $form, 32 | ) 33 | ) 34 | ); 35 | ?> 36 | 37 | $view, 41 | 'options' => array( 42 | 'operation' => $operation, 43 | 'form' => $form, 44 | ) 45 | ) 46 | ); ?> 47 |
48 |
49 |
50 | -------------------------------------------------------------------------------- /component/admin/Webservices/Layout/scopes.php: -------------------------------------------------------------------------------- 1 | 25 | 26 |
27 |
28 | $scopes) :?> 29 |
30 |

31 | 32 |

33 | 34 | 35 |
36 | 40 |
41 | 42 |
43 | 44 |
45 |
46 | 47 | 48 |
49 |
50 | -------------------------------------------------------------------------------- /component/admin/Webservices/Model/Fields/componentlist.php: -------------------------------------------------------------------------------- 1 | element); 50 | 51 | if (!isset(static::$cache[$hash])) 52 | { 53 | static::$cache[$hash] = parent::getOptions(); 54 | $lang = JFactory::getLanguage(); 55 | 56 | $options = array(); 57 | $db = JFactory::getDbo(); 58 | $query = $db->getQuery(true) 59 | ->select('*') 60 | ->from('#__extensions') 61 | ->where('type=' . $db->quote('component')); 62 | 63 | // Setup the query 64 | $db->setQuery($query); 65 | 66 | // Return the result 67 | $components = $db->loadObjectList(); 68 | 69 | if (!empty($components)) 70 | { 71 | foreach ($components as $value) 72 | { 73 | $extension = $value->element; 74 | $source = JPATH_ADMINISTRATOR . '/components/' . $extension; 75 | $lang->load($extension . '.sys', JPATH_ADMINISTRATOR, null, false, true) 76 | || $lang->load($extension . '.sys', $source, null, false, true); 77 | $contentElements = ''; 78 | 79 | if ($this->getAttribute('loadContentElements', 'false') == 'true') 80 | { 81 | $contentElementsArray = RTranslationHelper::getContentElements($value->name); 82 | 83 | if (!empty($contentElementsArray)) 84 | { 85 | $contentElements = ' (' . count($contentElementsArray) . ')'; 86 | } 87 | } 88 | 89 | if ($this->getAttribute('showFullName', 'false') == 'true') 90 | { 91 | $title = JText::_($value->name); 92 | } 93 | else 94 | { 95 | $title = $value->name; 96 | } 97 | 98 | $options[] = JHtml::_('select.option', $value->element, $title . $contentElements); 99 | } 100 | 101 | static::$cache[$hash] = array_merge(static::$cache[$hash], $options); 102 | } 103 | } 104 | 105 | $component = JFactory::getApplication()->input->get->getString('component', ''); 106 | 107 | if (!empty($component)) 108 | { 109 | $this->value = $component; 110 | } 111 | 112 | return static::$cache[$hash]; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /component/admin/Webservices/Model/Fields/tablelist.php: -------------------------------------------------------------------------------- 1 | element); 50 | 51 | if (!isset(static::$cache[$hash])) 52 | { 53 | static::$cache[$hash] = parent::getOptions(); 54 | 55 | $db = JFactory::getDbo(); 56 | $tables = $db->getTableList(); 57 | $tablePrefix = $db->getPrefix(); 58 | 59 | if (!empty($tables)) 60 | { 61 | foreach ($tables as $i => $table) 62 | { 63 | // Make sure we get the right tables based on prefix 64 | if (stripos($table, $tablePrefix) !== 0) 65 | { 66 | continue; 67 | } 68 | 69 | $table = substr($table, strlen($tablePrefix)); 70 | $options[] = JHtml::_('select.option', $table, $table); 71 | } 72 | 73 | static::$cache[$hash] = array_merge(static::$cache[$hash], $options); 74 | } 75 | } 76 | 77 | return static::$cache[$hash]; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /component/admin/Webservices/Model/Fields/webservicelist.php: -------------------------------------------------------------------------------- 1 | getWebservices(); 49 | 50 | // Build the field options. 51 | if (!empty($items)) 52 | { 53 | foreach ($items as $item) 54 | { 55 | $options[] = JHtml::_('select.option', $item->identifier, $item->displayName); 56 | } 57 | } 58 | 59 | return array_merge(parent::getOptions(), $options); 60 | } 61 | 62 | /** 63 | * Method to get the list of paths. 64 | * 65 | * @return array An array of path names. 66 | */ 67 | protected function getWebservices() 68 | { 69 | if (empty($this->cache)) 70 | { 71 | try 72 | { 73 | $container = (new Joomla\DI\Container) 74 | ->registerServiceProvider(new Joomla\Webservices\Service\ConfigurationProvider) 75 | ->registerServiceProvider(new Joomla\Webservices\Service\DatabaseProvider); 76 | } 77 | catch (\Exception $e) 78 | { 79 | throw new RuntimeException(JText::sprintf('COM_WEBSERVICES_WEBSERVICE_ERROR_DATABASE_CONNECTION', $e->getMessage()), 500, $e); 80 | } 81 | 82 | $db = $container->get('db'); 83 | 84 | $query = $db->getQuery(true) 85 | ->select('CONCAT_WS(" ", ' . $db->qn('client') . ', ' . $db->qn('name') . ', ' . $db->qn('version') . ') as displayName') 86 | ->select('id as identifier') 87 | ->from('#__webservices') 88 | ->order('client') 89 | ->order('name') 90 | ->order('version'); 91 | 92 | $db->setQuery($query); 93 | 94 | $result = $db->loadObjectList(); 95 | 96 | if (is_array($result)) 97 | { 98 | $this->cache = $result; 99 | } 100 | } 101 | 102 | return $this->cache; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /component/admin/Webservices/Model/Fields/webservicepaths.php: -------------------------------------------------------------------------------- 1 | getPaths(); 48 | 49 | // Build the field options. 50 | if (!empty($items)) 51 | { 52 | foreach ($items as $item) 53 | { 54 | $options[] = JHtml::_('select.option', $item->path, $item->path); 55 | } 56 | } 57 | 58 | return array_merge(parent::getOptions(), $options); 59 | } 60 | 61 | /** 62 | * Method to get the list of paths. 63 | * 64 | * @return array An array of path names. 65 | */ 66 | protected function getPaths() 67 | { 68 | if (empty($this->cache)) 69 | { 70 | try 71 | { 72 | $container = (new Joomla\DI\Container) 73 | ->registerServiceProvider(new Joomla\Webservices\Service\ConfigurationProvider) 74 | ->registerServiceProvider(new Joomla\Webservices\Service\DatabaseProvider); 75 | } 76 | catch (\Exception $e) 77 | { 78 | throw new RuntimeException(JText::sprintf('COM_WEBSERVICES_WEBSERVICE_ERROR_DATABASE_CONNECTION', $e->getMessage()), 500, $e); 79 | } 80 | 81 | $db = $container->get('db'); 82 | 83 | $query = $db->getQuery(true) 84 | ->select('path') 85 | ->from('#__webservices') 86 | ->order('path') 87 | ->group('path'); 88 | 89 | $db->setQuery($query); 90 | 91 | $result = $db->loadObjectList(); 92 | 93 | if (is_array($result)) 94 | { 95 | $this->cache = $result; 96 | } 97 | } 98 | 99 | return $this->cache; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /component/admin/Webservices/Model/Fields/webservicescopes.php: -------------------------------------------------------------------------------- 1 | element); 50 | 51 | try 52 | { 53 | $container = (new Joomla\DI\Container) 54 | ->registerServiceProvider(new Joomla\Webservices\Service\ConfigurationProvider) 55 | ->registerServiceProvider(new Joomla\Language\Service\LanguageFactoryProvider) 56 | ->registerServiceProvider(new Joomla\Webservices\Service\DatabaseProvider); 57 | } 58 | catch (\Exception $e) 59 | { 60 | throw new RuntimeException(JText::sprintf('COM_WEBSERVICES_WEBSERVICE_ERROR_DATABASE_CONNECTION', $e->getMessage()), 500, $e); 61 | } 62 | 63 | /** @var \Joomla\Database\DatabaseDriver $db */ 64 | $db = $container->get('db'); 65 | 66 | /** @var \Joomla\Language\LanguageFactory $languageFactory */ 67 | $languageFactory = $container->get('Joomla\\Language\\LanguageFactory'); 68 | $languageFactory->getLanguage()->load('lib_webservices'); 69 | $text = $languageFactory->getText(); 70 | 71 | if (!isset(static::$cache[$hash])) 72 | { 73 | static::$cache[$hash] = parent::getOptions(); 74 | 75 | $options = \Joomla\Webservices\Webservices\ConfigurationHelper::getWebserviceScopes($text, array(), $db); 76 | 77 | static::$cache[$hash] = array_merge(static::$cache[$hash], $options); 78 | } 79 | 80 | return static::$cache[$hash]; 81 | } 82 | 83 | /** 84 | * Method to get the field input markup for OAuth2 Scope Lists. 85 | * 86 | * @return string The field input markup. 87 | */ 88 | protected function getInput() 89 | { 90 | return JLayoutHelper::render( 91 | 'webservice.scopes', 92 | array( 93 | 'view' => $this, 94 | 'options' => array ( 95 | 'scopes' => $this->getOptions(), 96 | 'id' => $this->id, 97 | 'name' => $this->name, 98 | 'label' => $this->label, 99 | 'value' => $this->value, 100 | ) 101 | ) 102 | ); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /component/admin/Webservices/Model/Forms/filter_webservices.xml: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 11 | 19 | 20 | 21 | 22 | 23 | 31 | 32 | 33 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 56 | 57 |
58 | -------------------------------------------------------------------------------- /component/admin/Webservices/Table/WebserviceTable.php: -------------------------------------------------------------------------------- 1 | _tableName = '#__webservices'; 42 | $this->_tbl_key = 'id'; 43 | 44 | parent::__construct($this->_tableName, $this->_tbl_key, $db); 45 | } 46 | 47 | /** 48 | * Checks that the object is valid and able to be stored. 49 | * 50 | * This method checks that the parent_id is non-zero and exists in the database. 51 | * Note that the root node (parent_id = 0) cannot be manipulated with this class. 52 | * 53 | * @return boolean True if all checks pass. 54 | */ 55 | public function check() 56 | { 57 | // Check if client is not already created with this id. 58 | $client = clone $this; 59 | 60 | $this->client = trim($this->client); 61 | $this->name = trim($this->name); 62 | $this->version = trim($this->version); 63 | 64 | if (empty($this->version)) 65 | { 66 | $this->version = '1.0.0'; 67 | } 68 | else 69 | { 70 | $matches = array(); 71 | 72 | // Major 73 | $versionPattern = '/^(?[0-9]+\.[0-9]+\.[0-9]+)$/'; 74 | 75 | // Match the possible parts of a SemVer 76 | $matched = preg_match( 77 | $versionPattern, 78 | $this->version, 79 | $matches 80 | ); 81 | 82 | // No match, invalid 83 | if (!$matched) 84 | { 85 | $this->setError(\JText::_('COM_WEBSERVICES_WEBSERVICE_VERSION_WRONG_FORMAT')); 86 | 87 | return false; 88 | } 89 | 90 | $this->version = $matches['version']; 91 | } 92 | 93 | if (empty($this->name)) 94 | { 95 | $this->setError(\JText::_('COM_WEBSERVICES_WEBSERVICE_NAME_FIELD_CANNOT_BE_EMPTY')); 96 | 97 | return false; 98 | } 99 | 100 | if (empty($this->client)) 101 | { 102 | $this->setError(\JText::_('COM_WEBSERVICES_WEBSERVICE_CLIENT_FIELD_CANNOT_BE_EMPTY')); 103 | 104 | return false; 105 | } 106 | 107 | if ($client->load(array('client' => $this->client, 'name' => $this->name, 'version' => $this->version)) && $client->id != $this->id) 108 | { 109 | $this->setError(\JText::_('COM_WEBSERVICES_WEBSERVICE_ALREADY_EXISTS')); 110 | 111 | return false; 112 | } 113 | 114 | return true; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /component/admin/Webservices/View/DefaultHtmlView.php: -------------------------------------------------------------------------------- 1 | _output = null; 32 | 33 | $template = \JFactory::getApplication()->getTemplate(); 34 | $layout = $this->getLayout(); 35 | $layoutTemplate = $this->getLayoutTemplate(); 36 | 37 | // Create the template file name based on the layout 38 | $file = isset($tpl) ? $layout . '_' . $tpl : $layout; 39 | 40 | // Clean the file name 41 | $file = preg_replace('/[^A-Z0-9_\.-]/i', '', $file); 42 | $tpl = isset($tpl) ? preg_replace('/[^A-Z0-9_\.-]/i', '', $tpl) : $tpl; 43 | 44 | // Load the language file for the template 45 | $lang = \JFactory::getLanguage(); 46 | $lang->load('tpl_' . $template, JPATH_BASE, null, false, true) 47 | || $lang->load('tpl_' . $template, JPATH_THEMES . "/$template", null, false, true); 48 | 49 | // Change the template folder if alternative layout is in different template 50 | if (isset($layoutTemplate) && $layoutTemplate != '_' && $layoutTemplate != $template) 51 | { 52 | $this->_path['template'] = str_replace($template, $layoutTemplate, $this->_path['template']); 53 | } 54 | 55 | // Load the template script 56 | jimport('joomla.filesystem.path'); 57 | $filetofind = $this->_createFileName('template', array('name' => $file)); 58 | 59 | if (empty($this->paths_arr)) 60 | { 61 | $paths = $this->paths; 62 | 63 | $this->paths_arr = array(); 64 | while($paths->valid()){ 65 | 66 | $this->paths_arr[] = $paths->current(); 67 | 68 | $paths->next(); 69 | } 70 | } 71 | 72 | $this->_template = \JPath::find($this->paths_arr, $filetofind); 73 | 74 | // If alternate layout can't be found, fall back to default layout 75 | if ($this->_template == false) 76 | { 77 | $filetofind = $this->_createFileName('', array('name' => 'default' . (isset($tpl) ? '_' . $tpl : $tpl))); 78 | 79 | $this->_template = \JPath::find($this->paths_arr, $filetofind); 80 | } 81 | 82 | if ($this->_template != false) 83 | { 84 | // Unset so as not to introduce into template scope 85 | unset($tpl); 86 | unset($file); 87 | 88 | // Never allow a 'this' property 89 | if (isset($this->this)) 90 | { 91 | unset($this->this); 92 | } 93 | 94 | // Start capturing output into a buffer 95 | ob_start(); 96 | 97 | // Include the requested template filename in the local scope 98 | // (this will execute the view logic). 99 | include $this->_template; 100 | 101 | // Done with the requested template; get the buffer and 102 | // clear it. 103 | $this->_output = ob_get_contents(); 104 | ob_end_clean(); 105 | 106 | return $this->_output; 107 | } 108 | else 109 | { 110 | throw new \Exception(\JText::sprintf('JLIB_APPLICATION_ERROR_LAYOUTFILE_NOT_FOUND', $file), 500); 111 | } 112 | } 113 | 114 | /** 115 | * Get the layout template. 116 | * 117 | * @return string The layout template name 118 | */ 119 | public function getLayoutTemplate() 120 | { 121 | return $this->_layoutTemplate; 122 | } 123 | 124 | /** 125 | * Create the filename for a resource 126 | * 127 | * @param string $type The resource type to create the filename for 128 | * @param array $parts An associative array of filename information 129 | * 130 | * @return string The filename 131 | * 132 | * @since 12.2 133 | */ 134 | protected function _createFileName($type, $parts = array()) 135 | { 136 | switch ($type) 137 | { 138 | case 'template': 139 | $filename = strtolower($parts['name']) . '.' . $this->_layoutExt; 140 | break; 141 | 142 | default: 143 | $filename = strtolower($parts['name']) . '.php'; 144 | break; 145 | } 146 | 147 | return $filename; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /component/admin/Webservices/View/Webservice/WebserviceHtmlView.php: -------------------------------------------------------------------------------- 1 | model; 83 | 84 | $this->form = $model->getForm(); 85 | $this->state = $model->getState(); 86 | $this->fields = $model->fields; 87 | $this->resources = $model->resources; 88 | $this->formData = $model->formData; 89 | 90 | // Check if option is enabled 91 | try 92 | { 93 | $container = (new \Joomla\DI\Container) 94 | ->registerServiceProvider(new \Joomla\Webservices\Service\ConfigurationProvider); 95 | } 96 | catch (\Exception $e) 97 | { 98 | throw new RuntimeException(JText::sprintf('COM_WEBSERVICES_WEBSERVICE_ERROR_CONFIGURATION', $e->getMessage()), 500, $e); 99 | } 100 | 101 | $config = $container->get("config"); 102 | 103 | if ($config->get('webservices.enable_webservices', 0) == 0) 104 | { 105 | \JFactory::getApplication()->enqueueMessage( 106 | \JText::sprintf( 107 | 'COM_WEBSERVICES_WEBSERVICES_PLUGIN_LABEL_WARNING', 108 | '' . JText::_('COM_WEBSERVICES_CONFIGURE') . '' 109 | ), 110 | 'error'); 111 | } 112 | 113 | $this->canDo = \JHelperContent::getActions('com_webservices'); 114 | $input = \JFactory::getApplication()->input; 115 | $input->set('hidemainmenu', true); 116 | 117 | $this->addToolbar(); 118 | 119 | return parent::render(); 120 | } 121 | 122 | /** 123 | * Get the view title. 124 | * 125 | * @return string The view title. 126 | */ 127 | public function getTitle() 128 | { 129 | return \JText::_('COM_WEBSERVICES_WEBSERVICE_TITLE'); 130 | } 131 | 132 | /** 133 | * Add the page title and toolbar. 134 | * 135 | * @return void 136 | * 137 | * @since 1.0 138 | */ 139 | protected function addToolbar() 140 | { 141 | $user = \JFactory::getUser(); 142 | $isNew = isset($this->item->id) ? ($this->item->id == 0) : true; 143 | 144 | // Prepare the toolbar. 145 | \JToolbarHelper::title( 146 | $this->getTitle(), 147 | 'folder ' . ($isNew ? 'add' : 'edit') 148 | ); 149 | 150 | // For new records, check the create permission. 151 | if ($user->authorise('core.admin', 'com_webservices')) 152 | { 153 | \JToolbarHelper::apply('apply'); 154 | \JToolbarHelper::save('save'); 155 | \JToolbarHelper::save2new('save2new'); 156 | } 157 | 158 | if (empty($this->item->id)) 159 | { 160 | \JToolbarHelper::cancel('cancel'); 161 | } 162 | else 163 | { 164 | \JToolbarHelper::cancel('cancel', 'JTOOLBAR_CLOSE'); 165 | } 166 | 167 | \JToolbarHelper::divider(); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /component/admin/Webservices/View/Webservice/tmpl/default_create.php: -------------------------------------------------------------------------------- 1 | $this, 15 | 'options' => array( 16 | 'operation' => 'create', 17 | 'form' => $this->form, 18 | 'tabActive' => ' active in ', 19 | 'fieldList' => array('defaultValue', 'isRequiredField', 'isPrimaryField'), 20 | ) 21 | ), 22 | JPATH_COMPONENT_ADMINISTRATOR.'/Webservices/Layout' 23 | ); 24 | -------------------------------------------------------------------------------- /component/admin/Webservices/View/Webservice/tmpl/default_delete.php: -------------------------------------------------------------------------------- 1 | $this, 15 | 'options' => array( 16 | 'operation' => 'delete', 17 | 'form' => $this->form, 18 | 'tabActive' => ' active in ', 19 | 'fieldList' => array('defaultValue', 'isRequiredField', 'isPrimaryField'), 20 | ) 21 | ), 22 | JPATH_COMPONENT_ADMINISTRATOR.'/Webservices/Layout' 23 | ); 24 | -------------------------------------------------------------------------------- /component/admin/Webservices/View/Webservice/tmpl/default_documentation.php: -------------------------------------------------------------------------------- 1 | 12 |
13 |

14 |
15 |
16 | form->getLabel('authorizationNeeded', 'documentation'); ?> 17 |
18 |
19 | form->getInput('authorizationNeeded', 'documentation'); ?> 20 |
21 |
22 |
23 |
24 | form->getLabel('source', 'documentation'); ?> 25 |
26 |
27 | form->getInput('source', 'documentation'); ?> 28 |
29 |
30 |
31 |
32 | form->getLabel('url', 'documentation'); ?> 33 |
34 |
35 | form->getInput('url', 'documentation'); ?> 36 |
37 |
38 |
39 |
40 | form->getLabel('description', 'documentation'); ?> 41 |
42 |
43 | form->getInput('description', 'documentation'); ?> 44 |
45 |
46 | 47 | form->getInput('isEnabled', 'documentation'); ?> 48 |
49 | -------------------------------------------------------------------------------- /component/admin/Webservices/View/Webservice/tmpl/default_main.php: -------------------------------------------------------------------------------- 1 | 12 |
13 |

14 |
15 |
16 | form->getLabel('client', 'main'); ?> 17 |
18 |
19 | form->getInput('client', 'main'); ?> 20 |
21 |
22 |
23 |
24 | form->getLabel('name', 'main'); ?> 25 |
26 |
27 | form->getInput('name', 'main'); ?> 28 |
29 |
30 |
31 |
32 | form->getLabel('version', 'main'); ?> 33 |
34 |
35 | form->getInput('version', 'main'); ?> 36 |
37 |
38 |
39 |
40 | form->getLabel('path', 'main'); ?> 41 |
42 |
43 | 44 | // 45 | 46 | form->getInput('path', 'main'); ?> 47 | 48 | /form->getValue('xmlFile', 'main'); ?> 49 | 50 |
51 |
52 | 53 |
54 |
55 | form->getLabel('authorizationAssetName', 'main'); ?> 56 |
57 |
58 | form->getInput('authorizationAssetName', 'main'); ?> 59 |
60 |
61 |
62 |
63 | form->getLabel('title', 'main'); ?> 64 |
65 |
66 | form->getInput('title', 'main'); ?> 67 |
68 |
69 |
70 |
71 | form->getLabel('author', 'main'); ?> 72 |
73 |
74 | form->getInput('author', 'main'); ?> 75 |
76 |
77 |
78 |
79 | form->getLabel('copyright', 'main'); ?> 80 |
81 |
82 | form->getInput('copyright', 'main'); ?> 83 |
84 |
85 |
86 |
87 | form->getLabel('state', 'main'); ?> 88 |
89 |
90 | form->getInput('state', 'main'); ?> 91 |
92 |
93 |
94 |
95 | form->getLabel('description', 'main'); ?> 96 |
97 |
98 | form->getInput('description', 'main'); ?> 99 |
100 |
101 |
102 | -------------------------------------------------------------------------------- /component/admin/Webservices/View/Webservice/tmpl/default_read.php: -------------------------------------------------------------------------------- 1 | 13 |
14 | 26 |
27 |
28 | formData as $operation => $operationData): ?> 29 | $this, 42 | 'options' => array( 43 | 'operation' => $operation, 44 | 'form' => $this->form, 45 | 'tabActive' => $firstContentActive ? ' active in ' : '', 46 | 'fieldList' => $fieldList, 47 | ) 48 | ), 49 | JPATH_COMPONENT_ADMINISTRATOR.'/Webservices/Layout' 50 | ); 51 | 52 | $firstContentActive = false; 53 | endif; 54 | ?> 55 | 56 |
57 | -------------------------------------------------------------------------------- /component/admin/Webservices/View/Webservice/tmpl/default_task.php: -------------------------------------------------------------------------------- 1 | 13 |
14 |
15 |
16 |
17 | 19 | 20 | 24 | 25 |
26 |
27 |
28 |
29 |
30 | 42 |
43 |
44 | formData as $operation => $operationData): ?> 45 | $this, 51 | 'options' => array( 52 | 'operation' => $operation, 53 | 'form' => $this->form, 54 | 'tabActive' => $firstContentActive ? ' active in ' : '', 55 | 'fieldList' => array('defaultValue', 'isRequiredField', 'isPrimaryField'), 56 | ) 57 | ), 58 | JPATH_COMPONENT_ADMINISTRATOR.'/Webservices/Layout' 59 | ); 60 | 61 | $firstContentActive = false; 62 | endif; 63 | ?> 64 | 65 |
66 | -------------------------------------------------------------------------------- /component/admin/Webservices/View/Webservice/tmpl/default_update.php: -------------------------------------------------------------------------------- 1 | $this, 15 | 'options' => array( 16 | 'operation' => 'update', 17 | 'form' => $this->form, 18 | 'tabActive' => ' active in ', 19 | 'fieldList' => array('defaultValue', 'isRequiredField', 'isPrimaryField'), 20 | ) 21 | ), 22 | JPATH_COMPONENT_ADMINISTRATOR.'/Webservices/Layout' 23 | ); 24 | -------------------------------------------------------------------------------- /component/admin/access.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | -------------------------------------------------------------------------------- /component/admin/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
7 | 8 | 15 | 16 |
17 | 18 |
22 | 23 | 30 |
31 | 32 |
33 | -------------------------------------------------------------------------------- /component/admin/language/en-GB/en-GB.com_webservices.sys.ini: -------------------------------------------------------------------------------- 1 | ; WEBSERVICES 2 | ; Copyright (C) 2008 - 2015 redCOMPONENT.com. All rights reserved. 3 | ; License http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL, see LICENSE.php 4 | ; Note : All ini files need to be saved as UTF-8 5 | 6 | COM_WEBSERVICES="Webservices" 7 | COM_WEBSERVICES_DESC="Webservices for Joomla" 8 | 9 | COM_WEBSERVICES_WEBSERVICES="Webservices" 10 | -------------------------------------------------------------------------------- /component/admin/sql/install/mysql/install.sql: -------------------------------------------------------------------------------- 1 | SET FOREIGN_KEY_CHECKS = 0; 2 | 3 | -- ----------------------------------------------------- 4 | -- Table `#__webservices` 5 | -- ----------------------------------------------------- 6 | CREATE TABLE IF NOT EXISTS `#__webservices` ( 7 | `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, 8 | `name` VARCHAR(255) NOT NULL DEFAULT '', 9 | `version` VARCHAR(5) NOT NULL DEFAULT '1.0.0', 10 | `title` VARCHAR(255) NOT NULL DEFAULT '', 11 | `path` VARCHAR(255) NOT NULL DEFAULT '', 12 | `xmlFile` VARCHAR(255) NOT NULL DEFAULT '', 13 | `xmlHashed` VARCHAR(32) NOT NULL DEFAULT '', 14 | `operations` TEXT NULL, 15 | `scopes` TEXT NULL, 16 | `client` VARCHAR(15) NOT NULL DEFAULT 'site', 17 | `published` TINYINT(1) NOT NULL DEFAULT '1', 18 | `checked_out` INT(11) NULL DEFAULT NULL, 19 | `checked_out_time` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', 20 | `created_by` INT(11) NULL DEFAULT NULL, 21 | `created_date` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', 22 | `modified_by` INT(11) NULL DEFAULT NULL, 23 | `modified_date` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', 24 | PRIMARY KEY (`id`), 25 | KEY `idx_webservice_keys` (`client`, `name`, `version`) 26 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 27 | 28 | SET FOREIGN_KEY_CHECKS = 1; 29 | -------------------------------------------------------------------------------- /component/admin/sql/install/mysql/uninstall.sql: -------------------------------------------------------------------------------- 1 | SET FOREIGN_KEY_CHECKS = 0; 2 | 3 | DROP TABLE IF EXISTS `#__webservices`; 4 | 5 | SET FOREIGN_KEY_CHECKS = 1; 6 | -------------------------------------------------------------------------------- /component/admin/sql/updates/mysql/1.0.0.sql: -------------------------------------------------------------------------------- 1 | -- Register initial version 2 | -------------------------------------------------------------------------------- /component/admin/webservices.php: -------------------------------------------------------------------------------- 1 | authorise('core.manage', 'com_webservices')) 13 | { 14 | return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); 15 | } 16 | 17 | $applicationPath = realpath(JPATH_ROOT); 18 | $composerPath = $applicationPath . '/vendor/autoload.php'; 19 | define ('JPATH_API', $applicationPath); 20 | require_once($composerPath); 21 | 22 | // Application reference 23 | $app = JFactory::getApplication(); 24 | 25 | // Register the component namespace to the autoloader 26 | JLoader::registerNamespace('Webservices', __DIR__); 27 | 28 | // Build the controller class name based on task 29 | $task = $app->input->getCmd('task', 'display'); 30 | 31 | // If $task is an empty string, apply our default since JInput might not 32 | if ($task === '') 33 | { 34 | $task = 'display'; 35 | } 36 | $class = '\\Webservices\\Controller\\' . ucfirst(strtolower($task)) . 'Controller'; 37 | 38 | // Instantiate and execute the controller 39 | $controller = new $class($app->input, $app); 40 | $controller->execute(); 41 | -------------------------------------------------------------------------------- /component/media/webservices/js/component.min.js: -------------------------------------------------------------------------------- 1 | (function(a){a.fn.extend({enterSubmits:function(){var b=a(this);b.keydown(function(c){if(c.which===13){b.closest("form").submit()}});return a(this)}});a(document).ready(function(){a(".js-enter-submits").enterSubmits();a("*[rel=tooltip]").tooltip({animation:true,html:true});rRadioGroupButtonsSet();rRadioGroupButtonsEvent();if(typeof Joomla=="object"){Joomla.submitform=function(b,c){if(typeof(c)==="undefined"){c=document.getElementById("adminForm")}if(typeof(b)!=="undefined"&&b!==""){c.task.value=b}if(typeof c.onsubmit=="function"){c.onsubmit()}if(typeof c.fireEvent=="function"){c.fireEvent("submit")}c.submit()}}});a('select[class^="chzn-color"], select[class*=" chzn-color"]').on("liszt:ready",function(){var b=a(this);var d=this.className.replace(/^.(chzn-color[a-z0-9-_]*)$.*/,"\1");var c=b.next(".chzn-container").find(".chzn-single");c.addClass(d).attr("rel","value_"+b.val());b.on("change click",function(){c.attr("rel","value_"+b.val())})})})(jQuery);function rRadioGroupButtonsSet(a){a=typeof(a)!="undefined"?a:"";jQuery(a+" .radio.btn-group label").removeClass("btn").removeClass("btn-default").addClass("btn").addClass("btn-default");jQuery(a+" .btn-group label:not(.active)").click(function(){var c=jQuery(this);var b=jQuery("#"+c.attr("for"));if(!b.prop("checked")){c.closest(".btn-group").find("label").removeClass("active btn-success btn-danger btn-primary");if(b.val()==""){c.addClass("active btn-primary")}else{if(b.val()==0){c.addClass("active btn-danger")}else{c.addClass("active btn-success")}}b.prop("checked",true)}})}function rRadioGroupButtonsEvent(a){a=typeof(a)!="undefined"?a:"";jQuery(a+" .btn-group input[checked=checked]").each(function(){if(jQuery(this).val()==""){jQuery("label[for="+jQuery(this).attr("id")+"]").addClass("active btn-primary")}else{if(jQuery(this).val()==0){jQuery("label[for="+jQuery(this).attr("id")+"]").addClass("active btn-danger")}else{jQuery("label[for="+jQuery(this).attr("id")+"]").addClass("active btn-success")}}})}function listItemTaskForm(g,b,d){d=document.getElementById(d);if(typeof(d)==="undefined"){d=document.getElementById("adminForm")}var a=d[g];if(a){for(var c=0;true;c++){var e=d["cb"+c];if(!e){break}e.checked=false}a.checked=true;d.boxchecked.value=1;Joomla.submitform(b,d)}return false}; -------------------------------------------------------------------------------- /component/webservices.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | COM_WEBSERVICES 4 | April 2015 5 | redCOMPONENT 6 | email@redcomponent.com 7 | www.redcomponent.com 8 | Copyright (C) 2008 - 2015 redCOMPONENT.com. All rights reserved. 9 | GNU General Public License version 2 or later, see LICENSE. 10 | 1.0.0 11 | COM_WEBSERVICES_DESC 12 | 13 | 14 | 15 | sql/install/mysql/install.sql 16 | 17 | 18 | 19 | 20 | sql/install/mysql/uninstall.sql 21 | 22 | 23 | 24 | 25 | sql/updates/mysql 26 | 27 | 28 | 29 | 30 | 31 | language 32 | sql 33 | Webservices 34 | access.xml 35 | webservices.php 36 | 37 | 38 | en-GB/en-GB.com_webservices.ini 39 | en-GB/en-GB.com_webservices.sys.ini 40 | 41 | COM_WEBSERVICES 42 | 43 | 44 | 45 | 46 | js 47 | 48 | 49 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "joomla-projects/webservices", 3 | "type": "joomla-package", 4 | "description": "Joomla Webservices Application", 5 | "keywords": ["joomla", "cms", "webservices"], 6 | "homepage": "https://github.com/joomla-projects/webservices", 7 | "license": "GPL-2.0+", 8 | "require": { 9 | "php": ">=5.3.10", 10 | "joomla/application": "~1.4", 11 | "joomla/database": "~1.2", 12 | "joomla/input": "~1.2", 13 | "joomla/filter": "~1.1", 14 | "joomla/event": "2.*@dev", 15 | "joomla/uri": "~1.1", 16 | "joomla/filesystem": "~1.2", 17 | "joomla/authentication": "^1.1.1", 18 | "joomla/registry": "~1.4", 19 | "joomla/di": "~1.3", 20 | "joomla/utilities": "~1.3", 21 | "joomla/date": "2.*@dev", 22 | "joomla/language": "2.*@dev", 23 | "psr/log": "~1.0", 24 | "willdurand/Negotiation": "^2.0", 25 | "joomla/router": "dev-2.0-dev" 26 | }, 27 | "require-dev": { 28 | "codeception/codeception": "~2.1", 29 | "joomla-projects/joomla-browser": "dev-develop", 30 | "codegyre/robo": "dev-master", 31 | "flow/jsonpath": "dev-master", 32 | "phing/phing": "~2", 33 | "joomla-projects/robo": "dev-master", 34 | "joomla-projects/selenium-server-standalone": "v2.47.1", 35 | "cloudinary/cloudinary_php": "1.1.1" 36 | }, 37 | "autoload": { 38 | "psr-4": { 39 | "Joomla\\Webservices\\": "src/" 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /config.dist.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "driver" : "mysqli", 4 | "host" : "localhost", 5 | "user" : "root", 6 | "password" : "", 7 | "database" : "test_webservices", 8 | "prefix" : "jos_", 9 | "debug" : false 10 | }, 11 | "webservices": { 12 | "enable_webservices" : 1, 13 | "webservices_default_page_authorization": 0, 14 | "webservices_permission_check" : 1, 15 | "debug_webservices" : 0, 16 | "enable_soap" : 1, 17 | "content_types": [ 18 | "application/hal+json", 19 | "application/hal+xml", 20 | "application/json", 21 | "application/soap+xml", 22 | "application/xml" 23 | ], 24 | "routes": "/routes.json" 25 | }, 26 | "language" : { 27 | "basedir" : "", 28 | "default" : "en-GB" 29 | }, 30 | "errorReporting": -1 31 | } 32 | -------------------------------------------------------------------------------- /extension_packager.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 109 | 110 | 111 | 112 | 113 | 114 | 118 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /plugins/authentication/redcore_oauth2/language/en-GB/en-GB.plg_authentication_redcore_oauth2.ini: -------------------------------------------------------------------------------- 1 | ; webservices 2 | ; Copyright (C) 2008 - 2015 redCOMPONENT.com. All rights reserved. 3 | ; License http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL, see LICENSE.php 4 | ; Note : All ini files need to be saved as UTF-8 5 | 6 | PLG_AUTHENTICATION_REDCORE_OAUTH2="Webservices - Redcore OAuth2 plugin" 7 | PLG_AUTHENTICATION_REDCORE_OAUTH2_XML_DESCRIPTION="Plugin for authorization over redCORE OAuth2 server" 8 | 9 | PLG_AUTHENTICATION_REDCORE_OAUTH2_OAUTH2_SERVER_IS_NOT_ACTIVE="OAuth2 Server is not active. Cannot perform authorization." 10 | PLG_AUTHENTICATION_REDCORE_OAUTH2_OAUTH2_SERVER_ERROR="Error ir OAuth2 check: %s" 11 | -------------------------------------------------------------------------------- /plugins/authentication/redcore_oauth2/language/en-GB/en-GB.plg_authentication_redcore_oauth2.sys.ini: -------------------------------------------------------------------------------- 1 | ; Webservices 2 | ; Copyright (C) 2008 - 2015 redCOMPONENT.com. All rights reserved. 3 | ; License http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL, see LICENSE.php 4 | ; Note : All ini files need to be saved as UTF-8 5 | 6 | PLG_AUTHENTICATION_REDCORE_OAUTH2="Webservices - Redcore OAuth2 plugin" 7 | PLG_AUTHENTICATION_REDCORE_OAUTH2_XML_DESCRIPTION="Plugin for authorization over redCORE OAuth2 server" 8 | -------------------------------------------------------------------------------- /plugins/authentication/redcore_oauth2/redcore_oauth2.php: -------------------------------------------------------------------------------- 1 | type = 'redcore_oauth2'; 33 | $scopes = !empty($options['scopes']) ? $options['scopes'] : array(); 34 | $format = !empty($options['format']) ? $options['format'] : 'json'; 35 | 36 | // Check if redCORE OAuth2 server is installed 37 | if (class_exists('RApiOauth2Helper')) 38 | { 39 | /** @var $oauth2Response OAuth2\Response */ 40 | $oauth2Response = RApiOauth2Helper::verifyResourceRequest($scopes); 41 | 42 | if ($oauth2Response instanceof OAuth2\Response) 43 | { 44 | if (!$oauth2Response->isSuccessful()) 45 | { 46 | $response->status = JAuthentication::STATUS_FAILURE; 47 | $response->error_message = JText::sprintf('PLG_AUTHENTICATION_REDCORE_OAUTH2_OAUTH2_SERVER_ERROR', $oauth2Response->getResponseBody($format)); 48 | 49 | return false; 50 | } 51 | } 52 | elseif ($oauth2Response === false) 53 | { 54 | $response->status = JAuthentication::STATUS_FAILURE; 55 | $response->error_message = JText::_('PLG_AUTHENTICATION_REDCORE_OAUTH2_OAUTH2_SERVER_IS_NOT_ACTIVE'); 56 | 57 | return false; 58 | } 59 | else 60 | { 61 | $oauth2Response = json_decode($oauth2Response); 62 | 63 | if (!empty($oauth2Response->user_id)) 64 | { 65 | $user = JFactory::getUser($oauth2Response->user_id); 66 | 67 | // Load the JUser class on application for this client 68 | JFactory::getApplication()->loadIdentity($user); 69 | JFactory::getSession()->set('user', $user); 70 | 71 | // Bring this in line with the rest of the system 72 | $response->email = $user->email; 73 | $response->fullname = $user->name; 74 | 75 | if (JFactory::getApplication()->isAdmin()) 76 | { 77 | $response->language = $user->getParam('admin_language'); 78 | } 79 | else 80 | { 81 | $response->language = $user->getParam('language'); 82 | } 83 | 84 | $response->status = JAuthentication::STATUS_SUCCESS; 85 | $response->error_message = ''; 86 | 87 | return true; 88 | } 89 | } 90 | } 91 | 92 | return false; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /plugins/authentication/redcore_oauth2/redcore_oauth2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | PLG_AUTHENTICATION_REDCORE_OAUTH2 4 | redCOMPONENT 5 | April 2015 6 | Copyright (C) 2008 - 2015 redCOMPONENT.com. All rights reserved. 7 | GNU General Public License version 2 or later; see LICENSE.txt 8 | email@redcomponent.com 9 | www.redcomponent.com 10 | 1.0.0 11 | PLG_AUTHENTICATION_REDCORE_OAUTH2_XML_DESCRIPTION 12 | 13 | 14 | redcore_oauth2.php 15 | 16 | 17 | 18 | en-GB/en-GB.plg_authentication_redcore_oauth2.ini 19 | en-GB/en-GB.plg_authentication_redcore_oauth2.sys.ini 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /routes.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "contents", 4 | "description": "API contents (home) page", 5 | "style": "rest", 6 | "routes": { 7 | "/": ["GET"] 8 | } 9 | }, 10 | { 11 | "name": "categories", 12 | "description": "Categories collection and individual categories", 13 | "style": "rest", 14 | "routes": { 15 | "/categories": ["GET","POST"], 16 | "/categories/:id/:resource": ["GET"], 17 | "/categories/:id": ["GET","PUT","PATCH","DELETE"] 18 | }, 19 | "regex": { 20 | "id": "\\d+", 21 | "resource": "contacts" 22 | } 23 | }, 24 | { 25 | "name": "contacts", 26 | "description": "Contacts collection and individual contacts", 27 | "style": "rest", 28 | "routes": { 29 | "/contacts": ["GET","POST"], 30 | "/contacts/:id/:resource": ["GET"], 31 | "/contacts/:id": ["GET","PUT","PATCH","DELETE"] 32 | }, 33 | "regex": { 34 | "id": "\\d+", 35 | "resource": "categories|users" 36 | } 37 | }, 38 | { 39 | "name": "users", 40 | "description": "Users collection and individual users", 41 | "style": "rest", 42 | "routes": { 43 | "/users": ["GET","POST"], 44 | "/users/:id": ["GET","PUT","PATCH","DELETE"] 45 | }, 46 | "regex": { 47 | "id": "\\d+" 48 | } 49 | } 50 | ] 51 | -------------------------------------------------------------------------------- /src/Api/ApiInterface.php: -------------------------------------------------------------------------------- 1 | element->addAttribute('type', 'tns:' . $elementName . '_' . $field['name']); 48 | 49 | if (!empty($extraFields)) 50 | { 51 | SoapHelper::addElementFields($extraFields, $typeSchema, $elementName . '_' . $field['name'], true); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Api/Soap/Transform/TransformArrayRequired.php: -------------------------------------------------------------------------------- 1 | element->addAttribute('type', 'tns:' . $elementName . '_' . $field['name']); 48 | 49 | if (!empty($extraFields)) 50 | { 51 | SoapHelper::addElementFields($extraFields, $typeSchema, $elementName . '_' . $field['name']); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Api/Soap/Transform/TransformBase.php: -------------------------------------------------------------------------------- 1 | element)) 71 | { 72 | $this->element = $sequence->addChild('element', null, 'http://www.w3.org/2001/XMLSchema'); 73 | } 74 | 75 | if (!isset($this->element['minOccurs'])) 76 | { 77 | $this->element->addAttribute( 78 | 'minOccurs', 79 | (($validateOptional && XmlHelper::isAttributeTrue($field, 'isRequiredField') || !$validateOptional) ? '1' : '0') 80 | ); 81 | } 82 | 83 | if (!isset($this->element['maxOccurs'])) 84 | { 85 | $this->element->addAttribute('maxOccurs', XmlHelper::attributeToString($field, 'maxOccurs', 1)); 86 | } 87 | 88 | if (!isset($this->element['name']) && isset($field['name'])) 89 | { 90 | $this->element->addAttribute('name', $field['name']); 91 | } 92 | 93 | if ($this->type != '') 94 | { 95 | $this->element->addAttribute('type', $this->type); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Api/Soap/Transform/TransformBoolean.php: -------------------------------------------------------------------------------- 1 | defaultValue = date('Y-m-d h:i:s'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Api/Soap/Transform/TransformFloat.php: -------------------------------------------------------------------------------- 1 | user = \JUser::getInstance($id); 36 | } 37 | 38 | /** 39 | * Authorise the user in the class to perform the action 40 | * 41 | * @param string $action The action to check the user has permission to do 42 | * @param mixed $asset The asset the action is to performed on (either a string or an integer) 43 | * 44 | * @return mixed 45 | */ 46 | public function authorise($action, $asset) 47 | { 48 | return $this->user->authorise($action, $asset); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Integrations/Joomla/Table/Table.php: -------------------------------------------------------------------------------- 1 | _tableName = $table; 38 | 39 | if (is_array($key)) 40 | { 41 | $this->_tbl_keys = $key; 42 | $this->_tbl_key = $key; 43 | $this->_tableKey = $key[key($key)]; 44 | } 45 | else 46 | { 47 | $this->_tbl_key = $key; 48 | $this->_tableKey = $key; 49 | } 50 | 51 | // Set all columns from table as properties 52 | $columns = array(); 53 | $dbColumns = $db->getTableColumns('#__' . $table, false); 54 | 55 | if (count($dbColumns) > 0) 56 | { 57 | foreach ($dbColumns as $columnKey => $columnValue) 58 | { 59 | $columns[$columnValue->Field] = $columnValue->Default; 60 | } 61 | 62 | $this->setProperties($columns); 63 | } 64 | 65 | $table = '#__' . str_replace('#__', '', $table); 66 | 67 | parent::__construct($table, $key, $db); 68 | } 69 | 70 | /** 71 | * Method to get the primary key field name for the table. 72 | * 73 | * @param boolean $multiple True to return all primary keys (as an array) or false to return just the first one (as a string). 74 | * 75 | * @return mixed Array of primary key field names or string containing the first primary key field. 76 | * 77 | * @link https://docs.joomla.org/JTable/getKeyName 78 | * @since 11.1 79 | */ 80 | public function getKeyName($multiple = false) 81 | { 82 | // Count the number of keys 83 | if (count($this->_tbl_keys)) 84 | { 85 | if (count($this->_tbl_keys) > 1) 86 | { 87 | // If we want multiple keys, return the raw array. 88 | return $this->_tbl_keys; 89 | } 90 | else 91 | { 92 | // If we want the standard method, just return the first key. 93 | return $this->_tbl_keys[0]; 94 | } 95 | } 96 | 97 | return ''; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/Integrations/Joomla/defines.php: -------------------------------------------------------------------------------- 1 | options = $options; 53 | } 54 | // Received array 55 | elseif (is_array($options)) 56 | { 57 | $this->options = new Registry($options); 58 | } 59 | else 60 | { 61 | $this->options = new Registry; 62 | } 63 | 64 | return $this; 65 | } 66 | 67 | /** 68 | * Get the options 69 | * 70 | * @return Registry Object with the options 71 | * 72 | * @since 3.2 73 | */ 74 | public function getOptions() 75 | { 76 | // Always return a Registry instance 77 | if (!($this->options instanceof Registry)) 78 | { 79 | $this->resetOptions(); 80 | } 81 | 82 | return $this->options; 83 | } 84 | 85 | /** 86 | * Function to empty all the options 87 | * 88 | * @return JLayoutBase Instance of $this to allow chaining. 89 | * 90 | * @since 3.2 91 | */ 92 | public function resetOptions() 93 | { 94 | return $this->setOptions(null); 95 | } 96 | 97 | /** 98 | * Method to escape output. 99 | * 100 | * @param string $output The output to escape. 101 | * 102 | * @return string The escaped output. 103 | * 104 | * @since 3.0 105 | */ 106 | public function escape($output) 107 | { 108 | return htmlspecialchars($output, ENT_COMPAT, 'UTF-8'); 109 | } 110 | 111 | /** 112 | * Get the debug messages array 113 | * 114 | * @return array 115 | * 116 | * @since 3.2 117 | */ 118 | public function getDebugMessages() 119 | { 120 | return $this->debugMessages; 121 | } 122 | 123 | /** 124 | * Method to render the layout. 125 | * 126 | * @param object $displayData Object which properties are used inside the layout file to build displayed output 127 | * 128 | * @return string The necessary HTML to display the layout 129 | * 130 | * @since 3.0 131 | */ 132 | public function render($displayData) 133 | { 134 | return ''; 135 | } 136 | 137 | /** 138 | * Render the list of debug messages 139 | * 140 | * @return string Output text/HTML code 141 | * 142 | * @since 3.2 143 | */ 144 | public function renderDebugMessages() 145 | { 146 | return implode($this->debugMessages, "\n"); 147 | } 148 | 149 | /** 150 | * Add a debug message to the debug messages array 151 | * 152 | * @param string $message Message to save 153 | * 154 | * @return void 155 | * 156 | * @since 3.2 157 | */ 158 | public function addDebugMessage($message) 159 | { 160 | $this->debugMessages[] = $message; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/Layout/Layout.php: -------------------------------------------------------------------------------- 1 | render($displayData); 49 | 50 | return $renderedLayout; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Renderer/Application/Json.php: -------------------------------------------------------------------------------- 1 | setMimeEncoding('application/json', false); 44 | 45 | // Set document type. 46 | $this->setType('json'); 47 | } 48 | 49 | /** 50 | * Render a representation of a ResourceLink object. 51 | * 52 | * Adds an HTTP Link header to the application header buffer. 53 | * 54 | * @param Resource $resource A resource item object. 55 | * 56 | * @return void 57 | * 58 | * @see https://tools.ietf.org/html/rfc5988 59 | */ 60 | public function renderResourceLink(Resource $resource) 61 | { 62 | $linkText = '<' . $resource->getHref() . '>;' 63 | . ' rel="' . $resource->getRel() . '"' 64 | . ($resource->getTitle() != '' ? ' title="' . $resource->getTitle() . '"' : '') 65 | . ($resource->getTemplated() ? ' templated="true"' : ''); 66 | 67 | $this->app->setHeader('Link', $linkText, false); 68 | } 69 | 70 | /** 71 | * Render a representation of a ResourceList object. 72 | * 73 | * @param Resource $resource A resource list object. 74 | * 75 | * @return A representation of the object. 76 | */ 77 | public function renderResourceList(Resource $resource) 78 | { 79 | $properties = array(); 80 | $data = $resource->getData(); 81 | 82 | // Iterate through the links and add them as headers. 83 | foreach ($resource->getLinks() as $rel => $link) 84 | { 85 | // Drop first and previous page links on first page. 86 | if ($data['page'] == 1) 87 | { 88 | if ($rel == 'first' || $rel == 'previous') 89 | { 90 | continue; 91 | } 92 | } 93 | 94 | // Drop last and next page links on last page. 95 | if ($data['page'] == $data['totalPages']) 96 | { 97 | if ($rel == 'last' || $rel == 'next') 98 | { 99 | continue; 100 | } 101 | } 102 | 103 | // Add link to _links element. 104 | if ($link instanceof Resource) 105 | { 106 | $this->renderResourceLink($link); 107 | 108 | continue; 109 | } 110 | 111 | // An array of Link resources. 112 | foreach ($link as $linkResource) 113 | { 114 | $this->renderResourceLink($linkResource); 115 | } 116 | } 117 | 118 | // Iterate through the data properties and add them to the top-level array. 119 | foreach ($resource->getData() as $name => $property) 120 | { 121 | $properties[$name] = $property; 122 | } 123 | 124 | // Iterate through the embedded resources and add them to the _embedded element. 125 | foreach ($resource->getEmbedded() as $rel => $embedded) 126 | { 127 | foreach ($embedded as $item) 128 | { 129 | if ($item instanceof ResourceItem) 130 | { 131 | $properties['_embedded'][$rel][] = json_decode($this->render($item)); 132 | } 133 | } 134 | } 135 | 136 | return json_encode($properties); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/Renderer/Application/Soapxml.php: -------------------------------------------------------------------------------- 1 | documentFormat = $options['documentFormat']; 70 | 71 | // Sanity check - fall back to XML format 72 | if (!in_array($this->documentFormat, array('xml', 'json'))) 73 | { 74 | $this->documentFormat = 'xml'; 75 | } 76 | 77 | // Set default mime type. 78 | $this->setMimeEncoding('application/' . $mimeType, false); 79 | 80 | // Set document type. 81 | $this->setType('xml'); 82 | 83 | // Set absolute/relative hrefs. 84 | $this->absoluteHrefs = isset($options['absoluteHrefs']) ? $options['absoluteHrefs'] : true; 85 | 86 | // Set token if needed 87 | $this->uriParams = isset($options['uriParams']) ? $options['uriParams'] : array(); 88 | } 89 | 90 | /** 91 | * Render the document. 92 | * 93 | * @param boolean $cache If true, cache the output 94 | * @param array $params Associative array of attributes 95 | * 96 | * @return string The rendered data 97 | * 98 | * @since 1.4 99 | */ 100 | public function render($cache = false, $params = array()) 101 | { 102 | parent::render($cache, $params); 103 | $runtime = microtime(true) - $this->app->startTime; 104 | 105 | $this->app->setHeader('Status', $this->soap->statusCode . ' ' . $this->soap->statusText, true); 106 | $this->app->setHeader('Server', '', true); 107 | $this->app->setHeader('X-Runtime', $runtime, true); 108 | $this->app->setHeader('Access-Control-Allow-Origin', '*', true); 109 | $this->app->setHeader('Pragma', 'public', true); 110 | $this->app->setHeader('Expires', '0', true); 111 | $this->app->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true); 112 | $this->app->setHeader('Cache-Control', 'private', false); 113 | $this->app->setHeader('Content-type', $this->getMimeEncoding() . '; charset=' . $this->getCharset(), true); 114 | 115 | // $this->app->sendHeaders(); 116 | 117 | // Get the Soap string from the buffer. 118 | $content = $this->getBuffer(); 119 | 120 | return (string) $content; 121 | } 122 | 123 | /** 124 | * Sets Soap object to the document 125 | * 126 | * @param Api $soap Soap object 127 | * 128 | * @return $this 129 | * 130 | * @since 1.4 131 | */ 132 | public function setApiObject(Api $soap) 133 | { 134 | $this->soap = $soap; 135 | 136 | return $this; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/Renderer/Application/Xml.php: -------------------------------------------------------------------------------- 1 | setMimeEncoding('application/xml', false); 36 | 37 | // Set document type. 38 | $this->setType('xml'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Renderer/RendererInterface.php: -------------------------------------------------------------------------------- 1 | data; 45 | } 46 | 47 | /** 48 | * Gets all Embedded elements 49 | * 50 | * @return array 51 | */ 52 | public function getEmbedded() 53 | { 54 | return $this->embedded; 55 | } 56 | 57 | /** 58 | * Gets all links 59 | * 60 | * @return array 61 | */ 62 | public function getLinks() 63 | { 64 | return $this->links; 65 | } 66 | 67 | /** 68 | * Gets self link 69 | * 70 | * @return Link 71 | */ 72 | public function getSelf() 73 | { 74 | return $this->links['self']; 75 | } 76 | 77 | /** 78 | * Sets data to the resource 79 | * 80 | * @param string $rel Rel element 81 | * @param mixed $data Data for the resource 82 | * 83 | * @return $this 84 | */ 85 | public function setData($rel, $data = null) 86 | { 87 | if (is_array($rel) && null === $data) 88 | { 89 | foreach ($rel as $k => $v) 90 | { 91 | $this->data[$k] = $v; 92 | } 93 | } 94 | else 95 | { 96 | $this->data[$rel] = $data; 97 | } 98 | 99 | return $this; 100 | } 101 | 102 | /** 103 | * Sets Embedded resource 104 | * 105 | * @param string $rel Relation of the resource 106 | * @param Resource $resource Resource 107 | * @param bool $singular Force overwrite of the existing embedded element 108 | * 109 | * @return $this 110 | */ 111 | public function setEmbedded($rel, Resource $resource = null, $singular = false) 112 | { 113 | if ($singular) 114 | { 115 | $this->embedded[$rel] = $resource; 116 | } 117 | else 118 | { 119 | $this->embedded[$rel][] = $resource; 120 | } 121 | 122 | return $this; 123 | } 124 | 125 | /** 126 | * Add a link to the resource. 127 | * 128 | * Per the JSON-HAL specification, a link relation can reference a 129 | * single link or an array of links. By default, two or more links with 130 | * the same relation will be treated as an array of links. The $singular 131 | * flag will force links with the same relation to be overwritten. The 132 | * $plural flag will force links with only one relation to be treated 133 | * as an array of links. The $plural flag has no effect if $singular 134 | * is set to true. 135 | * 136 | * @param ResourceLink $link Link 137 | * @param boolean $singular Force overwrite of the existing link 138 | * @param boolean $plural Force plural mode even if only one link is present 139 | * 140 | * @return $this 141 | */ 142 | public function setLink(ResourceLink $link, $singular = false, $plural = false) 143 | { 144 | $rel = $link->getRel(); 145 | 146 | if ($singular || (!isset($this->links[$rel]) && !$plural)) 147 | { 148 | $this->links[$rel] = $link; 149 | } 150 | else 151 | { 152 | if (isset($this->links[$rel]) && !is_array($this->links[$rel])) 153 | { 154 | $orig_link = $this->links[$rel]; 155 | $this->links[$rel] = array($orig_link); 156 | } 157 | 158 | $this->links[$rel][] = $link; 159 | } 160 | 161 | return $this; 162 | } 163 | 164 | /** 165 | * Set multiple links at once. 166 | * 167 | * @param array $links List of links 168 | * @param bool $singular Force overwrite of the existing link 169 | * @param bool $plural Force plural mode even if only one link is present 170 | * 171 | * @return $this 172 | */ 173 | public function setLinks(array $links, $singular = false, $plural = false) 174 | { 175 | foreach ($links as $link) 176 | { 177 | $this->setLink($link, $singular, $plural); 178 | } 179 | 180 | return $this; 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /src/Resource/ResourceHome.php: -------------------------------------------------------------------------------- 1 | profile = $profile; 34 | } 35 | 36 | /** 37 | * Replace existing link to the resource. 38 | * 39 | * @param ResourceLink $link Link 40 | * @param mixed $group Groupped link container 41 | * 42 | * @return $this 43 | */ 44 | public function setReplacedLink(ResourceLink $link, $group = '') 45 | { 46 | $rel = $link->getRel(); 47 | 48 | if ($group !== '') 49 | { 50 | $this->links[$rel][$group] = $link; 51 | } 52 | else 53 | { 54 | $this->links[$rel] = $link; 55 | } 56 | 57 | return $this; 58 | } 59 | 60 | /** 61 | * Converts current Resource object to Array 62 | * 63 | * @return array 64 | */ 65 | public function toArray() 66 | { 67 | $data = array(); 68 | 69 | foreach ($this->links as $rel => $link) 70 | { 71 | $links = $this->_recourseLinks($link); 72 | 73 | if (!empty($links)) 74 | { 75 | $data['_links'][$rel] = $links; 76 | } 77 | } 78 | 79 | foreach ($this->data as $key => $value) 80 | { 81 | $data[$key] = $value; 82 | } 83 | 84 | foreach ($this->embedded as $rel => $embed) 85 | { 86 | $data['_embedded'][$rel] = $this->_recourseEmbedded($embed); 87 | } 88 | 89 | return $data; 90 | } 91 | 92 | /** 93 | * Recourse function for Embedded objects 94 | * 95 | * @param Resource|null|array $embedded Embedded object 96 | * 97 | * @return array 98 | */ 99 | protected function _recourseEmbedded($embedded) 100 | { 101 | if (is_null($embedded)) 102 | { 103 | return null; 104 | } 105 | 106 | $result = array(); 107 | 108 | if ($embedded instanceof self) 109 | { 110 | $result = $embedded->toArray(); 111 | } 112 | else 113 | { 114 | foreach ($embedded as $embed) 115 | { 116 | if ($embed instanceof self) 117 | { 118 | $result[] = $embed->toArray(); 119 | } 120 | } 121 | } 122 | 123 | return $result; 124 | } 125 | 126 | /** 127 | * Recourse function for Link objects 128 | * 129 | * @param array|Link $links Link object 130 | * 131 | * @return array 132 | */ 133 | protected function _recourseLinks($links) 134 | { 135 | $result = array(); 136 | 137 | if (!is_array($links)) 138 | { 139 | $result = $links->toArray(); 140 | } 141 | else 142 | { 143 | /** @var \Joomla\Webservices\Resource\Link $link */ 144 | foreach ($links as $link) 145 | { 146 | $result[] = $link->toArray(); 147 | } 148 | } 149 | 150 | return $result; 151 | } 152 | 153 | /** 154 | * Method to load an object or an array into this HAL object. 155 | * 156 | * @param object $object Object whose properties are to be loaded. 157 | * 158 | * @return object This method may be chained. 159 | */ 160 | public function load($object) 161 | { 162 | foreach ($object as $name => $value) 163 | { 164 | // For _links and _embedded, we merge rather than replace. 165 | if ($name == '_links') 166 | { 167 | $this->links = array_merge((array) $this->links, (array) $value); 168 | } 169 | elseif ($name == '_embedded') 170 | { 171 | $this->embedded = array_merge((array) $this->embedded, (array) $value); 172 | } 173 | else 174 | { 175 | $this->data[$name] = $value; 176 | } 177 | } 178 | 179 | return $this; 180 | } 181 | 182 | /** 183 | * Merges two resource fields 184 | * 185 | * @param array $resourceMain Resource array main 186 | * @param array $resourceChild Resource array child 187 | * 188 | * @return array 189 | */ 190 | public static function mergeResourceFields($resourceMain = array(), $resourceChild = array()) 191 | { 192 | foreach ($resourceMain as $key => $value) 193 | { 194 | $resourceMain[$key] = !empty($resourceChild[$key]) ? $resourceChild[$key] : $resourceMain[$key]; 195 | } 196 | 197 | return $resourceMain; 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/Service/ConfigurationProvider.php: -------------------------------------------------------------------------------- 1 | config = (new Registry)->loadObject($configObject); 57 | $this->config->set('language.basedir', JPATH_API . '/src'); 58 | } 59 | 60 | /** 61 | * Registers the service provider with a DI container. 62 | * 63 | * @param Container $container The DI container. 64 | * 65 | * @return void 66 | * 67 | * @since 1.0 68 | */ 69 | public function register(Container $container) 70 | { 71 | $container->set('config', 72 | function () 73 | { 74 | return $this->config; 75 | }, 76 | true, true 77 | ); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Service/DatabaseProvider.php: -------------------------------------------------------------------------------- 1 | alias("db", "Joomla\\Database\\DatabaseDriver") 33 | ->share( 34 | "Joomla\\Database\\DatabaseDriver", 35 | function () use ($container) 36 | { 37 | $config = $container->get("config"); 38 | 39 | return DatabaseDriver::getInstance((array) $config["database"]); 40 | }, 41 | true 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Service/EventProvider.php: -------------------------------------------------------------------------------- 1 | share( 33 | "Joomla\\Event\\Dispatcher", 34 | function () 35 | { 36 | return new Dispatcher; 37 | }, 38 | true 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Service/RendererProvider.php: -------------------------------------------------------------------------------- 1 | application = $application; 59 | $this->contentType = $contentType; 60 | $this->options = $options; 61 | } 62 | 63 | /** 64 | * Return a Renderer for the content type. 65 | * 66 | * @param Container $container Dependency injection container. 67 | * 68 | * @return Renderer object. 69 | */ 70 | public function register(Container $container) 71 | { 72 | $application = $this->application; 73 | $contentType = $this->contentType; 74 | $options = $this->options; 75 | 76 | $container->share('renderer', 77 | function () use ($container, $application, $contentType, $options) 78 | { 79 | // Split type and subtype strings from content type. 80 | $parts = explode('/', strtolower($contentType)); 81 | $typeName = ucfirst($parts[0]); 82 | $subtypeName = ucfirst(str_replace(['+', '-', '.'], '', $parts[1])); 83 | 84 | // Construct the class name. 85 | $rendererClass = 'Joomla\\Webservices\\Renderer\\' . $typeName . '\\' . $subtypeName; 86 | 87 | if (!class_exists($rendererClass)) 88 | { 89 | throw new \RuntimeException($container->get('text')->sprintf('LIB_WEBSERVICES_API_UNABLE_TO_LOAD_RENDERER', $rendererClass)); 90 | } 91 | 92 | try 93 | { 94 | $renderer = new $rendererClass($application, $options); 95 | } 96 | catch (\RuntimeException $e) 97 | { 98 | throw new \RuntimeException($container->get('text')->sprintf('LIB_WEBSERVICES_API_UNABLE_TO_INSTANTIATE_RENDERER', $e->getMessage())); 99 | } 100 | 101 | return $renderer; 102 | }, 103 | true 104 | ); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/Type/AbstractType.php: -------------------------------------------------------------------------------- 1 | constructed === true) 54 | { 55 | throw new \BadMethodCallException('This is an immutable object'); 56 | } 57 | 58 | $this->constructed = true; 59 | } 60 | 61 | /** 62 | * Prevent setting undeclared properties. 63 | * 64 | * @param string $name This is an immutable object, setting $name is not allowed. 65 | * @param mixed $value This is an immutable object, setting $value is not allowed. 66 | * 67 | * @return null This method always throws an exception. 68 | * 69 | * @throws \BadMethodCallException 70 | */ 71 | public function __set($name, $value) 72 | { 73 | throw new \BadMethodCallException('This is an immutable object'); 74 | } 75 | 76 | /** 77 | * Get the external value of the type. 78 | * 79 | * @return mixed 80 | */ 81 | public function getExternal() 82 | { 83 | return $this->external; 84 | } 85 | 86 | /** 87 | * Get the internal value of the type. 88 | * 89 | * @return mixed 90 | */ 91 | public function getInternal() 92 | { 93 | return $this->internal; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/Type/TypeArray.php: -------------------------------------------------------------------------------- 1 | internal = true; 40 | $boolean->external = 'true'; 41 | break; 42 | 43 | case 'false': 44 | case '0': 45 | case false: 46 | $boolean->internal = false; 47 | $boolean->external = 'false'; 48 | break; 49 | 50 | default: 51 | throw new \BadMethodCallException('Internal value must be "true", "1", "false" or "0", ' . $internalValue . ' given'); 52 | } 53 | 54 | return $boolean; 55 | } 56 | 57 | /** 58 | * Public named constructor to create a new object from an external value. 59 | * 60 | * @param mixed $externalValue External value. 61 | * 62 | * @return TypeBoolean object. 63 | * 64 | * @throws \BadMethodCallException 65 | */ 66 | public static function fromExternal($externalValue) 67 | { 68 | $boolean = new TypeBoolean; 69 | 70 | switch ($externalValue) 71 | { 72 | case 'true': 73 | case '1': 74 | case true: 75 | $boolean->internal = true; 76 | $boolean->external = 'true'; 77 | break; 78 | 79 | case 'false': 80 | case '0': 81 | case false: 82 | $boolean->internal = false; 83 | $boolean->external = 'false'; 84 | break; 85 | 86 | default: 87 | throw new \BadMethodCallException('External value must be "true", "1", "false" or "0", ' . $externalValue . ' given'); 88 | } 89 | 90 | return $boolean; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Type/TypeDatetime.php: -------------------------------------------------------------------------------- 1 | internal = \DateTime::createFromFormat('Y-m-d H:i:s', $internalValue); 43 | 44 | if ($datetime->internal instanceof \DateTime) 45 | { 46 | $datetime->external = $datetime->internal->format(\DateTime::ISO8601); 47 | } 48 | } 49 | catch (\Exception $e) 50 | { 51 | $errors = \DateTime::getLastErrors(); 52 | $errorMessage = 'Date/time parse error(s): '; 53 | $errorMessage .= implode(', ', array_merge($errors['warnings'], $errors['errors'])); 54 | 55 | throw new \BadMethodCallException($errorMessage); 56 | } 57 | 58 | return $datetime; 59 | } 60 | 61 | /** 62 | * Public named constructor to create a new object from an external value. 63 | * 64 | * @param string $externalValue External value (must be ISO8601 format). 65 | * 66 | * @return TypeDatetime object. 67 | * 68 | * @throws \BadMethodCallException 69 | */ 70 | public static function fromExternal($externalValue) 71 | { 72 | $datetime = new TypeDatetime; 73 | 74 | try 75 | { 76 | $datetime->external = \DateTime::createFromFormat('Y-m-d H:i:s', $externalValue); 77 | 78 | if ($datetime->external instanceof \DateTime) 79 | { 80 | $datetime->internal = $datetime->external->format('Y-m-d H:i:s'); 81 | } 82 | } 83 | catch (\Exception $e) 84 | { 85 | $errors = \DateTime::getLastErrors(); 86 | $errorMessage = 'Date/time parse error(s): '; 87 | $errorMessage .= implode(', ', array_merge($errors['warnings'], $errors['errors'])); 88 | 89 | throw new \BadMethodCallException($errorMessage); 90 | } 91 | 92 | return $datetime; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/Type/TypeFile.php: -------------------------------------------------------------------------------- 1 | internal = $internalValue; 34 | $integer->external = $internalValue; 35 | 36 | return $integer; 37 | } 38 | 39 | /** 40 | * Public named constructor to create a new object from an external value. 41 | * 42 | * @param integer $externalValue External value. 43 | * 44 | * @return TypeInteger object. 45 | * 46 | * @throws \BadMethodCallException 47 | */ 48 | public static function fromExternal($externalValue) 49 | { 50 | $integer = new TypeInteger; 51 | $integer->internal = $externalValue; 52 | $integer->external = $externalValue; 53 | 54 | return $integer; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Type/TypeInterface.php: -------------------------------------------------------------------------------- 1 | internal = $internalValue; 38 | $json->external = json_encode($internalValue); 39 | 40 | return $json; 41 | } 42 | 43 | /** 44 | * Public named constructor to create a new object from an external value. 45 | * 46 | * @param string $externalValue External value. 47 | * 48 | * @return TypeState object. 49 | * 50 | * @throws \BadMethodCallException 51 | */ 52 | public static function fromExternal($externalValue) 53 | { 54 | $json = new TypeJson; 55 | $json->external = $externalValue; 56 | $json->internal = json_decode($externalValue); 57 | 58 | return $json; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Type/TypeNone.php: -------------------------------------------------------------------------------- 1 | internal = $internalValue; 35 | $none->external = $internalValue; 36 | 37 | return $none; 38 | } 39 | 40 | /** 41 | * Public named constructor to create a new object from an external value. 42 | * 43 | * @param string $externalValue External value. 44 | * 45 | * @return TypeState object. 46 | * 47 | * @throws \BadMethodCallException 48 | */ 49 | public static function fromExternal($externalValue) 50 | { 51 | $none = new TypeNone; 52 | $none->internal = $externalValue; 53 | $none->external = $externalValue; 54 | 55 | return $none; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Type/TypePosition.php: -------------------------------------------------------------------------------- 1 | internal = $internalValue; 34 | $state->external = ''; 35 | 36 | switch ($internalValue) 37 | { 38 | case '0': 39 | $state->external = 'unpublished'; 40 | break; 41 | 42 | case '1': 43 | $state->external = 'published'; 44 | break; 45 | 46 | case '2': 47 | $state->external = 'archived'; 48 | break; 49 | 50 | case '-2': 51 | $state->external = 'trashed'; 52 | break; 53 | 54 | default: 55 | throw new \UnexpectedValueException('Internal value must be "0", "1", "2" or "-2"; ' . $internalValue . ' given'); 56 | } 57 | 58 | return $state; 59 | } 60 | 61 | /** 62 | * Public named constructor to create a new object from an external value. 63 | * 64 | * @param string $externalValue External value. 65 | * 66 | * @return TypeState object. 67 | * 68 | * @throws \BadMethodCallException 69 | */ 70 | public static function fromExternal($externalValue) 71 | { 72 | $state = new TypeState; 73 | $state->external = $externalValue; 74 | $state->internal = ''; 75 | 76 | switch ($externalValue) 77 | { 78 | case 'unpublished': 79 | $state->internal = '0'; 80 | break; 81 | 82 | case 'published': 83 | $state->internal = '1'; 84 | break; 85 | 86 | case 'archived': 87 | $state->internal = '2'; 88 | break; 89 | 90 | case 'trashed': 91 | $state->internal = '-2'; 92 | break; 93 | 94 | default: 95 | $message = 'External value must be "unpublished", "published", "archived" or "trashed"; ' . $externalValue . ' given'; 96 | throw new \UnexpectedValueException($message); 97 | } 98 | 99 | return $state; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/Type/TypeString.php: -------------------------------------------------------------------------------- 1 | internal = (string) $internalValue; 39 | $string->external = (string) $internalValue; 40 | 41 | return $string; 42 | } 43 | 44 | /** 45 | * Public named constructor to create a new object from an external value. 46 | * 47 | * @param string $externalValue External value. 48 | * 49 | * @return TypeString object. 50 | * 51 | * @throws \BadMethodCallException 52 | */ 53 | public static function fromExternal($externalValue) 54 | { 55 | if (!is_string($externalValue)) 56 | { 57 | throw new \BadMethodCallException('String expected'); 58 | } 59 | 60 | $string = new TypeString; 61 | $string->internal = (string) $externalValue; 62 | $string->external = (string) $externalValue; 63 | 64 | return $string; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Type/TypeTarget.php: -------------------------------------------------------------------------------- 1 | internal = $internalValue; 41 | $state->external = $internalValue; 42 | 43 | $parts = explode(':', $internalValue); 44 | 45 | if ($parts[0] != 'urn') 46 | { 47 | throw new \UnexpectedValueException('Internal value is not a URN: ' . $internalValue); 48 | } 49 | 50 | if ($parts[1] != 'joomla') 51 | { 52 | throw new \UnexpectedValueException('Internal value must be a URN in the "joomla" namespace, ' . $parts[1] . ' given'); 53 | } 54 | 55 | if (count($parts) != 4) 56 | { 57 | throw new \UnexpectedValueException('Internal value must be a URN with exactly 4 parts'); 58 | } 59 | 60 | return $state; 61 | } 62 | 63 | /** 64 | * Public named constructor to create a new object from an external value. 65 | * 66 | * @param string $externalValue External value. 67 | * 68 | * @return TypeUrn object. 69 | * 70 | * @throws \BadMethodCallException 71 | */ 72 | public static function fromExternal($externalValue) 73 | { 74 | $state = new TypeUrn; 75 | $state->external = $externalValue; 76 | $state->internal = $externalValue; 77 | 78 | $parts = explode(':', $externalValue); 79 | 80 | if ($parts[0] != 'urn') 81 | { 82 | throw new \UnexpectedValueException('External value is not a URN: ' . $externalValue); 83 | } 84 | 85 | if ($parts[1] != 'joomla') 86 | { 87 | throw new \UnexpectedValueException('External value must be a URN in the "joomla" namespace, ' . $parts[1] . ' given'); 88 | } 89 | 90 | if (count($parts) != 4) 91 | { 92 | throw new \UnexpectedValueException('External value must be a URN with exactly 4 parts'); 93 | } 94 | 95 | return $state; 96 | } 97 | 98 | /** 99 | * Return the raw id without the namespace and type stuff. 100 | * 101 | * @return integer 102 | */ 103 | public function getId() 104 | { 105 | $parts = explode(':', $this->internal); 106 | 107 | return $parts[3]; 108 | } 109 | 110 | /** 111 | * Return the type of the URN. 112 | * 113 | * @return string 114 | */ 115 | public function getType() 116 | { 117 | $parts = explode(':', $this->internal); 118 | 119 | return $parts[2]; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/Type/TypeYnglobal.php: -------------------------------------------------------------------------------- 1 | profile = $profile; 35 | 36 | // Check we have permission to perform this operation. 37 | if (!$this->triggerFunction('isOperationAllowed')) 38 | { 39 | return false; 40 | } 41 | 42 | // Get name for integration model/table. Could be different from the webserviceName. 43 | $this->elementName = ucfirst(strtolower((string) $this->getConfig('config.name'))); 44 | 45 | $this->operationConfiguration = $this->getConfig('operations.' . strtolower($this->operation)); 46 | 47 | $this->triggerFunction('apiCreate'); 48 | 49 | $this->resource = new ResourceItem($this->profile); 50 | 51 | // Set links from resources to the main document. 52 | $this->setDataValueToResource($this->resource, $this->resources, $this->data); 53 | 54 | return $this->resource; 55 | } 56 | 57 | /** 58 | * Execute the Api Create operation. 59 | * 60 | * @return mixed JApi object with information on success, boolean false on failure. 61 | * 62 | * @since 1.2 63 | */ 64 | public function apiCreate() 65 | { 66 | // Get resource profile from configuration. 67 | $profile = $this->profile->getResources($this->getOptions()); 68 | 69 | $model = $this->triggerFunction('loadModel', $this->elementName, $this->operationConfiguration); 70 | $functionName = XmlHelper::attributeToString($this->operationConfiguration, 'functionName', 'save'); 71 | 72 | $data = $this->profile->bindData((array) $this->getOptions()->get('data', array())); 73 | 74 | $data = $this->triggerFunction('validatePostData', $model, $data, $this->operationConfiguration); 75 | 76 | if ($data === false) 77 | { 78 | // Data failed validation. 79 | $this->setStatusCode(406); 80 | $this->triggerFunction('displayErrors', $model); 81 | $this->setData('result', $data); 82 | 83 | return; 84 | } 85 | 86 | // Prepare parameters for the function. 87 | $args = $this->profile->buildFunctionArgs($data); 88 | $result = null; 89 | $id = 0; 90 | 91 | // Checks if that method exists in model class file and executes it. 92 | if (method_exists($model, $functionName)) 93 | { 94 | $result = $this->triggerCallFunction($model, $functionName, $args); 95 | } 96 | else 97 | { 98 | $this->setStatusCode(400); 99 | } 100 | 101 | if (method_exists($model, 'getState')) 102 | { 103 | $id = $model->getState($model->getName() . '.id'); 104 | $this->setData('id', $id); 105 | } 106 | 107 | $this->setData('result', $result); 108 | $this->triggerFunction('displayErrors', $model); 109 | 110 | if ($this->statusCode < 400) 111 | { 112 | if ($result === false) 113 | { 114 | $this->setStatusCode(404); 115 | } 116 | else 117 | { 118 | $this->setStatusCode(201); 119 | $this->app->setHeader('Location', $this->webserviceName . '/' . $id, true); 120 | } 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/Webservices/Delete.php: -------------------------------------------------------------------------------- 1 | profile = $profile; 35 | 36 | // Check we have permission to perform this operation. 37 | if (!$this->triggerFunction('isOperationAllowed')) 38 | { 39 | return false; 40 | } 41 | 42 | // Get name for integration model/table. Could be different from the webserviceName. 43 | $this->elementName = ucfirst(strtolower((string) $this->getConfig('config.name'))); 44 | 45 | $this->operationConfiguration = $this->getConfig('operations.' . strtolower($this->operation)); 46 | 47 | $this->triggerFunction('apiDelete'); 48 | 49 | $this->resource = new ResourceItem($this->profile); 50 | 51 | // Set links from resources to the main document 52 | $this->setDataValueToResource($this->resource, $this->resources, $this->data); 53 | 54 | return $this->resource; 55 | } 56 | 57 | /** 58 | * Execute the Api Delete operation. 59 | * 60 | * @return mixed JApi object with information on success, boolean false on failure. 61 | * 62 | * @since 1.2 63 | */ 64 | public function apiDelete() 65 | { 66 | // Get resource list from configuration. 67 | $this->profile->getResources($this->getOptions()); 68 | 69 | // Delete function requires references and not values like we use in call_user_func_array so we use List delete function 70 | $model = $this->triggerFunction('loadModel', $this->elementName, $this->operationConfiguration); 71 | $functionName = XmlHelper::attributeToString($this->operationConfiguration, 'functionName', 'delete'); 72 | 73 | // Get data from request and validate it. 74 | // Note that we actually get the data from the request URI, but we process/validate it as if the data came from the request body. 75 | $data = $this->profile->bindData((array) $this->getOptions()->get('dataGet', array())); 76 | $data = $this->triggerFunction('validatePostData', $model, $data, $this->operationConfiguration); 77 | 78 | if ($data === false) 79 | { 80 | // 406 = Not acceptable. 81 | $this->setStatusCode(406); 82 | $this->triggerFunction('displayErrors', $model); 83 | $this->setData('result', $data); 84 | 85 | return; 86 | } 87 | 88 | $result = null; 89 | $args = $this->profile->buildFunctionArgs($data); 90 | 91 | // Prepare parameters for the function 92 | if (strtolower(XmlHelper::attributeToString($this->operationConfiguration, 'dataMode', 'model')) == 'table') 93 | { 94 | $primaryKeys = $this->profile->bindDataToPrimaryKeys($data, $this->operationConfiguration->getName()); 95 | 96 | if (!empty($primaryKeys)) 97 | { 98 | $result = $model->{$functionName}($primaryKeys); 99 | } 100 | else 101 | { 102 | $result = $model->{$functionName}($args); 103 | } 104 | } 105 | else 106 | { 107 | // Checks if that method exists in model class file and executes it 108 | if (method_exists($model, $functionName)) 109 | { 110 | $result = $this->triggerCallFunction($model, $functionName, $args); 111 | } 112 | else 113 | { 114 | $this->setStatusCode(400); 115 | } 116 | } 117 | 118 | $this->setData('result', $result); 119 | 120 | $this->triggerFunction('displayErrors', $model); 121 | 122 | if ($this->statusCode < 400) 123 | { 124 | if ($result === false) 125 | { 126 | // If delete failed then we set it to Internal Server Error status code 127 | $this->setStatusCode(500); 128 | } 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/Webservices/Exception/ConfigurationException.php: -------------------------------------------------------------------------------- 1 | resource = $resource; 35 | 36 | // Check we have permission to perform this operation. 37 | if (!$this->triggerFunction('isOperationAllowed')) 38 | { 39 | return false; 40 | } 41 | 42 | $this->elementName = ucfirst(strtolower((string) $this->getConfig('config.name'))); 43 | $this->operationConfiguration = $this->getConfig('operations.' . strtolower($this->operation)); 44 | $this->triggerFunction('apiUpdate'); 45 | 46 | // Set links from resources to the main document 47 | $this->setDataValueToResource($this->resource, $this->resources, $this->data); 48 | 49 | return $this->resource; 50 | } 51 | 52 | /** 53 | * Execute the Api Update operation. 54 | * 55 | * @return mixed JApi object with information on success, boolean false on failure. 56 | * 57 | * @since 1.2 58 | */ 59 | public function apiUpdate() 60 | { 61 | // Get resource list from configuration. 62 | $this->profile->getResources($this->getOptions()); 63 | 64 | $model = $this->triggerFunction('loadModel', $this->elementName, $this->operationConfiguration); 65 | $functionName = XmlHelper::attributeToString($this->operationConfiguration, 'functionName', 'save'); 66 | $data = $this->profile->bindData((array) $this->getOptions()->get('data', array())); 67 | 68 | $data = $this->triggerFunction('validatePostData', $model, $data, $this->operationConfiguration); 69 | 70 | if ($data === false) 71 | { 72 | // Not Acceptable 73 | $this->setStatusCode(406); 74 | $this->triggerFunction('displayErrors', $model); 75 | $this->setData('result', $data); 76 | 77 | return; 78 | } 79 | 80 | // Prepare parameters for the function 81 | $args = $this->profile->buildFunctionArgs($data); 82 | $result = null; 83 | 84 | // Checks if that method exists in model class and executes it 85 | if (method_exists($model, $functionName)) 86 | { 87 | $result = $this->triggerCallFunction($model, $functionName, $args); 88 | } 89 | else 90 | { 91 | $this->setStatusCode(400); 92 | } 93 | 94 | if (method_exists($model, 'getState')) 95 | { 96 | $this->setData('id', $model->getState(strtolower($this->elementName) . '.id')); 97 | } 98 | 99 | $this->setData('result', $result); 100 | $this->triggerFunction('displayErrors', $model); 101 | 102 | if ($this->statusCode < 400) 103 | { 104 | if ($result === false) 105 | { 106 | // If update failed then we set it to Internal Server Error status code 107 | $this->setStatusCode(500); 108 | } 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/Webservices/WebserviceHelper.php: -------------------------------------------------------------------------------- 1 | 24 | * $key is "displayGroup" 25 | * Then this method will return "something". 26 | * 27 | * @param \SimpleXMLElement|Array $element XML object or array 28 | * @param string $key Key to check 29 | * @param string $default Default value to return 30 | * 31 | * @return boolean 32 | * 33 | * @since __DEPLOY_VERSION__ 34 | */ 35 | public static function attributeToString($element, $key, $default = '') 36 | { 37 | if (!isset($element[$key])) 38 | { 39 | return $default; 40 | } 41 | 42 | $value = (string) $element[$key]; 43 | 44 | return !empty($value) ? $value : $default; 45 | } 46 | 47 | /** 48 | * Method to transform XML to array and get XML attributes 49 | * 50 | * @param \SimpleXMLElement|Array $element XML object or array 51 | * @param string $key Key to check 52 | * @param boolean $default Default value to return 53 | * 54 | * @return boolean 55 | * 56 | * @since __DEPLOY_VERSION__ 57 | */ 58 | public static function isAttributeTrue($element, $key, $default = false) 59 | { 60 | if (!isset($element[$key])) 61 | { 62 | return $default; 63 | } 64 | 65 | return strtolower($element[$key]) == "true" ? true : false; 66 | } 67 | 68 | /** 69 | * Method to transform XML to array and get XML attributes 70 | * 71 | * @param \SimpleXMLElement $xmlElement XML object to transform 72 | * @param boolean $onlyAttributes return only attributes or all elements 73 | * 74 | * @return array 75 | * 76 | * @since __DEPLOY_VERSION__ 77 | */ 78 | public static function getXMLElementAttributes($xmlElement, $onlyAttributes = true) 79 | { 80 | $transformedXML = json_decode(json_encode((array) $xmlElement), true); 81 | 82 | return $onlyAttributes ? $transformedXML['@attributes'] : $transformedXML; 83 | } 84 | } -------------------------------------------------------------------------------- /tests/_bootstrap.php: -------------------------------------------------------------------------------- 1 | config[$element]; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/_support/Helper/Api.php: -------------------------------------------------------------------------------- 1 | am('Administrator'); 12 | $I->wantToTest('Activate the default webservices'); 13 | $I->doAdministratorLogin(); 14 | $I->comment('I enable basic authentication'); 15 | $I->amOnPage('administrator/index.php?option=com_webservices'); 16 | $I->waitForText('Webservice Manager', 30, ['class' => 'page-title']); 17 | $I->click(['class' => 'lc-not_installed_webservices']); 18 | $I->click(['class' => 'lc-install_webservice_administrator_contact']); 19 | $I->waitForElement(['id' => 'mainComponentWebservices'], 30); 20 | $I->see('administrator.contact.1.0.0.xml',['class' => 'lc-webservice_file']); 21 | 22 | -------------------------------------------------------------------------------- /tests/acceptance/install/01-InstallJoomlaCept.php: -------------------------------------------------------------------------------- 1 | wantToTest('Joomla 3 Installation'); 14 | $I->installJoomlaRemovingInstallationFolder(); 15 | $I->doAdministratorLogin(); 16 | $I->setErrorReportingToDevelopment(); 17 | -------------------------------------------------------------------------------- /tests/acceptance/install/02-InstallExtensionCept.php: -------------------------------------------------------------------------------- 1 | am('Administrator'); 14 | $I->wantToTest('Webservices installation in Joomla 3'); 15 | $I->doAdministratorLogin(); 16 | $path = $I->getConfiguration('repo_folder'); 17 | $I->installExtensionFromFolder($path . '/component'); -------------------------------------------------------------------------------- /tests/acceptance/uninstall/ZZ-UninstallExtensionCept.php: -------------------------------------------------------------------------------- 1 | wantTo('Uninstall Webservices Extension'); 13 | $I->doAdministratorLogin(); 14 | $I->amOnPage('/administrator/index.php?option=com_installer&view=manage'); 15 | $I->waitForText('Extensions: Manage',30, ['css' => 'H1']); 16 | $I->searchForItem('Webservices'); 17 | $I->waitForElement(['id' => 'manageList']); 18 | $I->checkAllResults(); 19 | $I->click(['xpath' => "//div[@id='toolbar-delete']/button"]); 20 | $I->waitForElement(['id' => 'system-message-container'],30); 21 | $I->see('Uninstalling the component was successful.', ['id' => 'system-message-container']); 22 | $I->searchForItem('Webservices package'); 23 | $I->waitForElement(['class' => 'alert-no-items'],30); 24 | $I->see('There are no extensions installed matching your query.', ['class' => 'alert-no-items']); 25 | -------------------------------------------------------------------------------- /tests/api.suite.dist.yml: -------------------------------------------------------------------------------- 1 | class_name: ApiTester 2 | modules: 3 | enabled: 4 | - \Helper\Api 5 | - REST: 6 | depends: PhpBrowser 7 | url: http://localhost/tests/joomla-cms3/www/ 8 | -------------------------------------------------------------------------------- /tests/api/_bootstrap.php: -------------------------------------------------------------------------------- 1 | name = 'contact' . rand(0,1000); 18 | $this->id = 0; 19 | } 20 | 21 | public function WebserviceIsAvailable(ApiTester $I) 22 | { 23 | $I->wantTo("check the availability of the webservice"); 24 | $I->amHttpAuthenticated('admin', 'admin'); 25 | $I->sendGET('index.php' 26 | . '?option=contact' 27 | . '&api=Hal' 28 | . '&webserviceClient=administrator' 29 | . '&webserviceVersion=1.0.0' 30 | ); 31 | 32 | $I->seeResponseCodeIs(200); 33 | $I->seeResponseIsJson(); 34 | $I->seeHttpHeader('Webservice-Name', 'contact'); 35 | $I->seeHttpHeader('Webservice-Version', '1.0.0'); 36 | } 37 | 38 | 39 | /** 40 | * @todo 41 | * @depends WebserviceIsAvailable 42 | * 43 | public function create(ApiTester $I) 44 | { 45 | $I->wantTo('POST a new Contact in com_contacts'); 46 | $I->amHttpAuthenticated('admin', 'admin'); 47 | $I->sendPOST('index.php' 48 | . '?option=contact' 49 | . '&api=Hal' 50 | . '&webserviceClient=administrator' 51 | . '&webserviceVersion=1.0.0' 52 | . "&name=$this->name" 53 | // Uncategorised default category 54 | . '&catid=4' 55 | ); 56 | 57 | $I->seeResponseCodeIs(201); 58 | $I->seeResponseIsJson(); 59 | 60 | $links = $I->grabDataFromResponseByJsonPath('$._links'); 61 | $I->sendGET($links[0]['contact:self']['href']); 62 | $I->seeResponseCodeIs(200); 63 | $I->seeResponseIsJson(); 64 | $ids = $I->grabDataFromResponseByJsonPath('$.id'); 65 | $this->id = $ids[0]; 66 | $I->comment("The id of the new created contact with name '$this->name' is: $this->id"); 67 | } 68 | */ 69 | 70 | /** 71 | * @todo 72 | * @depends create 73 | * 74 | public function readItem(ApiTester $I) 75 | { 76 | $I->wantTo("GET an existing Contact"); 77 | $I->amHttpAuthenticated('admin', 'admin'); 78 | $I->sendGET('index.php' 79 | . '?option=contact' 80 | . '&api=Hal' 81 | . '&webserviceClient=administrator' 82 | . '&webserviceVersion=1.0.0' 83 | . "&id=$this->id" 84 | ); 85 | 86 | $I->seeResponseCodeIs(200); 87 | $I->seeResponseIsJson(); 88 | $I->seeResponseContains('"name":"'. $this->name.'"'); 89 | } 90 | */ 91 | 92 | /** 93 | * @todo 94 | * @depends readItem 95 | * 96 | public function update(ApiTester $I) 97 | { 98 | $I->wantTo('Update a new Contact in com_contacts using PUT'); 99 | $I->amHttpAuthenticated('admin', 'admin'); 100 | 101 | $this->name = 'new_' . $this->name; 102 | $I->sendPUT('index.php' 103 | . '?option=contact' 104 | . '&api=Hal' 105 | . '&webserviceClient=administrator' 106 | . '&webserviceVersion=1.0.0' 107 | . "&id=$this->id" 108 | . "&name=$this->name" 109 | // Uncategorised default category 110 | . '&catid=4' 111 | ); 112 | 113 | $I->seeResponseCodeIs(200); 114 | 115 | $I->sendGET('index.php' 116 | . '?option=contact' 117 | . '&api=Hal' 118 | . '&webserviceClient=administrator' 119 | . '&webserviceVersion=1.0.0' 120 | . "&id=$this->id" 121 | ); 122 | 123 | $I->seeResponseCodeIs(200); 124 | $I->seeResponseIsJson(); 125 | $I->seeResponseContains('"name":"' . $this->name . '"'); 126 | $I->comment("The contact name has been modified to: $this->name"); 127 | } 128 | */ 129 | 130 | /** 131 | * @todo delete depends on https://github.com/joomla-projects/webservices/issues/16 132 | */ 133 | } -------------------------------------------------------------------------------- /tests/functional/_bootstrap.php: -------------------------------------------------------------------------------- 1 | 2 | ServerAdmin webmaster@localhost 3 | DocumentRoot %TRAVIS_BUILD_DIR% 4 | 5 | 6 | Options FollowSymLinks 7 | AllowOverride All 8 | 9 | 10 | 11 | Options FollowSymLinks MultiViews ExecCGI 12 | AllowOverride All 13 | Order deny,allow 14 | Allow from all 15 | 16 | 17 | # Wire up Apache to use Travis CI's php-fpm. 18 | 19 | AddHandler php5-fcgi .php 20 | Action php5-fcgi /php5-fcgi 21 | Alias /php5-fcgi /usr/lib/cgi-bin/php5-fcgi 22 | FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -socket /tmp/php5-fpm.sock -pass-header Authorization 23 | 24 | 25 | ErrorLog ${APACHE_LOG_DIR}/error.log 26 | 27 | -------------------------------------------------------------------------------- /tests/unit/_bootstrap.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /www/htaccess.txt: -------------------------------------------------------------------------------- 1 | ## 2 | # @package Joomla 3 | # @copyright Copyright (C) 2005 - 2015 Open Source Matters. All rights reserved. 4 | # @license GNU General Public License version 2 or later; see LICENSE.txt 5 | ## 6 | 7 | ## 8 | # READ THIS COMPLETELY IF YOU CHOOSE TO USE THIS FILE! 9 | # 10 | # The line just below this section: 'Options +FollowSymLinks' may cause problems 11 | # with some server configurations. It is required for use of mod_rewrite, but may already 12 | # be set by your server administrator in a way that disallows changing it in 13 | # your .htaccess file. If using it causes your server to error out, comment it out (add # to 14 | # beginning of line), reload your site in your browser and test your sef url's. If they work, 15 | # it has been set by your server administrator and you do not need it set here. 16 | ## 17 | 18 | ## No directory listings 19 | IndexIgnore * 20 | 21 | ## Can be commented out if causes errors, see notes above. 22 | Options +FollowSymlinks 23 | Options -Indexes 24 | 25 | ## Mod_rewrite in use. 26 | 27 | RewriteEngine On 28 | 29 | ## Begin - Rewrite rules to block out some common exploits. 30 | # If you experience problems on your site block out the operations listed below 31 | # This attempts to block the most common type of exploit `attempts` to Joomla! 32 | # 33 | # Block out any script trying to base64_encode data within the URL. 34 | RewriteCond %{QUERY_STRING} base64_encode[^(]*\([^)]*\) [OR] 35 | # Block out any script that includes a