added database examples

This commit is contained in:
Bernhard Posselt
2012-12-05 03:19:05 +01:00
parent 7fa0d16e29
commit 4fe89f26ed

View File

@@ -359,27 +359,11 @@ and to the classloader
Database Access
---------------
.. note:: The advanced apptemplate doesn't feature a recommended way of doing database queries. We hope this will change with the introduction of the Doctrine ORM.
.. note:: This will likely change with the introduction of an ORM
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.
Your database schema will be inside :file:`appinfo/database.xml` in 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:
@@ -387,46 +371,241 @@ An example database XML file would look like this:
<?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>
<name>*dbname*</name>
<create>true</create>
<overwrite>false</overwrite>
<charset>utf8</charset>
<table>
<name>*dbprefix*yourapp_items</name>
<declaration>
<field>
<name>id</name>
<type>integer</type>
<default>0</default>
<notnull>true</notnull>
<autoincrement>1</autoincrement>
<length>4</length>
</field>
<field>
<name>user</name>
<type>text</type>
<notnull>true</notnull>
<length>64</length>
</field>
<field>
<name>name</name>
<type>text</type>
<notnull>true</notnull>
<length>100</length>
</field>
<field>
<name>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.
Your database layer should go into the **database/** folder. It's recommended to split your data entities from your database queries. You can do that by creating a very simple PHP object with getters and setters:
:file:`database/item.php`
.. code-block:: php
<?php
class Item {
private $id;
private $name;
private $path;
private $user;
public function __construct($fromRow=null){
if($fromRow){
$this->fromRow($fromRow);
}
}
public function fromRow($row){
$this->id = $row['id'];
$this->name = $row['name'];
$this->path = $row['path'];
$this->user = $row['user'];
}
public function getId(){
return $this->id;
}
public function getName(){
return $this->name;
}
public function getUser(){
return $this->user;
}
public function getPath(){
return $this->path;
}
public function setId($id){
$this->id = $id;
}
public function setName($name){
$this->name = $name;
}
public function setUser($user){
$this->user = $user;
}
public function setPath($path){
$this->path = $path;
}
}
All database queries for that object should be put into a wrapper class. The wrapper class could look like this (more method examples are in the advanced_apptemplate):
:file:`item.wrapper.php`
.. code-block:: php
<?php
class ItemMapper extends Mapper {
private $tableName;
/**
* @param API $api: Instance of the API abstraction layer
*/
public function __construct($api){
parent::__construct($api);
$this->tableName = '*PREFIX*apptemplate_advanced_items';
}
/**
* Finds an item by id
* @throws DoesNotExistException: if the item does not exist
* @return the item
*/
public function find($id){
$row = $this->findQuery($this->tableName, $id);
return new Item($row);
}
/**
* Finds an item by user id
* @param string $userId: the id of the user that we want to find
* @throws DoesNotExistException: if the item does not exist
* @return the item
*/
public function findByUserId($userId){
$sql = 'SELECT * FROM ' . $this->tableName . ' WHERE user = ?';
$params = array($userId);
$result = $this->execute($sql, $params)->fetchRow();
if($result){
return new Item($result);
} else {
throw new DoesNotExistException('Item with user id ' . $userId . ' does not exist!');
}
}
/**
* Saves an item into the database
* @param Item $item: the item to be saved
* @return the item with the filled in id
*/
public function save($item){
$sql = 'INSERT INTO '. $this->tableName . '(name, user, path)'.
' VALUES(?, ?, ?)';
$params = array(
$item->getName(),
$item->getUser(),
$item->getPath()
);
$this->execute($sql, $params);
$item->setId($this->api->getInsertId());
return $item;
}
/**
* Updates an item
* @param Item $item: the item to be updated
*/
public function update($item){
$sql = 'UPDATE '. $this->tableName . ' SET
name = ?,
user = ?,
path = ?
WHERE id = ?';
$params = array(
$item->getName(),
$item->getUser(),
$item->getPath(),
$item->getId()
);
$this->execute($sql, $params);
}
/**
* Deletes an item
* @param int $id: the id of the item
*/
public function delete($id){
$this->deleteQuery($this->tableName, $id);
}
}
.. note:: Always use **?** to mark placeholders for arguments in SQL queries and pass the arguments as a second parameter to the execute function to prevent `SQL Injection <http://php.net/manual/en/security.database.sql-injection.php>`_
**DONT**:
.. code-block:: php
<?php
$sql = 'SELECT * FROM ' . $this->tableName . ' WHERE user = ' . $user;
$result = $this->execute($sql);
**DO**:
.. code-block:: php
<?php
$sql = 'SELECT * FROM ' . $this->tableName . ' WHERE user = ?';
$params = array($userId);
$result = $this->execute($sql, $params);
For more information about MDB2 style prepared statements, please see the `official MDB2 documentation <http://pear.php.net/package/MDB2/docs>`_
Templates
---------
ownCloud uses its own templating system. Templates reside in the **template/** folder. In every template file you can easily access the template functions listed in :doc:`templates`