Vendor lock
This commit is contained in:
16
vendor/j4mie/paris/CONTRIBUTING.md
vendored
Normal file
16
vendor/j4mie/paris/CONTRIBUTING.md
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
### Feature complete
|
||||
|
||||
Paris is now considered to be feature complete as of version 1.5.0. Whilst it will continue to be maintained with bug fixes there will be no further new features added.
|
||||
|
||||
**Please do not submit feature requests or pull requests adding new features as they will be closed without ceremony.**
|
||||
|
||||
---
|
||||
|
||||
When making a pull request please include the following aspects:
|
||||
|
||||
- Update the changelog in the README.markdown file to include details of the pull request
|
||||
- If the documentation in the README or Sphinx docs needs to be amended please do so in the pull request
|
||||
- Include unit tests for any changes - if it is a bug include at least one regression test
|
||||
|
||||
|
169
vendor/j4mie/paris/README.markdown
vendored
Normal file
169
vendor/j4mie/paris/README.markdown
vendored
Normal file
@ -0,0 +1,169 @@
|
||||
Paris
|
||||
=====
|
||||
|
||||
[](https://travis-ci.org/j4mie/paris) [](https://packagist.org/packages/j4mie/paris) [](https://packagist.org/packages/j4mie/paris)
|
||||
|
||||
[http://j4mie.github.com/idiormandparis/](http://j4mie.github.com/idiormandparis/)
|
||||
|
||||
---
|
||||
### Feature complete
|
||||
|
||||
Paris is now considered to be feature complete as of version 1.5.0. Whilst it will continue to be maintained with bug fixes there will be no further new features added from this point on.
|
||||
|
||||
**Please do not submit feature requests or pull requests adding new features as they will be closed without ceremony.**
|
||||
|
||||
---
|
||||
|
||||
A lightweight Active Record implementation for PHP5.
|
||||
|
||||
Built on top of [Idiorm](http://github.com/j4mie/idiorm/).
|
||||
|
||||
Tested on PHP 5.2.0+ - may work on earlier versions with PDO and the correct database drivers.
|
||||
|
||||
Released under a [BSD license](http://en.wikipedia.org/wiki/BSD_licenses).
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Extremely simple configuration.
|
||||
* Exposes the full power of [Idiorm](http://github.com/j4mie/idiorm/)'s fluent query API.
|
||||
* Supports associations.
|
||||
* Simple mechanism to encapsulate common queries in filter methods.
|
||||
* Built on top of [PDO](http://php.net/pdo).
|
||||
* Uses [prepared statements](http://uk.php.net/manual/en/pdo.prepared-statements.php) throughout to protect against [SQL injection](http://en.wikipedia.org/wiki/SQL_injection) attacks.
|
||||
* Database agnostic. Currently supports SQLite, MySQL, Firebird and PostgreSQL. May support others, please give it a try!
|
||||
* Supports collections of models with method chaining to filter or apply actions to multiple results at once.
|
||||
* Multiple connections are supported
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
The documentation is hosted on Read the Docs: [paris.rtfd.org](http://paris.rtfd.org)
|
||||
|
||||
### Building the Docs ###
|
||||
|
||||
You will need to install [Sphinx](http://sphinx-doc.org/) and then in the docs folder run:
|
||||
|
||||
make html
|
||||
|
||||
The documentation will now be in docs/_build/html/index.html
|
||||
|
||||
Let's See Some Code
|
||||
-------------------
|
||||
```php
|
||||
class User extends Model {
|
||||
public function tweets() {
|
||||
return $this->has_many('Tweet');
|
||||
}
|
||||
}
|
||||
|
||||
class Tweet extends Model {}
|
||||
|
||||
$user = Model::factory('User')
|
||||
->where_equal('username', 'j4mie')
|
||||
->find_one();
|
||||
$user->first_name = 'Jamie';
|
||||
$user->save();
|
||||
|
||||
$tweets = $user->tweets()->find_many();
|
||||
foreach ($tweets as $tweet) {
|
||||
echo $tweet->text;
|
||||
}
|
||||
```
|
||||
|
||||
Changelog
|
||||
---------
|
||||
|
||||
#### 1.5.6 - released 2017-03-21
|
||||
|
||||
* Allow IDE's to autocomplete when `foreach` over `find_many()` result [[stratoss](https://github.com/stratoss)] - [issue #128](https://github.com/j4mie/paris/pull/128)
|
||||
* Document the @property PHPDoc comment for IDE autocomplete of model properties [[Treffynnon](https://github.com/Treffynnon)]
|
||||
|
||||
#### 1.5.5 - released 2016-12-14
|
||||
|
||||
* Fix join table name not generated correctly [[Ralphunter](https://github.com/Ralphunter)] - [issue #109](https://github.com/j4mie/paris/pull/109)
|
||||
* Add phpunit as dev dependency and composer script (`composer test`) to easily run tests [[Treffynnon](https://github.com/Treffynnon)]
|
||||
* Global setting to allow static requests to avoid being forced in to using the namespace + class as the auto table name [[michaelward82](https://github.com/michaelward82)] - [issue #100](https://github.com/j4mie/paris/issues/100)
|
||||
* Document conflict between static Model calling and auto_prefix_models [[michaelward82](https://github.com/michaelward82)] - [issue #102](https://github.com/j4mie/paris/issues/102)
|
||||
* Added @method tags for magic methods [[stellis](https://github.com/stellis)] - [issue #104](https://github.com/j4mie/paris/issues/104)
|
||||
* Add missing `__unset()` magic method [[qyanu](https://github.com/qyanu)] - [issue #106](https://github.com/j4mie/paris/issues/106)
|
||||
* Remove PHP 5.2 from travis-ci containers to test against (**note** Idiorm still supports PHP 5.2 despite this) [[Treffynnon](https://github.com/treffynnon)]
|
||||
|
||||
#### 1.5.4 - released 2014-09-23
|
||||
|
||||
* Corrects return value in docblock for 2 Model functions [[michaelward82](https://github.com/michaelward82)] - [issue #99](https://github.com/j4mie/paris/pull/99)
|
||||
|
||||
#### 1.5.3 - released 2014-06-25
|
||||
|
||||
* Remove erroneously committed git merge backup file
|
||||
|
||||
#### 1.5.2 - released 2014-06-23
|
||||
|
||||
* Paris incorrectly relying on old Idiorm version in the composer.json [[ilsenem](https://github.com/ilsenem)] - [issue #96](https://github.com/j4mie/paris/pull/96)
|
||||
|
||||
#### 1.5.1 - released 2014-06-22
|
||||
|
||||
* Remove HHVM build target from travis-ci as there is a bug in HHVM
|
||||
|
||||
#### 1.5.0 - released 2014-06-22
|
||||
|
||||
* Allows static calling of Model subclasses, ignoring namespace info during table name generation [[michaelward82](https://github.com/michaelward82)] - [issue #90](https://github.com/j4mie/paris/issues/90)
|
||||
* Prevent invalid method calls from triggering infinite recursion [[michaelward82](https://github.com/michaelward82)] - [issue #75](https://github.com/j4mie/idiorm/issues/75)
|
||||
* Allow chaining of the `set()` and `set_expr()` methods [[naga3](https://github.com/naga3)] - [issue #94](https://github.com/j4mie/paris/issues/94)
|
||||
* Add HHVM to travis-ci build matrix [[ptarjan](https://github.com/ptarjan)] - [issue #81](https://github.com/j4mie/idiorm/issues/81)
|
||||
* Improve join documentation [[rhynodesigns](https://github.com/rhynodesigns)] - [issue #92](https://github.com/j4mie/paris/issues/92)
|
||||
* Improve code docblock [[michaelward82](https://github.com/michaelward82)] - [issue #91](https://github.com/j4mie/paris/issues/91)
|
||||
* Improve code docblocks and whitespace [[michaelward82](https://github.com/michaelward82)] - [issue #93](https://github.com/j4mie/paris/issues/93)
|
||||
* Improve connections documentation [[kkeiper1103](https://github.com/kkeiper1103)] - [issue #79](https://github.com/j4mie/paris/issues/79)
|
||||
|
||||
#### 1.4.2 - released 2013-12-12
|
||||
|
||||
**Patch update to remove a broken pull request** - may have consequences for users of 1.4.0 and 1.4.1 that exploited the "`find_many()` now returns an associative array with the databases primary ID as the array keys" change that was merged in 1.4.0.
|
||||
|
||||
* Back out pull request/issue [#133](https://github.com/j4mie/idiorm/pull/133) as it breaks backwards compatibility in previously unexpected ways (see Idiorm issues [#162](https://github.com/j4mie/idiorm/pull/162), [#156](https://github.com/j4mie/idiorm/issues/156) and [#133](https://github.com/j4mie/idiorm/pull/133#issuecomment-29063108)) - sorry for merging this change into Paris - closes Idiorm [issue 156](https://github.com/j4mie/idiorm/issues/156)
|
||||
|
||||
#### 1.4.1 - released 2013-09-05
|
||||
|
||||
* Increment composer.json requirement for Idiorm to 1.4.0 [[michaelward82](https://github.com/michaelward82)] - [Issue #72](https://github.com/j4mie/paris/pull/72)
|
||||
|
||||
#### 1.4.0 - released 2013-09-05
|
||||
|
||||
* Call methods against model class directly eg. `User::find_many()` - PHP 5.3 only [[Lapayo](https://github.com/Lapayo)] - [issue #62](https://github.com/j4mie/idiorm/issues/62)
|
||||
* `find_many()` now returns an associative array with the databases primary ID as the array keys [[Surt](https://github.com/Surt)] - see commit [9ac0ae7](https://github.com/j4mie/paris/commit/9ac0ae7d302f1980c95b97a98cbd6d5b2c04923f) and Idiorm [issue #133](https://github.com/j4mie/idiorm/issues/133)
|
||||
* Add PSR-1 compliant camelCase method calls to Idiorm (PHP 5.3+ required) [[crhayes](https://github.com/crhayes)] - [issue #59](https://github.com/j4mie/idiorm/issues/59)
|
||||
* Allow specification of connection on relation methods [[alexandrusavin](https://github.com/alexandrusavin)] - [issue #55](https://github.com/j4mie/idiorm/issues/55)
|
||||
* Make tests/bootstrap.php HHVM compatible [[JoelMarcey](https://github.com/JoelMarcey)] - [issue #71](https://github.com/j4mie/idiorm/issues/71)
|
||||
* belongs_to doesn't work with $auto_prefix_models ([issue #70](https://github.com/j4mie/paris/issues/70))
|
||||
|
||||
#### 1.3.0 - released 2013-01-31
|
||||
|
||||
* Documentation moved to [paris.rtfd.org](http://paris.rtfd.org) and now built using [Sphinx](http://sphinx-doc.org/)
|
||||
* Add support for multiple database connections [[tag](https://github.com/tag)] - [issue #15](https://github.com/j4mie/idiorm/issues/15)
|
||||
* Allow a prefix for model class names - see Configuration in the documentation - closes [issues #33](https://github.com/j4mie/paris/issues/33)
|
||||
* Exclude tests and git files from git exports (used by composer)
|
||||
* Implement `set_expr` - closes [issue #39](https://github.com/j4mie/paris/issues/39)
|
||||
* Add `is_new` - closes [issue #40](https://github.com/j4mie/paris/issues/40)
|
||||
* Add support for the new IdiormResultSet object in Idiorm - closes [issue #14](https://github.com/j4mie/paris/issues/14)
|
||||
* Change Composer to use a classmap so that autoloading is better supported [[javierd](https://github.com/javiervd)] - [issue #44](https://github.com/j4mie/paris/issues/44)
|
||||
* Move tests into PHPUnit to match Idiorm
|
||||
* Update included Idiorm version for tests
|
||||
* Move documentation to use Sphinx
|
||||
|
||||
#### 1.2.0 - released 2012-11-14
|
||||
|
||||
* Setup composer for installation via packagist (j4mie/paris)
|
||||
* Add in basic namespace support, see [issue #20](https://github.com/j4mie/paris/issues/20)
|
||||
* Allow properties to be set as an associative array in `set()`, see [issue #13](https://github.com/j4mie/paris/issues/13)
|
||||
* Patch in idiorm now allows empty models to be saved (j4mie/idiorm see [issue #58](https://github.com/j4mie/paris/issues/58))
|
||||
|
||||
#### 1.1.1 - released 2011-01-30
|
||||
|
||||
* Fix incorrect tests, see [issue #12](https://github.com/j4mie/paris/issues/12)
|
||||
|
||||
#### 1.1.0 - released 2011-01-24
|
||||
|
||||
* Add `is_dirty` method
|
||||
|
||||
#### 1.0.0 - released 2010-12-01
|
||||
|
||||
* Initial release
|
49
vendor/j4mie/paris/composer.json
vendored
Normal file
49
vendor/j4mie/paris/composer.json
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "j4mie/paris",
|
||||
"type": "library",
|
||||
"description": "A lightweight Active Record implementation for PHP5, built on top of Idiorm",
|
||||
"keywords": ["paris", "orm", "active record", "model"],
|
||||
"homepage": "http://j4mie.github.com/idiormandparis",
|
||||
"support": {
|
||||
"issues": "https://github.com/j4mie/paris/issues",
|
||||
"source": "https://github.com/j4mie/paris"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jamie Matthews",
|
||||
"email": "jamie.matthews@gmail.com",
|
||||
"homepage": "http://j4mie.org",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Simon Holywell",
|
||||
"email": "treffynnon@php.net",
|
||||
"homepage": "http://simonholywell.com",
|
||||
"role": "Maintainer"
|
||||
},
|
||||
{
|
||||
"name": "Durham Hale",
|
||||
"email": "me@durhamhale.com",
|
||||
"homepage": "http://durhamhale.com",
|
||||
"role": "Maintainer"
|
||||
}
|
||||
],
|
||||
"license": [
|
||||
"BSD-2-Clause",
|
||||
"BSD-3-Clause",
|
||||
"BSD-4-Clause"
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.2.0",
|
||||
"j4mie/idiorm": "1.5.*"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "phpunit"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": ["paris.php"]
|
||||
}
|
||||
}
|
153
vendor/j4mie/paris/docs/Makefile
vendored
Normal file
153
vendor/j4mie/paris/docs/Makefile
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Paris.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Paris.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/Paris"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Paris"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
279
vendor/j4mie/paris/docs/associations.rst
vendored
Normal file
279
vendor/j4mie/paris/docs/associations.rst
vendored
Normal file
@ -0,0 +1,279 @@
|
||||
Associations
|
||||
============
|
||||
|
||||
Paris provides a simple API for one-to-one, one-to-many and many-to-many
|
||||
relationships (associations) between models. It takes a different
|
||||
approach to many other ORMs, which use associative arrays to add
|
||||
configuration metadata about relationships to model classes. These
|
||||
arrays can often be deeply nested and complex, and are therefore quite
|
||||
error-prone.
|
||||
|
||||
Instead, Paris treats the act of querying across a relationship as a
|
||||
*behaviour*, and supplies a family of helper methods to help generate
|
||||
such queries. These helper methods should be called from within
|
||||
*methods* on your model classes which are named to describe the
|
||||
relationship. These methods return ORM instances (rather than actual
|
||||
Model instances) and so, if necessary, the relationship query can be
|
||||
modified and added to before it is run.
|
||||
|
||||
Summary
|
||||
^^^^^^^
|
||||
|
||||
The following list summarises the associations provided by Paris, and
|
||||
explains which helper method supports each type of association:
|
||||
|
||||
One-to-one
|
||||
''''''''''
|
||||
|
||||
Use ``has_one`` in the base, and ``belongs_to`` in the associated model.
|
||||
|
||||
One-to-many
|
||||
'''''''''''
|
||||
|
||||
Use ``has_many`` in the base, and ``belongs_to`` in the associated
|
||||
model.
|
||||
|
||||
Many-to-many
|
||||
''''''''''''
|
||||
|
||||
Use ``has_many_through`` in both the base and associated models.
|
||||
|
||||
Below, each association helper method is discussed in detail.
|
||||
|
||||
Has-one
|
||||
^^^^^^^
|
||||
|
||||
One-to-one relationships are implemented using the ``has_one`` method.
|
||||
For example, say we have a ``User`` model. Each user has a single
|
||||
``Profile``, and so the ``user`` table should be associated with the
|
||||
``profile`` table. To be able to find the profile for a particular user,
|
||||
we should add a method called ``profile`` to the ``User`` class (note
|
||||
that the method name here is arbitrary, but should describe the
|
||||
relationship). This method calls the protected ``has_one`` method
|
||||
provided by Paris, passing in the class name of the related object. The
|
||||
``profile`` method should return an ORM instance ready for (optional)
|
||||
further filtering.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class Profile extends Model {
|
||||
}
|
||||
|
||||
class User extends Model {
|
||||
public function profile() {
|
||||
return $this->has_one('Profile');
|
||||
}
|
||||
}
|
||||
|
||||
The API for this method works as follows:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// Select a particular user from the database
|
||||
$user = Model::factory('User')->find_one($user_id);
|
||||
|
||||
// Find the profile associated with the user
|
||||
$profile = $user->profile()->find_one();
|
||||
|
||||
By default, Paris assumes that the foreign key column on the related
|
||||
table has the same name as the current (base) table, with ``_id``
|
||||
appended. In the example above, Paris will look for a foreign key column
|
||||
called ``user_id`` on the table used by the ``Profile`` class. To
|
||||
override this behaviour, add a second argument to your ``has_one`` call,
|
||||
passing the name of the column to use.
|
||||
|
||||
In addition, Paris assumes that the foreign key column in the current (base)
|
||||
table is the primary key column of the base table. In the example above,
|
||||
Paris will use the column called ``user_id`` (assuming ``user_id`` is the
|
||||
primary key for the user table) in the base table (in this case the user table)
|
||||
as the foreign key column in the base table. To override this behaviour,
|
||||
add a third argument to your ``has_one call``, passing the name of the column
|
||||
you intend to use as the foreign key column in the base table.
|
||||
|
||||
Has many
|
||||
^^^^^^^^
|
||||
|
||||
One-to-many relationships are implemented using the ``has_many`` method.
|
||||
For example, say we have a ``User`` model. Each user has several
|
||||
``Post`` objects. The ``user`` table should be associated with the
|
||||
``post`` table. To be able to find the posts for a particular user, we
|
||||
should add a method called ``posts`` to the ``User`` class (note that
|
||||
the method name here is arbitrary, but should describe the
|
||||
relationship). This method calls the protected ``has_many`` method
|
||||
provided by Paris, passing in the class name of the related objects.
|
||||
**Pass the model class name literally, not a pluralised version**. The
|
||||
``posts`` method should return an ORM instance ready for (optional)
|
||||
further filtering.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class Post extends Model {
|
||||
}
|
||||
|
||||
class User extends Model {
|
||||
public function posts() {
|
||||
return $this->has_many('Post'); // Note we use the model name literally - not a pluralised version
|
||||
}
|
||||
}
|
||||
|
||||
The API for this method works as follows:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// Select a particular user from the database
|
||||
$user = Model::factory('User')->find_one($user_id);
|
||||
|
||||
// Find the posts associated with the user
|
||||
$posts = $user->posts()->find_many();
|
||||
|
||||
By default, Paris assumes that the foreign key column on the related
|
||||
table has the same name as the current (base) table, with ``_id``
|
||||
appended. In the example above, Paris will look for a foreign key column
|
||||
called ``user_id`` on the table used by the ``Post`` class. To override
|
||||
this behaviour, add a second argument to your ``has_many`` call, passing
|
||||
the name of the column to use.
|
||||
|
||||
In addition, Paris assumes that the foreign key column in the current (base)
|
||||
table is the primary key column of the base table. In the example above, Paris
|
||||
will use the column called ``user_id`` (assuming ``user_id`` is the primary key
|
||||
for the user table) in the base table (in this case the user table) as the
|
||||
foreign key column in the base table. To override this behaviour, add a third
|
||||
argument to your ``has_many call``, passing the name of the column you intend
|
||||
to use as the foreign key column in the base table.
|
||||
|
||||
Belongs to
|
||||
^^^^^^^^^^
|
||||
|
||||
The ‘other side’ of ``has_one`` and ``has_many`` is ``belongs_to``. This
|
||||
method call takes identical parameters as these methods, but assumes the
|
||||
foreign key is on the *current* (base) table, not the related table.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class Profile extends Model {
|
||||
public function user() {
|
||||
return $this->belongs_to('User');
|
||||
}
|
||||
}
|
||||
|
||||
class User extends Model {
|
||||
}
|
||||
|
||||
The API for this method works as follows:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// Select a particular profile from the database
|
||||
$profile = Model::factory('Profile')->find_one($profile_id);
|
||||
|
||||
// Find the user associated with the profile
|
||||
$user = $profile->user()->find_one();
|
||||
|
||||
Again, Paris makes an assumption that the foreign key on the current
|
||||
(base) table has the same name as the related table with ``_id``
|
||||
appended. In the example above, Paris will look for a column named
|
||||
``user_id``. To override this behaviour, pass a second argument to the
|
||||
``belongs_to`` method, specifying the name of the column on the current
|
||||
(base) table to use.
|
||||
|
||||
Paris also makes an assumption that the foreign key in the associated (related)
|
||||
table is the primary key column of the related table. In the example above,
|
||||
Paris will look for a column named ``user_id`` in the user table (the related
|
||||
table in this example). To override this behaviour, pass a third argument to
|
||||
the belongs_to method, specifying the name of the column in the related table
|
||||
to use as the foreign key column in the related table.
|
||||
|
||||
Has many through
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
Many-to-many relationships are implemented using the
|
||||
``has_many_through`` method. This method has only one required argument:
|
||||
the name of the related model. Supplying further arguments allows us to
|
||||
override default behaviour of the method.
|
||||
|
||||
For example, say we have a ``Book`` model. Each ``Book`` may have
|
||||
several ``Author`` objects, and each ``Author`` may have written several
|
||||
``Books``. To be able to find the authors for a particular book, we
|
||||
should first create an intermediary model. The name for this model
|
||||
should be constructed by concatenating the names of the two related
|
||||
classes, in alphabetical order. In this case, our classes are called
|
||||
``Author`` and ``Book``, so the intermediate model should be called
|
||||
``AuthorBook``.
|
||||
|
||||
We should then add a method called ``authors`` to the ``Book`` class
|
||||
(note that the method name here is arbitrary, but should describe the
|
||||
relationship). This method calls the protected ``has_many_through``
|
||||
method provided by Paris, passing in the class name of the related
|
||||
objects. **Pass the model class name literally, not a pluralised
|
||||
version**. The ``authors`` method should return an ORM instance ready
|
||||
for (optional) further filtering.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class Author extends Model {
|
||||
public function books() {
|
||||
return $this->has_many_through('Book');
|
||||
}
|
||||
}
|
||||
|
||||
class Book extends Model {
|
||||
public function authors() {
|
||||
return $this->has_many_through('Author');
|
||||
}
|
||||
}
|
||||
|
||||
class AuthorBook extends Model {
|
||||
}
|
||||
|
||||
The API for this method works as follows:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// Select a particular book from the database
|
||||
$book = Model::factory('Book')->find_one($book_id);
|
||||
|
||||
// Find the authors associated with the book
|
||||
$authors = $book->authors()->find_many();
|
||||
|
||||
// Get the first author
|
||||
$first_author = $authors[0];
|
||||
|
||||
// Find all the books written by this author
|
||||
$first_author_books = $first_author->books()->find_many();
|
||||
|
||||
Overriding defaults
|
||||
'''''''''''''''''''
|
||||
|
||||
The ``has_many_through`` method takes up to six arguments, which allow
|
||||
us to progressively override default assumptions made by the method.
|
||||
|
||||
**First argument: associated model name** - this is mandatory and should
|
||||
be the name of the model we wish to select across the association.
|
||||
|
||||
**Second argument: intermediate model name** - this is optional and
|
||||
defaults to the names of the two associated models, sorted
|
||||
alphabetically and concatenated.
|
||||
|
||||
**Third argument: custom key to base table on intermediate table** -
|
||||
this is optional, and defaults to the name of the base table with
|
||||
``_id`` appended.
|
||||
|
||||
**Fourth argument: custom key to associated table on intermediate
|
||||
table** - this is optional, and defaults to the name of the associated
|
||||
table with ``_id`` appended.
|
||||
|
||||
**Fifth argument: foreign key column in the base table** -
|
||||
this is optional, and defaults to the name of the primary key column in
|
||||
the base table.
|
||||
|
||||
**Sixth argument: foreign key column in the associated table** -
|
||||
this is optional, and defaults to the name of the primary key column
|
||||
in the associated table.
|
242
vendor/j4mie/paris/docs/conf.py
vendored
Normal file
242
vendor/j4mie/paris/docs/conf.py
vendored
Normal file
@ -0,0 +1,242 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Paris documentation build configuration file, created by
|
||||
# sphinx-quickstart on Wed Nov 28 15:47:04 2012.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = []
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Paris'
|
||||
copyright = u'2014, Jamie Matthews and Simon Holywell'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = ''
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = ''
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'default'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'Parisdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'Paris.tex', u'Paris Documentation',
|
||||
u'Jamie Matthews and Simon Holywell', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'paris', u'Paris Documentation',
|
||||
[u'Jamie Matthews and Simon Holywell'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output ------------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'Paris', u'Paris Documentation',
|
||||
u'Jamie Matthews and Simon Holywell', 'Paris', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
123
vendor/j4mie/paris/docs/configuration.rst
vendored
Normal file
123
vendor/j4mie/paris/docs/configuration.rst
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
Configuration
|
||||
=============
|
||||
|
||||
Setup
|
||||
~~~~~
|
||||
|
||||
Paris requires `Idiorm`_. Install Idiorm and Paris somewhere in your
|
||||
project directory, and ``require`` both.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
require_once 'your/path/to/idiorm.php';
|
||||
require_once 'your/path/to/paris.php';
|
||||
|
||||
Then, you need to tell Idiorm how to connect to your database. **For
|
||||
full details of how to do this, see `Idiorm's documentation`_.**
|
||||
|
||||
Briefly, you need to pass a *Data Source Name* connection string to the
|
||||
``configure`` method of the ORM class.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
ORM::configure('sqlite:./example.db');
|
||||
|
||||
You may also need to pass a username and password to your database
|
||||
driver, using the ``username`` and ``password`` configuration options.
|
||||
For example, if you are using MySQL:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
ORM::configure('mysql:host=localhost;dbname=my_database');
|
||||
ORM::configure('username', 'database_user');
|
||||
ORM::configure('password', 'top_secret');
|
||||
|
||||
Model prefixing
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Setting: ``Model::$auto_prefix_models``
|
||||
|
||||
To save having type out model class name prefixes whenever code utilises ``Model::for_table()``
|
||||
it is possible to specify a prefix that will be prepended onto the class name.
|
||||
|
||||
The model prefix is treated the same way as any other class name when Paris
|
||||
attempts to convert it to a table name. This is documented in the :doc:`Models`
|
||||
section of the documentation.
|
||||
|
||||
Here is a namespaced example to make it clearer:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
Model::$auto_prefix_models = '\\Tests\\';
|
||||
Model::factory('Simple')->find_many(); // SQL executed: SELECT * FROM `tests_simple`
|
||||
Model::factory('SimpleUser')->find_many(); // SQL executed: SELECT * FROM `tests_simple_user`
|
||||
|
||||
Model prefixes are only compatible with the ``Model::factory()`` methods described above.
|
||||
Where the shorter ``SimpleUser::find_many()`` style syntax is used, the addition of a
|
||||
Model prefix will cause ``Class not found`` errors.
|
||||
|
||||
.. note::
|
||||
|
||||
Model class property ``$_table`` sets an explicit table name, ignoring the
|
||||
``$auto_prefix_models`` property in your individual model classes. See documentation in
|
||||
the :doc:`Models` section of the documentation.
|
||||
|
||||
Model prefixing
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Setting: ``Model::$short_table_names``
|
||||
|
||||
Set as ``true`` to disregard namespace information when computing table names
|
||||
from class names.
|
||||
|
||||
By default the class ``\Models\CarTyre`` expects the table name ``models_car_tyre``.
|
||||
With ``Model::$short_table_names = true`` the class ``\Models\CarTyre`` expects the
|
||||
table name ``car_tyre``.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
Model::$short_table_names = true;
|
||||
Model::factory('CarTyre')->find_many(); // SQL executed: SELECT * FROM `car_tyre`
|
||||
|
||||
namespace Models {
|
||||
class CarTyre extends Model {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Further Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The only other configuration options provided by Paris itself are the
|
||||
``$_table`` and ``$_id_column`` static properties on model classes. To
|
||||
configure the database connection, you should use Idiorm’s configuration
|
||||
system via the ``ORM::configure`` method.
|
||||
|
||||
If you are using multiple connections, the optional `$_connection_key` static property may also be used to provide a default string key indicating which database connection in `ORM` should be used.
|
||||
|
||||
**See `Idiorm's documentation`_ for full details.**
|
||||
|
||||
Query logging
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Idiorm can log all queries it executes. To enable query logging, set the
|
||||
``logging`` option to ``true`` (it is ``false`` by default).
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
ORM::configure('logging', true);
|
||||
|
||||
When query logging is enabled, you can use two static methods to access
|
||||
the log. ``ORM::get_last_query()`` returns the most recent query
|
||||
executed. ``ORM::get_query_log()`` returns an array of all queries
|
||||
executed.
|
||||
|
||||
.. _Idiorm's documentation: http://github.com/j4mie/idiorm/
|
||||
.. _Idiorm: http://github.com/j4mie/idiorm/
|
40
vendor/j4mie/paris/docs/connections.rst
vendored
Normal file
40
vendor/j4mie/paris/docs/connections.rst
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
Multiple Connections
|
||||
====================
|
||||
|
||||
Paris now works with multiple database conections (and necessarily relies on an updated version of Idiorm that also supports multiple connections). Database connections are identified by a string name, and default to ``OrmWrapper::DEFAULT_CONNECTION`` (which is really ``ORM::DEFAULT_CONNECTION``).
|
||||
|
||||
See `Idiorm’s documentation`_ for information about configuring multiple connections.
|
||||
|
||||
The connection to use can be specified in two separate ways. To indicate a default connection key for a subclass of ``Model``, create a public static property in your model class called ``$_connection_name``.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// A named connection, where 'alternate' is an arbitray key name
|
||||
ORM::configure('sqlite:./example2.db', null, 'alternate');
|
||||
|
||||
class SomeClass extends Model
|
||||
{
|
||||
public static $_connection_name = 'alternate';
|
||||
}
|
||||
|
||||
The connection to use can also be specified as an optional additional parameter to ``OrmWrapper::for_table()``, or to ``Model::factory()``. This will override the default setting (if any) found in the ``$_connection_name`` static property.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$person = Model::factory('Author', 'alternate')->find_one(1); // Uses connection named 'alternate'
|
||||
|
||||
The connection can be changed after a model is populated, should that be necessary:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$person = Model::factory('Author')->find_one(1); // Uses default connection
|
||||
$person->orm = Model::factory('Author', 'alternate'); // Switches to connection named 'alternate'
|
||||
$person->name = 'Foo';
|
||||
$person->save(); // *Should* now save through the updated connection
|
||||
|
||||
Queries across multiple connections are not supported. However, as the Paris methods ``has_one``, ``has_many`` and ``belongs_to`` don't require joins, these *should* work as expected, even when the objects on opposite sides of the relation belong to diffrent connections. The ``has_many_through`` relationship requires joins, and so will not reliably work across different connections.
|
||||
|
||||
.. _Idiorm’s documentation: http://github.com/j4mie/idiorm/
|
76
vendor/j4mie/paris/docs/filters.rst
vendored
Normal file
76
vendor/j4mie/paris/docs/filters.rst
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
Filters
|
||||
=======
|
||||
|
||||
It is often desirable to create reusable queries that can be used to
|
||||
extract particular subsets of data without repeating large sections of
|
||||
code. Paris allows this by providing a method called ``filter`` which
|
||||
can be chained in queries alongside the existing Idiorm query API. The
|
||||
filter method takes the name of a **public static** method on the
|
||||
current Model subclass as an argument. The supplied method will be
|
||||
called at the point in the chain where ``filter`` is called, and will be
|
||||
passed the ``ORM`` object as the first parameter. It should return the
|
||||
ORM object after calling one or more query methods on it. The method
|
||||
chain can then be continued if necessary.
|
||||
|
||||
It is easiest to illustrate this with an example. Imagine an application
|
||||
in which users can be assigned a role, which controls their access to
|
||||
certain pieces of functionality. In this situation, you may often wish
|
||||
to retrieve a list of users with the role ‘admin’. To do this, add a
|
||||
static method called (for example) ``admins`` to your Model class:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class User extends Model {
|
||||
public static function admins($orm) {
|
||||
return $orm->where('role', 'admin');
|
||||
}
|
||||
}
|
||||
|
||||
You can then use this filter in your queries:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$admin_users = Model::factory('User')->filter('admins')->find_many();
|
||||
|
||||
You can also chain it with other methods as normal:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$young_admins = Model::factory('User')
|
||||
->filter('admins')
|
||||
->where_lt('age', 18)
|
||||
->find_many();
|
||||
|
||||
Filters with arguments
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can also pass arguments to custom filters. Any additional arguments
|
||||
passed to the ``filter`` method (after the name of the filter to apply)
|
||||
will be passed through to your custom filter as additional arguments
|
||||
(after the ORM instance).
|
||||
|
||||
For example, let’s say you wish to generalise your role filter (see
|
||||
above) to allow you to retrieve users with any role. You can pass the
|
||||
role name to the filter as an argument:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class User extends Model {
|
||||
public static function has_role($orm, $role) {
|
||||
return $orm->where('role', $role);
|
||||
}
|
||||
}
|
||||
|
||||
$admin_users = Model::factory('User')->filter('has_role', 'admin')->find_many();
|
||||
$guest_users = Model::factory('User')->filter('has_role', 'guest')->find_many();
|
||||
|
||||
These examples may seem simple (``filter('has_role', 'admin')`` could
|
||||
just as easily be achieved using ``where('role', 'admin')``), but
|
||||
remember that filters can contain arbitrarily complex code - adding
|
||||
``raw_where`` clauses or even complete ``raw_query`` calls to perform
|
||||
joins, etc. Filters provide a powerful mechanism to hide complexity in
|
||||
your model’s query API.
|
34
vendor/j4mie/paris/docs/index.rst
vendored
Normal file
34
vendor/j4mie/paris/docs/index.rst
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
.. Paris documentation master file, created by
|
||||
sphinx-quickstart on Wed Nov 28 15:47:04 2012.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to Paris's documentation!
|
||||
=================================
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
philosophy
|
||||
installation
|
||||
configuration
|
||||
models
|
||||
associations
|
||||
querying
|
||||
filters
|
||||
transactions
|
||||
validation
|
||||
migrations
|
||||
connections
|
||||
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
19
vendor/j4mie/paris/docs/installation.rst
vendored
Normal file
19
vendor/j4mie/paris/docs/installation.rst
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Installation
|
||||
============
|
||||
|
||||
Packagist
|
||||
~~~~~~~~~
|
||||
|
||||
This library is available through Packagist with the vendor and package
|
||||
identifier of ``j4mie/paris``
|
||||
|
||||
Please see the `Packagist documentation`_ for further information.
|
||||
|
||||
Download
|
||||
~~~~~~~~
|
||||
|
||||
You can clone the git repository, download idiorm.php or a release tag
|
||||
and then drop the idiorm.php file in the vendors/3rd party/libs
|
||||
directory of your project.
|
||||
|
||||
.. _Packagist documentation: http://packagist.org/
|
190
vendor/j4mie/paris/docs/make.bat
vendored
Normal file
190
vendor/j4mie/paris/docs/make.bat
vendored
Normal file
@ -0,0 +1,190 @@
|
||||
@ECHO OFF
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set BUILDDIR=_build
|
||||
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
|
||||
set I18NSPHINXOPTS=%SPHINXOPTS% .
|
||||
if NOT "%PAPER%" == "" (
|
||||
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
|
||||
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
if "%1" == "help" (
|
||||
:help
|
||||
echo.Please use `make ^<target^>` where ^<target^> is one of
|
||||
echo. html to make standalone HTML files
|
||||
echo. dirhtml to make HTML files named index.html in directories
|
||||
echo. singlehtml to make a single large HTML file
|
||||
echo. pickle to make pickle files
|
||||
echo. json to make JSON files
|
||||
echo. htmlhelp to make HTML files and a HTML help project
|
||||
echo. qthelp to make HTML files and a qthelp project
|
||||
echo. devhelp to make HTML files and a Devhelp project
|
||||
echo. epub to make an epub
|
||||
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
|
||||
echo. text to make text files
|
||||
echo. man to make manual pages
|
||||
echo. texinfo to make Texinfo files
|
||||
echo. gettext to make PO message catalogs
|
||||
echo. changes to make an overview over all changed/added/deprecated items
|
||||
echo. linkcheck to check all external links for integrity
|
||||
echo. doctest to run all doctests embedded in the documentation if enabled
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "clean" (
|
||||
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
|
||||
del /q /s %BUILDDIR%\*
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "html" (
|
||||
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "dirhtml" (
|
||||
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "singlehtml" (
|
||||
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "pickle" (
|
||||
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can process the pickle files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "json" (
|
||||
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can process the JSON files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "htmlhelp" (
|
||||
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can run HTML Help Workshop with the ^
|
||||
.hhp project file in %BUILDDIR%/htmlhelp.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "qthelp" (
|
||||
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can run "qcollectiongenerator" with the ^
|
||||
.qhcp project file in %BUILDDIR%/qthelp, like this:
|
||||
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Paris.qhcp
|
||||
echo.To view the help file:
|
||||
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Paris.ghc
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "devhelp" (
|
||||
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "epub" (
|
||||
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The epub file is in %BUILDDIR%/epub.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latex" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "text" (
|
||||
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The text files are in %BUILDDIR%/text.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "man" (
|
||||
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The manual pages are in %BUILDDIR%/man.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "texinfo" (
|
||||
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "gettext" (
|
||||
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "changes" (
|
||||
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.The overview file is in %BUILDDIR%/changes.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "linkcheck" (
|
||||
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Link check complete; look for any errors in the above output ^
|
||||
or in %BUILDDIR%/linkcheck/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "doctest" (
|
||||
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Testing of doctests in the sources finished, look at the ^
|
||||
results in %BUILDDIR%/doctest/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
:end
|
24
vendor/j4mie/paris/docs/migrations.rst
vendored
Normal file
24
vendor/j4mie/paris/docs/migrations.rst
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
Migrations
|
||||
==========
|
||||
|
||||
Paris does not have native support for migrations, but some work has been
|
||||
done to integrate `PHPMig`_. If you want to have migrations in your project
|
||||
then this is recommended route as Paris will never have migrations directly
|
||||
implemented in the core. Please refer to the Paris and Idiorm Philosophy for
|
||||
reasons why.
|
||||
|
||||
To integrate Paris with PHPMig you will need to follow their `installation
|
||||
instructions`_ and then configure it to use the Paris PDO instance:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$container['db'] = $container->share(function(){
|
||||
return ORM::get_db();
|
||||
});
|
||||
$container['phpmig.adapter'] = $container->share(function() use ($container) {
|
||||
return new Adapter\PDO\Sql($container['db'], 'migrations');
|
||||
});
|
||||
|
||||
.. _PHPMig: https://github.com/davedevelopment/phpmig
|
||||
.. _installation instructions: https://github.com/davedevelopment/phpmig#getting-started
|
120
vendor/j4mie/paris/docs/models.rst
vendored
Normal file
120
vendor/j4mie/paris/docs/models.rst
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
Models
|
||||
======
|
||||
|
||||
Model classes
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
You should create a model class for each entity in your application. For
|
||||
example, if you are building an application that requires users, you
|
||||
should create a ``User`` class. Your model classes should extend the
|
||||
base ``Model`` class:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class User extends Model {
|
||||
}
|
||||
|
||||
Paris takes care of creating instances of your model classes, and
|
||||
populating them with *data* from the database. You can then add
|
||||
*behaviour* to this class in the form of public methods which implement
|
||||
your application logic. This combination of data and behaviour is the
|
||||
essence of the `Active Record pattern`_.
|
||||
|
||||
IDE Auto-complete
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
As Paris does not require you to specify a method/function per database column
|
||||
it can be difficult to know what properties are available on a particular model.
|
||||
Due to the magic nature of PHP's `__get()`_ method it is impossible for an IDE
|
||||
to give you autocomplete hints as well.
|
||||
|
||||
To work around this you can use PHPDoc comment blocks to list the properties of
|
||||
the model. These properties should mirror the names of your database tables
|
||||
columns.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $first_name
|
||||
* @property string $last_name
|
||||
* @property string $email
|
||||
*/
|
||||
class User extends Model {
|
||||
}
|
||||
|
||||
For more information please see the `PHPDoc manual @property`_ documentation.
|
||||
|
||||
Database tables
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Your ``User`` class should have a corresponding ``user`` table in your
|
||||
database to store its data.
|
||||
|
||||
By default, Paris assumes your class names are in *CapWords* style, and
|
||||
your table names are in *lowercase\_with\_underscores* style. It will
|
||||
convert between the two automatically. For example, if your class is
|
||||
called ``CarTyre``, Paris will look for a table named ``car_tyre``.
|
||||
|
||||
If you are using namespaces then they will be converted to a table name
|
||||
in a similar way. For example ``\Models\CarTyre`` would be converted to
|
||||
``models_car_tyre``. Note here that backslashes are replaced with underscores
|
||||
in addition to the *CapWords* replacement discussed in the previous paragraph.
|
||||
|
||||
To disregard namespace information when calculating the table name, set
|
||||
``Model::$short_table_names = true;``. Optionally this may be set or overridden at
|
||||
class level with the **public static** property ``$_table_use_short_name``. The
|
||||
|
||||
``$_table_use_short_name`` takes precedence over ``Model::$short_table_names``
|
||||
unless ``$_table_use_short_name`` is ``null`` (default).
|
||||
|
||||
Either setting results in ``\Models\CarTyre`` being converted to ``car_tyre``.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class User extends Model {
|
||||
public static $_table_use_short_name = true;
|
||||
}
|
||||
|
||||
To override the default naming behaviour and directly specify a table name,
|
||||
add a **public static** property to your class called ``$_table``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class User extends Model {
|
||||
public static $_table = 'my_user_table';
|
||||
}
|
||||
|
||||
Auto prefixing
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
To save having type out model class name prefixes whenever code utilises ``Model::for_table()``
|
||||
it is possible to specify a prefix that will be prepended onto the class name.
|
||||
|
||||
See the :doc:`Configuration` documentation for more details.
|
||||
|
||||
ID column
|
||||
~~~~~~~~~
|
||||
|
||||
Paris requires that your database tables have a unique primary key
|
||||
column. By default, Paris will use a column called ``id``. To override
|
||||
this default behaviour, add a **public static** property to your class
|
||||
called ``$_id_column``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class User extends Model {
|
||||
public static $_id_column = 'my_id_column';
|
||||
}
|
||||
|
||||
**Note** - Paris has its *own* default ID column name mechanism, and
|
||||
does not respect column names specified in Idiorm’s configuration.
|
||||
|
||||
.. _Active Record pattern: http://martinfowler.com/eaaCatalog/activeRecord.html
|
||||
.. ___get: https://secure.php.net/manual/en/language.oop5.overloading.php#object.get
|
||||
.. _PHPDoc manual @property: https://www.phpdoc.org/docs/latest/references/phpdoc/tags/property.html
|
6
vendor/j4mie/paris/docs/philosophy.rst
vendored
Normal file
6
vendor/j4mie/paris/docs/philosophy.rst
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
Philosophy
|
||||
==========
|
||||
|
||||
Paris is built with the same *less is more* philosophy as `Idiorm`_.
|
||||
|
||||
.. _Idiorm: http://github.com/j4mie/idiorm/
|
197
vendor/j4mie/paris/docs/querying.rst
vendored
Normal file
197
vendor/j4mie/paris/docs/querying.rst
vendored
Normal file
@ -0,0 +1,197 @@
|
||||
Querying
|
||||
========
|
||||
|
||||
Querying allows you to select data from your database and populate
|
||||
instances of your model classes. Queries start with a call to a static
|
||||
*factory method* on the base ``Model`` class that takes a single
|
||||
argument: the name of the model class you wish to use for your query.
|
||||
This factory method is then used as the start of a *method chain* which
|
||||
gives you full access to `Idiorm`_\ ’s fluent query API. **See Idiorm’s
|
||||
documentation for details of this API.**
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$users = Model::factory('User')
|
||||
->where('name', 'Fred')
|
||||
->where_gte('age', 20)
|
||||
->find_many();
|
||||
|
||||
You can also use the same shortcut provided by Idiorm when looking up a
|
||||
record by its primary key ID:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$user = Model::factory('User')->find_one($id);
|
||||
|
||||
If you are using PHP 5.3+ you can also do the following:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$users = User::where('name', 'Fred')
|
||||
->where_gte('age', 20)
|
||||
->find_many();
|
||||
|
||||
This does the same as the example above but is shorter and more readable.
|
||||
|
||||
|
||||
The only differences between using Idiorm and using Paris for querying
|
||||
are as follows:
|
||||
|
||||
1. You do not need to call the ``for_table`` method to specify the
|
||||
database table to use. Paris will supply this automatically based on
|
||||
the class name (or the ``$_table`` static property, if present).
|
||||
|
||||
2. The ``find_one`` and ``find_many`` methods will return instances of
|
||||
*your model subclass*, instead of the base ``ORM`` class. Like
|
||||
Idiorm, ``find_one`` will return a single instance or ``false`` if no
|
||||
rows matched your query, while ``find_many`` will return an array of
|
||||
instances, which may be empty if no rows matched.
|
||||
|
||||
3. Custom filtering, see next section.
|
||||
|
||||
You may also retrieve a count of the number of rows returned by your
|
||||
query. This method behaves exactly like Idiorm’s ``count`` method:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$count = Model::factory('User')->where_lt('age', 20)->count();
|
||||
|
||||
A note on PSR-1 and camelCase
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
All the methods detailed in the documentation can also be called in a PSR-1 way:
|
||||
underscores (_) become camelCase. Here follows an example of one query chain
|
||||
being converted to a PSR-1 compliant style.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// documented and default style
|
||||
$count = Model::factory('User')->where_lt('age', 20)->find_one();
|
||||
|
||||
// PSR-1 compliant style
|
||||
$count = Model::factory('User')->whereLt('age', 20)->findOne();
|
||||
|
||||
As you can see any method can be changed from the documented underscore (_) format
|
||||
to that of a camelCase method name.
|
||||
|
||||
.. note::
|
||||
|
||||
In the background the PSR-1 compliant style uses the `__call()` and
|
||||
`__callStatic()` magic methods to map the camelCase method name you supply
|
||||
to the original underscore method name. It then uses `call_user_func_array()`
|
||||
to apply the arguments to the method. If this minimal overhead is too great
|
||||
then you can simply revert to using the underscore methods to avoid it. In
|
||||
general this will not be a bottle neck in any application however and should
|
||||
be considered a micro-optimisation.
|
||||
|
||||
As `__callStatic()` was added in PHP 5.3.0 you will need at least that version
|
||||
of PHP to use this feature in any meaningful way.
|
||||
|
||||
Getting data from objects, updating and inserting data
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The model instances returned by your queries now behave exactly as if
|
||||
they were instances of Idiorm’s raw ``ORM`` class.
|
||||
|
||||
You can access data:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$user = Model::factory('User')->find_one($id);
|
||||
echo $user->name;
|
||||
|
||||
Update data and save the instance:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$user = Model::factory('User')->find_one($id);
|
||||
$user->name = 'Paris';
|
||||
$user->save();
|
||||
|
||||
To create a new (empty) instance, use the ``create`` method:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$user = Model::factory('User')->create();
|
||||
$user->name = 'Paris';
|
||||
$user->save();
|
||||
|
||||
To check whether a property has been changed since the object was
|
||||
created (or last saved), call the ``is_dirty`` method:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$name_has_changed = $person->is_dirty('name'); // Returns true or false
|
||||
|
||||
You can also use database expressions when setting values on your model:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$user = Model::factory('User')->find_one($id);
|
||||
$user->name = 'Paris';
|
||||
$user->set_expr('last_logged_in', 'NOW()');
|
||||
$user->save();
|
||||
|
||||
Of course, because these objects are instances of your base model
|
||||
classes, you can also call methods that you have defined on them:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class User extends Model {
|
||||
public function full_name() {
|
||||
return $this->first_name . ' ' . $this->last_name;
|
||||
}
|
||||
}
|
||||
|
||||
$user = Model::factory('User')->find_one($id);
|
||||
echo $user->full_name();
|
||||
|
||||
To delete the database row associated with an instance of your model,
|
||||
call its ``delete`` method:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$user = Model::factory('User')->find_one($id);
|
||||
$user->delete();
|
||||
|
||||
You can also get the all the data wrapped by a model subclass instance
|
||||
using the ``as_array`` method. This will return an associative array
|
||||
mapping column names (keys) to their values.
|
||||
|
||||
The ``as_array`` method takes column names as optional arguments. If one
|
||||
or more of these arguments is supplied, only matching column names will
|
||||
be returned.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class Person extends Model {
|
||||
}
|
||||
|
||||
$person = Model::factory('Person')->create();
|
||||
|
||||
$person->first_name = 'Fred';
|
||||
$person->surname = 'Bloggs';
|
||||
$person->age = 50;
|
||||
|
||||
// Returns array('first_name' => 'Fred', 'surname' => 'Bloggs', 'age' => 50)
|
||||
$data = $person->as_array();
|
||||
|
||||
// Returns array('first_name' => 'Fred', 'age' => 50)
|
||||
$data = $person->as_array('first_name', 'age');
|
||||
|
||||
.. _Idiorm: http://github.com/j4mie/idiorm/
|
21
vendor/j4mie/paris/docs/transactions.rst
vendored
Normal file
21
vendor/j4mie/paris/docs/transactions.rst
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
Transactions
|
||||
============
|
||||
|
||||
Paris (or Idiorm) doesn’t supply any extra methods to deal with
|
||||
transactions, but it’s very easy to use PDO’s built-in methods:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// Start a transaction
|
||||
ORM::get_db()->beginTransaction();
|
||||
|
||||
// Commit a transaction
|
||||
ORM::get_db()->commit();
|
||||
|
||||
// Roll back a transaction
|
||||
ORM::get_db()->rollBack();
|
||||
|
||||
For more details, see `the PDO documentation on Transactions`_.
|
||||
|
||||
.. _the PDO documentation on Transactions: http://www.php.net/manual/en/pdo.transactions.php
|
27
vendor/j4mie/paris/docs/validation.rst
vendored
Normal file
27
vendor/j4mie/paris/docs/validation.rst
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
A word on validation
|
||||
====================
|
||||
|
||||
It’s generally considered a good idea to centralise your data validation
|
||||
in a single place, and a good place to do this is inside your model
|
||||
classes. This is preferable to handling validation alongside form
|
||||
handling code, for example. Placing validation code inside models means
|
||||
that if you extend your application in the future to update your model
|
||||
via an alternative route (say a REST API rather than a form) you can
|
||||
re-use the same validation code.
|
||||
|
||||
Despite this, Paris doesn’t provide any built-in support for validation.
|
||||
This is because validation is potentially quite complex, and often very
|
||||
application-specific. Paris is deliberately quite ignorant about your
|
||||
actual data - it simply executes queries, and gives you the
|
||||
responsibility of making sure the data inside your models is valid and
|
||||
correct. Adding a full validation framework to Paris would probably
|
||||
require more code than Paris itself!
|
||||
|
||||
However, there are several simple ways that you could add validation to
|
||||
your models without any help from Paris. You could override the
|
||||
``save()`` method, check the data is valid, and return ``false`` on
|
||||
failure, or call ``parent::save()`` on success. You could create your
|
||||
own subclass of the ``Model`` base class and add your own generic
|
||||
validation methods. Or you could write your own external validation
|
||||
framework which you pass model instances to for checking. Choose
|
||||
whichever approach is most suitable for your own requirements.
|
726
vendor/j4mie/paris/paris.php
vendored
Normal file
726
vendor/j4mie/paris/paris.php
vendored
Normal file
@ -0,0 +1,726 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Paris
|
||||
*
|
||||
* http://github.com/j4mie/paris/
|
||||
*
|
||||
* A simple Active Record implementation built on top of Idiorm
|
||||
* ( http://github.com/j4mie/idiorm/ ).
|
||||
*
|
||||
* You should include Idiorm before you include this file:
|
||||
* require_once 'your/path/to/idiorm.php';
|
||||
*
|
||||
* BSD Licensed.
|
||||
*
|
||||
* Copyright (c) 2010, Jamie Matthews
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Subclass of Idiorm's ORM class that supports
|
||||
* returning instances of a specified class rather
|
||||
* than raw instances of the ORM class.
|
||||
*
|
||||
* You shouldn't need to interact with this class
|
||||
* directly. It is used internally by the Model base
|
||||
* class.
|
||||
*
|
||||
*
|
||||
* The methods documented below are magic methods that conform to PSR-1.
|
||||
* This documentation exposes these methods to doc generators and IDEs.
|
||||
* @see http://www.php-fig.org/psr/psr-1/
|
||||
*
|
||||
* @method void setClassName($class_name)
|
||||
* @method static \ORMWrapper forTable($table_name, $connection_name = parent::DEFAULT_CONNECTION)
|
||||
* @method \Model findOne($id=null)
|
||||
* @method Array|\IdiormResultSet findMany()
|
||||
*/
|
||||
class ORMWrapper extends ORM {
|
||||
|
||||
/**
|
||||
* The wrapped find_one and find_many classes will
|
||||
* return an instance or instances of this class.
|
||||
*
|
||||
* @var string $_class_name
|
||||
*/
|
||||
protected $_class_name;
|
||||
|
||||
/**
|
||||
* Set the name of the class which the wrapped
|
||||
* methods should return instances of.
|
||||
*
|
||||
* @param string $class_name
|
||||
* @return void
|
||||
*/
|
||||
public function set_class_name($class_name) {
|
||||
$this->_class_name = $class_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom filter to the method chain specified on the
|
||||
* model class. This allows custom queries to be added
|
||||
* to models. The filter should take an instance of the
|
||||
* ORM wrapper as its first argument and return an instance
|
||||
* of the ORM wrapper. Any arguments passed to this method
|
||||
* after the name of the filter will be passed to the called
|
||||
* filter function as arguments after the ORM class.
|
||||
*
|
||||
* @return ORMWrapper
|
||||
*/
|
||||
public function filter() {
|
||||
$args = func_get_args();
|
||||
$filter_function = array_shift($args);
|
||||
array_unshift($args, $this);
|
||||
if (method_exists($this->_class_name, $filter_function)) {
|
||||
return call_user_func_array(array($this->_class_name, $filter_function), $args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method, return an instance of this
|
||||
* class bound to the supplied table name.
|
||||
*
|
||||
* A repeat of content in parent::for_table, so that
|
||||
* created class is ORMWrapper, not ORM
|
||||
*
|
||||
* @param string $table_name
|
||||
* @param string $connection_name
|
||||
* @return ORMWrapper
|
||||
*/
|
||||
public static function for_table($table_name, $connection_name = parent::DEFAULT_CONNECTION) {
|
||||
self::_setup_db($connection_name);
|
||||
return new self($table_name, array(), $connection_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create an instance of the model class
|
||||
* associated with this wrapper and populate
|
||||
* it with the supplied Idiorm instance.
|
||||
*
|
||||
* @param ORM $orm
|
||||
* @return bool|Model
|
||||
*/
|
||||
protected function _create_model_instance($orm) {
|
||||
if ($orm === false) {
|
||||
return false;
|
||||
}
|
||||
$model = new $this->_class_name();
|
||||
$model->set_orm($orm);
|
||||
return $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap Idiorm's find_one method to return
|
||||
* an instance of the class associated with
|
||||
* this wrapper instead of the raw ORM class.
|
||||
*
|
||||
* @param null|integer $id
|
||||
* @return Model
|
||||
*/
|
||||
public function find_one($id=null) {
|
||||
return $this->_create_model_instance(parent::find_one($id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap Idiorm's find_many method to return
|
||||
* an array of instances of the class associated
|
||||
* with this wrapper instead of the raw ORM class.
|
||||
*
|
||||
* @return Array
|
||||
*/
|
||||
public function find_many() {
|
||||
$results = parent::find_many();
|
||||
foreach($results as $key => $result) {
|
||||
$results[$key] = $this->_create_model_instance($result);
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap Idiorm's create method to return an
|
||||
* empty instance of the class associated with
|
||||
* this wrapper instead of the raw ORM class.
|
||||
*
|
||||
* @return ORMWrapper|bool
|
||||
*/
|
||||
public function create($data=null) {
|
||||
return $this->_create_model_instance(parent::create($data));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Model base class. Your model objects should extend
|
||||
* this class. A minimal subclass would look like:
|
||||
*
|
||||
* class Widget extends Model {
|
||||
* }
|
||||
*
|
||||
*
|
||||
* The methods documented below are magic methods that conform to PSR-1.
|
||||
* This documentation exposes these methods to doc generators and IDEs.
|
||||
* @see http://www.php-fig.org/psr/psr-1/
|
||||
*
|
||||
* @method void setOrm($orm)
|
||||
* @method $this setExpr($property, $value = null)
|
||||
* @method bool isDirty($property)
|
||||
* @method bool isNew()
|
||||
* @method Array asArray()
|
||||
*/
|
||||
class Model {
|
||||
|
||||
// Default ID column for all models. Can be overridden by adding
|
||||
// a public static _id_column property to your model classes.
|
||||
const DEFAULT_ID_COLUMN = 'id';
|
||||
|
||||
// Default foreign key suffix used by relationship methods
|
||||
const DEFAULT_FOREIGN_KEY_SUFFIX = '_id';
|
||||
|
||||
/**
|
||||
* Set a prefix for model names. This can be a namespace or any other
|
||||
* abitrary prefix such as the PEAR naming convention.
|
||||
*
|
||||
* @example Model::$auto_prefix_models = 'MyProject_MyModels_'; //PEAR
|
||||
* @example Model::$auto_prefix_models = '\MyProject\MyModels\'; //Namespaces
|
||||
*
|
||||
* @var string $auto_prefix_models
|
||||
*/
|
||||
public static $auto_prefix_models = null;
|
||||
|
||||
/**
|
||||
* Set true to to ignore namespace information when computing table names
|
||||
* from class names.
|
||||
*
|
||||
* @example Model::$short_table_names = true;
|
||||
* @example Model::$short_table_names = false; // default
|
||||
*
|
||||
* @var bool $short_table_names
|
||||
*/
|
||||
public static $short_table_names = false;
|
||||
|
||||
/**
|
||||
* The ORM instance used by this model
|
||||
* instance to communicate with the database.
|
||||
*
|
||||
* @var ORM $orm
|
||||
*/
|
||||
public $orm;
|
||||
|
||||
/**
|
||||
* Retrieve the value of a static property on a class. If the
|
||||
* class or the property does not exist, returns the default
|
||||
* value supplied as the third argument (which defaults to null).
|
||||
*
|
||||
* @param string $class_name
|
||||
* @param string $property
|
||||
* @param null|string $default
|
||||
* @return string
|
||||
*/
|
||||
protected static function _get_static_property($class_name, $property, $default=null) {
|
||||
if (!class_exists($class_name) || !property_exists($class_name, $property)) {
|
||||
return $default;
|
||||
}
|
||||
$properties = get_class_vars($class_name);
|
||||
return $properties[$property];
|
||||
}
|
||||
|
||||
/**
|
||||
* Static method to get a table name given a class name.
|
||||
* If the supplied class has a public static property
|
||||
* named $_table, the value of this property will be
|
||||
* returned.
|
||||
*
|
||||
* If not, the class name will be converted using
|
||||
* the _class_name_to_table_name method method.
|
||||
*
|
||||
* If Model::$short_table_names == true or public static
|
||||
* property $_table_use_short_name == true then $class_name passed
|
||||
* to _class_name_to_table_name is stripped of namespace information.
|
||||
*
|
||||
* @param string $class_name
|
||||
*
|
||||
*@return string
|
||||
*/
|
||||
protected static function _get_table_name($class_name) {
|
||||
$specified_table_name = self::_get_static_property($class_name, '_table');
|
||||
|
||||
$use_short_class_name = self::_use_short_table_name($class_name);
|
||||
|
||||
if ($use_short_class_name) {
|
||||
$exploded_class_name = explode('\\', $class_name);
|
||||
$class_name = end($exploded_class_name);
|
||||
}
|
||||
|
||||
if (is_null($specified_table_name)) {
|
||||
return self::_class_name_to_table_name($class_name);
|
||||
}
|
||||
return $specified_table_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should short table names, disregarding class namespaces, be computed?
|
||||
*
|
||||
* $class_property overrides $global_option, unless $class_property is null
|
||||
*
|
||||
* @param string $class_name
|
||||
* @return bool
|
||||
*/
|
||||
protected static function _use_short_table_name($class_name) {
|
||||
$global_option = self::$short_table_names;
|
||||
$class_property = self::_get_static_property($class_name, '_table_use_short_name');
|
||||
return is_null($class_property) ? $global_option : $class_property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a namespace to the standard PEAR underscore format.
|
||||
*
|
||||
* Then convert a class name in CapWords to a table name in
|
||||
* lowercase_with_underscores.
|
||||
*
|
||||
* Finally strip doubled up underscores
|
||||
*
|
||||
* For example, CarTyre would be converted to car_tyre. And
|
||||
* Project\Models\CarTyre would be project_models_car_tyre.
|
||||
*
|
||||
* @param string $class_name
|
||||
* @return string
|
||||
*/
|
||||
protected static function _class_name_to_table_name($class_name) {
|
||||
return strtolower(preg_replace(
|
||||
array('/\\\\/', '/(?<=[a-z])([A-Z])/', '/__/'),
|
||||
array('_', '_$1', '_'),
|
||||
ltrim($class_name, '\\')
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ID column name to use for this class. If it is
|
||||
* not set on the class, returns null.
|
||||
*
|
||||
* @param string $class_name
|
||||
* @return string|null
|
||||
*/
|
||||
protected static function _get_id_column_name($class_name) {
|
||||
return self::_get_static_property($class_name, '_id_column', self::DEFAULT_ID_COLUMN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a foreign key based on a table name. If the first argument
|
||||
* (the specified foreign key column name) is null, returns the second
|
||||
* argument (the name of the table) with the default foreign key column
|
||||
* suffix appended.
|
||||
*
|
||||
* @param string $specified_foreign_key_name
|
||||
* @param string $table_name
|
||||
* @return string
|
||||
*/
|
||||
protected static function _build_foreign_key_name($specified_foreign_key_name, $table_name) {
|
||||
if (!is_null($specified_foreign_key_name)) {
|
||||
return $specified_foreign_key_name;
|
||||
}
|
||||
return $table_name . self::DEFAULT_FOREIGN_KEY_SUFFIX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method used to acquire instances of the given class.
|
||||
* The class name should be supplied as a string, and the class
|
||||
* should already have been loaded by PHP (or a suitable autoloader
|
||||
* should exist). This method actually returns a wrapped ORM object
|
||||
* which allows a database query to be built. The wrapped ORM object is
|
||||
* responsible for returning instances of the correct class when
|
||||
* its find_one or find_many methods are called.
|
||||
*
|
||||
* @param string $class_name
|
||||
* @param null|string $connection_name
|
||||
* @return ORMWrapper
|
||||
*/
|
||||
public static function factory($class_name, $connection_name = null) {
|
||||
$class_name = self::$auto_prefix_models . $class_name;
|
||||
$table_name = self::_get_table_name($class_name);
|
||||
|
||||
if ($connection_name == null) {
|
||||
$connection_name = self::_get_static_property(
|
||||
$class_name,
|
||||
'_connection_name',
|
||||
ORMWrapper::DEFAULT_CONNECTION
|
||||
);
|
||||
}
|
||||
$wrapper = ORMWrapper::for_table($table_name, $connection_name);
|
||||
$wrapper->set_class_name($class_name);
|
||||
$wrapper->use_id_column(self::_get_id_column_name($class_name));
|
||||
return $wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to construct the queries for both the has_one and
|
||||
* has_many methods. These two types of association are identical; the
|
||||
* only difference is whether find_one or find_many is used to complete
|
||||
* the method chain.
|
||||
*
|
||||
* @param string $associated_class_name
|
||||
* @param null|string $foreign_key_name
|
||||
* @param null|string $foreign_key_name_in_current_models_table
|
||||
* @param null|string $connection_name
|
||||
* @return ORMWrapper
|
||||
*/
|
||||
protected function _has_one_or_many($associated_class_name, $foreign_key_name=null, $foreign_key_name_in_current_models_table=null, $connection_name=null) {
|
||||
$base_table_name = self::_get_table_name(get_class($this));
|
||||
$foreign_key_name = self::_build_foreign_key_name($foreign_key_name, $base_table_name);
|
||||
|
||||
$where_value = ''; //Value of foreign_table.{$foreign_key_name} we're
|
||||
//looking for. Where foreign_table is the actual
|
||||
//database table in the associated model.
|
||||
|
||||
if(is_null($foreign_key_name_in_current_models_table)) {
|
||||
//Match foreign_table.{$foreign_key_name} with the value of
|
||||
//{$this->_table}.{$this->id()}
|
||||
$where_value = $this->id();
|
||||
} else {
|
||||
//Match foreign_table.{$foreign_key_name} with the value of
|
||||
//{$this->_table}.{$foreign_key_name_in_current_models_table}
|
||||
$where_value = $this->$foreign_key_name_in_current_models_table;
|
||||
}
|
||||
|
||||
return self::factory($associated_class_name, $connection_name)->where($foreign_key_name, $where_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to manage one-to-one relations where the foreign
|
||||
* key is on the associated table.
|
||||
*
|
||||
* @param string $associated_class_name
|
||||
* @param null|string $foreign_key_name
|
||||
* @param null|string $foreign_key_name_in_current_models_table
|
||||
* @param null|string $connection_name
|
||||
* @return ORMWrapper
|
||||
*/
|
||||
protected function has_one($associated_class_name, $foreign_key_name=null, $foreign_key_name_in_current_models_table=null, $connection_name=null) {
|
||||
return $this->_has_one_or_many($associated_class_name, $foreign_key_name, $foreign_key_name_in_current_models_table, $connection_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to manage one-to-many relations where the foreign
|
||||
* key is on the associated table.
|
||||
*
|
||||
* @param string $associated_class_name
|
||||
* @param null|string $foreign_key_name
|
||||
* @param null|string $foreign_key_name_in_current_models_table
|
||||
* @param null|string $connection_name
|
||||
* @return ORMWrapper
|
||||
*/
|
||||
protected function has_many($associated_class_name, $foreign_key_name=null, $foreign_key_name_in_current_models_table=null, $connection_name=null) {
|
||||
return $this->_has_one_or_many($associated_class_name, $foreign_key_name, $foreign_key_name_in_current_models_table, $connection_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to manage one-to-one and one-to-many relations where
|
||||
* the foreign key is on the base table.
|
||||
*
|
||||
* @param string $associated_class_name
|
||||
* @param null|string $foreign_key_name
|
||||
* @param null|string $foreign_key_name_in_associated_models_table
|
||||
* @param null|string $connection_name
|
||||
* @return $this|null
|
||||
*/
|
||||
protected function belongs_to($associated_class_name, $foreign_key_name=null, $foreign_key_name_in_associated_models_table=null, $connection_name=null) {
|
||||
$associated_table_name = self::_get_table_name(self::$auto_prefix_models . $associated_class_name);
|
||||
$foreign_key_name = self::_build_foreign_key_name($foreign_key_name, $associated_table_name);
|
||||
$associated_object_id = $this->$foreign_key_name;
|
||||
|
||||
$desired_record = null;
|
||||
|
||||
if( is_null($foreign_key_name_in_associated_models_table) ) {
|
||||
//"{$associated_table_name}.primary_key = {$associated_object_id}"
|
||||
//NOTE: primary_key is a placeholder for the actual primary key column's name
|
||||
//in $associated_table_name
|
||||
$desired_record = self::factory($associated_class_name, $connection_name)->where_id_is($associated_object_id);
|
||||
} else {
|
||||
//"{$associated_table_name}.{$foreign_key_name_in_associated_models_table} = {$associated_object_id}"
|
||||
$desired_record = self::factory($associated_class_name, $connection_name)->where($foreign_key_name_in_associated_models_table, $associated_object_id);
|
||||
}
|
||||
|
||||
return $desired_record;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to manage many-to-many relationships via an intermediate model. See
|
||||
* README for a full explanation of the parameters.
|
||||
*
|
||||
* @param string $associated_class_name
|
||||
* @param null|string $join_class_name
|
||||
* @param null|string $key_to_base_table
|
||||
* @param null|string $key_to_associated_table
|
||||
* @param null|string $key_in_base_table
|
||||
* @param null|string $key_in_associated_table
|
||||
* @param null|string $connection_name
|
||||
* @return ORMWrapper
|
||||
*/
|
||||
protected function has_many_through($associated_class_name, $join_class_name=null, $key_to_base_table=null, $key_to_associated_table=null, $key_in_base_table=null, $key_in_associated_table=null, $connection_name=null) {
|
||||
$base_class_name = get_class($this);
|
||||
|
||||
// The class name of the join model, if not supplied, is
|
||||
// formed by concatenating the names of the base class
|
||||
// and the associated class, in alphabetical order.
|
||||
if (is_null($join_class_name)) {
|
||||
$base_model = explode('\\', $base_class_name);
|
||||
$base_model_name = end($base_model);
|
||||
if (substr($base_model_name, 0, strlen(self::$auto_prefix_models)) == self::$auto_prefix_models) {
|
||||
$base_model_name = substr($base_model_name, strlen(self::$auto_prefix_models), strlen($base_model_name));
|
||||
}
|
||||
// Paris wasn't checking the name settings for the associated class.
|
||||
$associated_model = explode('\\', $associated_class_name);
|
||||
$associated_model_name = end($associated_model);
|
||||
if (substr($associated_model_name, 0, strlen(self::$auto_prefix_models)) == self::$auto_prefix_models) {
|
||||
$associated_model_name = substr($associated_model_name, strlen(self::$auto_prefix_models), strlen($associated_model_name));
|
||||
}
|
||||
$class_names = array($base_model_name, $associated_model_name);
|
||||
|
||||
sort($class_names, SORT_STRING);
|
||||
$join_class_name = join("", $class_names);
|
||||
}
|
||||
|
||||
// Get table names for each class
|
||||
$base_table_name = self::_get_table_name($base_class_name);
|
||||
$associated_table_name = self::_get_table_name(self::$auto_prefix_models . $associated_class_name);
|
||||
$join_table_name = self::_get_table_name(self::$auto_prefix_models . $join_class_name);
|
||||
|
||||
// Get ID column names
|
||||
$base_table_id_column = (is_null($key_in_base_table)) ?
|
||||
self::_get_id_column_name($base_class_name) :
|
||||
$key_in_base_table;
|
||||
$associated_table_id_column = (is_null($key_in_associated_table)) ?
|
||||
self::_get_id_column_name(self::$auto_prefix_models . $associated_class_name) :
|
||||
$key_in_associated_table;
|
||||
|
||||
// Get the column names for each side of the join table
|
||||
$key_to_base_table = self::_build_foreign_key_name($key_to_base_table, $base_table_name);
|
||||
$key_to_associated_table = self::_build_foreign_key_name($key_to_associated_table, $associated_table_name);
|
||||
|
||||
/*
|
||||
" SELECT {$associated_table_name}.*
|
||||
FROM {$associated_table_name} JOIN {$join_table_name}
|
||||
ON {$associated_table_name}.{$associated_table_id_column} = {$join_table_name}.{$key_to_associated_table}
|
||||
WHERE {$join_table_name}.{$key_to_base_table} = {$this->$base_table_id_column} ;"
|
||||
*/
|
||||
|
||||
return self::factory($associated_class_name, $connection_name)
|
||||
->select("{$associated_table_name}.*")
|
||||
->join($join_table_name, array("{$associated_table_name}.{$associated_table_id_column}", '=', "{$join_table_name}.{$key_to_associated_table}"))
|
||||
->where("{$join_table_name}.{$key_to_base_table}", $this->$base_table_id_column); ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the wrapped ORM instance associated with this Model instance.
|
||||
*
|
||||
* @param ORM $orm
|
||||
* @return void
|
||||
*/
|
||||
public function set_orm($orm) {
|
||||
$this->orm = $orm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic getter method, allows $model->property access to data.
|
||||
*
|
||||
* @param string $property
|
||||
* @return null|string
|
||||
*/
|
||||
public function __get($property) {
|
||||
return $this->orm->get($property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic setter method, allows $model->property = 'value' access to data.
|
||||
*
|
||||
* @param string $property
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function __set($property, $value) {
|
||||
$this->orm->set($property, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic unset method, allows unset($model->property)
|
||||
*
|
||||
* @param string $property
|
||||
* @return void
|
||||
*/
|
||||
public function __unset($property) {
|
||||
$this->orm->__unset($property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic isset method, allows isset($model->property) to work correctly.
|
||||
*
|
||||
* @param string $property
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($property) {
|
||||
return $this->orm->__isset($property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter method, allows $model->get('property') access to data
|
||||
*
|
||||
* @param string $property
|
||||
* @return string
|
||||
*/
|
||||
public function get($property) {
|
||||
return $this->orm->get($property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter method, allows $model->set('property', 'value') access to data.
|
||||
*
|
||||
* @param string|array $property
|
||||
* @param string|null $value
|
||||
* @return Model
|
||||
*/
|
||||
public function set($property, $value = null) {
|
||||
$this->orm->set($property, $value);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter method, allows $model->set_expr('property', 'value') access to data.
|
||||
*
|
||||
* @param string|array $property
|
||||
* @param string|null $value
|
||||
* @return Model
|
||||
*/
|
||||
public function set_expr($property, $value = null) {
|
||||
$this->orm->set_expr($property, $value);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given field has changed since the object was created or saved
|
||||
*
|
||||
* @param string $property
|
||||
* @return bool
|
||||
*/
|
||||
public function is_dirty($property) {
|
||||
return $this->orm->is_dirty($property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the model was the result of a call to create() or not
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_new() {
|
||||
return $this->orm->is_new();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for Idiorm's as_array method.
|
||||
*
|
||||
* @return Array
|
||||
*/
|
||||
public function as_array() {
|
||||
$args = func_get_args();
|
||||
return call_user_func_array(array($this->orm, 'as_array'), $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the data associated with this model instance to the database.
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function save() {
|
||||
return $this->orm->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the database row associated with this model instance.
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function delete() {
|
||||
return $this->orm->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the database ID of this model instance.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function id() {
|
||||
return $this->orm->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrate this model instance with an associative array of data.
|
||||
* WARNING: The keys in the array MUST match with columns in the
|
||||
* corresponding database table. If any keys are supplied which
|
||||
* do not match up with columns, the database will throw an error.
|
||||
*
|
||||
* @param Array $data
|
||||
* @return void
|
||||
*/
|
||||
public function hydrate($data) {
|
||||
$this->orm->hydrate($data)->force_all_dirty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls static methods directly on the ORMWrapper
|
||||
*
|
||||
* @param string $method
|
||||
* @param Array $parameters
|
||||
* @return Array
|
||||
*/
|
||||
public static function __callStatic($method, $parameters) {
|
||||
if(function_exists('get_called_class')) {
|
||||
$model = self::factory(get_called_class());
|
||||
return call_user_func_array(array($model, $method), $parameters);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method to capture calls to undefined class methods.
|
||||
* In this case we are attempting to convert camel case formatted
|
||||
* methods into underscore formatted methods.
|
||||
*
|
||||
* This allows us to call methods using camel case and remain
|
||||
* backwards compatible.
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @throws ParisMethodMissingException
|
||||
* @return bool|ORMWrapper
|
||||
*/
|
||||
public function __call($name, $arguments) {
|
||||
$method = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $name));
|
||||
if (method_exists($this, $method)) {
|
||||
return call_user_func_array(array($this, $method), $arguments);
|
||||
} else {
|
||||
throw new ParisMethodMissingException("Method $name() does not exist in class " . get_class($this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ParisMethodMissingException extends Exception {}
|
Reference in New Issue
Block a user