Commit 022781cc authored by Benjamin Eberlei's avatar Benjamin Eberlei

Convert Documentation from Markdown to RST.

parent 4af2a2a9
#!/bin/bash
FILES=`find -iname *.txt -print`
for FILE in $FILES
do
# replace the + to # chars
sed -i -r 's/^([+]{4})\s/#### /' $FILE
sed -i -r 's/^([+]{3})\s/### /' $FILE
sed -i -r 's/^([+]{2})\s/## /' $FILE
sed -i -r 's/^([+]{1})\s/# /' $FILE
sed -i -r 's/(\[php\])/<?php/' $FILE
# convert markdown to reStructured Text
pandoc -f markdown -t rst $FILE > ${FILE%.txt}.rst
done
\ No newline at end of file
#!/bin/bash
sphinx-build reference/en /var/www/docs
\ No newline at end of file
+ Introduction
+ Architecture
+ Configuration
+ Data Retrieval and Manipulation
+ Transactions
+ Platforms
+ Types
+ Schema Manager
+ Schema Representation
+ Events
+ Supporting Other Databases
+ Known Vendor Issues
\ No newline at end of file
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/DoctrineDBAL.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/DoctrineDBAL.qhc"
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
"run these through (pdf)latex."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
Architecture
============
As already said, the DBAL is a thin layer on top of PDO. PDO itself
is mainly defined in terms of 2 classes: ``PDO`` and
``PDOStatement``. The equivalent classes in the DBAL are
``Doctrine\DBAL\Connection`` and ``Doctrine\DBAL\Statement``. A
``Doctrine\DBAL\Connection`` wraps a
``Doctrine\DBAL\Driver\Connection`` and a
``Doctrine\DBAL\Statement`` wraps a
``Doctrine\DBAL\Driver\Statement``.
``Doctrine\DBAL\Driver\Connection`` and
``Doctrine\DBAL\Driver\Statement`` are just interfaces. These
interfaces are implemented by concrete drivers. For all PDO based
drivers, ``PDO`` and ``PDOStatement`` are the implementations of
these interfaces. Thus, for PDO-based drivers, a
``Doctrine\DBAL\Connection`` wraps a ``PDO`` instance and a
``Doctrine\DBAL\Statement`` wraps a ``PDOStatement`` instance. Even
more, a ``Doctrine\DBAL\Connection`` *is a*
``Doctrine\DBAL\Driver\Connection`` and a
``Doctrine\DBAL\Statement`` *is a*
``Doctrine\DBAL\Driver\Statement``.
What does a ``Doctrine\DBAL\Connection`` or a
``Doctrine\DBAL\Statement`` add to the underlying driver
implementations? The enhancements include SQL logging, events and
control over the transaction isolation level in a portable manner,
among others.
A DBAL driver is defined to the outside in terms of 3 interfaces:
``Doctrine\DBAL\Driver``, ``Doctrine\DBAL\Driver\Connection`` and
``Doctrine\DBAL\Driver\Statement``. The latter two resemble (a
subset of) the corresponding PDO API.
A concrete driver implementation must provide implementation
classes for these 3 interfaces.
The DBAL is separated into several different packages that
perfectly separate responsibilities of the different RDBMS layers.
Drivers
-------
The drivers abstract a PHP specific database API by enforcing two
interfaces:
- ``\Doctrine\DBAL\Driver\Driver``
- ``\Doctrine\DBAL\Driver\Statement``
The above two interfaces require exactly the same methods as PDO.
Platforms
---------
The platforms abstract the generation of queries and which database
features a platform supports. The
``\Doctrine\DBAL\Platforms\AbstractPlatform`` defines the common
denominator of what a database platform has to publish to the
userland, to be fully supportable by Doctrine. This includes the
SchemaTool, Transaction Isolation and many other features. The
Database platform for MySQL for example can be used by all 3 mysql
extensions, PDO, Mysqli and ext/mysql.
Logging
-------
The logging holds the interface and some implementations for
debugging of Doctrine SQL query execution during a request.
Schema
------
The schema offers an API for each database platform to execute DDL
statements against your platform or retrieve metadata about it. It
also holds the Schema Abstraction Layer which is used by the
different Schema Management facilities of Doctrine DBAL and ORM.
Types
-----
The types offer an abstraction layer for the converting and
generation of types between Databases and PHP. Doctrine comes
bundled with some common types but offers the ability for
developers to define custom types or extend existing ones easily.
As already said, the DBAL is a thin layer on top of PDO. PDO itself is mainly defined in terms of 2 classes:
`PDO` and `PDOStatement`. The equivalent classes in the DBAL are `Doctrine\DBAL\Connection` and
`Doctrine\DBAL\Statement`. A `Doctrine\DBAL\Connection` wraps a `Doctrine\DBAL\Driver\Connection`
and a `Doctrine\DBAL\Statement` wraps a `Doctrine\DBAL\Driver\Statement`.
`Doctrine\DBAL\Driver\Connection` and `Doctrine\DBAL\Driver\Statement` are just interfaces.
These interfaces are implemented by concrete drivers. For all PDO based drivers, `PDO` and
`PDOStatement` are the implementations of these interfaces. Thus, for PDO-based drivers, a
`Doctrine\DBAL\Connection` wraps a `PDO` instance and a `Doctrine\DBAL\Statement` wraps a
`PDOStatement` instance. Even more, a `Doctrine\DBAL\Connection` *is a* `Doctrine\DBAL\Driver\Connection`
and a `Doctrine\DBAL\Statement` *is a* `Doctrine\DBAL\Driver\Statement`.
What does a `Doctrine\DBAL\Connection` or a `Doctrine\DBAL\Statement` add to the underlying
driver implementations? The enhancements include SQL logging, events and control over the
transaction isolation level in a portable manner, among others.
A DBAL driver is defined to the outside in terms of 3 interfaces: `Doctrine\DBAL\Driver`,
`Doctrine\DBAL\Driver\Connection` and `Doctrine\DBAL\Driver\Statement`.
The latter two resemble (a subset of) the corresponding PDO API.
A concrete driver implementation must provide implementation classes for these 3 interfaces.
The DBAL is separated into several different packages that perfectly separate responsibilities of the different RDBMS layers.
++ Drivers
The drivers abstract a PHP specific database API by enforcing two interfaces:
* `\Doctrine\DBAL\Driver\Driver`
* `\Doctrine\DBAL\Driver\Statement`
The above two interfaces require exactly the same methods as PDO.
++ Platforms
The platforms abstract the generation of queries and which database features a platform supports. The `\Doctrine\DBAL\Platforms\AbstractPlatform` defines the common denominator of what a database platform has to publish to the userland, to be fully supportable by Doctrine. This includes the SchemaTool, Transaction Isolation and many other features. The Database platform for MySQL for example can be used by all 3 mysql extensions, PDO, Mysqli and ext/mysql.
++ Logging
The logging holds the interface and some implementations for debugging of Doctrine SQL query execution during a request.
++ Schema
The schema offers an API for each database platform to execute DDL statements against your platform or retrieve metadata about it. It also holds the Schema Abstraction Layer which is used by the different Schema Management facilities of Doctrine DBAL and ORM.
++ Types
The types offer an abstraction layer for the converting and generation of types between Databases and PHP. Doctrine comes bundled with some common types but offers the ability for developers to define custom types or extend existing ones easily.
\ No newline at end of file
# -*- coding: utf-8 -*-
#
# Doctrine DBAL documentation build configuration file, created by
# sphinx-quickstart on Mon Nov 1 19:50:57 2010.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.append(os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Doctrine DBAL'
copyright = u'2010, Roman Borschel, Guilherme Blanco, Benjamin Eberlei, Jonathan Wage'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '2.0'
# The full version, including alpha/beta/rc tags.
release = '2.0.0-BETA4'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
language = 'en'
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
#unused_docs = []
# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_trees = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
highlight_language = 'php'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_use_modindex = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = ''
# Output file base name for HTML help builder.
htmlhelp_basename = 'DoctrineDBALdoc'
# -- Options for LaTeX output --------------------------------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index2', 'DoctrineDBAL.tex', u'Doctrine DBAL Documentation',
u'Roman Borschel, Guilherme Blanco, Benjamin Eberlei, Jonathan Wage', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_use_modindex = True
Configuration
=============
Getting a Connection
--------------------
You can get a DBAL Connection through the
``Doctrine\DBAL\DriverManager`` class.
::
<?php
$config = new \Doctrine\DBAL\Configuration();
//..
$connectionParams = array(
'dbname' => 'mydb',
'user' => 'user',
'password' => 'secret',
'host' => 'localhost',
'driver' => 'pdo_mysql',
);
$conn = DriverManager::getConnection($connectionParams);
The ``DriverManager`` returns an instance of
``Doctrine\DBAL\Connection`` which is a wrapper around the
underlying driver connection (which is often a PDO instance).
The following sections describe the available connection parameters
in detail.
Driver
~~~~~~
The driver specifies the actual implementations of the DBAL
interfaces to use. It can be configured in one of three ways:
- ``driver``: The built-in driver implementation to use. The
following drivers are currently available:
- ``pdo_mysql``: A MySQL driver that uses the pdo\_mysql PDO
extension.
- ``pdo_sqlite``: An SQLite driver that uses the pdo\_sqlite PDO
extension.
- ``pdo_pgsql``: A PostgreSQL driver that uses the pdo\_pgsql PDO
extension.
- ``pdo_oci``: An Oracle driver that uses the pdo\_oci PDO
extension.
**Note that this driver caused problems in our tests. Prefer the oci8 driver if possible.**
- ``oci8``:\` An Oracle driver that uses the oci8 PHP extension.
- ``driverClass``: Specifies a custom driver implementation if no
'driver' is specified. This allows the use of custom drivers that
are not part of the Doctrine DBAL itself.
- ``pdo``: Specifies an existing PDO instance to use.
Wrapper Class
~~~~~~~~~~~~~
By default a ``Doctrine\DBAL\Connection`` is wrapped around a
driver ``Connection``. The ``wrapperClass`` option allows to
specify a custom wrapper implementation to use, however, custom
wrapper class must be a subclass of ``Doctrine\DBAL\Connection``.
Connection Details
~~~~~~~~~~~~~~~~~~
The connection details identify the database to connect to as well
as the credentials to use. The connection details can differ
depending on the used driver. The following sections describe the
options recognized by each built-in driver.
**NOTE** When using an existing PDO instance through the ``pdo``
option, specifying connection details is obviously not necessary.
pdo\_sqlite
^^^^^^^^^^^
- ``user`` (string): Username to use when connecting to the
database.
- ``password`` (string): Password to use when connecting to the
database.
- ``path`` (string): The filesystem path to the database file.
Mutually exclusive with ``memory``. ``path`` takes precedence.
- ``memory`` (boolean): True if the SQLite database should be
in-memory (non-persistent). Mutually exclusive with ``path``.
``path`` takes precedence.
pdo\_mysql
^^^^^^^^^^
- ``user`` (string): Username to use when connecting to the
database.
- ``password`` (string): Password to use when connecting to the
database.
- ``host`` (string): Hostname of the database to connect to.
- ``port`` (integer): Port of the database to connect to.
- ``dbname`` (string): Name of the database/schema to connect to.
- ``unix_socket`` (string): Name of the socket used to connect to
the database.
pdo\_pgsql
^^^^^^^^^^
- ``user`` (string): Username to use when connecting to the
database.
- ``password`` (string): Password to use when connecting to the
database.
- ``host`` (string): Hostname of the database to connect to.
- ``port`` (integer): Port of the database to connect to.
- ``dbname`` (string): Name of the database/schema to connect to.
pdo\_oci / oci8
^^^^^^^^^^^^^^^
- ``user`` (string): Username to use when connecting to the
database.
- ``password`` (string): Password to use when connecting to the
database.
- ``host`` (string): Hostname of the database to connect to.
- ``port`` (integer): Port of the database to connect to.
- ``dbname`` (string): Name of the database/schema to connect to.
- ``charset`` (string): The charset used when connecting to the
database.
Custom Platform
~~~~~~~~~~~~~~~
Each built-in driver uses a default implementation of
``Doctrine\DBAL\Platforms\AbstractPlatform``. If you wish to use a
customized or custom implementation, you can pass a precreated
instance in the ``platform`` option.
Custom Driver Options
~~~~~~~~~~~~~~~~~~~~~
The ``driverOptions`` option allows to pass arbitrary options
through to the driver. This is equivalent to the 4th argument of
the
`PDO constructor <http://php.net/manual/en/pdo.construct.php>`_.
++ Getting a Connection
You can get a DBAL Connection through the `Doctrine\DBAL\DriverManager` class.
[php]
$config = new \Doctrine\DBAL\Configuration();
//..
$connectionParams = array(
'dbname' => 'mydb',
'user' => 'user',
'password' => 'secret',
'host' => 'localhost',
'driver' => 'pdo_mysql',
);
$conn = DriverManager::getConnection($connectionParams);
The `DriverManager` returns an instance of `Doctrine\DBAL\Connection` which is a
wrapper around the underlying driver connection (which is often a PDO instance).
The following sections describe the available connection parameters in detail.
+++ Driver
The driver specifies the actual implementations of the DBAL interfaces to use.
It can be configured in one of three ways:
* `driver`: The built-in driver implementation to use. The following drivers are currently available:
* `pdo_mysql`: A MySQL driver that uses the pdo_mysql PDO extension.
* `pdo_sqlite`: An SQLite driver that uses the pdo_sqlite PDO extension.
* `pdo_pgsql`: A PostgreSQL driver that uses the pdo_pgsql PDO extension.
* `pdo_oci`: An Oracle driver that uses the pdo_oci PDO extension. **Note that this driver caused problems in our tests. Prefer the oci8 driver if possible.**
* `oci8`:` An Oracle driver that uses the oci8 PHP extension.
* `driverClass`: Specifies a custom driver implementation if no 'driver' is specified. This allows the use of custom drivers that are not part of the Doctrine DBAL itself.
* `pdo`: Specifies an existing PDO instance to use.
+++ Wrapper Class
By default a `Doctrine\DBAL\Connection` is wrapped around a driver `Connection`.
The `wrapperClass` option allows to specify a custom wrapper implementation to use,
however, custom wrapper class must be a subclass of `Doctrine\DBAL\Connection`.
+++ Connection Details
The connection details identify the database to connect to as well as the
credentials to use. The connection details can differ depending on the used
driver. The following sections describe the options recognized by each built-in
driver.
> **NOTE**
> When using an existing PDO instance through the `pdo` option, specifying
> connection details is obviously not necessary.
++++ pdo_sqlite
* `user` (string): Username to use when connecting to the database.
* `password` (string): Password to use when connecting to the database.
* `path` (string): The filesystem path to the database file. Mutually exclusive with `memory`. `path` takes precedence.
* `memory` (boolean): True if the SQLite database should be in-memory (non-persistent). Mutually exclusive with `path`. `path` takes precedence.
++++ pdo_mysql
* `user` (string): Username to use when connecting to the database.
* `password` (string): Password to use when connecting to the database.
* `host` (string): Hostname of the database to connect to.
* `port` (integer): Port of the database to connect to.
* `dbname` (string): Name of the database/schema to connect to.
* `unix_socket` (string): Name of the socket used to connect to the database.
++++ pdo_pgsql
* `user` (string): Username to use when connecting to the database.
* `password` (string): Password to use when connecting to the database.
* `host` (string): Hostname of the database to connect to.
* `port` (integer): Port of the database to connect to.
* `dbname` (string): Name of the database/schema to connect to.
++++ pdo_oci / oci8
* `user` (string): Username to use when connecting to the database.
* `password` (string): Password to use when connecting to the database.
* `host` (string): Hostname of the database to connect to.
* `port` (integer): Port of the database to connect to.
* `dbname` (string): Name of the database/schema to connect to.
* `charset` (string): The charset used when connecting to the database.
+++ Custom Platform
Each built-in driver uses a default implementation of `Doctrine\DBAL\Platforms\AbstractPlatform`.
If you wish to use a customized or custom implementation, you can pass a precreated instance
in the `platform` option.
+++ Custom Driver Options
The `driverOptions` option allows to pass arbitrary options through to the driver.
This is equivalent to the 4th argument of the [PDO constructor](http://php.net/manual/en/pdo.construct.php).
\ No newline at end of file
The DBAL contains several methods for executing queries against your configured
database for data retrieval and manipulation. Below we'll introduce these
methods and provide some examples for each of them.
Data Retrieval And Manipulation
===============================
++ prepare($sql)
The DBAL contains several methods for executing queries against
your configured database for data retrieval and manipulation. Below
we'll introduce these methods and provide some examples for each of
them.
Prepare a given sql statement and return the `\Doctrine\DBAL\Driver\Statement` instance:
prepare($sql)
-------------
[php]
Prepare a given sql statement and return the
``\Doctrine\DBAL\Driver\Statement`` instance:
::
<?php
$statement = $conn->prepare('SELECT * FROM user');
$statement->execute();
$users = $statement->fetchAll();
/*
array(
0 => array(
......@@ -20,28 +28,35 @@ Prepare a given sql statement and return the `\Doctrine\DBAL\Driver\Statement` i
)
*/
++ executeUpdate($sql, array $params = array(), array $types = array())
executeUpdate($sql, array $params = array(), array $types = array())
--------------------------------------------------------------------
Executes a prepared statement with the given sql and parameters and returns the
affected rows count:
Executes a prepared statement with the given sql and parameters and
returns the affected rows count:
[php]
::
<?php
$count = $conn->executeUpdate('UPDATE user SET username = ? WHERE id = ?', array('jwage', 1));
echo $count; // 1
The `$types` variable contains the PDO or Doctrine Type constants to perform
necessary type conversions between actual input parameters and expected database values.
See the [Types](./types#type-conversion) section for more information.
The ``$types`` variable contains the PDO or Doctrine Type constants
to perform necessary type conversions between actual input
parameters and expected database values. See the
`Types <./types#type-conversion>`_ section for more information.
executeQuery($sql, array $params = array(), array $types = array())
-------------------------------------------------------------------
++ executeQuery($sql, array $params = array(), array $types = array())
Creates a prepared statement for the given sql and passes the
parameters to the execute method, then returning the statement:
Creates a prepared statement for the given sql and passes the parameters to the
execute method, then returning the statement:
::
[php]
<?php
$statement = $conn->execute('SELECT * FROM user WHERE username = ?', array('jwage'));
$user = $statement->fetch();
/*
array(
0 => 'jwage',
......@@ -49,17 +64,21 @@ execute method, then returning the statement:
)
*/
The `$types` variable contains the PDO or Doctrine Type constants to perform
necessary type conversions between actual input parameters and expected database values.
See the [Types](./types#type-conversion) section for more information.
The ``$types`` variable contains the PDO or Doctrine Type constants
to perform necessary type conversions between actual input
parameters and expected database values. See the
`Types <./types#type-conversion>`_ section for more information.
++ fetchAll($sql, array $params)
fetchAll($sql, array $params)
-----------------------------
Execute the query and fetch all results into an array:
[php]
$users = $conn->fetchAll('SELECT * FROM user');
::
<?php
$users = $conn->fetchAll('SELECT * FROM user');
/*
array(
0 => array(
......@@ -69,14 +88,16 @@ Execute the query and fetch all results into an array:
)
*/
++ fetchArray($sql, array $params)
fetchArray($sql, array $params)
-------------------------------
Numeric index retrieval of first result row of the given query:
[php]
$user = $conn->fetchArray('SELECT * FROM user WHERE username = ?', array('jwage'));
::
<?php
$user = $conn->fetchArray('SELECT * FROM user WHERE username = ?', array('jwage'));
/*
array(
0 => 'jwage',
......@@ -84,19 +105,25 @@ Numeric index retrieval of first result row of the given query:
)
*/
++ fetchColumn($sql, array $params, $colnum)
fetchColumn($sql, array $params, $colnum)
-----------------------------------------
Retrieve only the given column of the first result row.
[php]
::
<?php
$username = $conn->fetchColumn('SELECT username FROM user WHERE id = ?', array(1), 0);
echo $username; // jwage
++ fetchAssoc($sql, array $params)
fetchAssoc($sql, array $params)
-------------------------------
Retrieve assoc row of the first result row.
[php]
::
<?php
$user = $conn->fetchAssoc('SELECT * FROM user WHERE username = ?', array('jwage'));
/*
array(
......@@ -107,46 +134,67 @@ Retrieve assoc row of the first result row.
There are also convenience methods for data manipulation queries:
++ delete($tableName, array $identifier)
delete($tableName, array $identifier)
-------------------------------------
Delete all rows of a table matching the given identifier, where keys are column names.
Delete all rows of a table matching the given identifier, where
keys are column names.
[php]
::
<?php
$conn->delete('user', array('id' => 1));
// DELETE FROM user WHERE id = ? (1)
++ insert($tableName, array $data)
insert($tableName, array $data)
-------------------------------
Insert a row into the given table name using the key value pairs of
data.
Insert a row into the given table name using the key value pairs of data.
::
[php]
<?php
$conn->insert('user', array('username' => 'jwage'));
// INSERT INTO user (username) VALUES (?) (jwage)
++ update($tableName, array $data, array $identifier)
update($tableName, array $data, array $identifier)
--------------------------------------------------
Update all rows for the matching key value identifiers with the given data.
Update all rows for the matching key value identifiers with the
given data.
[php]
::
<?php
$conn->update('user', array('username' => 'jwage'), array('id' => 1));
// UPDATE user (username) VALUES (?) WHERE id = ? (jwage, 1)
By default the Doctrine DBAL does no escaping. Escaping is a very tricky
business to do automatically, therefore there is none by default. The ORM
internally escapes all your values, because it has lots of metadata available
about the current context. When you use the Doctrine DBAL as standalone, you
have to take care of this yourself. The following methods help you with it:
By default the Doctrine DBAL does no escaping. Escaping is a very
tricky business to do automatically, therefore there is none by
default. The ORM internally escapes all your values, because it has
lots of metadata available about the current context. When you use
the Doctrine DBAL as standalone, you have to take care of this
yourself. The following methods help you with it:
++ quote($input, $type = null)
quote($input, $type = null)
---------------------------
Quote a value:
[php]
::
<?php
$quoted = $conn->quote('value');
++ quoteIdentifier($identifier)
quoteIdentifier($identifier)
----------------------------
Quote an identifier according to the platform details.
[php]
$quoted = $conn->quoteIdentifier('id');
\ No newline at end of file
::
<?php
$quoted = $conn->quoteIdentifier('id');
Events
======
Both ``Doctrine\DBAL\DriverManager`` and
``Doctrine\DBAL\Connection`` accept an instance of
``Doctrine\Common\EventManager``. The EventManager has a couple of
events inside the DBAL layer that are triggered for the user to
listen to.
PostConnect Event
-----------------
``Doctrine\DBAL\Events::postConnect`` is triggered right after the
connection to the database is established. It allows to specify any
relevant connection specific options and gives access to the
``Doctrine\DBAL\Connection`` instance that is responsible for the
connection management via an instance of
``Doctrine\DBAL\Event\ConnectionEventArgs`` event arguments
instance.
Doctrine is already shipped with two implementations for the
"PostConnect" event:
- ``Doctrine\DBAL\Event\Listeners\OracleSessionInit`` allows to
specify any number of Oracle Session related enviroment variables
that are set right after the connection is established.
- ``Doctrine\DBAL\Event\Listeners\MysqlSessionInit`` allows to
specify the Charset and Collation of the Client Connection if these
options are not configured correctly on the MySQL server side.
You can register events by subscribing them to the ``EventManager``
instance passed to the Connection factory:
::
<?php
$evm = new EventManager();
$evm->addEventSubscriber(new MysqlSessionInit('UTF8'));
$conn = DriverManager::getConnection($connectionParams, null, $evm);
Both `Doctrine\DBAL\DriverManager` and `Doctrine\DBAL\Connection` accept an
instance of `Doctrine\Common\EventManager`. The EventManager has a couple of
events inside the DBAL layer that are triggered for the user to listen to.
++ PostConnect Event
`Doctrine\DBAL\Events::postConnect` is triggered right after the connection to
the database is established. It allows to specify any relevant connection
specific options and gives access to the `Doctrine\DBAL\Connection` instance
that is responsible for the connection management via an instance of
`Doctrine\DBAL\Event\ConnectionEventArgs` event arguments instance.
Doctrine is already shipped with two implementations for the "PostConnect" event:
* `Doctrine\DBAL\Event\Listeners\OracleSessionInit` allows to specify any number of Oracle Session related enviroment variables that are set right after the connection is established.
* `Doctrine\DBAL\Event\Listeners\MysqlSessionInit` allows to specify the Charset and Collation of the Client Connection if these options are not configured correctly on the MySQL server side.
You can register events by subscribing them to the `EventManager` instance
passed to the Connection factory:
[php]
$evm = new EventManager();
$evm->addEventSubscriber(new MysqlSessionInit('UTF8'));
$conn = DriverManager::getConnection($connectionParams, null, $evm);
\ No newline at end of file
.. Doctrine DBAL documentation master file, created by
sphinx-quickstart on Mon Nov 1 19:16:59 2010.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to Doctrine DBAL's documentation!
=========================================
Contents:
.. toctree::
:maxdepth: 2
introduction
architecture
configuration
data-retrieval-and-manipulation
transactions
platforms
types
schema-manager
schema-representation
events
supporting-other-databases
known-vendor-issues
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
Introduction
============
The Doctrine database abstraction & access layer (DBAL) offers a
leightweight and thin runtime layer around a PDO-like API and a lot
of additional, horizontal features like database schema
introspection and manipulation through an OO API.
The fact that the Doctrine DBAL abstracts the concrete PDO API away
through the use of interfaces that closely resemble the existing
PDO API makes it possible to implement custom drivers that may use
existing native or self-made APIs. For example, the DBAL ships with
a driver for Oracle databases that uses the oci8 extension under
the hood.
The Doctrine 2 database layer can be used independently of the
object-relational mapper. In order to use the DBAL all you need is
the ``Doctrine\Common`` and ``Doctrine\DBAL`` namespaces. Once you
have the Common and DBAL namespaces you must setup a class loader
to be able to autoload the classes:
::
<?php
use Doctrine\Common\ClassLoader;
require '/path/to/doctrine/lib/Doctrine/Common/ClassLoader.php';
$classLoader = new ClassLoader('Doctrine', '/path/to/doctrine');
$classLoader->register();
Now you are able to load classes that are in the
``/path/to/doctrine`` directory like
``/path/to/doctrine/Doctrine/DBAL/DriverManager.php`` which we will
use later in this documentation to configure our first Doctrine
DBAL connection.
The Doctrine database abstraction & access layer (DBAL) offers a leightweight
and thin runtime layer around a PDO-like API and a lot of additional, horizontal
features like database schema introspection and manipulation through an OO API.
The fact that the Doctrine DBAL abstracts the concrete PDO API away through the
use of interfaces that closely resemble the existing PDO API makes it possible
to implement custom drivers that may use existing native or self-made APIs. For
example, the DBAL ships with a driver for Oracle databases that uses the oci8
extension under the hood.
The Doctrine 2 database layer can be used independently of the object-relational
mapper. In order to use the DBAL all you need is the `Doctrine\Common` and
`Doctrine\DBAL` namespaces. Once you have the Common and DBAL namespaces you
must setup a class loader to be able to autoload the classes:
[php]
use Doctrine\Common\ClassLoader;
require '/path/to/doctrine/lib/Doctrine/Common/ClassLoader.php';
$classLoader = new ClassLoader('Doctrine', '/path/to/doctrine');
$classLoader->register();
Now you are able to load classes that are in the `/path/to/doctrine` directory
like `/path/to/doctrine/Doctrine/DBAL/DriverManager.php` which we will use later
in this documentation to configure our first Doctrine DBAL connection.
\ No newline at end of file
This section describes known compatability issues with all the supported database vendors:
Known Vendor Issues
===================
++ PostgreSQL
This section describes known compatability issues with all the
supported database vendors:
+++ DateTime, DateTimeTz and Time Types
PostgreSQL
----------
Postgres has a variable return format for the datatype TIMESTAMP(n) and TIME(n)
if microseconds are allowed (n > 0). Whenever you save a value with microseconds = 0.
PostgreSQL will return this value in the format:
DateTime, DateTimeTz and Time Types
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Postgres has a variable return format for the datatype TIMESTAMP(n)
and TIME(n) if microseconds are allowed (n > 0). Whenever you save
a value with microseconds = 0. PostgreSQL will return this value in
the format:
::
2010-10-10 10:10:10 (Y-m-d H:i:s)
However if you save a value with microseconds it will return the full representation:
However if you save a value with microseconds it will return the
full representation:
::
2010-10-10 10:10:10.123456 (Y-m-d H:i:s.u)
Using the DateTime, DateTimeTz or Time type with microseconds enabled columns
can lead to errors because internally types expect the exact format 'Y-m-d H:i:s'
in combination with `DateTime::createFromFormat()`. This method is twice a fast
as passing the date to the constructor of `DateTime`.
Using the DateTime, DateTimeTz or Time type with microseconds
enabled columns can lead to errors because internally types expect
the exact format 'Y-m-d H:i:s' in combination with
``DateTime::createFromFormat()``. This method is twice a fast as
passing the date to the constructor of ``DateTime``.
This is why Doctrine always wants to create the time related types without microseconds:
This is why Doctrine always wants to create the time related types
without microseconds:
* DateTime to `TIMESTAMP(0) WITHOUT TIME ZONE`
* DateTimeTz to `TIMESTAMP(0) WITH TIME ZONE`
* Time to `TIME(0) WITHOUT TIME ZONE`
If you do not let Doctrine create the date column types and rather use types with microseconds
you have replace the "DateTime", "DateTimeTz" and "Time" types with a more liberal DateTime parser
- DateTime to ``TIMESTAMP(0) WITHOUT TIME ZONE``
- DateTimeTz to ``TIMESTAMP(0) WITH TIME ZONE``
- Time to ``TIME(0) WITHOUT TIME ZONE``
If you do not let Doctrine create the date column types and rather
use types with microseconds you have replace the "DateTime",
"DateTimeTz" and "Time" types with a more liberal DateTime parser
that detects the format automatically:
[php]
use Doctrine\DBAL\Types\Type;
::
use Doctrine\DBAL\Types\Type;
Type::overrideType('datetime', 'Doctrine\DBAL\Types\VarDateTime');
Type::overrideType('datetimetz', 'Doctrine\DBAL\Types\VarDateTime');
Type::overrideType('time', 'Doctrine\DBAL\Types\VarDateTime');
+++ Timezones and DateTimeTz
Timezones and DateTimeTz
~~~~~~~~~~~~~~~~~~~~~~~~
Postgres does not save the actual Timezone Name but UTC-Offsets. The difference is subtle but can be potentially
very nasty. Derick Rethans explains it very well [in a blog post of his](http://derickrethans.nl/storing-date-time-in-database.html).
Postgres does not save the actual Timezone Name but UTC-Offsets.
The difference is subtle but can be potentially very nasty. Derick
Rethans explains it very well
`in a blog post of his <http://derickrethans.nl/storing-date-time-in-database.html>`_.
++ MySQL
MySQL
-----
+++ DateTimeTz
DateTimeTz
~~~~~~~~~~
MySQL does not support saving timezones or offsets. The DateTimeTz type therefore behave like the DateTime type.
MySQL does not support saving timezones or offsets. The DateTimeTz
type therefore behave like the DateTime type.
++ Sqlite
Sqlite
------
+++ DateTimeTz
DateTimeTz
~~~~~~~~~~
Sqlite does not support saving timezones or offsets. The DateTimeTz type therefore behave like the DateTime type.
Sqlite does not support saving timezones or offsets. The DateTimeTz
type therefore behave like the DateTime type.
++ IBM DB2
IBM DB2
-------
+++ DateTimeTz
DateTimeTz
~~~~~~~~~~
DB2 does not save the actual Timezone Name but UTC-Offsets. The difference is subtle but can be potentially
very nasty. Derick Rethans explains it very well [in a blog post of his](http://derickrethans.nl/storing-date-time-in-database.html).
DB2 does not save the actual Timezone Name but UTC-Offsets. The
difference is subtle but can be potentially very nasty. Derick
Rethans explains it very well
`in a blog post of his <http://derickrethans.nl/storing-date-time-in-database.html>`_.
++ Oracle
Oracle
------
+++ DateTimeTz
DateTimeTz
~~~~~~~~~~
Oracle does not save the actual Timezone Name but UTC-Offsets. The difference is subtle but can be potentially
very nasty. Derick Rethans explains it very well [in a blog post of his](http://derickrethans.nl/storing-date-time-in-database.html).
Oracle does not save the actual Timezone Name but UTC-Offsets. The
difference is subtle but can be potentially very nasty. Derick
Rethans explains it very well
`in a blog post of his <http://derickrethans.nl/storing-date-time-in-database.html>`_.
+++ OCI8: SQL Queries with Question Marks
OCI8: SQL Queries with Question Marks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We had to implement a question mark to named parameter translation inside the OCI8 DBAL Driver. This means that
you cannot execute queries that contain question marks in the SQL string. For example:
We had to implement a question mark to named parameter translation
inside the OCI8 DBAL Driver. This means that you cannot execute
queries that contain question marks in the SQL string. For
example:
.. code-block:: sql
[sql]
SELECT * FROM users WHERE name = 'bar?'
Will be rewritten into:
[sql]
.. code-block:: sql
SELECT * FROM users WHERE name = 'bar:oci1'
For this reason you should always use prepared statements with Oracle OCI8, never use string literals inside the queries.
A query for the user 'bar?' should look like:
For this reason you should always use prepared statements with
Oracle OCI8, never use string literals inside the queries. A query
for the user 'bar?' should look like:
::
[php]
$sql = 'SELECT * FROM users WHERE name = ?'
$stmt = $conn->prepare($sql);
$stmt->bindValue(1, 'bar?');
$stmt->execute();
We will probably fix this issue in the future by implementing a little parser inside the OCI8 Driver that can detect
the difference between question mark needles and literal questions marks.
We will probably fix this issue in the future by implementing a
little parser inside the OCI8 Driver that can detect the difference
between question mark needles and literal questions marks.
OCI-LOB instances
~~~~~~~~~~~~~~~~~
Doctrine 2 always requests CLOB columns as strings, so that you as
a developer never get access to the ``OCI-LOB`` instance. Since we
are using prepared statements for all write operations inside the
ORM, using strings instead of the ``OCI-LOB`` does not cause any
problems.
+++ OCI-LOB instances
Microsoft SQL Server
--------------------
Doctrine 2 always requests CLOB columns as strings, so that you as a developer never get access to the `OCI-LOB` instance.
Since we are using prepared statements for all write operations inside the ORM,
using strings instead of the `OCI-LOB` does not cause any problems.
Unique and NULL
~~~~~~~~~~~~~~~
++ Microsoft SQL Server
Microsoft SQL Server takes Unique very seriously. There is only
ever one NULL allowed contrary to the standard where you can have
multiple NULLs in a unique column.
+++ Unique and NULL
Microsoft SQL Server takes Unique very seriously. There is only ever one NULL allowed contrary to the standard
where you can have multiple NULLs in a unique column.
\ No newline at end of file
@ECHO OFF
REM Command file for Sphinx documentation
set SPHINXBUILD=sphinx-build
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\DoctrineDBAL.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\DoctrineDBAL.ghc
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end
Platforms
=========
Platforms abstract query generation and the subtle differences of
the supported database vendors. In most cases you don't need to
interact with the ``Doctrine\DBAL\Platforms`` package a lot, but
there might be certain cases when you are programming database
independent where you want to access the platform to generate
queries for you.
The platform can be accessed from any ``Doctrine\DBAL\Connection``
instance by calling the ``getDatabasePlatform()`` method.
::
<?php
$platform = $conn->getDatabasePlatform();
Each database driver has a platform associated with it by default.
Several drivers also share the same platform, for example PDO\_OCI
and OCI8 share the ``OraclePlatform``.
If you want to overwrite parts of your platform you can do so when
creating a connection. There is a ``platform`` option you can pass
an instance of the platform you want the connection to use:
::
<?php
$myPlatform = new MyPlatform();
$options = array(
'driver' => 'pdo_sqlite',
'path' => 'database.sqlite',
'platform' => $myPlatform
);
$conn = DriverManager::getConnection($options);
This way you can optimize your schema or generated SQL code with
features that might not be portable for instance, however are
required for your special needs. This can include using triggers or
views to simulate features or adding behaviour to existing SQL
functions.
Platforms are also responsible to know which database type
translates to which PHP Type. This is a very tricky issue across
all the different database vendors, for example MySQL BIGINT and
Oracle NUMBER should be handled as integer. Doctrine 2 offers a
powerful way to abstract the database to php and back conversion,
which is described in the next section.
Platforms abstract query generation and the subtle differences of the supported database vendors. In most cases you don't need to interact
with the `Doctrine\DBAL\Platforms` package a lot, but there might be certain cases when you are programming database
independent where you want to access the platform to generate queries for you.
The platform can be accessed from any `Doctrine\DBAL\Connection` instance by calling the `getDatabasePlatform()` method.
[php]
$platform = $conn->getDatabasePlatform();
Each database driver has a platform associated with it by default. Several drivers also share the same platform,
for example PDO_OCI and OCI8 share the `OraclePlatform`.
If you want to overwrite parts of your platform you can do so when creating a connection.
There is a `platform` option you can pass an instance of the platform you want the connection to use:
[php]
$myPlatform = new MyPlatform();
$options = array(
'driver' => 'pdo_sqlite',
'path' => 'database.sqlite',
'platform' => $myPlatform
);
$conn = DriverManager::getConnection($options);
This way you can optimize your schema or generated SQL code with features that might not be portable for instance, however
are required for your special needs. This can include using triggers or views to simulate features or adding behaviour
to existing SQL functions.
Platforms are also responsible to know which database type translates to which PHP Type. This is a very tricky issue
across all the different database vendors, for example MySQL BIGINT and Oracle NUMBER should be handled as integer.
Doctrine 2 offers a powerful way to abstract the database to php and back conversion, which is described in the
next section.
\ No newline at end of file
A Schema Manager instance helps you with the abstraction of the generation of SQL assets such as Tables, Sequences, Foreign Keys and Indexes.
Schema-Manager
==============
To retrieve the `SchemaManager` for your connection you can use the `getSchemaManager()` method:
A Schema Manager instance helps you with the abstraction of the
generation of SQL assets such as Tables, Sequences, Foreign Keys
and Indexes.
[php]
To retrieve the ``SchemaManager`` for your connection you can use
the ``getSchemaManager()`` method:
::
<?php
$sm = $conn->getSchemaManager();
Now with the `SchemaManager` instance in `$em` you can use the available methods to learn about your database schema:
Now with the ``SchemaManager`` instance in ``$em`` you can use the
available methods to learn about your database schema:
**NOTE**
Parameters containing identifiers passed to the SchemaManager
methods are *NOT* quoted automatically! Identifier quoting is
really difficult to do manually in a consistent way across
different databases. You have to manually quote the identifiers
when you accept data from user- or other sources not under your
control.
> **NOTE**
>
> Parameters containing identifiers passed to the SchemaManager methods are *NOT* quoted automatically!
> Identifier quoting is really difficult to do manually in a consistent way across different databases.
> You have to manually quote the identifiers when you accept data from user- or other sources not under
> your control.
++ listDatabases()
listDatabases()
---------------
Retrieve an array of databases on the configured connection:
[php]
::
<?php
$databases = $sm->listDatabases();
++ listSequences($database = null)
listSequences($database = null)
-------------------------------
Retrieve an array of ``Doctrine\DBAL\Schema\Sequence`` instances
that exist for a database:
Retrieve an array of `Doctrine\DBAL\Schema\Sequence` instances that exist for a database:
::
[php]
<?php
$sequences = $sm->listSequences();
Or if you want to manually specify a database name:
[php]
::
<?php
$sequences = $sm->listSequences('dbname');
Now you can loop over the array inspecting each sequence object:
[php]
::
<?php
foreach ($sequences as $sequence) {
echo $sequence->getName() . "\n";
}
++ listTableColumns($tableName)
listTableColumns($tableName)
----------------------------
Retrieve an array of ``Doctrine\DBAL\Schema\Column`` instances that
exist for the given table:
Retrieve an array of `Doctrine\DBAL\Schema\Column` instances that exist for the given table:
::
[php]
<?php
$columns = $sm->listTableColumns('user');
Now you can loop over the array inspecting each column object:
[php]
::
<?php
foreach ($columns as $column) {
echo $column->getName() . ': ' . $column->getType() . "\n";
}
++ listTableDetails($tableName)
listTableDetails($tableName)
----------------------------
Retrieve a single `Doctrine\DBAL\Schema\Table` instance that encapsulates all the details of the given table:
Retrieve a single ``Doctrine\DBAL\Schema\Table`` instance that
encapsulates all the details of the given table:
[php]
::
<?php
$table = $sm->listTableDetails('user');
Now you can call methods on the table to manipulate the in memory schema for that table. For example we can add a new column:
Now you can call methods on the table to manipulate the in memory
schema for that table. For example we can add a new column:
::
[php]
<?php
$table->addColumn('email_address', 'string');
++ listTableForeignKeys($tableName)
listTableForeignKeys($tableName)
--------------------------------
Retrieve an array of ``Doctrine\DBAL\Schema\ForeignKeyConstraint``
instances that exist for the given table:
Retrieve an array of `Doctrine\DBAL\Schema\ForeignKeyConstraint` instances that exist for the given table:
::
[php]
<?php
$foreignKeys = $sm->listTableForeignKeys('user');
Now you can loop over the array inspecting each foreign key object:
Now you can loop over the array inspecting each foreign key
object:
[php]
::
<?php
foreach ($foreignKeys as $foreignKey) {
echo $foreignKey->getName() . ': ' . $foreignKey->getLocalTableName() ."\n";
}
++ listTableIndexes($tableName)
listTableIndexes($tableName)
----------------------------
Retrieve an array of ``Doctrine\DBAL\Schema\Index`` instances that
exist for the given table:
Retrieve an array of `Doctrine\DBAL\Schema\Index` instances that exist for the given table:
::
[php]
<?php
$indexes = $sm->listTableIndexes('user');
Now you can loop over the array inspecting each index object:
[php]
::
<?php
foreach ($indexes as $index) {
echo $index->getName() . ': ' . ($index->isUnique() ? 'unique' : 'not unique') . "\n";
}
++ listTables()
listTables()
------------
Retrieve an array of ``Doctrine\DBAL\Schema\Table`` instances that
exist in the connections database:
Retrieve an array of `Doctrine\DBAL\Schema\Table` instances that exist in the connections database:
::
[php]
<?php
$tables = $sm->listTables();
Each `Doctrine\DBAl\Schema\Table` instance is populated with information provided by all the above methods. So it encapsulates an array of `Doctrine\DBAL\Schema\Column` instances that can be retrieved with the `getColumns()` method:
Each ``Doctrine\DBAl\Schema\Table`` instance is populated with
information provided by all the above methods. So it encapsulates
an array of ``Doctrine\DBAL\Schema\Column`` instances that can be
retrieved with the ``getColumns()`` method:
[php]
::
<?php
foreach ($tables as $table) {
echo $table->getName() . " columns:\n\n";
foreach ($table->getColumns() as $column) {
echo ' - ' . $column->getName() . "\n";
}
echo $table->getName() . " columns:\n\n";
foreach ($table->getColumns() as $column) {
echo ' - ' . $column->getName() . "\n";
}
}
listViews()
-----------
++ listViews()
Retrieve an array of ``Doctrine\DBAL\Schema\View`` instances that
exist in the connections database:
Retrieve an array of `Doctrine\DBAL\Schema\View` instances that exist in the connections database:
::
[php]
<?php
$views = $sm->listViews();
Now you can loop over the array inspecting each view object:
[php]
::
<?php
foreach ($views as $view) {
echo $view->getName() . ': ' . $view->getSql() . "\n";
}
++ createSchema()
createSchema()
--------------
For a complete representation of the current database you can use
the ``createSchema()`` method which returns an instance of
``Doctrine\DBAL\Schema\Schema``, which you can use in conjunction
with the SchemaTool or Schema Comparator.
For a complete representation of the current database you can use the `createSchema()` method which returns an instance of `Doctrine\DBAL\Schema\Schema`, which you can use in conjunction with the SchemaTool or Schema Comparator.
::
[php]
<?php
$fromSchema = $sm->createSchema();
Now we can clone the `$fromSchema` to `$toSchema` and drop a table:
Now we can clone the ``$fromSchema`` to ``$toSchema`` and drop a
table:
[php]
::
<?php
$toSchema = clone $fromSchema;
$toSchema->dropTable('user');
Now we can compare the two schema instances in order to calculate the differences between them and return the sql required to make the changes on the database:
Now we can compare the two schema instances in order to calculate
the differences between them and return the sql required to make
the changes on the database:
::
[php]
<?php
$sql = $fromSchema->getMigrateToSql($toSchema, $conn->getDatabasePlatform());
The `$sql` array should give you a sql query to drop the user table:
The ``$sql`` array should give you a sql query to drop the user
table:
[php]
print_r($sql);
::
<?php
print_r($sql);
/*
array(
0 => 'DROP TABLE user'
)
*/
\ No newline at end of file
*/
Doctrine has a very powerful abstraction of database schemas. It offers an object-oriented representation of a database schema with support for all the details of Tables, Sequences, Indexes and Foreign Keys. These Schema instances generate a representation that is equal for all the supported platforms. Internally this functionality is used by the ORM Schema Tool to offer you create, drop and update database schema methods from your Doctrine ORM Metadata model. Up to very specific functionality of your database system this allows you to generate SQL code that makes your Domain model work.
Schema-Representation
=====================
You will be pleased to hear, that Schema representation is completly decoupled from the Doctrine ORM though, that is you can also use it in any other project to implement database migrations or for SQL schema generation for any metadata model that your application has. You can easily generate a Schema, as a simple example shows:
Doctrine has a very powerful abstraction of database schemas. It
offers an object-oriented representation of a database schema with
support for all the details of Tables, Sequences, Indexes and
Foreign Keys. These Schema instances generate a representation that
is equal for all the supported platforms. Internally this
functionality is used by the ORM Schema Tool to offer you create,
drop and update database schema methods from your Doctrine ORM
Metadata model. Up to very specific functionality of your database
system this allows you to generate SQL code that makes your Domain
model work.
[php]
You will be pleased to hear, that Schema representation is
completly decoupled from the Doctrine ORM though, that is you can
also use it in any other project to implement database migrations
or for SQL schema generation for any metadata model that your
application has. You can easily generate a Schema, as a simple
example shows:
::
<?php
$schema = new \Doctrine\DBAL\Schema\Schema();
$myTable = $schema->createTable("my_table");
$myTable->addColumn("id", "integer", array("unsigned" => true));
......@@ -10,24 +29,36 @@ You will be pleased to hear, that Schema representation is completly decoupled f
$myTable->setPrimaryKey(array("id"));
$myTable->addUniqueIndex(array("username"));
$schema->createSequence("my_table_seq");
$myForeign = $schema->createTable("my_foreign");
$myForeign->addColumn("id", "integer");
$myForeign->addColumn("user_id", "integer");
$myForeign->addForeignKeyConstraint($myTable, array("user_id"), array("id"), array("onUpdate" => "CASCADE"));
$queries = $schema->toSql($myPlatform); // get queries to create this schema.
$dropSchema = $schema->toDropSql($myPlatform); // get queries to safely delete this schema.
Now if you want to compare this schema with another schema, you can use the `Comparator` class to get instances of `SchemaDiff`, `TableDiff` and `ColumnDiff`, aswell as information about other foreign key, sequence and index changes.
Now if you want to compare this schema with another schema, you can
use the ``Comparator`` class to get instances of ``SchemaDiff``,
``TableDiff`` and ``ColumnDiff``, aswell as information about other
foreign key, sequence and index changes.
[php]
::
<?php
$comparator = new \Doctrine\DBAL\Schema\Comparator();
$schemaDiff = $comparator->compare($fromSchema, $toSchema);
$queries = $schemaDiff->toSql($myPlatform); // queries to get from one to another schema.
$saveQueries = $schemaDiff->toSaveSql($myPlatform);
The Save Diff mode is a specific mode that prevents the deletion of tables and sequences that might occour when making a diff of your schema. This is often necessary when your target schema is not complete but only describes a subset of your application.
The Save Diff mode is a specific mode that prevents the deletion of
tables and sequences that might occour when making a diff of your
schema. This is often necessary when your target schema is not
complete but only describes a subset of your application.
All methods that generate SQL queries for you make much effort to
get the order of generation correct, so that no problems will ever
occour with missing links of foreign keys.
All methods that generate SQL queries for you make much effort to get the order of generation correct, so that no problems will ever occour with missing links of foreign keys.
\ No newline at end of file
Supporting Other Databases
==========================
To support a database which is not currently shipped with Doctrine
you have to implement the following interfaces and abstract
classes:
- ``\Doctrine\DBAL\Driver\Driver``
- ``\Doctrine\DBAL\Driver\Statement``
- ``\Doctrine\DBAL\Platforms\AbstractPlatform``
- ``\Doctrine\DBAL\Schema\AbstractSchemaManager``
For an already supported platform but unsupported driver you only
need to implement the first two interfaces, since the SQL
Generation and Schema Management is already supported by the
respective platform and schema instances. You can also make use of
several Abstract Unittests in the ``\Doctrine\Tests\DBAL`` package
to check if your platform behaves like all the others which is
necessary for SchemaTool support, namely:
- ``\Doctrine\Tests\DBAL\Platforms\AbstractPlatformTestCase``
- ``\Doctrine\Tests\DBAL\Functional\Schema\AbstractSchemaManagerTestCase``
We would be very happy if any support for new databases would be
contributed back to Doctrine to make it an even better product.
To support a database which is not currently shipped with Doctrine you have to implement the following interfaces and abstract classes:
* `\Doctrine\DBAL\Driver\Driver`
* `\Doctrine\DBAL\Driver\Statement`
* `\Doctrine\DBAL\Platforms\AbstractPlatform`
* `\Doctrine\DBAL\Schema\AbstractSchemaManager`
For an already supported platform but unsupported driver you only need to implement the first two interfaces, since the SQL Generation and Schema Management is already supported by the respective platform and schema instances. You can also make use of several Abstract Unittests in the `\Doctrine\Tests\DBAL` package to check if your platform behaves like all the others which is necessary for SchemaTool support, namely:
* `\Doctrine\Tests\DBAL\Platforms\AbstractPlatformTestCase`
* `\Doctrine\Tests\DBAL\Functional\Schema\AbstractSchemaManagerTestCase`
We would be very happy if any support for new databases would be contributed back to Doctrine to make it an even better product.
\ No newline at end of file
Transactions
============
A ``Doctrine\DBAL\Connection`` provides a PDO-like API for
transaction management, with the methods
``Connection#beginTransaction()``, ``Connection#commit()`` and
``Connection#rollback()``.
Transaction demarcation with the Doctrine DBAL looks as follows:
::
<?php
$conn->beginTransaction();
try{
// do stuff
$conn->commit();
} catch(Exception $e) {
$conn->rollback();
throw $e;
}
Alternatively, the control abstraction
``Connection#transactional($func)`` can be used to make the code
more concise and to make sure you never forget to rollback the
transaction in the case of an exception. The following code snippet
is functionally equivalent to the previous one:
::
<?php
$conn->transactional(function($conn) {
// do stuff
});
The ``Doctrine\DBAL\Connection`` also has methods to control the
transaction isolation level as supported by the underlying
database. ``Connection#setTransactionIsolation($level)`` and
Connection#getTransactionIsolation() can be used for that purpose.
The possible isolation levels are represented by the following
constants:
::
<?php
Connection::TRANSACTION_READ_UNCOMMITTED
Connection::TRANSACTION_READ_COMMITTED
Connection::TRANSACTION_REPEATABLE_READ
Connection::TRANSACTION_SERIALIZABLE
The default transaction isolation level of a
``Doctrine\DBAL\Connection`` is chosen by the underlying platform
but it is always at least READ\_COMMITTED.
Transaction Nesting
-------------------
A ``Doctrine\DBAL\Connection`` also adds support for nesting
transactions, or rather propagating transaction control up the call
stack. For that purpose, the ``Connection`` class keeps an internal
counter that represents the nesting level and is
increased/decreased as ``beginTransaction()``, ``commit()`` and
``rollback()`` are invoked. ``beginTransaction()`` increases the
nesting level whilst
``commit()`` and``rollback()``decrease the nesting level. The nesting level starts at 0. Whenever the nesting level transitions from 0 to 1,``beginTransaction()``is invoked on the underlying driver connection and whenever the nesting level transitions from 1 to 0,``commit()``or``rollback()``is invoked on the underlying driver, depending on whether the transition was caused by``Connection#commit()``or``Connection#rollback()\`.
What this means is that transaction control is basically passed to
code higher up in the call stack and the inner transaction block is
ignored, with one important exception that is described further
below. Do not confuse this with "real" nested transactions or
savepoints. These are not supported by Doctrine. There is always
only a single, real database transaction.
To visualize what this means in practice, consider the following
example:
::
<?php
// $conn instanceof Doctrine\DBAL\Connection
$conn->beginTransaction(); // 0 => 1, "real" transaction started
try {
...
// nested transaction block, this might be in some other API/library code that is
// unaware of the outer transaction.
$conn->beginTransaction(); // 1 => 2
try {
...
$conn->commit(); // 2 => 1
} catch (Exception $e) {
$conn->rollback(); // 2 => 1, transaction marked for rollback only
throw $e;
}
...
$conn->commit(); // 1 => 0, "real" transaction committed
} catch (Exception $e) {
$conn->rollback(); // 1 => 0, "real" transaction rollback
throw $e;
}
However,
**a rollback in a nested transaction block will always mark the current transaction so that the only possible outcome of the transaction is to be rolled back**.
That means in the above example, the rollback in the inner
transaction block marks the whole transaction for rollback only.
Even if the nested transaction block would not rethrow the
exception, the transaction is marked for rollback only and the
commit of the outer transaction would trigger an exception, leading
to the final rollback. This also means that you can not
successfully commit some changes in an outer transaction if an
inner transaction block fails and issues a rollback, even if this
would be the desired behavior (i.e. because the nested operation is
"optional" for the purpose of the outer transaction block). To
achieve that, you need to restructure your application logic so as
to avoid nesting transaction blocks. If this is not possible
because the nested transaction blocks are in a third-party API
you're out of luck.
All that is guaruanteed to the inner transaction is that it still
happens atomically, all or nothing, the transaction just gets a
wider scope and the control is handed to the outer scope.
**CAUTION** The transaction nesting described here is a debated
feature that has it's critics. Form your own opinion. We recommend
avoiding nesting transaction blocks when possible, and most of the
time, it is possible. Transaction control should mostly be left to
a service layer and not be handled in data access objects or
similar.
-
**CAUTION** Directly invoking ``PDO#beginTransaction()``,
``PDO#commit()`` or ``PDO#rollback()`` or the corresponding methods
on the particular ``Doctrine\DBAL\Driver\Connection`` instance in
use bybasses the transparent transaction nesting that is provided
by ``Doctrine\DBAL\Connection`` and can therefore corrupt the
nesting level, causing errors with broken transaction boundaries
that may be hard to debug.
A `Doctrine\DBAL\Connection` provides a PDO-like API for transaction management, with the
methods `Connection#beginTransaction()`, `Connection#commit()` and `Connection#rollback()`.
Transaction demarcation with the Doctrine DBAL looks as follows:
[php]
$conn->beginTransaction();
try{
// do stuff
$conn->commit();
} catch(Exception $e) {
$conn->rollback();
throw $e;
}
Alternatively, the control abstraction `Connection#transactional($func)` can be used to make
the code more concise and to make sure you never forget to rollback the transaction in the case
of an exception. The following code snippet is functionally equivalent to the previous one:
[php]
$conn->transactional(function($conn) {
// do stuff
});
The `Doctrine\DBAL\Connection` also has methods to control the transaction isolation level as supported by the underlying database.
`Connection#setTransactionIsolation($level)` and Connection#getTransactionIsolation() can be used for that purpose.
The possible isolation levels are represented by the following constants:
[php]
Connection::TRANSACTION_READ_UNCOMMITTED
Connection::TRANSACTION_READ_COMMITTED
Connection::TRANSACTION_REPEATABLE_READ
Connection::TRANSACTION_SERIALIZABLE
The default transaction isolation level of a `Doctrine\DBAL\Connection` is chosen by the underlying
platform but it is always at least READ_COMMITTED.
++ Transaction Nesting
A `Doctrine\DBAL\Connection` also adds support for nesting transactions, or rather propagating transaction control up the call stack.
For that purpose, the `Connection` class keeps an internal counter that represents the nesting level and is increased/decreased as
`beginTransaction()`, `commit()` and `rollback()` are invoked. `beginTransaction()` increases the nesting level whilst `commit()``
and `rollback()` decrease the nesting level. The nesting level starts at 0. Whenever the nesting level transitions from 0 to 1,
`beginTransaction()` is invoked on the underlying driver connection and whenever the nesting level transitions from 1 to 0,
`commit()` or `rollback()` is invoked on the underlying driver, depending on whether the transition was caused by `Connection#commit()`
or `Connection#rollback()`.
What this means is that transaction control is basically passed to code higher up in the call stack and
the inner transaction block is ignored, with one important exception that is described further below.
Do not confuse this with "real" nested transactions or savepoints. These are not supported by Doctrine.
There is always only a single, real database transaction.
To visualize what this means in practice, consider the following example:
[php]
// $conn instanceof Doctrine\DBAL\Connection
$conn->beginTransaction(); // 0 => 1, "real" transaction started
try {
...
// nested transaction block, this might be in some other API/library code that is
// unaware of the outer transaction.
$conn->beginTransaction(); // 1 => 2
try {
...
$conn->commit(); // 2 => 1
} catch (Exception $e) {
$conn->rollback(); // 2 => 1, transaction marked for rollback only
throw $e;
}
...
$conn->commit(); // 1 => 0, "real" transaction committed
} catch (Exception $e) {
$conn->rollback(); // 1 => 0, "real" transaction rollback
throw $e;
}
However, **a rollback in a nested transaction block will always mark the current transaction so that the only possible outcome of the transaction is to be rolled back**.
That means in the above example, the rollback in the inner transaction block marks the whole transaction for rollback only.
Even if the nested transaction block would not rethrow the exception, the transaction is marked for rollback only and the commit of
the outer transaction would trigger an exception, leading to the final rollback.
This also means that you can not successfully commit some changes in an outer transaction if an inner transaction block fails and issues a rollback,
even if this would be the desired behavior (i.e. because the nested operation is "optional" for the purpose of the outer transaction block).
To achieve that, you need to restructure your application logic so as to avoid nesting transaction blocks. If this is not possible
because the nested transaction blocks are in a third-party API you're out of luck.
All that is guaruanteed to the inner transaction is that it still happens atomically, all or nothing, the transaction just gets a wider scope
and the control is handed to the outer scope.
> **CAUTION**
> The transaction nesting described here is a debated feature that has it's critics. Form your own opinion.
> We recommend avoiding nesting transaction blocks when possible, and most of the time, it is possible.
> Transaction control should mostly be left to a service layer and not be handled in data access objects or similar.
-
> **CAUTION**
> Directly invoking `PDO#beginTransaction()`, `PDO#commit()` or `PDO#rollback()` or the
> corresponding methods on the particular `Doctrine\DBAL\Driver\Connection` instance in
> use bybasses the transparent transaction nesting that is provided by
> `Doctrine\DBAL\Connection` and can therefore corrupt the nesting level, causing errors
> with broken transaction boundaries that may be hard to debug.
\ No newline at end of file
Besides abstraction of SQL one needs a translation between database and PHP data-types to implement database independent applications.
Doctrine 2 has a type translation system baked in that supports the conversion from and to PHP values from any
database platform, aswell as platform independent SQL generation for any Doctrine Type.
Using the ORM you generally don't need to know about the Type system. This is unless you wan't to make use of database
vendor specific database types not included in Doctrine 2. The following PHP Types are abstracted across all
the supported database vendors:
* Integer
* SmallInt
* BigInt
* String (string with maximum length, for example 255)
* Text (strings without maximum length)
* Decimal (restricted floats, *NOTE* Only works with a setlocale() configuration that uses decimal points!)
* Boolean
* DateTime
* Date (DateTime instance where only Y-m-d get persisted)
* Time (DateTime instance where only H:i:s get persisted)
* Array (serialized into a text field for all vendors by default)
* Object (serialized into a text field for all vendors by default)
* Float (*NOTE* Only works with a setlocale() configuration that uses decimal points!)
Types are flyweights. This means there is only ever one instance of a type and it is not allowed to contain any state.
Creation of type instances is abstracted through a static get method `Doctrine\DBAL\Types\Type::getType()`.
> **NOTE**
>
> See the [Known Vendor Issue](./../known-vendor-issues) section for details about the different
> handling of microseconds and timezones across all the different vendors.
++ Detection of Database Types
When calling table inspection methods on your connections `SchemaManager` instance
the retrieved database column types are translated into Doctrine mapping types.
Translation is necessary to allow database abstraction and metadata comparisons
for example for Migrations or the ORM SchemaTool.
Each database platform has a default mapping of database types to Doctrine types. You can inspect this mapping
for platform of your choice looking at the `AbstractPlatform::initializeDoctrineTypeMappings()`
Types
=====
Besides abstraction of SQL one needs a translation between database
and PHP data-types to implement database independent applications.
Doctrine 2 has a type translation system baked in that supports the
conversion from and to PHP values from any database platform,
aswell as platform independent SQL generation for any Doctrine
Type.
Using the ORM you generally don't need to know about the Type
system. This is unless you wan't to make use of database vendor
specific database types not included in Doctrine 2. The following
PHP Types are abstracted across all the supported database
vendors:
- Integer
- SmallInt
- BigInt
- String (string with maximum length, for example 255)
- Text (strings without maximum length)
- Decimal (restricted floats, *NOTE* Only works with a setlocale()
configuration that uses decimal points!)
- Boolean
- DateTime
- Date (DateTime instance where only Y-m-d get persisted)
- Time (DateTime instance where only H:i:s get persisted)
- Array (serialized into a text field for all vendors by default)
- Object (serialized into a text field for all vendors by default)
- Float (*NOTE* Only works with a setlocale() configuration that
uses decimal points!)
Types are flyweights. This means there is only ever one instance of
a type and it is not allowed to contain any state. Creation of type
instances is abstracted through a static get method
``Doctrine\DBAL\Types\Type::getType()``.
**NOTE**
See the `Known Vendor Issue <./../known-vendor-issues>`_ section
for details about the different handling of microseconds and
timezones across all the different vendors.
Detection of Database Types
---------------------------
When calling table inspection methods on your connections
``SchemaManager`` instance the retrieved database column types are
translated into Doctrine mapping types. Translation is necessary to
allow database abstraction and metadata comparisons for example for
Migrations or the ORM SchemaTool.
Each database platform has a default mapping of database types to
Doctrine types. You can inspect this mapping for platform of your
choice looking at the
``AbstractPlatform::initializeDoctrineTypeMappings()``
implementation.
If you want to change how Doctrine maps a database type to a `Doctrine\DBAL\Types\Type` instance
you can use the `AbstractPlatform::registerDoctrineTypeMapping($dbType, $doctrineType)` method to
add new database types or overwrite existing ones.
If you want to change how Doctrine maps a database type to a
``Doctrine\DBAL\Types\Type`` instance you can use the
``AbstractPlatform::registerDoctrineTypeMapping($dbType, $doctrineType)``
method to add new database types or overwrite existing ones.
> **NOTE**
>
> You can only map a database type to exactly one Doctrine type. Database vendors that allow
> to define custom types like PostgreSql can help to overcome this issue.
**NOTE**
++ Custom Mapping Types
You can only map a database type to exactly one Doctrine type.
Database vendors that allow to define custom types like PostgreSql
can help to overcome this issue.
Just redefining how database types are mapped to all the existing Doctrine types is not at all that useful.
You can define your own Doctrine Mapping Types by extending `Doctrine\DBAL\Types\Type`. You are required
to implement 4 different methods to get this working.
See this example of how to implement a Money object in PostgreSQL. For this we create the type in PostgreSQL as:
Custom Mapping Types
--------------------
Just redefining how database types are mapped to all the existing
Doctrine types is not at all that useful. You can define your own
Doctrine Mapping Types by extending ``Doctrine\DBAL\Types\Type``.
You are required to implement 4 different methods to get this
working.
See this example of how to implement a Money object in PostgreSQL.
For this we create the type in PostgreSQL as:
.. code-block:: sql
[sql]
CREATE DOMAIN MyMoney AS DECIMAL(18,3);
Now we implement our `Doctrine\DBAL\Types\Type` instance:
Now we implement our ``Doctrine\DBAL\Types\Type`` instance:
[php]
namespace My\Project\Types;
::
<?php
namespace My\Project\Types;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* My custom datatype.
*/
class MoneyType extends Type
{
const MONEY = 'money'; // modify to match your type name
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return 'MyMoney';
}
public function convertToPHPValue($value, AbstractPlatform $platform)
{
return new Money($value);
}
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
return $value->toDecimal();
}
public function getName()
{
return self::MONEY;
}
}
Now we have to register this type with the Doctrine Type system and hook it into the database platform:
Now we have to register this type with the Doctrine Type system and
hook it into the database platform:
[php]
::
<?php
Type::addType('money', 'My\Project\Types\MoneyType');
$conn->getDatabasePlatform()->registerDoctrineTypeMapping('MyMoney', 'money');
This would allow to use a money type in the ORM for example and have Doctrine automatically convert
it back and forth to the database.
\ No newline at end of file
This would allow to use a money type in the ORM for example and
have Doctrine automatically convert it back and forth to the
database.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment