mirror of
https://github.com/nextcloud/documentation.git
synced 2026-01-03 02:09:45 +07:00
429 lines
13 KiB
ReStructuredText
429 lines
13 KiB
ReStructuredText
App Tutorial
|
||
============
|
||
|
||
This will teach you how to get develop your own owncloud app.
|
||
|
||
Before you start, please check if there already is a `similar app <http://apps.owncloud.com>`_ you could contribute to. Also, feel free to communicate your idea and plans to the `mailing list <https://mail.kde.org/mailman/listinfo/owncloud>`_ so other contributors might join in.
|
||
|
||
|
||
Getting Started
|
||
---------------
|
||
To get started you'll need to clone the basic git repositories into your web directory. Depending on your distro this will either be :file:`/var/www or` :file:`/srv/http`
|
||
|
||
.. code-block:: bash
|
||
|
||
sudo chmod a+rw /var/www # only do this on your dev machine!
|
||
cd /var/www
|
||
git clone https://github.com/owncloud/core.git owncloud
|
||
git clone https://github.com/owncloud/apps.git apps
|
||
git clone https://github.com/owncloud/3rdparty.git 3rdparty
|
||
|
||
Now restart your apache server and get ready to set up owncloud at http://localhost/owncloud
|
||
|
||
|
||
Enable debugging mode
|
||
---------------------
|
||
To disable caching of JavaScript and CSS you'll have to turn on debugging in the :file:`/var/www/owncloud/config/config.php` by adding this to the end of the file::
|
||
|
||
DEFINE('DEBUG', true);
|
||
|
||
|
||
Create your app
|
||
---------------
|
||
The best way to create your application is to simply use and modify the app template.
|
||
|
||
To do that execute:
|
||
|
||
.. code-block:: bash
|
||
|
||
cd /var/www/apps
|
||
sudo cp -r apptemplate yourappname
|
||
sudo chown -R youruser:yourgroup yourappname
|
||
|
||
To enable your app, simply link it into the apps directory:
|
||
|
||
|
||
.. code-block:: bash
|
||
|
||
ln -s /var/www/apps/yourappname /var/www/owncloud/apps/yourappname
|
||
|
||
or set the apps directory in your :file:`/var/www/owncloud/config.php` (see :doc:`configfile`)
|
||
|
||
**Don't forget to enable it on the apps settings page!**
|
||
|
||
Now change into your app directory::
|
||
|
||
cd /var/www/apps/yourappname
|
||
|
||
|
||
Remove/Replace apptemplate specific things
|
||
------------------------------------------
|
||
Certain things are still apptemplate specific that you will have to replace for your app.
|
||
|
||
.. todo::
|
||
|
||
Provide some sed commands for simple transformation
|
||
|
||
The following things will need to be changed:
|
||
|
||
* AGPL Header: author and copyright
|
||
* **\\OC_App::getAppPath('apptemplate')** to **\\OC_App::getAppPath('yourappname')**
|
||
* **namespace OCA\\AppTemplate** to **namespace OCA\\YourAppName**
|
||
* The Classpaths in :file:`appinfo/bootstrap.php`
|
||
|
||
|
||
App information
|
||
---------------
|
||
You will want to set certain metainformation for your application. To do that open the :file:`appinfo/app.php` and adjust it to look like this
|
||
|
||
.. code-block:: php
|
||
|
||
<?php
|
||
|
||
require_once \OC_App::getAppPath('yourappname') . '/appinfo/bootstrap.php';
|
||
|
||
\OCP\App::addNavigationEntry( array(
|
||
|
||
// the string under which your app will be referenced
|
||
// in owncloud, for instance: \OC_App::getAppPath('APP_ID')
|
||
'id' => 'yourappname',
|
||
|
||
// sorting weight for the navigation. The higher the number, the higher
|
||
// it will be listed in the navigation
|
||
'order' => 74,
|
||
|
||
// the route that will be shown on startup
|
||
'href' => \OC_Helper::linkToRoute('yourappname_index'),
|
||
|
||
// the icon that will be shown in the navigation
|
||
'icon' => \OCP\Util::imagePath('yourappname', 'example.png' ),
|
||
|
||
// the title of your application. This will be used in the
|
||
// navigation or on the settings page of your app
|
||
'name' => \OC_L10N::get('yourappname')->t('Your App')
|
||
|
||
));
|
||
|
||
?>
|
||
|
||
The second place where app specifc information is stored is in :file:`appinfo/info.xml`
|
||
|
||
.. code-block:: xml
|
||
|
||
<?xml version="1.0"?>
|
||
<info>
|
||
<id>yourappname</id>
|
||
<name>Your App</name>
|
||
<description>Your App description</description>
|
||
<version>1.0</version>
|
||
<licence>AGPL</licence>
|
||
<author>Your Name</author>
|
||
<require>4</require>
|
||
</info>
|
||
|
||
|
||
Classloader
|
||
-----------
|
||
The classloader is configured in :file:`appinfo/bootstrap.php`. The classloader frees you from requiring your classes when you use them. If a class is used and its not yet available, the loader will automatically require the given file.
|
||
|
||
To add a class to the classloader, simply use something like this:
|
||
|
||
.. code-block:: php
|
||
|
||
<?php
|
||
// loads the class MyClass from the file folder/myclass.php
|
||
\OC::$CLASSPATH['OCA\YourAppName\MyClass'] = 'apps/yourappname/folder/myclass.php';
|
||
?>
|
||
|
||
|
||
Dependency Injection
|
||
--------------------
|
||
Dependency Injection helps you to create testable code. A good overview how it works and what the benefits are can be seen on `Google's Clean Code Talks <http://www.youtube.com/watch?v=RlfLCWKxHJ0>`_
|
||
|
||
The container is configured in :file:`appinfo/bootstrap.php`. We use Pimple for the container. The documentation on how to use it can be seen on the `Pimple Homepage <http://pimple.sensiolabs.org/>`_
|
||
|
||
To add your own class simply add a new line inside the **createDIContainer** function:
|
||
|
||
.. code-block:: php
|
||
|
||
<?php
|
||
|
||
$container['MyClass'] = function($c){
|
||
return new MyClass($c['SomeOtherClass']);
|
||
};
|
||
|
||
?>
|
||
|
||
|
||
|
||
Controllers
|
||
-----------
|
||
The App Template provides a simple baseclass for adding controllers. Controllers connect your view (templates) with your database and is connected to one or more routes.
|
||
|
||
The apptemplate comes with several different Controllers. A simple controller would look like:
|
||
|
||
.. code-block:: php
|
||
|
||
<?php
|
||
|
||
namespace OCA\YourApp;
|
||
|
||
|
||
class MyController extends Controller {
|
||
|
||
|
||
/**
|
||
* @param Request $request: an instance of the request
|
||
* @param API $api: an api wrapper instance
|
||
*/
|
||
public function __construct($api, $request){
|
||
parent::__construct($api, $request);
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief sets a global system value
|
||
* @param array $urlParams: an array with the values, which were matched in
|
||
* the routes file
|
||
*/
|
||
public function myControllerMethod($urlParams=array()){
|
||
$value = $this->params('somesetting');
|
||
|
||
$response = new JSONResponse($this->appName);
|
||
$response->setParams(array('value' => $value));
|
||
return $response;
|
||
}
|
||
|
||
}
|
||
|
||
?>
|
||
|
||
An instance of the api is passed via dependency injection, the same goes for a request instance. POST and GET parameters are abstracted by the Request class and can be accessed via **$this->params('myPostOrGetKey')** in the controller. This has been done to make the app better testable.
|
||
|
||
If a POST and GET value exist with the same key, the POST value is preferred. You should avoid to have both values with the same key though.
|
||
|
||
Every controller method has to return a response. All possible reponses can be found in :file:`lib/response.php`. The file contains wrappers for Ownclouds internal template engine and JSON response and is used to create a uniform response object which is testable.
|
||
|
||
Don't forget to add your controller to the dependency container in :file:`appinfo/bootstrap.php`
|
||
|
||
.. code-block:: php
|
||
|
||
<?php
|
||
|
||
// in the createDIContainer function
|
||
|
||
$container['MyController'] = function($c){
|
||
return new MyController($c['API'], $c['Request']);
|
||
};
|
||
|
||
?>
|
||
|
||
and to the classloader
|
||
|
||
.. code-block:: php
|
||
|
||
<?php
|
||
\OC::$CLASSPATH['OCA\YourAppName\MyController'] = 'apps/yourappname/controllers/my.controller.php';
|
||
?>
|
||
|
||
|
||
Database Access
|
||
---------------
|
||
ownCloud uses a database abstraction layer on top of either MDB2 or PDO, depending on the availability of PDO on the server.
|
||
|
||
Apps should always use prepared statements when accessing the database as seen in the following example:
|
||
|
||
.. code-block:: php
|
||
|
||
<?php
|
||
$userId = 'tom';
|
||
$query = \OC_DB::prepare("SELECT * FROM *PREFIX*mytable WHERE user = ?");
|
||
$result = $query->execute(array($userId));
|
||
$data = $result->fetchAll();
|
||
?>
|
||
|
||
|
||
‘*PREFIX*’ in the query string will be replaced by the configured database table prefix while preparing the query. Arguments for the prepared statement are denoted by a ‘?’ in the query string and passed during execution in an array.
|
||
|
||
For more information about MDB2 style prepared statements, please see the `official MDB2 documentation <http://pear.php.net/package/MDB2/docs>`_
|
||
|
||
If an app requires additional tables in the database they can be automatically created and updated by specifying them inside :file:`appinfo/database.xml` using MDB2′s xml scheme notation where the placeholders ‘*dbprefix*’ and ‘*dbname*’ can be used for the configured database table prefix and database name.
|
||
|
||
An example database XML file would look like this:
|
||
|
||
.. code-block:: xml
|
||
|
||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||
<database>
|
||
<name>*dbname*</name>
|
||
<create>true</create>
|
||
<overwrite>false</overwrite>
|
||
<charset>utf8</charset>
|
||
<table>
|
||
<name>*dbprefix*yourapp_items</name>
|
||
<declaration>
|
||
<field>
|
||
<name>item_id</name>
|
||
<type>integer</type>
|
||
<default>0</default>
|
||
<notnull>true</notnull>
|
||
<autoincrement>1</autoincrement>
|
||
<length>4</length>
|
||
</field>
|
||
<field>
|
||
<name>uid_owner</name>
|
||
<type>text</type>
|
||
<notnull>true</notnull>
|
||
<length>64</length>
|
||
</field>
|
||
<field>
|
||
<name>item_name</name>
|
||
<type>text</type>
|
||
<notnull>true</notnull>
|
||
<length>100</length>
|
||
</field>
|
||
<field>
|
||
<name>item_path</name>
|
||
<type>clob</type>
|
||
<notnull>true</notnull>
|
||
</field>
|
||
</declaration>
|
||
</table>
|
||
</database>
|
||
|
||
|
||
To update the tables used by the app, simply adjust the database.xml file and increase the app version number in :file:`appinfo/version` to trigger an update.
|
||
|
||
|
||
|
||
Routes
|
||
------
|
||
Routing connects your URL with your controller methods and allows you to create constant and nice URLs. Its also easy to extract values from the URL.
|
||
|
||
Owncloud uses `Symphony Routing <http://symfony.com/doc/2.0/book/routing.html>`_
|
||
|
||
Routes are declared in :file:`appinfo/routes.php`
|
||
|
||
A simple route would look like this:
|
||
|
||
.. code-block:: php
|
||
|
||
<?php
|
||
$this->create('yourappname_routename', '/myurl/{value}')->action(
|
||
function($params){
|
||
callController('MyController', 'methodName', $params);
|
||
}
|
||
);
|
||
?>
|
||
|
||
The first argument is the name of your route. This is used to get url of the route in your Javascript for instance.
|
||
|
||
The second parameter is the URL which should be matched. You can extract values from the url by using **{KEY}** in the section that you want to get. That value is than present under **$params['KEY']**, for the above example it would be **$params['value']**.
|
||
|
||
The $params array is passed to your controllermethod as $urlParams.
|
||
|
||
You can also limit the route to GET or POST requests by simply appending ->post() or ->get() before the action method like:
|
||
|
||
.. code-block:: php
|
||
|
||
<?php
|
||
$this->create('yourappname_routename', '/myurl/{value}')->post()->action(
|
||
function($params){
|
||
callAjaxController('MyController', 'methodName', $params);
|
||
}
|
||
);
|
||
?>
|
||
|
||
**Dont forget to use callAjaxController() for Ajax requests!**
|
||
|
||
In JavaScript you can call the routes like this:
|
||
|
||
.. code-block:: javascript
|
||
|
||
var params = {value: 'hi'};
|
||
var url = OC.Router.generate('yourappname_routename', params);
|
||
|
||
You can also omit the second generate parameter if you dont extract any values from the URL.
|
||
|
||
|
||
**See also:** :doc:`routing`
|
||
|
||
|
||
API abstraction layer
|
||
---------------------
|
||
Owncloud currently has a ton of static methods which is a very bad thing concerning testability. Therefore the app template comes with an api abstraction layer which is located at :file:`lib/api.php`.
|
||
|
||
If you find yourself in need to use an Owncloud internal static method, add it to the api layer by simply creating a new method like:
|
||
|
||
.. code-block:: php
|
||
|
||
<?php
|
||
|
||
// inside the API class
|
||
|
||
public function methodName($someParam){
|
||
\OCP\Util::methodName($this->appName, $someParam);
|
||
}
|
||
?>
|
||
|
||
That way you can easily create unittests with a simple API class mock if you dont want to call Owncloud internal stuff.
|
||
|
||
This will eventually be replaced with an internal Owncloud API layer.
|
||
|
||
|
||
Templates
|
||
---------
|
||
Templates reside in the **template/** folder. To use them in your controller, use the TemplateResponse class, for instance
|
||
|
||
.. code-block:: php
|
||
|
||
<?php
|
||
// in your controller
|
||
|
||
public function index($urlParams=array()){
|
||
|
||
// main is the template name. Owncloud will look for template/main.php
|
||
$response = new TemplateResponse($this->appName, 'main');
|
||
|
||
$params = array('templateVar' => 1);
|
||
$response->setParams($params);
|
||
|
||
return $response;
|
||
}
|
||
?>
|
||
|
||
|
||
**For more info, see** :doc:`templates`
|
||
|
||
JavaScript and CSS
|
||
------------------
|
||
JavaScript files go to the **js/** directory, CSS files to the **css/** directory. They are both minified in production and must therefore be declared in your controller method.
|
||
|
||
To add a script in your controller method, use the controller's **addScript** and **addStyle** methods.
|
||
|
||
.. code-block:: php
|
||
|
||
<?php
|
||
|
||
// in your controller
|
||
public function index($urlParams=array()){
|
||
|
||
// adds the js/admin.js file
|
||
$this->api->addScript('admin');
|
||
|
||
// adds the css/admin.css file
|
||
$this->api->addStyle('admin');
|
||
|
||
// etc
|
||
}
|
||
|
||
?>
|
||
|
||
If you have to include an image in your CSS, use %appswebroot% and %webroot% for creating absolute paths to your image, for instance:
|
||
|
||
|
||
.. code-block:: css
|
||
|
||
.folder > .title {
|
||
background-image: url('%webroot%/core/img/places/folder.svg');
|
||
} |