From 95bd6100a5fe94aec9fba11968208eb9bf91bf64 Mon Sep 17 00:00:00 2001 From: doctrine Date: Sun, 23 Jul 2006 21:08:06 +0000 Subject: [PATCH] Manual added --- ...Eventlisteners - Creating new listener.php | 34 ++ ...ents - Eventlisteners - List of events.php | 45 ++ ...ts - Eventlisteners - Listening events.php | 13 + ... components - Hook - Parameter hooking.php | 3 + ... Validators - Analyzing the ErrorStack.php | 27 + ...components - Validators - Intruduction.php | 5 + ...- Validators - Validating transactions.php | 42 ++ ...ents - Collection - Accessing elements.php | 15 + ...nts - Collection - Adding new elements.php | 8 + ...nts - Collection - Deleting collection.php | 7 + ...nts - Collection - Fetching strategies.php | 52 ++ ... Collection - Getting collection count.php | 9 + ...s - Collection - Saving the collection.php | 9 + ...mponents - Manager - Managing sessions.php | 25 + ...ents - Manager - Opening a new session.php | 18 + ... Components - Query - Bound parameters.php | 6 + ...ents - Query - FROM - selecting tables.php | 15 + ...mponents - Query - Fetching strategies.php | 25 + ...nd OFFSET - limiting the query results.php | 11 + ...nents - Query - Lazy property fetching.php | 6 + ...omponents - Query - Method overloading.php | 12 + ...ery - ORDER BY - sorting query results.php | 21 + ...omponents - Query - Relation operators.php | 15 + ...ery - WHERE - setting query conditions.php | 27 + ...mponents - RawSql - Method overloading.php | 10 + .../Basic Components - RawSql - Using SQL.php | 7 + ...onents - Record - Accessing properties.php | 21 + ...onents - Record - Creating new records.php | 20 + ...Components - Record - Deleting records.php | 20 + ...ponents - Record - Getting object copy.php | 3 + ...onents - Record - Getting record state.php | 31 + ...- Record - Retrieving existing records.php | 24 + ...asic Components - Record - Serializing.php | 5 + ...Components - Record - Updating records.php | 13 + ...nents - Session - Flushing the session.php | 11 + ...nts - Session - Getting a table object.php | 11 + ...ents - Session - Getting session state.php | 16 + ...ents - Session - Querying the database.php | 10 + ...ic Components - Table - Custom finders.php | 22 + ...ponents - Table - Custom table classes.php | 13 + ...ic Components - Table - Finder methods.php | 20 + ...ts - Table - Getting table information.php | 11 + ...iguration - Custom getters and setters.php | 21 + ...figuration - Custom primary key column.php | 9 + ...tion - Setting attributes - Batch size.php | 5 + ... - Setting attributes - Event listener.php | 5 + ...Setting attributes - Fetching strategy.php | 5 + ...g attributes - Offset collection limit.php | 5 + ... Setting attributes - Session lockmode.php | 5 + ... - Setting attributes - Table creation.php | 5 + ...tion - Setting attributes - Validation.php | 5 + ...ration - Setting default eventlistener.php | 10 + ...figuration - Setting default fetchmode.php | 11 + .../codes/Configuration - Using sequences.php | 9 + ...Database operations - Limit and offset.php | 7 + ...abase operations - Nested transactions.php | 17 + .../Database operations - Query logging.php | 15 + .../codes/Database operations - Sequences.php | 7 + .../Database operations - Transactions.php | 14 + .../codes/Getting started - Installation.php | 13 + ...ing started - Setting table definition.php | 15 + ...Getting started - Starting new project.php | 13 + ...h relations - Creating related records.php | 14 + ...h relations - Deleting related records.php | 9 + ...relations - Retrieving related records.php | 7 + ...h relations - Updating related records.php | 9 + ...ssociations - One-to-Many, Many-to-One.php | 18 + ... Foreign key associations - One-to-One.php | 28 + ...eign key associations - Tree structure.php | 12 + ...ons - Inheritance - Column aggregation.php | 22 + ...- Inheritance - One table many classes.php | 14 + ...ns - Inheritance - One table one class.php | 26 + ...Join table associations - Many-to-Many.php | 49 ++ ... table associations - Self-referencing.php | 16 + ...ng object relations - Relation aliases.php | 26 + ...ance - Internal optimizations - DELETE.php | 24 + ...ance - Internal optimizations - INSERT.php | 28 + ...eal world examples - Forum application.php | 52 ++ ...orld examples - User management system.php | 79 +++ .../Runtime classes - Doctrine_Record.php | 40 ++ .../Runtime classes - Doctrine_Session.php | 30 + manual/codes/Transactions - Introduction.php | 13 + manual/codes/Transactions - Nesting.php | 23 + manual/codes/Transactions - Unit of work.php | 18 + ...nced components - Cache - Introduction.php | 2 + ...Eventlisteners - Creating new listener.php | 1 + ...ents - Eventlisteners - List of events.php | 1 + ...anced components - Hook - Introduction.php | 3 + ...components - Validators - Intruduction.php | 11 + ...dators - List of predefined validators.php | 124 ++++ ...- Validators - Validating transactions.php | 5 + ...vanced components - View - Intoduction.php | 2 + ...ents - Collection - Accessing elements.php | 1 + ...nts - Collection - Deleting collection.php | 9 + ...nts - Collection - Fetching strategies.php | 42 ++ ...ic Components - Manager - Introduction.php | 1 + ...mponents - Manager - Managing sessions.php | 3 + ...ents - Manager - Opening a new session.php | 3 + ...ponents - Query - DQL - SQL conversion.php | 52 ++ ...asic Components - Query - Introduction.php | 8 + ...omponents - Query - Method overloading.php | 1 + ...ery - ORDER BY - sorting query results.php | 1 + ...omponents - Query - Relation operators.php | 7 + ...onents - Record - Accessing properties.php | 3 + ...c Components - Record - Adding records.php | 3 + ...onents - Record - Creating new records.php | 3 + ...Components - Record - Deleting records.php | 2 + ...ponents - Record - Getting object copy.php | 2 + ...onents - Record - Getting record state.php | 7 + ...- Record - Retrieving existing records.php | 3 + ...asic Components - Record - Serializing.php | 2 + ...Components - Record - Updating records.php | 3 + ...nents - Session - Flushing the session.php | 2 + ...nts - Session - Getting a table object.php | 1 + ...ents - Session - Getting session state.php | 2 + ...ic Components - Table - Custom finders.php | 2 + ...ponents - Table - Custom table classes.php | 2 + ...ic Components - Table - Finder methods.php | 2 + ...ents - Exceptions - List of exceptions.php | 24 + manual/docs/Cache - Configuration.php | 26 + manual/docs/Cache - Overview.php | 40 ++ ...onfiguration - Levels of configuration.php | 18 + .../Configuration - List of attributes.php | 44 ++ .../docs/Getting started - Installation.php | 3 + .../docs/Getting started - Requirements.php | 3 + ...efinition - Constraints and validators.php | 35 ++ ...le definition - Data types and lengths.php | 41 ++ ...etting table definition - Introduction.php | 7 + ...Getting started - Starting new project.php | 10 + ... relations - Composites and aggregates.php | 8 + ...h relations - Creating related records.php | 1 + ...h relations - Deleting related records.php | 2 + ...relations - Retrieving related records.php | 2 + ...h relations - Updating related records.php | 2 + ... Foreign key associations - One-to-One.php | 7 + ...ons - Inheritance - Column aggregation.php | 8 + ...- Inheritance - One table many classes.php | 7 + ...ns - Inheritance - One table one class.php | 5 + ...Join table associations - Many-to-Many.php | 5 + ... table associations - Self-referencing.php | 1 + ...e-to-Many and One-to-One relationships.php | 1 + ...ng object relations - Relation aliases.php | 1 + ...orld examples - User management system.php | 21 + ...Runtime classes - Doctrine_Association.php | 1 + .../Runtime classes - Doctrine_Collection.php | 1 + ...me classes - Doctrine_Collection_Batch.php | 1 + ...lasses - Doctrine_Collection_Immediate.php | 1 + ...ime classes - Doctrine_Collection_Lazy.php | 1 + .../Runtime classes - Doctrine_ForeignKey.php | 1 + .../Runtime classes - Doctrine_Manager.php | 2 + .../Runtime classes - Doctrine_Record.php | 2 + .../Runtime classes - Doctrine_Session.php | 3 + .../docs/Runtime classes - Doctrine_Table.php | 2 + .../Technology - Design patterns used.php | 46 ++ manual/docs/Technology - Speed.php | 35 ++ manual/documentation.php | 532 +++++++++++++++++ manual/highlight.php | 560 ++++++++++++++++++ manual/images/docflash.jpg | Bin 0 -> 56287 bytes manual/images/docflashbg.jpg | Bin 0 -> 8912 bytes manual/images/docnew.gif | Bin 0 -> 2864 bytes manual/images/gradient1.jpg | Bin 0 -> 8273 bytes manual/images/gradient2.jpg | Bin 0 -> 8260 bytes manual/images/gradient3.jpg | Bin 0 -> 8285 bytes manual/images/logo.jpg | Bin 0 -> 12414 bytes manual/images/tausta2.jpg | Bin 0 -> 8148 bytes manual/styles/basic.css | 49 ++ manual/styles/steel.css | 45 ++ manual/top.php | 22 + 168 files changed, 3413 insertions(+) create mode 100644 manual/codes/Advanced components - Eventlisteners - Creating new listener.php create mode 100644 manual/codes/Advanced components - Eventlisteners - List of events.php create mode 100644 manual/codes/Advanced components - Eventlisteners - Listening events.php create mode 100644 manual/codes/Advanced components - Hook - Parameter hooking.php create mode 100644 manual/codes/Advanced components - Validators - Analyzing the ErrorStack.php create mode 100644 manual/codes/Advanced components - Validators - Intruduction.php create mode 100644 manual/codes/Advanced components - Validators - Validating transactions.php create mode 100644 manual/codes/Basic Components - Collection - Accessing elements.php create mode 100644 manual/codes/Basic Components - Collection - Adding new elements.php create mode 100644 manual/codes/Basic Components - Collection - Deleting collection.php create mode 100644 manual/codes/Basic Components - Collection - Fetching strategies.php create mode 100644 manual/codes/Basic Components - Collection - Getting collection count.php create mode 100644 manual/codes/Basic Components - Collection - Saving the collection.php create mode 100644 manual/codes/Basic Components - Manager - Managing sessions.php create mode 100644 manual/codes/Basic Components - Manager - Opening a new session.php create mode 100644 manual/codes/Basic Components - Query - Bound parameters.php create mode 100644 manual/codes/Basic Components - Query - FROM - selecting tables.php create mode 100644 manual/codes/Basic Components - Query - Fetching strategies.php create mode 100644 manual/codes/Basic Components - Query - LIMIT and OFFSET - limiting the query results.php create mode 100644 manual/codes/Basic Components - Query - Lazy property fetching.php create mode 100644 manual/codes/Basic Components - Query - Method overloading.php create mode 100644 manual/codes/Basic Components - Query - ORDER BY - sorting query results.php create mode 100644 manual/codes/Basic Components - Query - Relation operators.php create mode 100644 manual/codes/Basic Components - Query - WHERE - setting query conditions.php create mode 100644 manual/codes/Basic Components - RawSql - Method overloading.php create mode 100644 manual/codes/Basic Components - RawSql - Using SQL.php create mode 100644 manual/codes/Basic Components - Record - Accessing properties.php create mode 100644 manual/codes/Basic Components - Record - Creating new records.php create mode 100644 manual/codes/Basic Components - Record - Deleting records.php create mode 100644 manual/codes/Basic Components - Record - Getting object copy.php create mode 100644 manual/codes/Basic Components - Record - Getting record state.php create mode 100644 manual/codes/Basic Components - Record - Retrieving existing records.php create mode 100644 manual/codes/Basic Components - Record - Serializing.php create mode 100644 manual/codes/Basic Components - Record - Updating records.php create mode 100644 manual/codes/Basic Components - Session - Flushing the session.php create mode 100644 manual/codes/Basic Components - Session - Getting a table object.php create mode 100644 manual/codes/Basic Components - Session - Getting session state.php create mode 100644 manual/codes/Basic Components - Session - Querying the database.php create mode 100644 manual/codes/Basic Components - Table - Custom finders.php create mode 100644 manual/codes/Basic Components - Table - Custom table classes.php create mode 100644 manual/codes/Basic Components - Table - Finder methods.php create mode 100644 manual/codes/Basic Components - Table - Getting table information.php create mode 100644 manual/codes/Configuration - Custom getters and setters.php create mode 100644 manual/codes/Configuration - Custom primary key column.php create mode 100644 manual/codes/Configuration - Setting attributes - Batch size.php create mode 100644 manual/codes/Configuration - Setting attributes - Event listener.php create mode 100644 manual/codes/Configuration - Setting attributes - Fetching strategy.php create mode 100644 manual/codes/Configuration - Setting attributes - Offset collection limit.php create mode 100644 manual/codes/Configuration - Setting attributes - Session lockmode.php create mode 100644 manual/codes/Configuration - Setting attributes - Table creation.php create mode 100644 manual/codes/Configuration - Setting attributes - Validation.php create mode 100644 manual/codes/Configuration - Setting default eventlistener.php create mode 100644 manual/codes/Configuration - Setting default fetchmode.php create mode 100644 manual/codes/Configuration - Using sequences.php create mode 100644 manual/codes/Database operations - Limit and offset.php create mode 100644 manual/codes/Database operations - Nested transactions.php create mode 100644 manual/codes/Database operations - Query logging.php create mode 100644 manual/codes/Database operations - Sequences.php create mode 100644 manual/codes/Database operations - Transactions.php create mode 100644 manual/codes/Getting started - Installation.php create mode 100644 manual/codes/Getting started - Setting table definition.php create mode 100644 manual/codes/Getting started - Starting new project.php create mode 100644 manual/codes/Mapping object relations - Dealing with relations - Creating related records.php create mode 100644 manual/codes/Mapping object relations - Dealing with relations - Deleting related records.php create mode 100644 manual/codes/Mapping object relations - Dealing with relations - Retrieving related records.php create mode 100644 manual/codes/Mapping object relations - Dealing with relations - Updating related records.php create mode 100644 manual/codes/Mapping object relations - Foreign key associations - One-to-Many, Many-to-One.php create mode 100644 manual/codes/Mapping object relations - Foreign key associations - One-to-One.php create mode 100644 manual/codes/Mapping object relations - Foreign key associations - Tree structure.php create mode 100644 manual/codes/Mapping object relations - Inheritance - Column aggregation.php create mode 100644 manual/codes/Mapping object relations - Inheritance - One table many classes.php create mode 100644 manual/codes/Mapping object relations - Inheritance - One table one class.php create mode 100644 manual/codes/Mapping object relations - Join table associations - Many-to-Many.php create mode 100644 manual/codes/Mapping object relations - Join table associations - Self-referencing.php create mode 100644 manual/codes/Mapping object relations - Relation aliases.php create mode 100644 manual/codes/Performance - Internal optimizations - DELETE.php create mode 100644 manual/codes/Performance - Internal optimizations - INSERT.php create mode 100644 manual/codes/Real world examples - Forum application.php create mode 100644 manual/codes/Real world examples - User management system.php create mode 100644 manual/codes/Runtime classes - Doctrine_Record.php create mode 100644 manual/codes/Runtime classes - Doctrine_Session.php create mode 100644 manual/codes/Transactions - Introduction.php create mode 100644 manual/codes/Transactions - Nesting.php create mode 100644 manual/codes/Transactions - Unit of work.php create mode 100644 manual/docs/Advanced components - Cache - Introduction.php create mode 100644 manual/docs/Advanced components - Eventlisteners - Creating new listener.php create mode 100644 manual/docs/Advanced components - Eventlisteners - List of events.php create mode 100644 manual/docs/Advanced components - Hook - Introduction.php create mode 100644 manual/docs/Advanced components - Validators - Intruduction.php create mode 100644 manual/docs/Advanced components - Validators - List of predefined validators.php create mode 100644 manual/docs/Advanced components - Validators - Validating transactions.php create mode 100644 manual/docs/Advanced components - View - Intoduction.php create mode 100644 manual/docs/Basic Components - Collection - Accessing elements.php create mode 100644 manual/docs/Basic Components - Collection - Deleting collection.php create mode 100644 manual/docs/Basic Components - Collection - Fetching strategies.php create mode 100644 manual/docs/Basic Components - Manager - Introduction.php create mode 100644 manual/docs/Basic Components - Manager - Managing sessions.php create mode 100644 manual/docs/Basic Components - Manager - Opening a new session.php create mode 100644 manual/docs/Basic Components - Query - DQL - SQL conversion.php create mode 100644 manual/docs/Basic Components - Query - Introduction.php create mode 100644 manual/docs/Basic Components - Query - Method overloading.php create mode 100644 manual/docs/Basic Components - Query - ORDER BY - sorting query results.php create mode 100644 manual/docs/Basic Components - Query - Relation operators.php create mode 100644 manual/docs/Basic Components - Record - Accessing properties.php create mode 100644 manual/docs/Basic Components - Record - Adding records.php create mode 100644 manual/docs/Basic Components - Record - Creating new records.php create mode 100644 manual/docs/Basic Components - Record - Deleting records.php create mode 100644 manual/docs/Basic Components - Record - Getting object copy.php create mode 100644 manual/docs/Basic Components - Record - Getting record state.php create mode 100644 manual/docs/Basic Components - Record - Retrieving existing records.php create mode 100644 manual/docs/Basic Components - Record - Serializing.php create mode 100644 manual/docs/Basic Components - Record - Updating records.php create mode 100644 manual/docs/Basic Components - Session - Flushing the session.php create mode 100644 manual/docs/Basic Components - Session - Getting a table object.php create mode 100644 manual/docs/Basic Components - Session - Getting session state.php create mode 100644 manual/docs/Basic Components - Table - Custom finders.php create mode 100644 manual/docs/Basic Components - Table - Custom table classes.php create mode 100644 manual/docs/Basic Components - Table - Finder methods.php create mode 100644 manual/docs/Basic components - Exceptions - List of exceptions.php create mode 100644 manual/docs/Cache - Configuration.php create mode 100644 manual/docs/Cache - Overview.php create mode 100644 manual/docs/Configuration - Levels of configuration.php create mode 100644 manual/docs/Configuration - List of attributes.php create mode 100644 manual/docs/Getting started - Installation.php create mode 100644 manual/docs/Getting started - Requirements.php create mode 100644 manual/docs/Getting started - Setting table definition - Constraints and validators.php create mode 100644 manual/docs/Getting started - Setting table definition - Data types and lengths.php create mode 100644 manual/docs/Getting started - Setting table definition - Introduction.php create mode 100644 manual/docs/Getting started - Starting new project.php create mode 100644 manual/docs/Mapping object relations - Composites and aggregates.php create mode 100644 manual/docs/Mapping object relations - Dealing with relations - Creating related records.php create mode 100644 manual/docs/Mapping object relations - Dealing with relations - Deleting related records.php create mode 100644 manual/docs/Mapping object relations - Dealing with relations - Retrieving related records.php create mode 100644 manual/docs/Mapping object relations - Dealing with relations - Updating related records.php create mode 100644 manual/docs/Mapping object relations - Foreign key associations - One-to-One.php create mode 100644 manual/docs/Mapping object relations - Inheritance - Column aggregation.php create mode 100644 manual/docs/Mapping object relations - Inheritance - One table many classes.php create mode 100644 manual/docs/Mapping object relations - Inheritance - One table one class.php create mode 100644 manual/docs/Mapping object relations - Join table associations - Many-to-Many.php create mode 100644 manual/docs/Mapping object relations - Join table associations - Self-referencing.php create mode 100644 manual/docs/Mapping object relations - One-to-Many and One-to-One relationships.php create mode 100644 manual/docs/Mapping object relations - Relation aliases.php create mode 100644 manual/docs/Real world examples - User management system.php create mode 100644 manual/docs/Runtime classes - Doctrine_Association.php create mode 100644 manual/docs/Runtime classes - Doctrine_Collection.php create mode 100644 manual/docs/Runtime classes - Doctrine_Collection_Batch.php create mode 100644 manual/docs/Runtime classes - Doctrine_Collection_Immediate.php create mode 100644 manual/docs/Runtime classes - Doctrine_Collection_Lazy.php create mode 100644 manual/docs/Runtime classes - Doctrine_ForeignKey.php create mode 100644 manual/docs/Runtime classes - Doctrine_Manager.php create mode 100644 manual/docs/Runtime classes - Doctrine_Record.php create mode 100644 manual/docs/Runtime classes - Doctrine_Session.php create mode 100644 manual/docs/Runtime classes - Doctrine_Table.php create mode 100644 manual/docs/Technology - Design patterns used.php create mode 100644 manual/docs/Technology - Speed.php create mode 100644 manual/documentation.php create mode 100644 manual/highlight.php create mode 100644 manual/images/docflash.jpg create mode 100644 manual/images/docflashbg.jpg create mode 100644 manual/images/docnew.gif create mode 100644 manual/images/gradient1.jpg create mode 100644 manual/images/gradient2.jpg create mode 100644 manual/images/gradient3.jpg create mode 100644 manual/images/logo.jpg create mode 100644 manual/images/tausta2.jpg create mode 100644 manual/styles/basic.css create mode 100644 manual/styles/steel.css create mode 100644 manual/top.php diff --git a/manual/codes/Advanced components - Eventlisteners - Creating new listener.php b/manual/codes/Advanced components - Eventlisteners - Creating new listener.php new file mode 100644 index 000000000..4ae75f0d7 --- /dev/null +++ b/manual/codes/Advanced components - Eventlisteners - Creating new listener.php @@ -0,0 +1,34 @@ +getTable()->getComponentName()." just got loaded!"; + } + public function onSave(Doctrine_Record $record) { + print "saved data access object!"; + } +} +class MyListener2 extends Doctrine_EventListener { + public function onPreUpdate() { + try { + $record->set("updated",time()); + } catch(InvalidKeyException $e) { + } + } +} + + +// setting global listener +$manager = Doctrine_Manager::getInstance(); + +$manager->setAttribute(Doctrine::ATTR_LISTENER,new MyListener()); + +// setting session level listener +$session = $manager->openSession($dbh); + +$session->setAttribute(Doctrine::ATTR_LISTENER,new MyListener2()); + +// setting factory level listener +$table = $session->getTable("User"); + +$table->setAttribute(Doctrine::ATTR_LISTENER,new MyListener()); +?> diff --git a/manual/codes/Advanced components - Eventlisteners - List of events.php b/manual/codes/Advanced components - Eventlisteners - List of events.php new file mode 100644 index 000000000..daf382388 --- /dev/null +++ b/manual/codes/Advanced components - Eventlisteners - List of events.php @@ -0,0 +1,45 @@ + diff --git a/manual/codes/Advanced components - Eventlisteners - Listening events.php b/manual/codes/Advanced components - Eventlisteners - Listening events.php new file mode 100644 index 000000000..f3f09f616 --- /dev/null +++ b/manual/codes/Advanced components - Eventlisteners - Listening events.php @@ -0,0 +1,13 @@ +getTable("User"); + +$table->setEventListener(new MyListener2()); + +// retrieve user whose primary key is 2 +$user = $table->find(2); + +$user->name = "John Locke"; + +// update event will be listened and current time will be assigned to the field 'updated' +$user->save(); +?> diff --git a/manual/codes/Advanced components - Hook - Parameter hooking.php b/manual/codes/Advanced components - Hook - Parameter hooking.php new file mode 100644 index 000000000..44eb80df5 --- /dev/null +++ b/manual/codes/Advanced components - Hook - Parameter hooking.php @@ -0,0 +1,3 @@ + diff --git a/manual/codes/Advanced components - Validators - Analyzing the ErrorStack.php b/manual/codes/Advanced components - Validators - Analyzing the ErrorStack.php new file mode 100644 index 000000000..8e6097eb8 --- /dev/null +++ b/manual/codes/Advanced components - Validators - Analyzing the ErrorStack.php @@ -0,0 +1,27 @@ +name = "this is an example of too long name"; + $user->Email->address = "drink@@notvalid.."; + $user->save(); +} catch(Doctrine_Validator_Exception $e) { + $stack = $e->getErrorStack(); + foreach($stack as $component => $err) { + foreach($err as $field => $type) { + switch($type): + case Doctrine_Validator::ERR_TYPE: + print $field." is not right type"; + break; + case Doctrine_Validator::ERR_UNIQUE: + print $field." is not unique"; + break; + case Doctrine_Validator::ERR_VALID: + print $field." is not valid"; + break; + case Doctrine_Validator::ERR_LENGTH: + print $field." is too long"; + break; + endswitch; + } + } +} +?> diff --git a/manual/codes/Advanced components - Validators - Intruduction.php b/manual/codes/Advanced components - Validators - Intruduction.php new file mode 100644 index 000000000..be47e66bd --- /dev/null +++ b/manual/codes/Advanced components - Validators - Intruduction.php @@ -0,0 +1,5 @@ +setAttribute(Doctrine::ATTR_VLD, true); +?> diff --git a/manual/codes/Advanced components - Validators - Validating transactions.php b/manual/codes/Advanced components - Validators - Validating transactions.php new file mode 100644 index 000000000..419f20310 --- /dev/null +++ b/manual/codes/Advanced components - Validators - Validating transactions.php @@ -0,0 +1,42 @@ +ownsOne("Email","User.email_id"); + } + public function setTableDefinition() { + // no special validators used only types + // and lengths will be validated + $this->hasColumn("name","string",15); + $this->hasColumn("email_id","integer"); + $this->hasColumn("created","integer",11); + } +} +class Email extends Doctrine_Record { + public function setTableDefinition() { + // specialized validators 'email' and 'unique' used + $this->hasColumn("address","string",150,"email|unique"); + } +} +$session = Doctrine_Manager::getInstance()->openSession(new PDO("dsn","username","password")); +$user = new User(); +$user->name = "this is an example of too long name"; + +$user->save(); // throws a Doctrine_Validator_Exception + +$user->name = "valid name"; +$user->created = "not valid"; // not valid type +$user->save(); // throws a Doctrine_Validator_Exception + + +$user->created = time(); +$user->Email->address = "drink@.."; // not valid email address +$user->save(); // throws a Doctrine_Validator_Exception + +$user->Email->address = "drink@drinkmore.info"; +$user->save(); // saved + + +$user = $session->create("User"); +$user->Email->address = "drink@drinkmore.info"; // not unique! +$user->save(); // throws a Doctrine_Validator_Exception +?> diff --git a/manual/codes/Basic Components - Collection - Accessing elements.php b/manual/codes/Basic Components - Collection - Accessing elements.php new file mode 100644 index 000000000..47e8519b6 --- /dev/null +++ b/manual/codes/Basic Components - Collection - Accessing elements.php @@ -0,0 +1,15 @@ +getTable("User"); + +$users = $table->findAll(); + +// accessing elements with ArrayAccess interface + +$users[0]->name = "Jack Daniels"; + +$users[1]->name = "John Locke"; + +// accessing elements with get() + +print $users->get(1)->name; +?> diff --git a/manual/codes/Basic Components - Collection - Adding new elements.php b/manual/codes/Basic Components - Collection - Adding new elements.php new file mode 100644 index 000000000..dec8c7693 --- /dev/null +++ b/manual/codes/Basic Components - Collection - Adding new elements.php @@ -0,0 +1,8 @@ +findAll(); + +print count($users); // 5 + +$users[5]->name = "new user 1"; +$users[6]->name = "new user 2"; +?> diff --git a/manual/codes/Basic Components - Collection - Deleting collection.php b/manual/codes/Basic Components - Collection - Deleting collection.php new file mode 100644 index 000000000..d4f288459 --- /dev/null +++ b/manual/codes/Basic Components - Collection - Deleting collection.php @@ -0,0 +1,7 @@ +findBySql("name LIKE '%John%'"); + +$users->delete(); +?> diff --git a/manual/codes/Basic Components - Collection - Fetching strategies.php b/manual/codes/Basic Components - Collection - Fetching strategies.php new file mode 100644 index 000000000..ee5cd03ef --- /dev/null +++ b/manual/codes/Basic Components - Collection - Fetching strategies.php @@ -0,0 +1,52 @@ +getTable("User"); + +$table->setAttribute(Doctrine::ATTR_FETCHMODE, Doctrine::FETCH_IMMEDIATE); + +$users = $table->findAll(); + +// or + +$users = $session->query("FROM User-I"); // immediate collection + +foreach($users as $user) { + print $user->name; +} + + +$table->setAttribute(Doctrine::ATTR_FETCHMODE, Doctrine::FETCH_LAZY); + +$users = $table->findAll(); + +// or + +$users = $session->query("FROM User-L"); // lazy collection + +foreach($users as $user) { + print $user->name; +} + +$table->setAttribute(Doctrine::ATTR_FETCHMODE, Doctrine::FETCH_BATCH); + +$users = $table->findAll(); + +// or + +$users = $session->query("FROM User-B"); // batch collection + +foreach($users as $user) { + print $user->name; +} + +$table->setAttribute(Doctrine::ATTR_FETCHMODE, Doctrine::FETCH_OFFSET); + +$users = $table->findAll(); + +// or + +$users = $session->query("FROM User-O"); // offset collection + +foreach($users as $user) { + print $user->name; +} +?> diff --git a/manual/codes/Basic Components - Collection - Getting collection count.php b/manual/codes/Basic Components - Collection - Getting collection count.php new file mode 100644 index 000000000..a2e88a5d1 --- /dev/null +++ b/manual/codes/Basic Components - Collection - Getting collection count.php @@ -0,0 +1,9 @@ +findAll(); + +$users->count(); + +// or + +count($users); // Doctrine_Collection implements Countable interface +?> diff --git a/manual/codes/Basic Components - Collection - Saving the collection.php b/manual/codes/Basic Components - Collection - Saving the collection.php new file mode 100644 index 000000000..7ef541270 --- /dev/null +++ b/manual/codes/Basic Components - Collection - Saving the collection.php @@ -0,0 +1,9 @@ +findAll(); + +$users[0]->name = "Jack Daniels"; + +$users[1]->name = "John Locke"; + +$users->save(); +?> diff --git a/manual/codes/Basic Components - Manager - Managing sessions.php b/manual/codes/Basic Components - Manager - Managing sessions.php new file mode 100644 index 000000000..ac67cb878 --- /dev/null +++ b/manual/codes/Basic Components - Manager - Managing sessions.php @@ -0,0 +1,25 @@ +openSession(new PDO("dsn","username","password"), "session 1"); + +// open second session + +$session2 = $manager->openSession(new PDO("dsn2","username2","password2"), "session 2"); + +$manager->getCurrentSession(); // $session2 + +$manager->setCurrentSession("session 1"); + +$manager->getCurrentSession(); // $session + +// iterating through sessions + +foreach($manager as $session) { + +} +?> diff --git a/manual/codes/Basic Components - Manager - Opening a new session.php b/manual/codes/Basic Components - Manager - Opening a new session.php new file mode 100644 index 000000000..8e774cb8e --- /dev/null +++ b/manual/codes/Basic Components - Manager - Opening a new session.php @@ -0,0 +1,18 @@ +openSession(); + +// or if you want to use Doctrine Doctrine_DB and its +// performance monitoring capabilities + +$dsn = "schema://username:password@dsn/dbname"; +$dbh = Doctrine_DB::getConnection($dsn); +$session = $manager->openSession(); +?> diff --git a/manual/codes/Basic Components - Query - Bound parameters.php b/manual/codes/Basic Components - Query - Bound parameters.php new file mode 100644 index 000000000..9bb9a97af --- /dev/null +++ b/manual/codes/Basic Components - Query - Bound parameters.php @@ -0,0 +1,6 @@ +from("User") + ->where("User.name = ?"); + +$query->execute(array('Jack Daniels')); +?> diff --git a/manual/codes/Basic Components - Query - FROM - selecting tables.php b/manual/codes/Basic Components - Query - FROM - selecting tables.php new file mode 100644 index 000000000..ebaafeda8 --- /dev/null +++ b/manual/codes/Basic Components - Query - FROM - selecting tables.php @@ -0,0 +1,15 @@ +query("FROM User"); + +// find all groups + +$coll = $session->query("FROM Group"); + +// find all users and user emails + +$coll = $session->query("FROM User, User.Email"); + +?> diff --git a/manual/codes/Basic Components - Query - Fetching strategies.php b/manual/codes/Basic Components - Query - Fetching strategies.php new file mode 100644 index 000000000..efdd801c4 --- /dev/null +++ b/manual/codes/Basic Components - Query - Fetching strategies.php @@ -0,0 +1,25 @@ +query("FROM User-I"); + +// or + +$coll = $session->query("FROM User-IMMEDIATE"); + +// select all users and load the data in batches + +$coll = $session->query("FROM User-B"); + +// or + +$coll = $session->query("FROM User-BATCH"); + +// select all user and use lazy fetching + +$coll = $session->query("FROM User-L"); + +// or + +$coll = $session->query("FROM User-LAZY"); +?> diff --git a/manual/codes/Basic Components - Query - LIMIT and OFFSET - limiting the query results.php b/manual/codes/Basic Components - Query - LIMIT and OFFSET - limiting the query results.php new file mode 100644 index 000000000..02edc71b6 --- /dev/null +++ b/manual/codes/Basic Components - Query - LIMIT and OFFSET - limiting the query results.php @@ -0,0 +1,11 @@ +query("FROM User, User.Email LIMIT 10"); + +// find the first ten users starting from the user number 5 + +$coll = $session->query("FROM User LIMIT 10 OFFSET 5"); + +?> diff --git a/manual/codes/Basic Components - Query - Lazy property fetching.php b/manual/codes/Basic Components - Query - Lazy property fetching.php new file mode 100644 index 000000000..d9eba2558 --- /dev/null +++ b/manual/codes/Basic Components - Query - Lazy property fetching.php @@ -0,0 +1,6 @@ +query("FROM User(id, name)"); +?> diff --git a/manual/codes/Basic Components - Query - Method overloading.php b/manual/codes/Basic Components - Query - Method overloading.php new file mode 100644 index 000000000..33d39bad7 --- /dev/null +++ b/manual/codes/Basic Components - Query - Method overloading.php @@ -0,0 +1,12 @@ +openSession(new PDO("dsn","username","password")); + +$query = new Doctrine_Query($session); + +$query->from("User-b") + ->where("User.name LIKE 'Jack%'") + ->orderby("User.created"); + ->limit(5); + +$users = $query->execute(); +?> diff --git a/manual/codes/Basic Components - Query - ORDER BY - sorting query results.php b/manual/codes/Basic Components - Query - ORDER BY - sorting query results.php new file mode 100644 index 000000000..e3650e7ce --- /dev/null +++ b/manual/codes/Basic Components - Query - ORDER BY - sorting query results.php @@ -0,0 +1,21 @@ +query("FROM User ORDER BY User.name DESC"); + +// find all users sort by name ascending + +$coll = $session->query("FROM User ORDER BY User.name ASC"); + +// or + +$coll = $session->query("FROM User ORDER BY User.name"); + +// find all users and their emails, sort by email address + +$coll = $session->query("FROM User, User.Email ORDER BY User.Email.address"); + +// find all users and their emails, sort by user name and email address + +$coll = $session->query("FROM User, User.Email ORDER BY User.name, User.Email.address"); +?> diff --git a/manual/codes/Basic Components - Query - Relation operators.php b/manual/codes/Basic Components - Query - Relation operators.php new file mode 100644 index 000000000..977624130 --- /dev/null +++ b/manual/codes/Basic Components - Query - Relation operators.php @@ -0,0 +1,15 @@ +from("User:Email"); + +$query->execute(); + +// executed SQL query: +// SELECT ... FROM user INNER JOIN email ON ... + +$query->from("User.Email"); + +$query->execute(); + +// executed SQL query: +// SELECT ... FROM user LEFT JOIN email ON ... +?> diff --git a/manual/codes/Basic Components - Query - WHERE - setting query conditions.php b/manual/codes/Basic Components - Query - WHERE - setting query conditions.php new file mode 100644 index 000000000..0b48cc55e --- /dev/null +++ b/manual/codes/Basic Components - Query - WHERE - setting query conditions.php @@ -0,0 +1,27 @@ +query("FROM Group WHERE Group.id > 10"); + +// find all users where users where user name matches a regular expression, +// REGEXP keyword must be supported by the underlying database + +$coll = $session->query("FROM User WHERE User.name REGEXP '[ad]'"); + +// find all users and their associated emails where SOME of the users phonenumbers +// (the association between user and phonenumber tables is Many-To-Many) starts with 123 + +$coll = $session->query("FROM User, User.Email WHERE User.Phonenumber.phonenumber LIKE '123%'"); + +// multiple conditions + +$coll = $session->query("FROM User WHERE User.name LIKE '%Jack%' && User.Email.address LIKE '%@drinkmore.info'"); + +// nesting conditions + +$coll = $session->query("FROM User WHERE (User.name LIKE '%Jack%' || User.name LIKE '%John%') && User.Email.address LIKE '%@drinkmore.info'"); + +?> diff --git a/manual/codes/Basic Components - RawSql - Method overloading.php b/manual/codes/Basic Components - RawSql - Method overloading.php new file mode 100644 index 000000000..8b49c705b --- /dev/null +++ b/manual/codes/Basic Components - RawSql - Method overloading.php @@ -0,0 +1,10 @@ +select('{entity.name}') + ->from('entity'); + +$query->addComponent("entity", "User"); + +$coll = $query->execute(); +?> diff --git a/manual/codes/Basic Components - RawSql - Using SQL.php b/manual/codes/Basic Components - RawSql - Using SQL.php new file mode 100644 index 000000000..973ec6744 --- /dev/null +++ b/manual/codes/Basic Components - RawSql - Using SQL.php @@ -0,0 +1,7 @@ +parseQuery("SELECT {entity.name} FROM entity"); + +$entities = $query->execute(); +?> diff --git a/manual/codes/Basic Components - Record - Accessing properties.php b/manual/codes/Basic Components - Record - Accessing properties.php new file mode 100644 index 000000000..f02e1d2c7 --- /dev/null +++ b/manual/codes/Basic Components - Record - Accessing properties.php @@ -0,0 +1,21 @@ +find(3); + +// access property through overloading + +$name = $user->name; + +// access property with get() + +$name = $user->get("name"); + +// access property with ArrayAccess interface + +$name = $user['name']; + +// iterating through properties + +foreach($user as $key => $value) { + +} +?> diff --git a/manual/codes/Basic Components - Record - Creating new records.php b/manual/codes/Basic Components - Record - Creating new records.php new file mode 100644 index 000000000..97bee6142 --- /dev/null +++ b/manual/codes/Basic Components - Record - Creating new records.php @@ -0,0 +1,20 @@ +create("User"); + +// alternative way: + +$table = $session->getTable("User"); + +$user = $table->create(); + +// the simpliest way: + +$user = new User(); + + +// records support array access +$user["name"] = "John Locke"; + +// save user into database +$user->save(); +?> diff --git a/manual/codes/Basic Components - Record - Deleting records.php b/manual/codes/Basic Components - Record - Deleting records.php new file mode 100644 index 000000000..5cf6a1630 --- /dev/null +++ b/manual/codes/Basic Components - Record - Deleting records.php @@ -0,0 +1,20 @@ +getTable("User"); + +try { + $user = $table->find(2); +} catch(Doctrine_Find_Exception $e) { + print "Couldn't find user"; +} + +// deletes user and all related composite objects + +$user->delete(); + + +$users = $table->findAll(); + + +// delete all users and their related composite objects +$users->delete(); +?> diff --git a/manual/codes/Basic Components - Record - Getting object copy.php b/manual/codes/Basic Components - Record - Getting object copy.php new file mode 100644 index 000000000..e5d527d75 --- /dev/null +++ b/manual/codes/Basic Components - Record - Getting object copy.php @@ -0,0 +1,3 @@ +copy(); +?> diff --git a/manual/codes/Basic Components - Record - Getting record state.php b/manual/codes/Basic Components - Record - Getting record state.php new file mode 100644 index 000000000..21148fca2 --- /dev/null +++ b/manual/codes/Basic Components - Record - Getting record state.php @@ -0,0 +1,31 @@ +getState(); + +switch($state): + case Doctrine_Record::STATE_PROXY: + // data access object is in proxy state, + // meaning its persistent but not all of its properties are + // loaded from the database + break; + case Doctrine_Record::STATE_TCLEAN: + // data access object is transient clean, + // meaning its transient and + // none of its properties are changed + break; + case Doctrine_Record::STATE_TDIRTY: + // data access object is transient dirty, + // meaning its transient and + // some of its properties are changed + break; + case Doctrine_Record::STATE_DIRTY: + // data access object is dirty, + // meaning its persistent and + // some of its properties are changed + break; + case Doctrine_Record::STATE_CLEAN: + // data access object is clean, + // meaning its persistent and + // none of its properties are changed + break; +endswitch; +?> diff --git a/manual/codes/Basic Components - Record - Retrieving existing records.php b/manual/codes/Basic Components - Record - Retrieving existing records.php new file mode 100644 index 000000000..cee6a20fb --- /dev/null +++ b/manual/codes/Basic Components - Record - Retrieving existing records.php @@ -0,0 +1,24 @@ +getTable("User"); + +// find by primary key +try { + $user = $table->find(2); +} catch(Doctrine_Find_Exception $e) { + print "Couldn't find user"; +} + +// get all users +foreach($table->findAll() as $user) { + print $user->name; +} + +// finding by sql +foreach($table->findBySql("name LIKE '%John%'") as $user) { + print $user->created; +} + +// finding objects with DQL + +$users = $session->query("FROM User WHERE User.name LIKE '%John%'"); +?> diff --git a/manual/codes/Basic Components - Record - Serializing.php b/manual/codes/Basic Components - Record - Serializing.php new file mode 100644 index 000000000..1ae2e9933 --- /dev/null +++ b/manual/codes/Basic Components - Record - Serializing.php @@ -0,0 +1,5 @@ + diff --git a/manual/codes/Basic Components - Record - Updating records.php b/manual/codes/Basic Components - Record - Updating records.php new file mode 100644 index 000000000..b5d318364 --- /dev/null +++ b/manual/codes/Basic Components - Record - Updating records.php @@ -0,0 +1,13 @@ +getTable("User"); + +try { + $user = $table->find(2); +} catch(Doctrine_Find_Exception $e) { + print "Couldn't find user"; +} + +$user->name = "Jack Daniels"; + +$user->save(); +?> diff --git a/manual/codes/Basic Components - Session - Flushing the session.php b/manual/codes/Basic Components - Session - Flushing the session.php new file mode 100644 index 000000000..1f56b7e1f --- /dev/null +++ b/manual/codes/Basic Components - Session - Flushing the session.php @@ -0,0 +1,11 @@ +name = "Jack"; + +$group = $session->create("Group"); +$group->name = "Drinking Club"; + +// saves all the changed objects into database + +$session->flush(); +?> diff --git a/manual/codes/Basic Components - Session - Getting a table object.php b/manual/codes/Basic Components - Session - Getting a table object.php new file mode 100644 index 000000000..1f5e21983 --- /dev/null +++ b/manual/codes/Basic Components - Session - Getting a table object.php @@ -0,0 +1,11 @@ +openSession(new PDO("dsn","username","password")); + +// getting a table object + +$table = $session->getTable("User"); +?> diff --git a/manual/codes/Basic Components - Session - Getting session state.php b/manual/codes/Basic Components - Session - Getting session state.php new file mode 100644 index 000000000..b1589f815 --- /dev/null +++ b/manual/codes/Basic Components - Session - Getting session state.php @@ -0,0 +1,16 @@ +getState()) + case Doctrine_Session::STATE_ACTIVE: + // session open and zero open transactions + break; + case Doctrine_Session::STATE_ACTIVE: + // one open transaction + break; + case Doctrine_Session::STATE_BUSY: + // multiple open transactions + break; + case Doctrine_Session::STATE_CLOSED: + // session closed + break; +endswitch; +?> diff --git a/manual/codes/Basic Components - Session - Querying the database.php b/manual/codes/Basic Components - Session - Querying the database.php new file mode 100644 index 000000000..cfea02b91 --- /dev/null +++ b/manual/codes/Basic Components - Session - Querying the database.php @@ -0,0 +1,10 @@ +query("FROM User"); + +// select all users where user email is jackdaniels@drinkmore.info + +$session->query("FROM User WHERE User.Email.address = 'jackdaniels@drinkmore.info'"); +?> diff --git a/manual/codes/Basic Components - Table - Custom finders.php b/manual/codes/Basic Components - Table - Custom finders.php new file mode 100644 index 000000000..50e0f6732 --- /dev/null +++ b/manual/codes/Basic Components - Table - Custom finders.php @@ -0,0 +1,22 @@ +getSession()->query("FROM User WHERE name LIKE '%$name%'"); + } +} +class User extends Doctrine_Record { } + +$session = Doctrine_Manager::getInstance()->openSession(new PDO("dsn","username","password")); + +// doctrine will now check if a class called UserTable exists and if it inherits Doctrine_Table + +$table = $session->getTable("User"); + +print get_class($table); // UserTable + +$users = $table->findByName("Jack"); + +?> diff --git a/manual/codes/Basic Components - Table - Custom table classes.php b/manual/codes/Basic Components - Table - Custom table classes.php new file mode 100644 index 000000000..138d5a445 --- /dev/null +++ b/manual/codes/Basic Components - Table - Custom table classes.php @@ -0,0 +1,13 @@ + + + diff --git a/manual/codes/Basic Components - Table - Finder methods.php b/manual/codes/Basic Components - Table - Finder methods.php new file mode 100644 index 000000000..a78103611 --- /dev/null +++ b/manual/codes/Basic Components - Table - Finder methods.php @@ -0,0 +1,20 @@ +getTable("User"); + +// find by primary key +try { + $user = $table->find(2); +} catch(Doctrine_Find_Exception $e) { + print "Couldn't find user"; +} + +// get all users +foreach($table->findAll() as $user) { + print $user->name; +} + +// finding by sql +foreach($table->findBySql("name LIKE '%John%'") as $user) { + print $user->created; +} +?> diff --git a/manual/codes/Basic Components - Table - Getting table information.php b/manual/codes/Basic Components - Table - Getting table information.php new file mode 100644 index 000000000..ed077cdda --- /dev/null +++ b/manual/codes/Basic Components - Table - Getting table information.php @@ -0,0 +1,11 @@ +getTable('User'); + +// getting column names + +$names = $table->getColumnNames(); + +// getting column information + +$columns = $table->getColumns(); +?> diff --git a/manual/codes/Configuration - Custom getters and setters.php b/manual/codes/Configuration - Custom getters and setters.php new file mode 100644 index 000000000..0cf8a244f --- /dev/null +++ b/manual/codes/Configuration - Custom getters and setters.php @@ -0,0 +1,21 @@ +isValidName($name)) + $this->set("name",$name); + } + public function getName() { + return $this->get("name"); + } +} +?> diff --git a/manual/codes/Configuration - Custom primary key column.php b/manual/codes/Configuration - Custom primary key column.php new file mode 100644 index 000000000..1535df124 --- /dev/null +++ b/manual/codes/Configuration - Custom primary key column.php @@ -0,0 +1,9 @@ +setPrimaryKeyColumn("group_id"); + } +} +?> diff --git a/manual/codes/Configuration - Setting attributes - Batch size.php b/manual/codes/Configuration - Setting attributes - Batch size.php new file mode 100644 index 000000000..d7640f7e3 --- /dev/null +++ b/manual/codes/Configuration - Setting attributes - Batch size.php @@ -0,0 +1,5 @@ +setAttribute(Doctrine::ATTR_BATCH_SIZE, 7); +?> diff --git a/manual/codes/Configuration - Setting attributes - Event listener.php b/manual/codes/Configuration - Setting attributes - Event listener.php new file mode 100644 index 000000000..9d308e058 --- /dev/null +++ b/manual/codes/Configuration - Setting attributes - Event listener.php @@ -0,0 +1,5 @@ +setAttribute(Doctrine::ATTR_LISTENER, new MyListener()); +?> diff --git a/manual/codes/Configuration - Setting attributes - Fetching strategy.php b/manual/codes/Configuration - Setting attributes - Fetching strategy.php new file mode 100644 index 000000000..576f6aa7f --- /dev/null +++ b/manual/codes/Configuration - Setting attributes - Fetching strategy.php @@ -0,0 +1,5 @@ +setAttribute(Doctrine::ATTR_FETCHMODE, Doctrine::FETCH_LAZY); +?> diff --git a/manual/codes/Configuration - Setting attributes - Offset collection limit.php b/manual/codes/Configuration - Setting attributes - Offset collection limit.php new file mode 100644 index 000000000..1f3c02bae --- /dev/null +++ b/manual/codes/Configuration - Setting attributes - Offset collection limit.php @@ -0,0 +1,5 @@ +setAttribute(Doctrine::ATTR_COLL_LIMIT, 10); +?> diff --git a/manual/codes/Configuration - Setting attributes - Session lockmode.php b/manual/codes/Configuration - Setting attributes - Session lockmode.php new file mode 100644 index 000000000..e92f4e233 --- /dev/null +++ b/manual/codes/Configuration - Setting attributes - Session lockmode.php @@ -0,0 +1,5 @@ +setAttribute(Doctrine::ATTR_LOCKMODE, Doctrine::LOCK_PESSIMISTIC); +?> diff --git a/manual/codes/Configuration - Setting attributes - Table creation.php b/manual/codes/Configuration - Setting attributes - Table creation.php new file mode 100644 index 000000000..87b2c645a --- /dev/null +++ b/manual/codes/Configuration - Setting attributes - Table creation.php @@ -0,0 +1,5 @@ +setAttribute(Doctrine::ATTR_CREATE_TABLES, false); +?> diff --git a/manual/codes/Configuration - Setting attributes - Validation.php b/manual/codes/Configuration - Setting attributes - Validation.php new file mode 100644 index 000000000..008d2b7b9 --- /dev/null +++ b/manual/codes/Configuration - Setting attributes - Validation.php @@ -0,0 +1,5 @@ +setAttribute(Doctrine::ATTR_VLD, true); +?> diff --git a/manual/codes/Configuration - Setting default eventlistener.php b/manual/codes/Configuration - Setting default eventlistener.php new file mode 100644 index 000000000..a3cb4920b --- /dev/null +++ b/manual/codes/Configuration - Setting default eventlistener.php @@ -0,0 +1,10 @@ +setAttribute(Doctrine::ATTR_LISTENER,new MyListener()); + } + public function setTableDefinition() { + $this->hasColumn("address","string",150,"email|unique"); + } +} +?> diff --git a/manual/codes/Configuration - Setting default fetchmode.php b/manual/codes/Configuration - Setting default fetchmode.php new file mode 100644 index 000000000..bee2e999c --- /dev/null +++ b/manual/codes/Configuration - Setting default fetchmode.php @@ -0,0 +1,11 @@ +setAttribute(Doctrine::ATTR_FETCHMODE,Doctrine::FETCH_IMMEDIATE); + } +} +?> diff --git a/manual/codes/Configuration - Using sequences.php b/manual/codes/Configuration - Using sequences.php new file mode 100644 index 000000000..16ed99419 --- /dev/null +++ b/manual/codes/Configuration - Using sequences.php @@ -0,0 +1,9 @@ +setSequenceName("user_seq"); + } +} +?> diff --git a/manual/codes/Database operations - Limit and offset.php b/manual/codes/Database operations - Limit and offset.php new file mode 100644 index 000000000..b770a6f6b --- /dev/null +++ b/manual/codes/Database operations - Limit and offset.php @@ -0,0 +1,7 @@ +openSession(new PDO("dsn","username","password")); + +// select first ten rows starting from the row 20 + +$sess->select("select * from user",10,20); +?> diff --git a/manual/codes/Database operations - Nested transactions.php b/manual/codes/Database operations - Nested transactions.php new file mode 100644 index 000000000..22cf0924e --- /dev/null +++ b/manual/codes/Database operations - Nested transactions.php @@ -0,0 +1,17 @@ +beginTransaction(); + + $user->save(); + + $session->beginTransaction(); + $group->save(); + $email->save(); + + $session->commit(); + + $session->commit(); +} catch(Exception $e) { + $session->rollback(); +} +?> diff --git a/manual/codes/Database operations - Query logging.php b/manual/codes/Database operations - Query logging.php new file mode 100644 index 000000000..2694b96c9 --- /dev/null +++ b/manual/codes/Database operations - Query logging.php @@ -0,0 +1,15 @@ +getDBH(); + +$times = $dbh->getExecTimes(); + +// print all executed queries and their execution times + +foreach($dbh->getQueries() as $index => $query) { + print $query." ".$times[$index]; +} + +?> diff --git a/manual/codes/Database operations - Sequences.php b/manual/codes/Database operations - Sequences.php new file mode 100644 index 000000000..b671dad1d --- /dev/null +++ b/manual/codes/Database operations - Sequences.php @@ -0,0 +1,7 @@ +openSession(new PDO("dsn","username","password")); + +// gets the next ID from a sequence + +$sess->getNextID($sequence); +?> diff --git a/manual/codes/Database operations - Transactions.php b/manual/codes/Database operations - Transactions.php new file mode 100644 index 000000000..46d515774 --- /dev/null +++ b/manual/codes/Database operations - Transactions.php @@ -0,0 +1,14 @@ +openSession(new PDO("dsn","username","password")); +try { +$sess->beginTransaction(); + + // some database operations + +$sess->commit(); + +} catch(Exception $e) { + $sess->rollback(); +} + +?> diff --git a/manual/codes/Getting started - Installation.php b/manual/codes/Getting started - Installation.php new file mode 100644 index 000000000..374c50e47 --- /dev/null +++ b/manual/codes/Getting started - Installation.php @@ -0,0 +1,13 @@ + diff --git a/manual/codes/Getting started - Setting table definition.php b/manual/codes/Getting started - Setting table definition.php new file mode 100644 index 000000000..23b9057be --- /dev/null +++ b/manual/codes/Getting started - Setting table definition.php @@ -0,0 +1,15 @@ +hasColumn("address","string",200,"email|unique"); + } +} +?> diff --git a/manual/codes/Getting started - Starting new project.php b/manual/codes/Getting started - Starting new project.php new file mode 100644 index 000000000..5cda71396 --- /dev/null +++ b/manual/codes/Getting started - Starting new project.php @@ -0,0 +1,13 @@ +hasColumn("name","string",30); + $this->hasColumn("username","string",20); + $this->hasColumn("password","string",16); + $this->hasColumn("created","integer",11); + } +} +?> diff --git a/manual/codes/Mapping object relations - Dealing with relations - Creating related records.php b/manual/codes/Mapping object relations - Dealing with relations - Creating related records.php new file mode 100644 index 000000000..03c7edcc9 --- /dev/null +++ b/manual/codes/Mapping object relations - Dealing with relations - Creating related records.php @@ -0,0 +1,14 @@ +Email; + +$email->address = "jackdaniels@drinkmore.info"; + +$user->save(); + +// alternative: + +$user->Email->address = "jackdaniels@drinkmore.info"; + +$user->save(); +?> diff --git a/manual/codes/Mapping object relations - Dealing with relations - Deleting related records.php b/manual/codes/Mapping object relations - Dealing with relations - Deleting related records.php new file mode 100644 index 000000000..e936c3cff --- /dev/null +++ b/manual/codes/Mapping object relations - Dealing with relations - Deleting related records.php @@ -0,0 +1,9 @@ +Email->delete(); + +$user->Phonenumber[3]->delete(); + +// deleting user and all related objects: + +$user->delete(); +?> diff --git a/manual/codes/Mapping object relations - Dealing with relations - Retrieving related records.php b/manual/codes/Mapping object relations - Dealing with relations - Retrieving related records.php new file mode 100644 index 000000000..d2d9d7511 --- /dev/null +++ b/manual/codes/Mapping object relations - Dealing with relations - Retrieving related records.php @@ -0,0 +1,7 @@ +Email["address"]; + +print $user->Phonenumber[0]->phonenumber; + +print $user->Group[0]->get("name"); +?> diff --git a/manual/codes/Mapping object relations - Dealing with relations - Updating related records.php b/manual/codes/Mapping object relations - Dealing with relations - Updating related records.php new file mode 100644 index 000000000..6df14cb1a --- /dev/null +++ b/manual/codes/Mapping object relations - Dealing with relations - Updating related records.php @@ -0,0 +1,9 @@ +Email["address"] = "koskenkorva@drinkmore.info"; + +$user->Phonenumber[0]->phonenumber = "123123"; + +$user->save(); + +// saves the email and phonenumber +?> diff --git a/manual/codes/Mapping object relations - Foreign key associations - One-to-Many, Many-to-One.php b/manual/codes/Mapping object relations - Foreign key associations - One-to-Many, Many-to-One.php new file mode 100644 index 000000000..6b05ecb83 --- /dev/null +++ b/manual/codes/Mapping object relations - Foreign key associations - One-to-Many, Many-to-One.php @@ -0,0 +1,18 @@ +ownsMany("Phonenumber","Phonenumber.user_id"); + } + public function setTableDefition() { + $this->hasColumn("name","string",50); + $this->hasColumn("loginname","string",20); + $this->hasColumn("password","string",16); + } +} +class Phonenumber extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("phonenumber","string",50); + $this->hasColumn("user_id","integer"); + } +} +?> diff --git a/manual/codes/Mapping object relations - Foreign key associations - One-to-One.php b/manual/codes/Mapping object relations - Foreign key associations - One-to-One.php new file mode 100644 index 000000000..9b91f625a --- /dev/null +++ b/manual/codes/Mapping object relations - Foreign key associations - One-to-One.php @@ -0,0 +1,28 @@ +hasOne("Address","Address.user_id"); + $this->ownsOne("Email","User.email_id"); + $this->ownsMany("Phonenumber","Phonenumber.user_id"); + } + public function setTableDefition() { + $this->hasColumn("name","string",50); + $this->hasColumn("loginname","string",20); + $this->hasColumn("password","string",16); + + // foreign key column for email ID + $this->hasColumn("email_id","integer"); + } +} +class Email extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("address","string",150); + } +} +class Address extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("street","string",50); + $this->hasColumn("user_id","integer"); + } +} +?> diff --git a/manual/codes/Mapping object relations - Foreign key associations - Tree structure.php b/manual/codes/Mapping object relations - Foreign key associations - Tree structure.php new file mode 100644 index 000000000..eacecde72 --- /dev/null +++ b/manual/codes/Mapping object relations - Foreign key associations - Tree structure.php @@ -0,0 +1,12 @@ +hasOne("Task as Parent","Task.parent_id"); + $this->hasMany("Task as Subtask","Subtask.parent_id"); + } + public function setTableDefinition() { + $this->hasColumn("name","string",100); + $this->hasColumn("parent_id","integer"); + } +} +?> diff --git a/manual/codes/Mapping object relations - Inheritance - Column aggregation.php b/manual/codes/Mapping object relations - Inheritance - Column aggregation.php new file mode 100644 index 000000000..ad192fa37 --- /dev/null +++ b/manual/codes/Mapping object relations - Inheritance - Column aggregation.php @@ -0,0 +1,22 @@ +hasColumn("name","string",30); + $this->hasColumn("username","string",20); + $this->hasColumn("password","string",16); + $this->hasColumn("created","integer",11); + } +} + +class User extends Entity { + public function setUp() { + $this->setInheritanceMap(array("type"=>1); + } +} + +class Group extends Entity { + public function setUp() { + $this->setInheritanceMap(array("type"=>2); + } +} +?> diff --git a/manual/codes/Mapping object relations - Inheritance - One table many classes.php b/manual/codes/Mapping object relations - Inheritance - One table many classes.php new file mode 100644 index 000000000..543972352 --- /dev/null +++ b/manual/codes/Mapping object relations - Inheritance - One table many classes.php @@ -0,0 +1,14 @@ +hasColumn("name","string",30); + $this->hasColumn("username","string",20); + $this->hasColumn("password","string",16); + $this->hasColumn("created","integer",11); + } +} + +class User extends Entity { } + +class Group extends Entity { } +?> diff --git a/manual/codes/Mapping object relations - Inheritance - One table one class.php b/manual/codes/Mapping object relations - Inheritance - One table one class.php new file mode 100644 index 000000000..a93adeb92 --- /dev/null +++ b/manual/codes/Mapping object relations - Inheritance - One table one class.php @@ -0,0 +1,26 @@ +hasColumn("name","string",30); + $this->hasColumn("username","string",20); + $this->hasColumn("password","string",16); + $this->hasColumn("created","integer",11); + } +} + +class User extends Entity { + public function setTableDefinition() { + // the following method call is needed in + // one-table-one-class inheritance + parent::setTableDefinition(); + } +} + +class Group extends Entity { + public function setTableDefinition() { + // the following method call is needed in + // one-table-one-class inheritance + parent::setTableDefinition(); + } +} +?> diff --git a/manual/codes/Mapping object relations - Join table associations - Many-to-Many.php b/manual/codes/Mapping object relations - Join table associations - Many-to-Many.php new file mode 100644 index 000000000..82571d303 --- /dev/null +++ b/manual/codes/Mapping object relations - Join table associations - Many-to-Many.php @@ -0,0 +1,49 @@ +hasMany("Group","Groupuser.group_id"); + } + public function setTableDefinition() { + $this->hasColumn("name","string",30); + } +} + +class Group extends Doctrine_Record { + public function setUp() { + $this->hasMany("User","Groupuser.user_id"); + } + public function setTableDefinition() { + $this->hasColumn("name","string",30); + } +} + +class Groupuser extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("user_id","integer"); + $this->hasColumn("group_id","integer"); + } +} + + +$user = new User(); + +// add two groups +$user->Group[0]->name = "First Group"; + +$user->Group[1]->name = "Second Group"; + +// save changes into database +$user->save(); + +$groups = new Doctrine_Collection($session->getTable("Group")); + +$groups[0]->name = "Third Group"; + +$groups[1]->name = "Fourth Group"; + +$user->Group[2] = $groups[0]; +// $user will now have 3 groups + +$user->Group = $groups; +// $user will now have two groups 'Third Group' and 'Fourth Group' +?> diff --git a/manual/codes/Mapping object relations - Join table associations - Self-referencing.php b/manual/codes/Mapping object relations - Join table associations - Self-referencing.php new file mode 100644 index 000000000..57fdcd0c3 --- /dev/null +++ b/manual/codes/Mapping object relations - Join table associations - Self-referencing.php @@ -0,0 +1,16 @@ +hasMany("User as Friend","UserReference.user_id-user_id2"); + } + public function setTableDefinition() { + $this->hasColumn("name","string",30); + } +} +class UserReference extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("user_id","integer"); + $this->hasColumn("user_id2","integer"); + } +} +?> diff --git a/manual/codes/Mapping object relations - Relation aliases.php b/manual/codes/Mapping object relations - Relation aliases.php new file mode 100644 index 000000000..e2ce4c75d --- /dev/null +++ b/manual/codes/Mapping object relations - Relation aliases.php @@ -0,0 +1,26 @@ +hasColumn("name", "string", 100); + $this->hasColumn("description", "string", 5000); + } + public function setUp() { + // notice the 'as' keyword here + $this->ownsMany("Forum_Thread as Threads", "Forum_Thread.board_id"); + } +} + +class Forum_Thread extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("board_id", "integer", 10); + $this->hasColumn("updated", "integer", 10); + $this->hasColumn("closed", "integer", 1); + } + public function setUp() { + // notice the 'as' keyword here + $this->hasOne("Forum_Board as Board", "Forum_Thread.board_id"); + } +} +$board = new Board(); +$board->Threads[0]->updated = time(); +?> diff --git a/manual/codes/Performance - Internal optimizations - DELETE.php b/manual/codes/Performance - Internal optimizations - DELETE.php new file mode 100644 index 000000000..2276fe51a --- /dev/null +++ b/manual/codes/Performance - Internal optimizations - DELETE.php @@ -0,0 +1,24 @@ +delete(); +/** + * On session drivers other than mysql doctrine would now perform three queries + * regardless of how many users, emails and phonenumbers there are + * + * the queries would look something like: + * DELETE FROM entity WHERE entity.id IN (1,2,3, ... ,15) + * DELETE FROM phonenumber WHERE phonenumber.id IN (4,6,7,8) + * DELETE FROM email WHERE email.id IN (1,2, ... ,10) + * + * On mysql doctrine is EVEN SMARTER! Now it would perform only one query! + * the query would look like: + * DELETE entity, email, phonenumber FROM entity + * LEFT JOIN phonenumber ON entity.id = phonenumber.entity_id, email + * WHERE (entity.email_id = email.id) && (entity.id IN(4, 5, 6, 7, 8, 9, 10, 11)) && (entity.type = 0) + */ + + +?> diff --git a/manual/codes/Performance - Internal optimizations - INSERT.php b/manual/codes/Performance - Internal optimizations - INSERT.php new file mode 100644 index 000000000..43a9958b0 --- /dev/null +++ b/manual/codes/Performance - Internal optimizations - INSERT.php @@ -0,0 +1,28 @@ +save(); +/** + * now doctrine would perform prepared queries in the following order: + * + * first the emails since every user needs to get the primary key of their newly created email + * INSERT INTO email (address) VALUES (:address) + * INSERT INTO email (address) VALUES (:address) + * INSERT INTO email (address) VALUES (:address) + * + * then the users + * INSERT INTO entity (name,email_id) VALUES (:name,:email_id) + * INSERT INTO entity (name,email_id) VALUES (:name,:email_id) + * INSERT INTO entity (name,email_id) VALUES (:name,:email_id) + * + * and at last the phonenumbers since they need the primary keys of the newly created users + * INSERT INTO phonenumber (phonenumber,entity_id) VALUES (:phonenumber,:entity_id) + * INSERT INTO phonenumber (phonenumber,entity_id) VALUES (:phonenumber,:entity_id) + * INSERT INTO phonenumber (phonenumber,entity_id) VALUES (:phonenumber,:entity_id) + * INSERT INTO phonenumber (phonenumber,entity_id) VALUES (:phonenumber,:entity_id) + * INSERT INTO phonenumber (phonenumber,entity_id) VALUES (:phonenumber,:entity_id) + * + * These operations are considerably fast, since many databases perform multiple + * prepared queries very rapidly + */ +?> diff --git a/manual/codes/Real world examples - Forum application.php b/manual/codes/Real world examples - Forum application.php new file mode 100644 index 000000000..dbe0fe77e --- /dev/null +++ b/manual/codes/Real world examples - Forum application.php @@ -0,0 +1,52 @@ +hasColumn("root_category_id", "integer", 10); + $this->hasColumn("parent_category_id", "integer", 10); + $this->hasColumn("name", "string", 50); + $this->hasColumn("description", "string", 99999); + } + public function setUp() { + $this->hasMany("Forum_Category as Subcategory", "Subcategory.parent_category_id"); + $this->hasOne("Forum_Category as Rootcategory", "Forum_Category.root_category_id"); + } +} +class Forum_Board extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("category_id", "integer", 10); + $this->hasColumn("name", "string", 100); + $this->hasColumn("description", "string", 5000); + } + public function setUp() { + $this->hasOne("Forum_Category as Category", "Forum_Board.category_id"); + $this->ownsMany("Forum_Thread as Threads", "Forum_Thread.board_id"); + } +} + +class Forum_Entry extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("author", "string", 50); + $this->hasColumn("topic", "string", 100); + $this->hasColumn("message", "string", 99999); + $this->hasColumn("parent_entry_id", "integer", 10); + $this->hasColumn("thread_id", "integer", 10); + $this->hasColumn("date", "integer", 10); + } + public function setUp() { + $this->hasOne("Forum_Entry as Parent", "Forum_Entry.parent_entry_id"); + $this->hasOne("Forum_Thread as Thread", "Forum_Entry.thread_id"); + } +} + +class Forum_Thread extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("board_id", "integer", 10); + $this->hasColumn("updated", "integer", 10); + $this->hasColumn("closed", "integer", 1); + } + public function setUp() { + $this->hasOne("Forum_Board as Board", "Forum_Thread.board_id"); + $this->ownsMany("Forum_Entry as Entries", "Forum_Entry.thread_id"); + } +} +?> diff --git a/manual/codes/Real world examples - User management system.php b/manual/codes/Real world examples - User management system.php new file mode 100644 index 000000000..de04d2763 --- /dev/null +++ b/manual/codes/Real world examples - User management system.php @@ -0,0 +1,79 @@ +ownsOne("Email","Entity.email_id"); + $this->ownsMany("Phonenumber","Phonenumber.entity_id"); + $this->setAttribute(Doctrine::ATTR_FETCHMODE,Doctrine::FETCH_BATCH); + $this->setAttribute(Doctrine::ATTR_LISTENER,new EntityListener()); + } + public function setTableDefinition() { + $this->hasColumn("name","string",50); + $this->hasColumn("loginname","string",20); + $this->hasColumn("password","string",16); + $this->hasColumn("type","integer",1); + $this->hasColumn("created","integer",11); + $this->hasColumn("updated","integer",11); + $this->hasColumn("email_id","integer"); + } + } +} +class Group extends Entity { + public function setUp() { + parent::setUp(); + $this->hasMany("User","Groupuser.user_id"); + $this->setInheritanceMap(array("type"=>1)); + } +} +class User extends Entity { + public function setUp() { + parent::setUp(); + $this->hasMany("Group","Groupuser.group_id"); + $this->setInheritanceMap(array("type"=>0)); + } +} +class Groupuser extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("group_id","integer"); + $this->hasColumn("user_id","integer"); + } +} + +class Phonenumber extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("phonenumber","string",20); + $this->hasColumn("entity_id","integer"); + } +} +class Email extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("address","string",150,"email|unique"); + } +} +class EntityListener extends Doctrine_EventListener { + public function onPreUpdate(Doctrine_Record $record) { + $record->updated = time(); + } + public function onPreInsert(Doctrine_Record $record) { + $record->created = time(); + } +} + +// USER MANAGEMENT SYSTEM IN ACTION: + +$manager = Doctrine_Manager::getInstance(); + +$session = $manager->openSession(new PDO("DSN","username","password")); + +$user = new User(); + +$user->name = "Jack Daniels"; +$user->Email->address = "jackdaniels@drinkmore.info"; +$user->Phonenumber[0]->phonenumber = "123 123"; +$user->Phonenumber[1]->phonenumber = "133 133"; +$user->save(); + +$user->Group[0]->name = "beer lovers"; +$user->Group[0]->Email->address = "beerlovers@drinkmore.info"; +$user->Group[0]->save(); + +?> diff --git a/manual/codes/Runtime classes - Doctrine_Record.php b/manual/codes/Runtime classes - Doctrine_Record.php new file mode 100644 index 000000000..0264a5ccf --- /dev/null +++ b/manual/codes/Runtime classes - Doctrine_Record.php @@ -0,0 +1,40 @@ +find(2); + +// get state +$state = $user->getState(); + +print $user->name; + +print $user["name"]; + +print $user->get("name"); + +$user->name = "Jack Daniels"; + +$user->set("name","Jack Daniels"); + +// serialize record + +$serialized = serialize($user); + +$user = unserialize($serialized); + +// create a copy + +$copy = $user->copy(); + +// get primary key + +$id = $user->getID(); + +// print lots of useful info + +print $user; + +// save all the properties and composites +$user->save(); + +// delete this data access object and related objects +$user->delete(); +?> diff --git a/manual/codes/Runtime classes - Doctrine_Session.php b/manual/codes/Runtime classes - Doctrine_Session.php new file mode 100644 index 000000000..b3c802415 --- /dev/null +++ b/manual/codes/Runtime classes - Doctrine_Session.php @@ -0,0 +1,30 @@ +openSession(Doctrine_DB::getConnection("schema://username:password@hostname/database")); + +// get session state: +switch($sess): + case Doctrine_Session::STATE_BUSY: + // multiple open transactions + break; + case Doctrine_Session::STATE_ACTIVE: + // one open transaction + break; + case Doctrine_Session::STATE_CLOSED: + // closed state + break; + case Doctrine_Session::STATE_OPEN: + // open state and zero open transactions + break; +endswitch; + +// getting database handler + +$dbh = $sess->getDBH(); + +// flushing the session +$sess->flush(); + + +// print lots of useful info about session: +print $sess; +?> diff --git a/manual/codes/Transactions - Introduction.php b/manual/codes/Transactions - Introduction.php new file mode 100644 index 000000000..5c02299e0 --- /dev/null +++ b/manual/codes/Transactions - Introduction.php @@ -0,0 +1,13 @@ +beginTransaction(); + +$user = new User(); +$user->name = 'New user'; +$user->save(); + +$user = $session->getTable('User')->find(5); +$user->name = 'Modified user'; +$user->save(); + +$session->commit(); // all the queries are executed here +?> diff --git a/manual/codes/Transactions - Nesting.php b/manual/codes/Transactions - Nesting.php new file mode 100644 index 000000000..d64ec24c1 --- /dev/null +++ b/manual/codes/Transactions - Nesting.php @@ -0,0 +1,23 @@ +beginTransaction(); + + $user->save(); + + $group->save(); + + $session->commit(); +} + +try { + $session->beginTransaction(); + + saveUserAndGroup($session,$user,$group); + saveUserAndGroup($session,$user2,$group2); + saveUserAndGroup($session,$user3,$group3); + + $session->commit(); +} catch(Doctrine_Exception $e) { + $session->rollback(); +} +?> diff --git a/manual/codes/Transactions - Unit of work.php b/manual/codes/Transactions - Unit of work.php new file mode 100644 index 000000000..3946438bc --- /dev/null +++ b/manual/codes/Transactions - Unit of work.php @@ -0,0 +1,18 @@ +beginTransaction(); + +$user = new User(); +$user->name = 'New user'; +$user->save(); + +$user = $session->getTable('User')->find(5); +$user->name = 'Modified user'; +$user->save(); + + +$pending = $session->getInserts(); // an array containing one element + +$pending = $session->getUpdates(); // an array containing one element + +$session->commit(); // all the queries are executed here +?> diff --git a/manual/docs/Advanced components - Cache - Introduction.php b/manual/docs/Advanced components - Cache - Introduction.php new file mode 100644 index 000000000..e7abab911 --- /dev/null +++ b/manual/docs/Advanced components - Cache - Introduction.php @@ -0,0 +1,2 @@ +Caching is one of the most influental things when it comes to performance tuning. Doctrine_Cache provides means for +caching queries and for managing the cached queries. diff --git a/manual/docs/Advanced components - Eventlisteners - Creating new listener.php b/manual/docs/Advanced components - Eventlisteners - Creating new listener.php new file mode 100644 index 000000000..57f733cc0 --- /dev/null +++ b/manual/docs/Advanced components - Eventlisteners - Creating new listener.php @@ -0,0 +1 @@ +Creating a new listener is very easy. You can set the listener in global, session or factory level. diff --git a/manual/docs/Advanced components - Eventlisteners - List of events.php b/manual/docs/Advanced components - Eventlisteners - List of events.php new file mode 100644 index 000000000..95524cd93 --- /dev/null +++ b/manual/docs/Advanced components - Eventlisteners - List of events.php @@ -0,0 +1 @@ +Here is a list of availible events and their parameters: diff --git a/manual/docs/Advanced components - Hook - Introduction.php b/manual/docs/Advanced components - Hook - Introduction.php new file mode 100644 index 000000000..f5e977f91 --- /dev/null +++ b/manual/docs/Advanced components - Hook - Introduction.php @@ -0,0 +1,3 @@ +Many web applications have different kinds of lists. The lists may contain data from multiple components (= database tables) and +they may have actions such as paging, sorting and setting conditions. Doctrine_Hook helps building these lists. It has a simple API for +building search criteria forms as well as building a DQL query from the 'hooked' parameters. diff --git a/manual/docs/Advanced components - Validators - Intruduction.php b/manual/docs/Advanced components - Validators - Intruduction.php new file mode 100644 index 000000000..737dc2cd7 --- /dev/null +++ b/manual/docs/Advanced components - Validators - Intruduction.php @@ -0,0 +1,11 @@ +With Doctrine validators you can validate a whole transaction and get info of everything +that went wrong. Some Doctrine validators also act as a database level constraints. For example +adding a unique validator to column 'name' also adds a database level unique constraint into that +column. +

+Validators are added as a 4 argument for hasColumn() method. Validators should be separated +by '|' mark. For example email|unique would validate a value using Doctrine_Validator_Email +and Doctrine_Validator_Unique. +

+Doctrine has many predefined validators (see chapter 13.3). If you wish to use +custom validators just write *Validator classes and doctrine will automatically use them. diff --git a/manual/docs/Advanced components - Validators - List of predefined validators.php b/manual/docs/Advanced components - Validators - List of predefined validators.php new file mode 100644 index 000000000..186a75ef0 --- /dev/null +++ b/manual/docs/Advanced components - Validators - List of predefined validators.php @@ -0,0 +1,124 @@ +Here is a list of predefined validators. You cannot use these names for your custom validators. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ name + + arguments + + task +
+ email + + + + Checks if value is valid email. +
+ notblank + + + + Checks if value is not blank. +
+ notnull + + + + Checks if value is not null. +
+ country + + + + Checks if value is valid country code. +
+ ip + + + + Checks if value is valid internet protocol address. +
+ htmlcolor + + + + Checks if value is valid html color. +
+ nospace + + + + Checks if value has no space chars. +
+ range + + [min, max] + + Checks if value is in range specified by arguments. +
+ unique + + + + Checks if value is unique in its database table. +
+ regexp + + [expression] + + Checks if value matches a given regexp. +
diff --git a/manual/docs/Advanced components - Validators - Validating transactions.php b/manual/docs/Advanced components - Validators - Validating transactions.php new file mode 100644 index 000000000..f93b361d5 --- /dev/null +++ b/manual/docs/Advanced components - Validators - Validating transactions.php @@ -0,0 +1,5 @@ +When the validation attribute is set as true all transactions will be validated, so whenever Doctrine_Record::save(), +Doctrine_Session::flush() or any other saving method is used all the properties of all records in that transaction will have their values +validated. +

+Validation errors are being stacked into Doctrine_Validator_Exception. diff --git a/manual/docs/Advanced components - View - Intoduction.php b/manual/docs/Advanced components - View - Intoduction.php new file mode 100644 index 000000000..8ca580f33 --- /dev/null +++ b/manual/docs/Advanced components - View - Intoduction.php @@ -0,0 +1,2 @@ +Database views can greatly increase the performance of complex queries. You can think of them as +cached queries. Doctrine_View provides integration between database views and DQL queries. diff --git a/manual/docs/Basic Components - Collection - Accessing elements.php b/manual/docs/Basic Components - Collection - Accessing elements.php new file mode 100644 index 000000000..1fe766630 --- /dev/null +++ b/manual/docs/Basic Components - Collection - Accessing elements.php @@ -0,0 +1 @@ +You can access the elements of Doctrine_Collection with set() and get() methods or with ArrayAccess interface. diff --git a/manual/docs/Basic Components - Collection - Deleting collection.php b/manual/docs/Basic Components - Collection - Deleting collection.php new file mode 100644 index 000000000..a33028dc2 --- /dev/null +++ b/manual/docs/Basic Components - Collection - Deleting collection.php @@ -0,0 +1,9 @@ +Doctrine Collections can be deleted in very same way is Doctrine Records you just call delete() method. +As for all collections Doctrine knows how to perform single-shot-delete meaning it only performs one +database query for the each collection. +

+For example if we have collection of users which own [0-*] phonenumbers. When deleting the collection +of users doctrine only performs two queries for this whole transaction. The queries would look something like: +

+DELETE FROM user WHERE id IN (1,2,3, ... ,N)
+DELETE FROM phonenumber WHERE id IN (1,2,3, ... ,M)
diff --git a/manual/docs/Basic Components - Collection - Fetching strategies.php b/manual/docs/Basic Components - Collection - Fetching strategies.php new file mode 100644 index 000000000..2b0423b60 --- /dev/null +++ b/manual/docs/Basic Components - Collection - Fetching strategies.php @@ -0,0 +1,42 @@ +Whenever you fetch records with eg. Doctrine_Table::findAll or Doctrine_Session::query methods an instance of +Doctrine_Collection is returned. There are many types of collections in Doctrine and it is crucial to understand +the differences of these collections. Remember choosing the right fetching strategy (collection type) is one of the most +influental things when it comes to boosting application performance. +

+
  • Immediate Collection +
  • Batch Collection +
  • Lazy Collection +
  • Offset Collection + diff --git a/manual/docs/Basic Components - Manager - Introduction.php b/manual/docs/Basic Components - Manager - Introduction.php new file mode 100644 index 000000000..199e55816 --- /dev/null +++ b/manual/docs/Basic Components - Manager - Introduction.php @@ -0,0 +1 @@ +Doctrine_Manager is the heart of every Doctrine based application. Doctrine_Manager handles all sessions (database connections). diff --git a/manual/docs/Basic Components - Manager - Managing sessions.php b/manual/docs/Basic Components - Manager - Managing sessions.php new file mode 100644 index 000000000..54455e382 --- /dev/null +++ b/manual/docs/Basic Components - Manager - Managing sessions.php @@ -0,0 +1,3 @@ +Switching between sessions in Doctrine is very easy, you just call Doctrine_Manager::setCurrentSession() method. +You can access the session by calling Doctrine_Manager::getSession() or Doctrine_Manager::getCurrentSession() if you only +want to get the current session. diff --git a/manual/docs/Basic Components - Manager - Opening a new session.php b/manual/docs/Basic Components - Manager - Opening a new session.php new file mode 100644 index 000000000..239e736fe --- /dev/null +++ b/manual/docs/Basic Components - Manager - Opening a new session.php @@ -0,0 +1,3 @@ +In order to get your first application started you first +need to get an instance of Doctrine_Manager which handles all the sessions (database connections). +The second thing to do is to open a new session. diff --git a/manual/docs/Basic Components - Query - DQL - SQL conversion.php b/manual/docs/Basic Components - Query - DQL - SQL conversion.php new file mode 100644 index 000000000..1229ccf80 --- /dev/null +++ b/manual/docs/Basic Components - Query - DQL - SQL conversion.php @@ -0,0 +1,52 @@ +SELECT",$line); + $l = str_replace("FROM","
    FROM",$l); + $l = str_replace("LEFT JOIN","
    LEFT JOIN",$l); + $l = str_replace("WHERE","
    WHERE",$l); + $l = str_replace("AS","AS",$l); + $l = str_replace("ON","ON",$l); + $l = str_replace("ORDER BY","ORDER BY",$l); + $l = str_replace("LIMIT","LIMIT",$l); + $l = str_replace("OFFSET","OFFSET",$l); + $l = str_replace(" ","
    ",$l); + if(substr($l,0,3) == "DQL") print "
    "; + print $l."
    "; + +} + +?> diff --git a/manual/docs/Basic Components - Query - Introduction.php b/manual/docs/Basic Components - Query - Introduction.php new file mode 100644 index 000000000..2a80f0189 --- /dev/null +++ b/manual/docs/Basic Components - Query - Introduction.php @@ -0,0 +1,8 @@ +DQL (Doctrine Query Language) is a object query language which allows +you to find objects. DQL understands things like object relationships, polymorphism and +inheritance (including column aggregation inheritance). +

    +So instead of writing lots of SQL inner and outer joins, unions and subselects yourself, +you can write simple DQL queries where relationships are being referenced with dot-notation. +

    +You can execute DQL queries with Doctrine_Session::query() method. diff --git a/manual/docs/Basic Components - Query - Method overloading.php b/manual/docs/Basic Components - Query - Method overloading.php new file mode 100644 index 000000000..1dfc1c89e --- /dev/null +++ b/manual/docs/Basic Components - Query - Method overloading.php @@ -0,0 +1 @@ +You can overload the query object by calling the dql query parts as methods. diff --git a/manual/docs/Basic Components - Query - ORDER BY - sorting query results.php b/manual/docs/Basic Components - Query - ORDER BY - sorting query results.php new file mode 100644 index 000000000..642ec5d6e --- /dev/null +++ b/manual/docs/Basic Components - Query - ORDER BY - sorting query results.php @@ -0,0 +1 @@ +ORDER BY - part works in much same way as SQL ORDER BY. diff --git a/manual/docs/Basic Components - Query - Relation operators.php b/manual/docs/Basic Components - Query - Relation operators.php new file mode 100644 index 000000000..1ebde18d7 --- /dev/null +++ b/manual/docs/Basic Components - Query - Relation operators.php @@ -0,0 +1,7 @@ +Doctrine provides two relation operators: '.' aka dot and ':' aka colon. +

    +The dot-operator is used for SQL LEFT JOINs and the colon-operator is used +for SQL INNER JOINs. Basically you should use dot operator if you want for example +to select all users and their phonenumbers AND it doesn't matter if the users actually have any phonenumbers. +

    +On the other hand if you want to select only the users which actually have phonenumbers you should use the colon-operator. diff --git a/manual/docs/Basic Components - Record - Accessing properties.php b/manual/docs/Basic Components - Record - Accessing properties.php new file mode 100644 index 000000000..a56f41558 --- /dev/null +++ b/manual/docs/Basic Components - Record - Accessing properties.php @@ -0,0 +1,3 @@ +You can retrieve existing objects (database rows) with Doctrine_Table or Doctrine_Session. +Doctrine_Table provides simple methods like findBySql, findAll and find for finding objects whereas +Doctrine_Session provides complete OQL API for retrieving objects (see chapter 9). diff --git a/manual/docs/Basic Components - Record - Adding records.php b/manual/docs/Basic Components - Record - Adding records.php new file mode 100644 index 000000000..b766d4b09 --- /dev/null +++ b/manual/docs/Basic Components - Record - Adding records.php @@ -0,0 +1,3 @@ +There are three possible ways to access the properties of a record (fields of database row). +You can use overloading, ArrayAccess interface or simply Doctrine_Record::get() method. +Doctrine_Record objects have always all properties in lowercase. diff --git a/manual/docs/Basic Components - Record - Creating new records.php b/manual/docs/Basic Components - Record - Creating new records.php new file mode 100644 index 000000000..d4843ba8f --- /dev/null +++ b/manual/docs/Basic Components - Record - Creating new records.php @@ -0,0 +1,3 @@ +There are couple of ways for creating new records. Propably the easiest is using +native php new -operator. The other ways are calling Doctrine_Table::create() or Doctrine_Session::create(). +The last two exists only for backward compatibility. The recommended way of creating new objects is the new operator. diff --git a/manual/docs/Basic Components - Record - Deleting records.php b/manual/docs/Basic Components - Record - Deleting records.php new file mode 100644 index 000000000..cc8b3883e --- /dev/null +++ b/manual/docs/Basic Components - Record - Deleting records.php @@ -0,0 +1,2 @@ +Deleting records in Doctrine is handled by Doctrine_Record::delete(), Doctrine_Collection::delete() and +Doctrine_Session::delete() methods. diff --git a/manual/docs/Basic Components - Record - Getting object copy.php b/manual/docs/Basic Components - Record - Getting object copy.php new file mode 100644 index 000000000..89858805f --- /dev/null +++ b/manual/docs/Basic Components - Record - Getting object copy.php @@ -0,0 +1,2 @@ +Sometimes you may want to get a copy of your object (a new object with all properties copied). +Doctrine provides a simple method for this: Doctrine_Record::copy(). diff --git a/manual/docs/Basic Components - Record - Getting record state.php b/manual/docs/Basic Components - Record - Getting record state.php new file mode 100644 index 000000000..dc9a5c9d3 --- /dev/null +++ b/manual/docs/Basic Components - Record - Getting record state.php @@ -0,0 +1,7 @@ +Every Doctrine_Record has a state. First of all record can be transient or persistent. +Every record that is retrieved from database is persistent and every newly created record is transient. +If a Doctrine_Record is retrieved from database but the only loaded property is its primary key, then this record +has a state called proxy. +

    +Every transient and persistent Doctrine_Record is either clean or dirty. Doctrine_Record is clean when none of its properties are changed and +dirty when atleast one of its properties has changed. diff --git a/manual/docs/Basic Components - Record - Retrieving existing records.php b/manual/docs/Basic Components - Record - Retrieving existing records.php new file mode 100644 index 000000000..ca7639fa7 --- /dev/null +++ b/manual/docs/Basic Components - Record - Retrieving existing records.php @@ -0,0 +1,3 @@ +Doctrine provides many ways for record retrieval. The fastest ways for retrieving existing records +are the finder methods provided by Doctrine_Table. If you need to use more complex queries take a look at +DQL API and Doctrine_Session::query method. diff --git a/manual/docs/Basic Components - Record - Serializing.php b/manual/docs/Basic Components - Record - Serializing.php new file mode 100644 index 000000000..45a642d0c --- /dev/null +++ b/manual/docs/Basic Components - Record - Serializing.php @@ -0,0 +1,2 @@ +Sometimes you may want to serialize your record objects (possibly for caching purposes). Records can be serialized, +but remember: Doctrine cleans all relations, before doing this. So remember to persist your objects into database before serializing them. diff --git a/manual/docs/Basic Components - Record - Updating records.php b/manual/docs/Basic Components - Record - Updating records.php new file mode 100644 index 000000000..f9415397f --- /dev/null +++ b/manual/docs/Basic Components - Record - Updating records.php @@ -0,0 +1,3 @@ +Updating objects is very easy, you just call the Doctrine_Record::save() method. The other way +(perhaps even easier) is to call Doctrine_Session::flush() which saves all objects. It should be noted though +that flushing is a much heavier operation than just calling save method. diff --git a/manual/docs/Basic Components - Session - Flushing the session.php b/manual/docs/Basic Components - Session - Flushing the session.php new file mode 100644 index 000000000..c3888aada --- /dev/null +++ b/manual/docs/Basic Components - Session - Flushing the session.php @@ -0,0 +1,2 @@ +Creating new record (database row) is very easy. You can either use the Doctrine_Session::create() or Doctrine_Table::create() +method to do this or just simple use the new operator. diff --git a/manual/docs/Basic Components - Session - Getting a table object.php b/manual/docs/Basic Components - Session - Getting a table object.php new file mode 100644 index 000000000..0795c7d9b --- /dev/null +++ b/manual/docs/Basic Components - Session - Getting a table object.php @@ -0,0 +1 @@ +In order to get table object for specified record just call Doctrine_Record::getTable() or Doctrine_Session::getTable(). diff --git a/manual/docs/Basic Components - Session - Getting session state.php b/manual/docs/Basic Components - Session - Getting session state.php new file mode 100644 index 000000000..f6ae741b9 --- /dev/null +++ b/manual/docs/Basic Components - Session - Getting session state.php @@ -0,0 +1,2 @@ +Session state gives you information about how active session currently is. You can get the current state +by calling Doctrine_Session::getState(). diff --git a/manual/docs/Basic Components - Table - Custom finders.php b/manual/docs/Basic Components - Table - Custom finders.php new file mode 100644 index 000000000..fb595a24e --- /dev/null +++ b/manual/docs/Basic Components - Table - Custom finders.php @@ -0,0 +1,2 @@ +You can add custom finder methods to your custom table object. These finder methods may use fast +Doctrine_Table finder methods or DQL API (Doctrine_Session::query()). diff --git a/manual/docs/Basic Components - Table - Custom table classes.php b/manual/docs/Basic Components - Table - Custom table classes.php new file mode 100644 index 000000000..f267c2ac9 --- /dev/null +++ b/manual/docs/Basic Components - Table - Custom table classes.php @@ -0,0 +1,2 @@ +Adding custom table classes is very easy. Only thing you need to do is name the classes as [componentName]Table and make them +inherit Doctrine_Table. diff --git a/manual/docs/Basic Components - Table - Finder methods.php b/manual/docs/Basic Components - Table - Finder methods.php new file mode 100644 index 000000000..a93e45cd9 --- /dev/null +++ b/manual/docs/Basic Components - Table - Finder methods.php @@ -0,0 +1,2 @@ +Doctrine_Table provides basic finder methods. These finder methods are very fast and should be used if you only need to fetch +data from one database table. If you need queries that use several components (database tables) use Doctrine_Session::query(). diff --git a/manual/docs/Basic components - Exceptions - List of exceptions.php b/manual/docs/Basic components - Exceptions - List of exceptions.php new file mode 100644 index 000000000..a3a7b55fa --- /dev/null +++ b/manual/docs/Basic components - Exceptions - List of exceptions.php @@ -0,0 +1,24 @@ +
    +InvalidKeyException
    +
    +Doctrine_Exception
    +
    +DQLException
    +
    +Doctrine_PrimaryKey_Exception          thrown when Doctrine_Record is loaded and there is no primary key field
    +
    +Doctrine_Refresh_Exception             thrown when Doctrine_Record is refreshed and the refreshed primary key doens't match the old one
    +
    +Doctrine_Find_Exception                thrown when user tries to find a Doctrine_Record for given primary key and that object is not found
    +
    +Doctrine_Naming_Exception              thrown when user defined Doctrine_Table is badly named
    +
    +
    +Doctrine_Session_Exception             thrown when user tries to get the current
    +                                       session and there are no open sessions
    +
    +Doctrine_Table_Exception               thrown when user tries to initialize a new instance of Doctrine_Table,
    +                                       while there already exists an instance of that factory
    +
    +Doctrine_Mapping_Exception             thrown when user tries to get a foreign key object but the mapping is not done right
    +
    diff --git a/manual/docs/Cache - Configuration.php b/manual/docs/Cache - Configuration.php new file mode 100644 index 000000000..12b5d869b --- /dev/null +++ b/manual/docs/Cache - Configuration.php @@ -0,0 +1,26 @@ +There are couple of availible Cache attributes on Doctrine: +
      +
    • Doctrine::ATTR_CACHE_SIZE +
        +
      • Defines which cache container Doctrine uses +
      • Possible values: Doctrine::CACHE_* (for example Doctrine::CACHE_FILE) +
      +
    • Doctrine::ATTR_CACHE_DIR +
        +
      • cache directory where .cache files are saved +
      • the default cache dir is %ROOT%/cachedir, where + %ROOT% is automatically converted to doctrine root dir +
      +
    • Doctrine::ATTR_CACHE_SLAM +
        +
      • On very busy servers whenever you start the server or modify files you can create a race of many processes all trying to cache the same file at the same time. This option sets the percentage of processes that will skip trying to cache an uncached file. Or think of it as the probability of a single process to skip caching. For example, setting apc.slam_defense to 75 would mean that there is a 75% chance that the process will not cache an uncached file. So, the higher the setting the greater the defense against cache slams. Setting this to 0 disables this feature +
      +
    • Doctrine::ATTR_CACHE_SIZE +
        +
      • Cache size attribute +
      +
    • Doctrine::ATTR_CACHE_TTL +
        +
      • How often the cache is cleaned +
      +
    diff --git a/manual/docs/Cache - Overview.php b/manual/docs/Cache - Overview.php new file mode 100644 index 000000000..cd3ad0866 --- /dev/null +++ b/manual/docs/Cache - Overview.php @@ -0,0 +1,40 @@ +Doctrine has very comprehensive and fast caching solution. +Its cache is always up-to-date. +In order to achieve this doctrine does the following things: +

    + + +
    +1. Every Doctrine_Table has its own cache directory. The default is cache/componentname/. All the cache files are saved into that directory. +The format of each cache file is [primarykey].cache. +

    +2. When retrieving records from the database doctrine always tries to hit the cache first. +

    +3. If a record (Doctrine_Record) is retrieved from database or inserted into database it will be saved into cache. +

    +4. When a Data Access Object is deleted or updated it will be deleted from the cache +
    +

    +Now one might wonder that this kind of solution won't work since eventually the cache will be a copy of database! +So doctrine does the following things to ensure the cache won't get too big: +

    + + + +
    + +1. Every time a cache file is accessed the id of that record will be added into the $fetched property of Doctrine_Cache +

    +2. At the end of each script the Doctrine_Cache destructor will write all these primary keys at the end of a stats.cache file +

    +3. Doctrine does propabalistic cache cleaning. The default interval is 200 page loads (= 200 constructed Doctrine_Managers). Basically this means +that the average number of page loads between cache cleans is 200. +

    +4. On every cache clean stats.cache files are being read and the least accessed cache files +(cache files that have the smallest id occurance in the stats file) are then deleted. +For example if the cache size is set to 200 and the number of files in cache is 300, then 100 least accessed files are being deleted. +Doctrine also clears every stats.cache file. + +
    +

    +So for every 199 fast page loads there is one page load which suffers a little overhead from the cache cleaning operation. diff --git a/manual/docs/Configuration - Levels of configuration.php b/manual/docs/Configuration - Levels of configuration.php new file mode 100644 index 000000000..6b8bc07a2 --- /dev/null +++ b/manual/docs/Configuration - Levels of configuration.php @@ -0,0 +1,18 @@ +Doctrine has a three-level configuration structure. You can set configuration attributes in global, session and table level. +If the same attribute is set on both lower level and upper level, the uppermost attribute will always be used. So for example +if user first sets default fetchmode in global level to Doctrine::FETCH_BATCH and then sets 'example' table fetchmode to Doctrine::FETCH_LAZY, +the lazy fetching strategy will be used whenever the records of 'example' table are being fetched. + +

    +
  • Global level +
      + The attributes set in global level will affect every session and every table in each session. +
    +
  • Session level +
      + The attributes set in session level will take effect on each table in that session. +
    +
  • Table level +
      + The attributes set in table level will take effect only on that table. +
    diff --git a/manual/docs/Configuration - List of attributes.php b/manual/docs/Configuration - List of attributes.php new file mode 100644 index 000000000..f238ab886 --- /dev/null +++ b/manual/docs/Configuration - List of attributes.php @@ -0,0 +1,44 @@ +
  • Doctrine::ATTR_LISTENER +
  • Doctrine::ATTR_FETCHMODE = 2; + +
  • Doctrine::ATTR_CACHE_DIR = 3; + +
  • Doctrine::ATTR_CACHE_TTL = 4; + +
  • Doctrine::ATTR_CACHE_SIZE = 5; + +
  • Doctrine::ATTR_CACHE_SLAM = 6; + +
  • Doctrine::ATTR_CACHE = 7; + +
  • Doctrine::ATTR_BATCH_SIZE = 8; + +
  • Doctrine::ATTR_PK_COLUMNS = 9; + /** + * primary key type attribute + */ +
  • Doctrine::ATTR_PK_TYPE = 10; + /** + * locking attribute + */ +
  • Doctrine::ATTR_LOCKMODE = 11; + /** + * validatate attribute + */ +
  • Doctrine::ATTR_VLD = 12; + /** + * name prefix attribute + */ +
  • Doctrine::ATTR_NAME_PREFIX = 13; + /** + * create tables attribute + */ +
  • Doctrine::ATTR_CREATE_TABLES = 14; + /** + * collection key attribute + */ +
  • Doctrine::ATTR_COLL_KEY = 15; + /** + * collection limit attribute + */ +
  • Doctrine::ATTR_COLL_LIMIT = 16; diff --git a/manual/docs/Getting started - Installation.php b/manual/docs/Getting started - Installation.php new file mode 100644 index 000000000..3473b5ec4 --- /dev/null +++ b/manual/docs/Getting started - Installation.php @@ -0,0 +1,3 @@ +The installation of doctrine is very easy. Just extract doctrine.*.zip into your www folder. +

    +In the beginning of your every script you can put: diff --git a/manual/docs/Getting started - Requirements.php b/manual/docs/Getting started - Requirements.php new file mode 100644 index 000000000..3fcc3431f --- /dev/null +++ b/manual/docs/Getting started - Requirements.php @@ -0,0 +1,3 @@ +Doctrine requires PHP >= 5.1. it doesn't require any external libraries. +For database abstraction Doctrine uses PDO which is bundled with php by default. Doctrine also requires a little +adodb-hack for table creation, which comes with doctrine as of beta4. diff --git a/manual/docs/Getting started - Setting table definition - Constraints and validators.php b/manual/docs/Getting started - Setting table definition - Constraints and validators.php new file mode 100644 index 000000000..4063fc442 --- /dev/null +++ b/manual/docs/Getting started - Setting table definition - Constraints and validators.php @@ -0,0 +1,35 @@ +Following data types and constraints are availible in doctrine +
      +
    • unique +
        Acts as database level unique constraint. Also validates that the specified column is unique. +
      +
    • nospace +
        Nospace validator. This validator validates that specified column doesn't contain any space/newline characters.
        +
      +
    • notblank +
        Notblank validator. This validator validates that specified column doesn't contain only space/newline characters. Useful in for example comment posting applications + where users are not allowed to post empty comments.
        +
      +
    • notnull +
      Acts as database level notnull constraint as well as notnull validator for the specified column.
      +
    • email +
      Email validator. Validates that specified column is a valid email address. +
    • date +
      Date validator. +
    • range:[args] +
      Range validator, eg range:1-32 +
    • enum:[args] +
      Enum validator, eg enum:city1-city2-city3 +
    • country +
        Country code validator validates that specified column has a valid country code. +
      +
    • regexp:[args] +
        Regular expression validator validates that specified column matches a regular expression, eg regexp:[John] +
      +
    • ip +
        Ip validator validates that specified column is a valid internet protocol address. +
      +
    • usstate +
        Usstate validator validates that specified column is a valid usstate. +
      +
    diff --git a/manual/docs/Getting started - Setting table definition - Data types and lengths.php b/manual/docs/Getting started - Setting table definition - Data types and lengths.php new file mode 100644 index 000000000..ffe066415 --- /dev/null +++ b/manual/docs/Getting started - Setting table definition - Data types and lengths.php @@ -0,0 +1,41 @@ +Following data types are availible in doctrine: +
      +
    • string / s +
      The same as type 'string' in php +
    • float / double / f +
      The same as type 'float' in php
      +
    • integer / int / i +
      The same as type 'integer' in php
      +
    • boolean / bool +
      The same as type 'boolean' in php
      +
    • array / a +
        The same as type 'array' in php. Automatically serialized when saved into database and unserialized when retrieved from database.
      +
    • object / o +
        The same as type 'object' in php. Automatically serialized when saved into database and unserialized when retrieved from database.
      +
    • enum / e +
        Unified 'enum' type. Automatically converts the string values into index numbers and vice versa. The possible values for the column + can be specified with Doctrine_Record::setEnumValues(columnName, array values).
      +
    • timestamp / t +
      Database 'timestamp' type +
    • clob +
      Database 'clob' type +
    • blob +
      Database 'blob' type +
    • date / d +
      Database 'date' type +
    + +It should be noted that the length of the column affects in database level type +as well as application level validated length (the length that is validated with Doctrine validators).
    + +
    Example 1. Column named 'content' with type 'string' and length 3000 results in database type 'TEXT' of which has database level length of 4000. +However when the record is validated it is only allowed to have 'content' -column with maximum length of 3000.
    + +
    Example 2. Column with type 'integer' and length 1 results in 'TINYINT' on many databases. +

    + +In general Doctrine is smart enough to know which integer/string type to use depending on the specified length. + +
    + + diff --git a/manual/docs/Getting started - Setting table definition - Introduction.php b/manual/docs/Getting started - Setting table definition - Introduction.php new file mode 100644 index 000000000..1dbd9dd27 --- /dev/null +++ b/manual/docs/Getting started - Setting table definition - Introduction.php @@ -0,0 +1,7 @@ +Setting up a table definition in doctrine is done by using hasColumn method calls inside setTableDefinition method. +Doctrine_Record::hasColumn() takes 4 arguments:
    + +1. [column name]
    +2. [column type]
    +3. [column length]
    +4. [column constraints and validators] diff --git a/manual/docs/Getting started - Starting new project.php b/manual/docs/Getting started - Starting new project.php new file mode 100644 index 000000000..1d257e3b9 --- /dev/null +++ b/manual/docs/Getting started - Starting new project.php @@ -0,0 +1,10 @@ +Doctrine_Record is the basic component of every doctrine-based project. +There should be atleast one Doctrine_Record for each of your database tables. +Doctrine_Record follows Active Record pattern. +

    +Doctrine auto-creates database tables and always adds a primary key column named 'id' to tables. Only thing you need to for creating database tables +is defining a class which extends Doctrine_Record and setting a setTableDefinition method with hasColumn() method calls. +

    +Consider we want to create a database table called 'user' with columns id(primary key), name, username, password and created. You only need couple of lines of code +to create a simple CRUD (Create, Retrieve, Update, Delete) application for this database table. + diff --git a/manual/docs/Mapping object relations - Composites and aggregates.php b/manual/docs/Mapping object relations - Composites and aggregates.php new file mode 100644 index 000000000..a512fb3e3 --- /dev/null +++ b/manual/docs/Mapping object relations - Composites and aggregates.php @@ -0,0 +1,8 @@ +Doctrine supports aggregates and composites. When binding composites you can use methods Doctrine_Table::ownsOne() and Doctrine_Table::ownsMany(). When binding +aggregates you can use methods Doctrine_Table::hasOne() and Doctrine_Table::hasMany(). +

    +In Doctrine if you bind an Email to a User using ownsOne or ownsMany methods, everytime User record calls save or delete the associated +Email record is also saved/deleted. +

    +Then again if you bind an Email to a User using hasOne or hasMany methods, everytime User record calls save or delete the associated +Email record is NOT saved/deleted. diff --git a/manual/docs/Mapping object relations - Dealing with relations - Creating related records.php b/manual/docs/Mapping object relations - Dealing with relations - Creating related records.php new file mode 100644 index 000000000..6955476a6 --- /dev/null +++ b/manual/docs/Mapping object relations - Dealing with relations - Creating related records.php @@ -0,0 +1 @@ +When accessing related records and if those records do not exists Doctrine automatically creates new records. diff --git a/manual/docs/Mapping object relations - Dealing with relations - Deleting related records.php b/manual/docs/Mapping object relations - Dealing with relations - Deleting related records.php new file mode 100644 index 000000000..37f75d0c2 --- /dev/null +++ b/manual/docs/Mapping object relations - Dealing with relations - Deleting related records.php @@ -0,0 +1,2 @@ +You can delete related records individually be calling delete() on each record. If you want to delete a whole record graph just call +delete on the owner record. diff --git a/manual/docs/Mapping object relations - Dealing with relations - Retrieving related records.php b/manual/docs/Mapping object relations - Dealing with relations - Retrieving related records.php new file mode 100644 index 000000000..903277284 --- /dev/null +++ b/manual/docs/Mapping object relations - Dealing with relations - Retrieving related records.php @@ -0,0 +1,2 @@ +You can retrieve related records by the very same Doctrine_Record methods you've already propably used for accessing record properties. +When accessing related record you just simply use the class names. diff --git a/manual/docs/Mapping object relations - Dealing with relations - Updating related records.php b/manual/docs/Mapping object relations - Dealing with relations - Updating related records.php new file mode 100644 index 000000000..7712c53c4 --- /dev/null +++ b/manual/docs/Mapping object relations - Dealing with relations - Updating related records.php @@ -0,0 +1,2 @@ +You can update the related records by calling save for each related object / collection individually or by calling +save on the object that owns the other objects. You can also call Doctrine_Session::flush which saves all pending objects. diff --git a/manual/docs/Mapping object relations - Foreign key associations - One-to-One.php b/manual/docs/Mapping object relations - Foreign key associations - One-to-One.php new file mode 100644 index 000000000..b279556ff --- /dev/null +++ b/manual/docs/Mapping object relations - Foreign key associations - One-to-One.php @@ -0,0 +1,7 @@ +Binding One-To-One foreign key associations is done with Doctrine_Record::ownsOne() and Doctrine_Record::hasOne() methods. +In the following example user owns one email and has one address. So the relationship between user and email is one-to-one composite. +The relationship between user and address is one-to-one aggregate. +

    +The Email component here is mapped to User component's column email_id hence their relation is called LOCALKEY relation. +On the other hand the Address component is mapped to User by it's user_id column hence the relation between User and Address is called +FOREIGNKEY relation. diff --git a/manual/docs/Mapping object relations - Inheritance - Column aggregation.php b/manual/docs/Mapping object relations - Inheritance - Column aggregation.php new file mode 100644 index 000000000..8d399c14c --- /dev/null +++ b/manual/docs/Mapping object relations - Inheritance - Column aggregation.php @@ -0,0 +1,8 @@ +In the following example we have one database table called 'entity'. +Users and groups are both entities and they share the same database table. +

    +The entity table has a column called 'type' which tells whether an entity is a group or a user. +Then we decide that users are type 1 and groups type 2. + +The only thing we have to do is to create 3 records (the same as before) and add +call the Doctrine_Table::setInheritanceMap() method inside the setUp() method. diff --git a/manual/docs/Mapping object relations - Inheritance - One table many classes.php b/manual/docs/Mapping object relations - Inheritance - One table many classes.php new file mode 100644 index 000000000..689114886 --- /dev/null +++ b/manual/docs/Mapping object relations - Inheritance - One table many classes.php @@ -0,0 +1,7 @@ +When it comes to handling inheritance Doctrine is very smart. +In the following example we have one database table called 'entity'. +Users and groups are both entities and they share the same database table. +The only thing we have to make is 3 records (Entity, Group and User). +

    +Doctrine is smart enough to know that the inheritance type here is one-table-many-classes. + diff --git a/manual/docs/Mapping object relations - Inheritance - One table one class.php b/manual/docs/Mapping object relations - Inheritance - One table one class.php new file mode 100644 index 000000000..603eef0e8 --- /dev/null +++ b/manual/docs/Mapping object relations - Inheritance - One table one class.php @@ -0,0 +1,5 @@ +In the following example we have three database tables called 'entity', 'user' and 'group'. +Users and groups are both entities. +The only thing we have to do is write 3 classes (Entity, Group and User) and make iterative +setTableDefinition method calls. +

    diff --git a/manual/docs/Mapping object relations - Join table associations - Many-to-Many.php b/manual/docs/Mapping object relations - Join table associations - Many-to-Many.php new file mode 100644 index 000000000..62be7e80f --- /dev/null +++ b/manual/docs/Mapping object relations - Join table associations - Many-to-Many.php @@ -0,0 +1,5 @@ +If you are coming from relational database background it may be familiar to you +how many-to-many associations are handled: an additional association table is needed. +

    +In the following example we have Groups and Users of which relation is defined as +many-to-many. In this case we also need to define an additional class called Groupuser. diff --git a/manual/docs/Mapping object relations - Join table associations - Self-referencing.php b/manual/docs/Mapping object relations - Join table associations - Self-referencing.php new file mode 100644 index 000000000..7e41044c4 --- /dev/null +++ b/manual/docs/Mapping object relations - Join table associations - Self-referencing.php @@ -0,0 +1 @@ +Self-referencing with join tables is done as follows: diff --git a/manual/docs/Mapping object relations - One-to-Many and One-to-One relationships.php b/manual/docs/Mapping object relations - One-to-Many and One-to-One relationships.php new file mode 100644 index 000000000..d3f5a12fa --- /dev/null +++ b/manual/docs/Mapping object relations - One-to-Many and One-to-One relationships.php @@ -0,0 +1 @@ + diff --git a/manual/docs/Mapping object relations - Relation aliases.php b/manual/docs/Mapping object relations - Relation aliases.php new file mode 100644 index 000000000..6ba9c1515 --- /dev/null +++ b/manual/docs/Mapping object relations - Relation aliases.php @@ -0,0 +1 @@ +Doctrine supports relation aliases through 'as' keyword. diff --git a/manual/docs/Real world examples - User management system.php b/manual/docs/Real world examples - User management system.php new file mode 100644 index 000000000..3ba1e772f --- /dev/null +++ b/manual/docs/Real world examples - User management system.php @@ -0,0 +1,21 @@ +In the following example we make a user management system where +

    +1. Each user and group are entities +

    +2. User is an entity of type 0 +

    +3. Group is an entity of type 1 +

    +4. Each entity (user/group) has 0-1 email +

    +5. Each entity has 0-* phonenumbers +

    +6. If an entity is saved all its emails and phonenumbers are also saved +

    +7. If an entity is deleted all its emails and phonenumbers are also deleted +

    +8. When an entity is created and saved a current timestamp will be assigned to 'created' field +

    +9. When an entity is updated a current timestamp will be assigned to 'updated' field +

    +10. Entities will always be fetched in batches diff --git a/manual/docs/Runtime classes - Doctrine_Association.php b/manual/docs/Runtime classes - Doctrine_Association.php new file mode 100644 index 000000000..d29d1e7ff --- /dev/null +++ b/manual/docs/Runtime classes - Doctrine_Association.php @@ -0,0 +1 @@ +Doctrine_Association represents a many-to-many association between database tables. diff --git a/manual/docs/Runtime classes - Doctrine_Collection.php b/manual/docs/Runtime classes - Doctrine_Collection.php new file mode 100644 index 000000000..775cb0c86 --- /dev/null +++ b/manual/docs/Runtime classes - Doctrine_Collection.php @@ -0,0 +1 @@ +Doctrine_Collection is a collection of Data Access Objects. Doctrine_Collection represents a record set. diff --git a/manual/docs/Runtime classes - Doctrine_Collection_Batch.php b/manual/docs/Runtime classes - Doctrine_Collection_Batch.php new file mode 100644 index 000000000..77b2e4f41 --- /dev/null +++ b/manual/docs/Runtime classes - Doctrine_Collection_Batch.php @@ -0,0 +1 @@ +Doctrine_Collection_Batch is a Doctrine_Collection with batch fetching strategy. diff --git a/manual/docs/Runtime classes - Doctrine_Collection_Immediate.php b/manual/docs/Runtime classes - Doctrine_Collection_Immediate.php new file mode 100644 index 000000000..dde19e48b --- /dev/null +++ b/manual/docs/Runtime classes - Doctrine_Collection_Immediate.php @@ -0,0 +1 @@ +Doctrine_Collection_Immediate is a Doctrine_Collection with immediate fetching strategy. diff --git a/manual/docs/Runtime classes - Doctrine_Collection_Lazy.php b/manual/docs/Runtime classes - Doctrine_Collection_Lazy.php new file mode 100644 index 000000000..d36ad04dc --- /dev/null +++ b/manual/docs/Runtime classes - Doctrine_Collection_Lazy.php @@ -0,0 +1 @@ +Doctrine_Collection_Lazy is a Doctrine_Collection with lazy fetching strategy. diff --git a/manual/docs/Runtime classes - Doctrine_ForeignKey.php b/manual/docs/Runtime classes - Doctrine_ForeignKey.php new file mode 100644 index 000000000..a039df04d --- /dev/null +++ b/manual/docs/Runtime classes - Doctrine_ForeignKey.php @@ -0,0 +1 @@ +Doctrine_ForeignKey represents a one-to-many association or one-to-one association between two database tables. diff --git a/manual/docs/Runtime classes - Doctrine_Manager.php b/manual/docs/Runtime classes - Doctrine_Manager.php new file mode 100644 index 000000000..9af9f4b0b --- /dev/null +++ b/manual/docs/Runtime classes - Doctrine_Manager.php @@ -0,0 +1,2 @@ +Doctrine_Manager is the base component of Doctrine ORM framework. Doctrine_Manager is a colletion of Doctrine_Sessions. All the new sessions are being +opened by Doctrine_Manager::openSession(). diff --git a/manual/docs/Runtime classes - Doctrine_Record.php b/manual/docs/Runtime classes - Doctrine_Record.php new file mode 100644 index 000000000..488d59ab9 --- /dev/null +++ b/manual/docs/Runtime classes - Doctrine_Record.php @@ -0,0 +1,2 @@ +Doctrine_Record is a wrapper for database row. + diff --git a/manual/docs/Runtime classes - Doctrine_Session.php b/manual/docs/Runtime classes - Doctrine_Session.php new file mode 100644 index 000000000..2d80442da --- /dev/null +++ b/manual/docs/Runtime classes - Doctrine_Session.php @@ -0,0 +1,3 @@ +Doctrine_Session is a wrapper for database connection. It creates Doctrine_Tables and keeps track of all the created tables. +Doctrine_Session provides things that are missing from PDO like sequence support and limit/offset emulation. + diff --git a/manual/docs/Runtime classes - Doctrine_Table.php b/manual/docs/Runtime classes - Doctrine_Table.php new file mode 100644 index 000000000..748406d97 --- /dev/null +++ b/manual/docs/Runtime classes - Doctrine_Table.php @@ -0,0 +1,2 @@ +Doctrine_Table creates records and holds info of all foreign keys and associations. Doctrine_Table +represents a database table. diff --git a/manual/docs/Technology - Design patterns used.php b/manual/docs/Technology - Design patterns used.php new file mode 100644 index 000000000..243a57235 --- /dev/null +++ b/manual/docs/Technology - Design patterns used.php @@ -0,0 +1,46 @@ +GoF [Gang Of Four] design patterns used: +
    +
  • Singleton
    +
    For forcing only one instance of Doctrine_Manager + +
  • Composite
    +
    For leveled configuration + +
  • Factory
    +
    For session driver loading and many other things + +
  • Observer
    +
    For event listening + +
  • Flyweight
    +
    For efficient usage of validators + +
  • Iterator
    +
    For iterating through components [Tables, Sessions, Records etc.] + +
  • State
    +
    For state-wise sessions + +
  • Strategy
    +
    For algorithm strategies +

    +Enterprise application design patterns used: +
    +
  • Active Record
    +
    Doctrine is an implementation of this pattern +
  • UnitOfWork
    +
    For maintaining a list of objects affected in a transaction +
  • Identity Field
    +
    For maintaining the identity between record and database row +
  • Metadata Mapping
    +
    For Doctrine DataDict +
  • Dependent Mapping
    +
    For mapping in general, since all records extend Doctrine_Record which performs all mappings +
  • Foreign Key Mapping
    +
    For one-to-one, one-to-many and many-to-one relationships +
  • Association Table Mapping
    +
    For association table mapping (most commonly many-to-many relationships) +
  • Lazy Load
    +
    For lazy loading of objects and object properties +
  • Query Object
    +
    DQL API is actually an extension to the basic idea of Query Object pattern diff --git a/manual/docs/Technology - Speed.php b/manual/docs/Technology - Speed.php new file mode 100644 index 000000000..6fb95f2d2 --- /dev/null +++ b/manual/docs/Technology - Speed.php @@ -0,0 +1,35 @@ +
  • Lazy initialization
    +For collection elements +

    +
  • Subselect fetching
    +Doctrine knows how to fetch collections efficiently using a subselect. +

    +
  • Executing SQL statements later, when needed
    +The session never issues an INSERT or UPDATE until it is actually needed. So if an exception occurs and you need to abort the transaction, some statements will never actually be issued. Furthermore, this keeps lock times in the database as short as possible (from the late UPDATE to the transaction end). +

    +
  • Join fetching
    +Doctrine knows how to fetch complex object graphs using joins and subselects +

    +
  • Multiple collection fetching strategies
    +Doctrine has multiple collection fetching strategies for performance tuning. +

    +
  • Dynamic mixing of fetching strategies
    +Fetching strategies can be mixed and for example users can be fetched in a batch collection while +users' phonenumbers are loaded in offset collection using only one query. +

    +
  • Driver specific optimizations
    +Doctrine knows things like bulk-insert on mysql +

    +
  • Transactional single-shot delete
    +Doctrine knows how to gather all the primary keys of the pending objects in delete list and performs only one sql delete statement per table. +

    +
  • Updating only the modified columns.
    +Doctrine always knows which columns have been changed. +

    +
  • Never inserting/updating unmodified objects.
    +Doctrine knows if the the state of the record has changed. +

    +
  • PDO for database abstraction
    +PDO is by far the fastest availible database abstraction layer for php. +

    + diff --git a/manual/documentation.php b/manual/documentation.php new file mode 100644 index 000000000..284b1c573 --- /dev/null +++ b/manual/documentation.php @@ -0,0 +1,532 @@ +".$t."

    \n"; + $c = ""; + + if(file_exists("docs/$e.php")) { + rename("docs/$e.php","docs/$title - $t.php"); + } + if(file_exists("docs/$t.php")) { + rename("docs/$t.php","docs/$title - $t.php"); + } + if(file_exists("docs/$title - $t.php")) { + $c = file_get_contents("docs/$title - $t.php"); + if(substr($c,0,5) == "
    "; + } + $c = ""; + if(file_exists("codes/$e.php")) { + rename("codes/$e.php","codes/$title - $t.php"); + } + if(file_exists("codes/$t.php")) { + rename("codes/$t.php","codes/$title - $t.php"); + } + if(file_exists("codes/$title - $t.php")) { + print ""; + print ""; + print "
    "; + $c = file_get_contents("codes/$title - $t.php"); + $h->loadString($c); + print $h->toHtml(); + print "
    "; + } + print "
    "; +} + +function render_block($name) { + $h = new PHP_Highlight; + if(file_exists("docs/$name.php")) { + $c = file_get_contents("docs/$name.php"); + if(substr($c,0,5) == "
    "; + } + } + if(file_exists("codes/$name.php")) { + print ""; + print ""; + print "
    "; + $c = file_get_contents("codes/$name.php"); + $h->loadString($c); + print $h->toHtml(); + print "
    "; + } +} +function array2path($array, $path = '') { + $arrayValues = array(); + + $index = 1; + foreach ($array as $k => $value) { + $p = ($path !== '')?$path.".".$index:$index; + + if (is_scalar($value) || is_resource($value)) { + $arrayValues[$p] = $value; + } elseif (is_array($value)) { + $arrayValues[$p] = $k; + $arrayValues = $arrayValues + array2path($value, $p); + } + $index++; + } + + return $arrayValues; +} +$menu = array("Getting started" => + array( + "Requirements", + "Installation", + "Starting new project", + "Setting table definition" => array( + "Introduction", + "Data types and lengths", + "Constraints and validators", + ), + ), + "Basic Components" => + array( + "Manager" + => array("Introduction", + "Opening a new session", + "Managing sessions"), + "Record" + => array("Introduction", + "Creating new records", + "Retrieving existing records", + "Accessing properties", + "Updating records", + "Deleting records", + "Getting record state", + "Getting object copy", + "Serializing", + "Getting identifiers", + "Callbacks"), + "Session" + => array("Introduction", + "Availible drivers", + "Getting a table object", + "Flushing the session", + "Limiting queries", + "Querying the database", + "Getting session state"), + + "Collection" + => array("Introduction", + "Accessing elements", + "Adding new elements", + "Getting collection count", + "Saving the collection", + "Deleting collection", + "Fetching strategies", + "Collection expanding", + ), + + "Table" => array("Introduction", + "Getting table information", + "Finder methods", + "Custom table classes", + "Custom finders", + "Getting relation objects"), + + "Query" => array("Introduction", + "FROM - selecting tables", + "LIMIT and OFFSET - limiting the query results", + "WHERE - setting query conditions", + "ORDER BY - sorting query results", + "Fetching strategies", + "Lazy property fetching", + "Method overloading", + "Relation operators", + "Bound parameters", + "Aggregate functions", + "DQL - SQL conversion"), + "RawSql" => array( + "Introduction", + "Using SQL", + "Adding components", + "Method overloading"), + "Statement - UNDER CONSTRUCTION" => array("Introduction", + "Setting parameters", + "Getting parameters", + "Getting row count", + "Executing the statement"), + + "Exceptions" => array( + "Overview", + "List of exceptions" + ) + ), + "Mapping object relations" => + array( + "Introduction", + "Composites and aggregates", + "Relation aliases", + "Foreign key associations" => array( + "One-to-One", + "One-to-Many, Many-to-One", + "Tree structure"), + + "Join table associations" => array( + "One-to-One", + "One-to-Many, Many-to-One", + "Many-to-Many", + "Self-referencing"), + "Dealing with relations" => array( + "Creating related records", + "Retrieving related records", + "Updating related records", + "Deleting related records"), + "Inheritance" => + array("One table many classes", + "One table one class", + "Column aggregation" + ), + ), + "Configuration" => + array( + "Introduction", + "Levels of configuration", + "Setting attributes" => array( + "Table creation", + "Fetching strategy", + "Batch size", + "Session lockmode", + "Event listener", + "Validation", + "Offset collection limit" + ) + ), + + + + "Advanced components" => array( + "Eventlisteners" => + array( + "Introduction", + "Creating new listener", + "List of events", + "Listening events", + "Chaining", + ), + "Validators" => array( + "Intruduction", + "Validating transactions", + "Analyzing the ErrorStack", + "List of predefined validators" + ), + "View" => array( + "Intoduction", + "Managing views", + "Using views" + ), + /** + "Hook" => array( + "Introduction", + "Parameter hooking", + "Paging", + "Setting conditions", + "Sorting" + ), + */ + "Cache" => array( + "Introduction", + "Query cache"), + + "Locking Manager" => array( + "Introduction", + "Pessimistic locking", + "Examples"), + /** + "Debugger" => array( + "Introduction", + "Debugging actions"), + "Library" => array( + "Introduction", + "Using library functions"), + "Iterator" => array( + "Introduction", + "BatchIterator", + "ExpandableIterator", + "OffsetIterator") + */ + ), + "Transactions" => array( + "Introduction", + "Unit of work", + "Locking strategies" => + array("Pessimistic locking", + "Optimistic locking"), + "Nesting" + ), + /** + "Developer components" => array( + "DataDict" => array( + "Introduction", + "Usage" + ), + "IndexGenerator" => + array( + "Introduction", + "Usage"), + "Relation" => array( + "Introduction", + "Types of relations", + ), + "Null" => array( + "Introduction", + "Extremely fast null value checking" + ), + "Access" => array( + "Introduction", + "Usage" + ), + "Configurable" => array( + "Introduction", + "Usage" + ), + ), + */ + "Technology" => array( + "Architecture", + "Design patterns used", + "Speed", + "Internal optimizations" => + + array("DELETE", + "INSERT", + "UPDATE"), + ), + "Real world examples" => array("User management system","Forum application","Album lister") + ); + +?> + + + + +
    + + + + + + + + + + + + + + +
    + Doctrine - PHP Data Persistence and ORM Tool +
    +
    + $titles) { + print $i.". ".$title."
    \n"; + $i2 = 1; + foreach($titles as $k => $t) { + $e = "$i.".$i2.""; + if(is_array($t)) { + print "
    ".$e." ".$k."
    \n"; + + $i3 = 1; + foreach($t as $k2 => $v2) { + $str = ""; + if( ! file_exists("docs/$title - $k - $v2.php")) { + $missing[0]++; + $str .= " [ doc ] "; + } + if( ! file_exists("codes/$title - $k - $v2.php")) { + $missing[1]++; + $str .= " [ code ] "; + } + + $e = implode(".",array($i,$i2,$i3)); + print "
    ".$e." ".$v2."
    \n"; + $i3++; + } + } else { + $str = ""; + if( ! file_exists("docs/$title - $t.php")) { + $missing[0]++; + $str .= " [ doc ] "; + } + if( ! file_exists("codes/$title - $t.php")) { + $missing[1]++; + $str .= " [ code ] "; + } + print "
    ".$e." ".$t."
    \n"; + } + $i2++; + } + $i++; + } + } else { + $i = 1; + $ex = explode(".",$_REQUEST["index"]); + + + $paths = array2path($menu); + + if( ! isset($paths[$ex[0]])) + exit; + + $break = false; + $tmp = $paths; + foreach($tmp as $path => $title) { + $e = explode(".", $path); + if(count($e) > 2) { + unset($tmp[$path]); + } + } + $prev = 1; + foreach($tmp as $path => $title) { + if($break) + break; + + if($path == $_REQUEST["index"]) { + $break = true; + } else { + $prev = $path; + } + } + $index = $_REQUEST['index']; + print ""; + print ""; + print ""; + print ""; + print ""; + print ""; + print "
    ".$paths[$ex[0]]."
    PrevNext
     
    "; + + + $tmp = $ex; + if(count($tmp) > 2) { + //array_pop($tmp); + } + foreach($tmp as $k => $v) { + $numbers[] = $v; + $curr = implode(".",$numbers); + $stack[] = $paths[$curr]; + } + if(isset($ex[1])) { + $name = implode(" - ", $stack); + + print "".$paths[$curr]."
    "; + + $n = $numbers; + + $o = $paths[$n[0]]; + $s = implode(".", array($n[0], $n[1])); + $o2 = $paths[$s]; + + $value = $menu[$o]; + if( ! is_array($value)) + exit; + + + if(in_array($o2, $value)) { + render_block($name); + } else { + $value = $menu[$o][$o2]; + + if(is_array($value)) { + foreach($value as $k => $title) { + print "
    ".$title."
    "; + + $s = $name." - ".$title; + + render_block($s); + } + } + } + } else { + //if( ! isset($menu[$ex[0]])) + // exit; + $tmp = $paths[$ex[0]]; + $i = 1; + foreach($menu[$tmp] as $title => $value) { + $n = $ex[0].".".$i; + + if(is_scalar($value)) { + print "
    ".$n.". ".$value."
    \n"; + } else { + print "
    ".$n.". ".$title."
    \n"; + } + $i++; + } + } + } + ?> +
    + -- index
    \n"; + foreach($menu as $title => $titles) { + print "
    ".$i.". ".$title."
    \n"; + $i++; + } + ?> +
    +
    + $titles) { + if($i == $ex[0]) { + + print $i.". ".$title."

    \n"; + $i2 = 1; + foreach($titles as $k => $t) { + $e = "$i.".$i2; + + if(is_array($t)) { + $tmp = "$title - $k"; + + if( ! isset($ex[1]) || $i2 != $ex[1]) { + $i2++; + continue; + } + + print $e." ".$k."


    \n"; + foreach($t as $k2 => $t2) { + if( ! isset($ex[1]) || $i2 != $ex[1]) + break; + $e = "$i.".$i2.".".($k2+1); + render($tmp,$t2,$e); + } + } else { + if( ! isset($ex[1])) { + render($title,$t,$e); + } + } + $i2++; + } + } + $i++; + + } + */ + ?> +
    +
    diff --git a/manual/highlight.php b/manual/highlight.php new file mode 100644 index 000000000..d0e2c2af7 --- /dev/null +++ b/manual/highlight.php @@ -0,0 +1,560 @@ + Formatted HTML + * * toHtmlComment => Formatted HTML, specifically for comments on messageboards + * * toList => Ordered lists + * * toArray => Associative array + * + * Highlighting can be inline (with styles), or the same as + * highlight_file() where colors are taken from php.ini. + * + * @author Aidan Lister + * @author Based on an idea by Matthew Harris + * @version 1.3.0 + * @link http://aidanlister.com/repos/v/PHP_Highlight.php + */ +if (!defined('T_ML_COMMENT')) { + define('T_ML_COMMENT', T_COMMENT); +} else { + define('T_DOC_COMMENT', T_ML_COMMENT); +} +class PHP_Highlight +{ + /** + * Hold highlight colors + * + * Contains an associative array of token types and colours. + * By default, it contains the colours as specified by php.ini + * + * For example, to change the colour of strings, use something + * simular to $h->highlight['string'] = 'blue'; + * + * @var array + * @access public + */ + var $highlight; + + /** + * Things to be replaced for formatting or otherwise reasons + * + * The first element contains the match array, the second the replace + * array. + * + * @var array + * @access public + */ + var $replace = array( + 0 => array("\t", ' '), + 1 => array('    ', ' ')); + + /** + * Format of the link to the PHP manual page + * + * @var string + * @access public + */ + var $manual = '%s'; + + /** + * Format of the span tag to be wrapped around each token + * + * @var string + * @access public + */ + var $span; + + /** + * Hold the source + * + * @var string + * @access private + */ + var $_source = false; + + /** + * Hold plaintext keys + * + * An array of lines which are plaintext + * + * @var array + * @access private + */ + var $_plaintextkeys = array(); + + + /** + * Constructor + * + * Populates highlight array + * + * @param bool $inline If inline styles rather than colors are to be used + * @param bool $plaintext Do not format code outside PHP tags + */ + function PHP_Highlight($inline = false) + { + // Inline + if ($inline === false) { + // Default colours from php.ini + $this->highlight = array( + 'string' => ini_get('highlight.string'), + 'comment' => ini_get('highlight.comment'), + 'keyword' => ini_get('highlight.keyword'), + 'bg' => ini_get('highlight.bg'), + 'default' => ini_get('highlight.default'), + 'html' => ini_get('highlight.html') + ); + $this->span = '%s'; + } else { + // Basic styles + $this->highlight = array( + 'string' => 'string', + 'comment' => 'comment', + 'keyword' => 'keyword', + 'bg' => 'bg', + 'default' => 'default', + 'html' => 'html' + ); + $this->span = '%s'; + } + } + + + /** + * Load a file + * + * @access public + * @param string $file The file to load + * @return bool Returns TRUE + */ + function loadFile($file) + { + $this->_source = file_get_contents($file); + return true; + } + + + /** + * Load a string + * + * @access public + * @param string $string The string to load + * @return bool Returns TRUE + */ + function loadString($string) + { + $this->_source = $string; + return true; + } + + + /** + * Parse the loaded string into an array + * Source is returned with the element key corresponding to the line number + * + * @access public + * @param bool $funcref Reference functions to the PHP manual + * @param bool $blocks Whether to ignore processing plaintext + * @return array An array of highlighted source code + */ + function toArray($funcref = true, $blocks = false) + { + // Ensure source has been loaded + if ($this->_source == false) { + return false; + } + + // Init + $tokens = token_get_all($this->_source); + $manual = $this->manual; + $span = $this->span; + $i = 0; + $out = array(); + $out[$i] = ''; + + // Loop through each token + foreach ($tokens as $j => $token) { + // Single char + if (is_string($token)) { + // Skip token2color check for speed + $out[$i] .= sprintf($span, $this->highlight['keyword'], htmlspecialchars($token)); + + // Heredocs behave strangely + list($tb) = isset($tokens[$j - 1]) ? $tokens[$j - 1] : false; + if ($tb === T_END_HEREDOC) { + $out[++$i] = ''; + } + + continue; + } + + // Proper token + list ($token, $value) = $token; + + // Make the value safe + $value = htmlspecialchars($value); + $value = str_replace($this->replace[0], $this->replace[1], $value); + + // Process + if ($value === "\n") { + // End this line and start the next + $out[++$i] = ''; + } else { + // Function linking + if ($funcref === true && $token === T_STRING) { + // Look ahead 1, look ahead 2, and look behind 3 + if ((isset($tokens[$j + 1]) && $tokens[$j + 1] === '(' || + isset($tokens[$j + 2]) && $tokens[$j + 2] === '(') && + isset($tokens[$j - 3][0]) && $tokens[$j - 3][0] !== T_FUNCTION + && function_exists($value)) { + + // Insert the manual link + $value = sprintf($manual, $value, $value); + } + } + + // Explode token block + $lines = explode("\n", $value); + foreach ($lines as $jj => $line) { + $line = trim($line); + if ($line !== '') { + // This next line is helpful for debugging + //$out[$i] .= token_name($token); + + // Check for plaintext + if ($blocks === true && $token === T_INLINE_HTML) { + $this->_plaintextkeys[] = $i; + $out[$i] .= $line; + } else { + $out[$i] .= sprintf($span, $this->_token2color($token), $line); + } + } + + + // Start a new line + if (isset($lines[$jj + 1])) { + $out[++$i] = ''; + } + } + } + } + + return $out; + } + + + /** + * Convert the source to an ordered list. + * Each line is wrapped in
  • tags. + * + * @access public + * @param bool $return Return rather than print the results + * @param bool $funcref Reference functions to the PHP manual + * @param bool $blocks Whether to use code blocks around plaintext + * @return string A HTML ordered list + */ + function toList($return = false, $funcref = true, $blocks = true) + { + // Ensure source has been loaded + if ($this->_source == false) { + return false; + } + + // Format list + $source = $this->toArray($funcref, $blocks); + $out = "
      \n"; + foreach ($source as $i => $line) { + $out .= "
    1. "; + + // Some extra juggling for lines which are not code + if (empty($line)) { + $out .= ' '; + } elseif ($blocks === true && in_array($i, $this->_plaintextkeys)) { + $out .= $line; + } else { + $out .= "$line"; + } + + $out .= "
    2. \n"; + } + $out .= "
    \n"; + + if ($return === true) { + return $out; + } else { + echo $out; + } + } + + + /** + * Convert the source to formatted HTML. + * Each line ends with
    . + * + * @access public + * @param bool $return Return rather than print the results + * @param bool $linenum Display line numbers + * @param string $format Specify format of line numbers displayed + * @param bool $funcref Reference functions to the PHP manual + * @return string A HTML block of code + */ + function toHtml($return = false, $linenum = false, $format = null, $funcref = true) + { + // Ensure source has been loaded + if ($this->_source == false) { + return false; + } + + // Line numbering + if ($linenum === true && $format === null) { + $format = '%02d '; + } + + // Format code + $source = $this->toArray($funcref); + $out = "\n"; + foreach ($source as $i => $line) { + $out .= ' '; + + if ($linenum === true) { + $out .= sprintf($format, $i); + } + + $out .= empty($line) ? ' ' : $line; + $out .= "
    \n"; + } + $out .= "
    \n"; + + if ($return === true) { + return $out; + } else { + echo $out; + } + } + + + /** + * Convert the source to formatted HTML blocks. + * Each line ends with
    . + * + * This method ensures only PHP is between blocks. + * + * @access public + * @param bool $return Return rather than print the results + * @param bool $linenum Display line numbers + * @param string $format Specify format of line numbers displayed + * @param bool $reset Reset the line numbering each block + * @param bool $funcref Reference functions to the PHP manual + * @return string A HTML block of code + */ + function toHtmlBlocks($return = false, $linenum = false, $format = null, $reset = true, $funcref = true) + { + // Ensure source has been loaded + if ($this->_source == false) { + return false; + } + + // Default line numbering + if ($linenum === true && $format === null) { + $format = '%03d '; + } + + // Init + $source = $this->toArray($funcref, true); + $out = ''; + $wasplain = true; + $k = 0; + + // Loop through each line and decide which block to use + foreach ($source as $i => $line) { + // Empty line + if (empty($line)) { + if ($wasplain === true) { + $out .= ' '; + } else { + if (in_array($i+1, $this->_plaintextkeys)) { + $out .= "\n"; + + // Reset line numbers + if ($reset === true) { + $k = 0; + } + } else { + $out .= ' '; + // Add line number + if ($linenum === true) { + $out .= sprintf($format, ++$k); + } + } + } + + // Plain text + } elseif (in_array($i, $this->_plaintextkeys)) { + if ($wasplain === false) { + $out .= "\n"; + + // Reset line numbers + if ($reset === true) { + $k = 0; + } + } + + $wasplain = true; + $out .= str_replace(' ', ' ', $line); + + // Code + } else { + if ($wasplain === true) { + $out .= "\n"; + } + $wasplain = false; + + $out .= ' '; + // Add line number + if ($linenum === true) { + $out .= sprintf($format, ++$k); + } + $out .= $line; + } + + $out .= "
    \n"; + } + + // Add final code tag + if ($wasplain === false) { + $out .= "
    \n"; + } + + // Output method + if ($return === true) { + return $out; + } else { + echo $out; + } + } + + + /** + * Assign a color based on the name of a token + * + * @access private + * @param int $token The token + * @return string The color of the token + */ + function _token2color($token) + { + + switch ($token): + case T_CONSTANT_ENCAPSED_STRING: + return $this->highlight['string']; + break; + + case T_INLINE_HTML: + return $this->highlight['html']; + break; + + case T_COMMENT: + case T_DOC_COMMENT: + case T_ML_COMMENT: + return $this->highlight['comment']; + break; + + case T_ABSTRACT: + case T_ARRAY: + case T_ARRAY_CAST: + case T_AS: + case T_BOOLEAN_AND: + case T_BOOLEAN_OR: + case T_BOOL_CAST: + case T_BREAK: + case T_CASE: + case T_CATCH: + case T_CLASS: + case T_CLONE: + case T_CONCAT_EQUAL: + case T_CONTINUE: + case T_DEFAULT: + case T_DOUBLE_ARROW: + case T_DOUBLE_CAST: + case T_ECHO: + case T_ELSE: + case T_ELSEIF: + case T_EMPTY: + case T_ENDDECLARE: + case T_ENDFOR: + case T_ENDFOREACH: + case T_ENDIF: + case T_ENDSWITCH: + case T_ENDWHILE: + case T_END_HEREDOC: + case T_EXIT: + case T_EXTENDS: + case T_FINAL: + case T_FOREACH: + case T_FUNCTION: + case T_GLOBAL: + case T_IF: + case T_INC: + case T_INCLUDE: + case T_INCLUDE_ONCE: + case T_INSTANCEOF: + case T_INT_CAST: + case T_ISSET: + case T_IS_EQUAL: + case T_IS_IDENTICAL: + case T_IS_NOT_IDENTICAL: + case T_IS_SMALLER_OR_EQUAL: + case T_NEW: + case T_OBJECT_CAST: + case T_OBJECT_OPERATOR: + case T_PAAMAYIM_NEKUDOTAYIM: + case T_PRIVATE: + case T_PROTECTED: + case T_PUBLIC: + case T_REQUIRE: + case T_REQUIRE_ONCE: + case T_RETURN: + case T_SL: + case T_SL_EQUAL: + case T_SR: + case T_SR_EQUAL: + case T_START_HEREDOC: + case T_STATIC: + case T_STRING_CAST: + case T_THROW: + case T_TRY: + case T_UNSET_CAST: + case T_VAR: + case T_WHILE: + return $this->highlight['keyword']; + break; + + case T_CLOSE_TAG: + case T_OPEN_TAG: + case T_OPEN_TAG_WITH_ECHO: + default: + return $this->highlight['default']; + + endswitch; + } + +} + +?> diff --git a/manual/images/docflash.jpg b/manual/images/docflash.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0e0d6a71bf69014f17a8788a2ee47e2a3f8009f3 GIT binary patch literal 56287 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 literal 0 HcmV?d00001 diff --git a/manual/images/docflashbg.jpg b/manual/images/docflashbg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3821958dbb497382d7b9055f56ee7c155eb08876 GIT binary patch literal 8912 zcmeHMd2mz58Q-T{vau~6T$zc5F^JIGvLxTdc8qU|IE*obbjs*>l7(eGTYADrClL^i zKs)Jhg+SX0XGqdE6hcBE!%zs}2s2G=z~)FG2Eq~In#+ce*xPTPo@9&A2DOtvI-}L> z@g4i^Z@;(4)BErl{3VK+R9aDrC;^2E;fHXiu(zbiZbisoK;scYG9;y9kq}xG{17z~ ziMcjHChDm`dmc58*8xpRiv*w(57|ZO0_~;C>`27-{Ug-JAdlc_t}e7NCR#PEhG7|Z z4O6emN=-w$w6u&|tu9xmRY94SnVX@7E=ahM@{NZvLK_7EyVOQupnZZULXuEI9-Cw^ zero6de(LD}en1Ys;Biu81p(Uvf|sOn$lwWIje~tyPPn)WMRIeQTVy~2{7)3cQOL4@ z^u*`UViYNp$>g#~xja%Cp@>i>L`OzOCk&5^ONfgbu8iaoU-^hfOKM0&#E_^VF;P)5 z@ljDx@uY}~_jOS|i2?j~q?Dlrh!RpsNT8&IN(z4g)28rYssK=mDJ}tEl7z58L}H0l zCRaqjG6)t@NFekJV-O{xgaVO3ES1Q_!bm*`l|s>|Sgp8lx-l-PVWCbEzjD*giKCMf zDi50U>8?esMba^=X58w$ZFXl2-Ms6ivBj&aEG37wu$jZ!W?rK2yu0|Llb*|WOVw+( zF4?{I@Tn{Jw!Qc9>92aKt@D?@`o{Z5+OPIzmCdp>E?c*K&(V%+_mxN>0JI_wlT;$k z;2@0B#)<$zLsFbrw{T@VL2$6L^_D)_)ahEZs%S=n*`0oSjD!G?j?FmK1|YT!vy{xt zWa&!*2>%{|dH@1Gha!dCm`YTDda71cj48mM@pWrY)w(QH{A}@p zzpF%osYQv_B3bpE=S9`5(>)KOTp2w>xhopheyHfLLv}w zJ$pEva-^|ZLE?ZC_B$ks=WJTPA;8gb{5eqibuu_k$^eJ6`2c8y>S0emHVLm2@nc2! zf02=~MKWR=k-5UW1<(32@5QHq>+_n=KO+e#tboEdA3`ETPC#-}DbP&hL@csHb|4yA zPzoZ)D3Lvy2J=YUe~Je51}pfPJV-)1Jq`y{8XQ0ktH*T^{E^W=pjZA%aqYh+GS*E3ouYsb3M%~D}2g? zLnIY-HWgGq_56h%m!qm=b`=c8JC`^=m}79;=pc^7=wPdiwjf@VnTCFJ6If@n;ZupYbhR?z|C25>jvl3gRr17eI!EP1ZiVEewatH2iiDeml6@`+xs-!0m=n zu&fc>B;1ZbC>kz&3u2H7E)*4-hH9YALUwa4xH3`Pk7%e+7D`2F#GvmM^W9xi_|L(O zfjeW%Ygo2ESEF&dQ;p=`L8_Ul(=-|DHQLlP4VqBURBtrb(yYov!^xee?*8zAT4lH7 zsb^&v(hT)Qbd9~d#YN9(nNnqLsWs$5V{3YCA}#(IO{@gw@5KwX^%MpdaM0K;I& zEoRJ~I@-xr6zBUqW?{@QY`y;zsacxVL9 zPoKhrgyiF}yTa}Y$paxNhgVnFT_JfOB<1kx3cD*L4}_!~UR_~#h2(*dl*6kl?5>bJ z5R!6ub%os(k_SRk{%=*B|6m zJZEoSzW%Mf$IssQc6{!nIrCapYkhvDZ2OMhhWuZ7FI0a2JB(VtIQx3v>fh8JUj5+HuAA4@eYJZd`q!Vq=)zTu z{`w~`Ztd9Df9B}+xfKcd`@OjBY;^y^8~w8q?|#+D^uIEt1EX&aT-bf|dvz~HJKLvV zbZ}WWMtzyfF|t%A_MYg#PmGJl*P4mZt=kv#z1OaH9q1dH=f$W!x_Nc~?g_uesMP!L z&k(tOe&4~@d%EsR`+r~1GwFQ)ZVzrt{q;lr_G=xQ7JTw^Z~s%vzU=6`T=u;8T2v86 s@8lmjaC7-T3hp&w^!7Aw`#TG~H*Log?^%HCNbK3O1OKSgcyMR`1=yjz*#H0l literal 0 HcmV?d00001 diff --git a/manual/images/docnew.gif b/manual/images/docnew.gif new file mode 100644 index 0000000000000000000000000000000000000000..60a9c7080ad47b8ff0227f46ee09866262090af0 GIT binary patch literal 2864 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 Kv~LCKnEwK~Qyhu_ literal 0 HcmV?d00001 diff --git a/manual/images/gradient3.jpg b/manual/images/gradient3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cc86606f152214b4f3246da308badad72b281907 GIT binary patch literal 8285 zcmeHMX>c1?9e=wktq#kwQjaB9%_@O1Dcc@(V)`+SBCNw#*aK2M>@^+DY!om*IgP-?gJ4q zByc-oqAW@=G0k;5JCLWN!{>K*_&r|E?eY71{O)crLCkSVolj8^I!+h-QpcIX7{`el zOEFq(Y;pY5nw9ve^@aE$a==21lWM06zUeKhJB$)WLcJ@iVR#c+$XdQQ6hO4{cVs0L ziadlZl~>RqWHB0zCZokH3Rkp?&i>0QqslL9kzP`z3Ax*of#GO4=T~$?Wt**6N zYa6UqYXk1A4XTOle{rDv64{LK_$Y>IL9~rxY?Sh6ST?0RNA*LLdWtj%7&itIM5kvB zMw7V;(x6mGA)3hxYZ0ZR7+Oc`4XjbmSiB&#F}e+PZvDVczP@Geeh=Gl_{6h=8(SME z&WF66nFE)G3~fgyZ!Ii_CEuEpXAZUx9}PxEE}W9P)?S{vCM=yjbn!~|`tqp#*y)GQ zJ^tK_ufF-MAN=YMe|>A$%!7}7{o6nM^&fA%-Mw{pbnek_eCJ2M`P1Ltu_2mF_YZK0-9L9MRdlHYi0%{3FzTl2944-k zy+OsN8I#O7bn1FAi3)q78BL)Sl2IJ41QJjLIglIVc<;Eg74z^ozjqb%iWTxqEl5nJ zvWW!T@V3i_#B3@eZ4d1U1Etwbgk?N6P5=~ytu-O0qIitkHep6CrUzv)snH~iiD)b@ z$KF^e5f2N}uEaJ8D5_*0J&^&s4lV;B#)pf18=@I8n=WCoVkRDqr-W2C2{x9IN$h<) z;Q?LEXJv7#kP3~URDVgfrf=Gi66rkI$SA4tTbd8BI8#gFCLU}=a5 zGki87!_f4gkdaqW-<4;Vs#k@gLt;YA6oG3~{SR&}2*3p0FQzcoCRt2x&&raJPYf(G zCm@kNz_o-#84~IP{3>|Fu{+htH_(QiAxhhW@UI9paVa9TV3Njr2nGvZI7xA0gC?BO zO>l%&&g9COeBtvaBsxkzs0<{pSW^>8^=sM zAqyFa6Qpoo%g{s%7U%pRNeVL0<&ue%4I4a9`R`c2TWw<$W+6yoJ>3|$Hf%K!_g=A*|XVr z#P1U#-928xE!tc-)%Q@`E~Q@Kw$M5^G_g|biu3~ zw;33LfPYvFXOluo9v|MKA{G(DFl{>j?n$2k(4}>W%l}*G;6}NEaFdBSr^3)W>wV z=~+E#ENd_r4F=X^GMk|;S=uOuVe~q^iDgaIW|O(P2G<*FplS(CyIEAK)UH4k)f=He zS6Xj831J$F%Z*5}2bCC^$BF z4xcbIs`b7F@0!r9*35y$wxQ0+BPY*&v+2C}bagT&+8PNZGMxY&w>E?3>^H@$)ae_U_%i)wLZz{0ZvwDWSAtW72*=ZYoCswWy{(-?2i6>!Y&#h~bHN~8_FWr3xHfncsDLmn-vl@^yuOJe?rkV{LNx8HkVS$uCXs-TUh74*!$8+U!-MFn+z`t`5< S`?Ig?4$b}k)&9>bSN{VXl_XIB literal 0 HcmV?d00001 diff --git a/manual/images/logo.jpg b/manual/images/logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8f3660ece8c13faf6cf231f85858c682928c4d9e GIT binary patch literal 12414 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 JR>54<{{mWihynlr literal 0 HcmV?d00001 diff --git a/manual/images/tausta2.jpg b/manual/images/tausta2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b79d65692c303589473cf324ef55b68bf05eae02 GIT binary patch literal 8148 zcmeHMTW}Lq82&e#d(*V(1rQxr3N-4NdoMK8Qt6GxA+)vyI=(oYWRr#_*|58zp)Ud= zJcGB9@qvq%XYVumpdemeK?N`4jK%AWgMx_qBJn?GH)#U(5*?n*$(*z2zn=g9_TO{b z-NMI(FQDq@?L9hyHxi6BAH0;aGOhL^xbb9rzu47$P(V5bzs_EL+_-~ianX0yd?vsi47 zI%}PywZUd~?z#8SE{piQ}I*D7*y@ zGp1o=nKsZl7}miQKF73~!WpI?^D;2BVZfxZSRi_X(PXw*>#z(eg$(G}qOcJdJ;Uns zI)lk*Hn6q;3LUI|O_R^C>3+VsZPz}(vE}gb7Y5d@Yn?b133N#N&kmZ_ADO(oa3v~t zE<5q!!|g+lPQ`{#pH#Y*pWAj(`01qsZ-0>c^6H55v1cB6`SCL!e)aRSue|fo*Vnek zcOQJ>xmVvk|IIJmn|CDU4n6t&Ywun7_E!h!bQrCk#$+-YI%x=Nd`)_cU{_nS!N2ct z3yI*=#M#S%b&&;W|B=DT)~MWZWxbIEU~2C?eGY>-xjZ(!txFLumO}XR2%L){6g~wT zOV@NjKb-%5_4Vo3S6^>@==ZUSQ2s>duEHmUOQ!3KRUW`9-!Kpg>(^7L8|hd!5E*+( zlaZR!;ZM6#yLKwGFPil41=V9c<&j#>Q_b5-^eXE0Dy1!S#DP(*tdzzICpu0w9xJVQ zBG6IGYgA_xJn=Y6QaIwXg^kfT$DcY{;`k~50UV1uos{ERxCRFJo)w#Y~^73&zN4B1WCO_T@?mH9R$ zBr%t*U>QXznMh`YOfHQ!w&6+QeT?#uuIF=#xLL>u60Zm`WWdy(te`1dRb|2z^~+l<%CedG4d&8iceJV>`?*jguD`xN2kJDBBGcg4$Vb& zg|cNvl;$_3l8GWx4QleEMK)TRVnUqHr4*c6b_92hSyNa@H*swdQNe<`iC>4ec;-fR`UEV%7t!R@nlL7B$*TBXkXjlL>m$3gD6Q03eV-!sf--V_c^IS5a)#LadK2e zneB5v7#h(WBGu>A5}TWw zbI%3bqLlFXdU|?1UcblhccF$$-jh-IyelKG#r0?)$?1|=1s=(13I{G^<>*pFn2wap zDoHWJ@p#}Vea>7i84GrJc|RWybh>=L&K?|MJ+4TE?{W#<(Qdz&kHn+?h||gy^X9YR z@X{+5??5{3!Bsh~7a8Gja7c{i(n3ZF4Q*5ri-}QOHe38pr5HfquL9^L_qWm+rsW|J zmgR-Hsyu`h0rr$`8VTptx7s3AVO)c&23J)GRHa<2t{PlbAyAcat-5M(RfRxR%C+jM z!BrIkRVml1s|Ht92vnt9tF9VcRUuH7^1rPve7{qCD + + + + + + +
    + +
    + + + + + +
    + main | documentation | download | FAQ | about | forums + +
    +