Skip to content

Latest commit

 

History

History
154 lines (135 loc) · 8.04 KB

2. Active Record.md

File metadata and controls

154 lines (135 loc) · 8.04 KB

PHPFUI\ORM Active Record

Note: Referenced namespaces in this document refer to the PHPFUI\ORM defaults.

All database tables have a corresponding Record class in the \App\Record namespace named after the table name with an upper cased first letter.

An instance of an active record object represents on row of data in the corresponding table. All database fields are represented as publically accessible members of the active record object. For example:

$customer = new \App\Record\Customer(10);
echo $customer->first_name . ' ' . $customer->last_name;

The above will read record 10 from the customer table and print the first and last name. You can also add methods to the \App\Record\Customer class to get or set common things. For example you could also use $customer->fullName() in the above example by adding the following to the Customer class:

public function fullName() : string
  {
  return $this->first_name . ' ' . $this->last_name;
  }

This will update the customer record.

$customer->first_name = 'Fred';
$customer->update();

Record::__construct

A Record constructor attempts to read the specified row from the table. It can be constructed 4 ways:

  • int primary key value, will load object values if the primary key value exists.
  • string primary key value, will load object values if the primary key value exists.
  • array record is attempted to be read from database using the values of the fields provided.
  • \PHPFUI\ORM\DataObject record is constructed from an existing DataObject
  • null (default) constructs an empty object.

Both int and string parameters to the constructor are type checked. Calling the constructor with a parameter can be see as the same as the following, but with type checking:

$customer = new \App\Record\Customer();
$customer->read($value);

The basic CRUD methods:

  • insert() or create()
    • Adds the current record to the database. If the primary key already exists in the database, the insert fails. The auto increment primary key is updated with the value inserted.
    • insert() returns the primary key value inserted, true if no primary key and the record was successfully inserted or false on error.
  • insertOrUpdate() or save()
    • Will try to insert the record and on a duplicate key, will update the record with the current values.
    • insertOrUpdate() returns the same values as insert().
    • If the record only consists of primary keys, then this method is equivalent to insertOrIgnore().
  • insertOrIgnore()
    • Will try to insert the record and on a duplicate key, will not update.
    • insertOrIgnore() returns the same values as insert().
  • read(int | string | array $find)
    • Will try to load the first record matching the values passed in. If $find is an array, each key is used as a where condition equal to the value.
    • If not an array, read uses $find to search by primary key.
    • read() returns true on success or false if no match found
  • update()
    • Returns true if the record saved to the database.
  • delete()
    • Deletes the record from the database. Defined child records are also deleted. You can overload delete() to do other custom work, like deleting an associated file if desired.
    • delete() returns true on success

Other useful methods:

  • empty()
    • Returns true if all current values are the defaults
  • loaded()
    • Returns true if actually read from the database, rather than being created programmatically.
  • reload()
    • Gets the most recent version from the database and overwrites existing data.
  • setEmpty()
    • Sets all the record values to defaults.
  • setFrom(array)
    • Sets fields from the key / value array passed in.

Advanced methods:

  • clean()
    • Can be overridden to perform actions before any write to the database.
  • setCustomValidator(string $className)
    • Overrides the default validator with this class name.
  • validate(string $optionalMethod = '', ?self $originalRecord = NULL)
    • Validates the record. You can pass an optional method to validate against and original record if required by the validation.
    • Returns an array of errors indexed by field name. Empty array means the record has correctly validated.

Related Records

Related records are indicated by field name ending in the id suffix (default: 'Id'). The field name before the 'Id' must be the same as the corresponding table name. See See Virtual Fields for more advanced Related Records.

Accessing Related Records

You access the related record by the base field name (without the id suffix). The field with the id suffix is the primary key of the related record.

The following are all valid for the northwind database:

$orderDetail = new \App\Record\OrderDetail(40);
echo $orderDetail->order->employee->company . "\n";
echo $orderDetail-product->list_price . "\n";
echo $orderDetail->purchase_order->supplier->company . "\n";

Null records will return the default value.

Since a related record is read from the database every time it is accessed, if you need to do more than one thing with the record, it is best of create a local copy and perform actions on the local copy to avoid multiple database reads.

$orderDetail = new \App\Record\OrderDetail(40);
$supplier = $orderDetail->purchase_order->supplier;
echo "Supplier Address:\n{$supplier->company}\nATTN: {$supplier->first_name} {$supplier->last_name}\n{$supplier->address}\n{$supplier->city} {$supplier->state} {$supplier->zip_postal_code}\n{$supplier->country_region}\n";

Setting Related Records

You can also set a related record. An (incomplete) example of creating a new order:

$customer = new \Tests\App\Record\Customer();
$customer->address = '123 Broadway';
$customer->business_phone = '212-987-6543';
$customer->city = 'New York';
$customer->company = 'PHPFUI';
$customer->country_region = 'USA';
$customer->fax_number = '212-345-6789';
$customer->home_phone = '987-654-3210';
$customer->job_title = 'Head Honcho';
$customer->mobile_phone = '123-456-7890';
$customer->state_province = 'NY';
$customer->web_page = 'http://www.phpfui.com';
$customer->zip_postal_code = '10021';

$order = new \Tests\App\Record\Order();
$order->employee_id = 9;
$order->customer = $customer;
$order->order_date = date("Y-m-d H:i:s");
$shipper = new \Tests\App\Record\Shipper();
$shipper->read(['company' => 'Shipping Company B']);
$order->shipper = $shipper;
$order->ship_name = $customer->company;
$order->ship_address = $customer->address;
$order->ship_city = $customer->city;
$order->ship_state_province = $customer->state_province;
$order->ship_zip_postal_code = $customer->zip_postal_code;
$order->ship_country_region = $customer->country_region;
$order->shipping_fee = 12.95;
$order->taxes = 2.37;
$order->payment_type = 'PO 54321';
$order->notes = 'Test Order';
$order->tax_rate = 5.25;
$order->order_tax_status_id = 1;
$order->order_status_id = 1;
$order->insert();

Notice that we did not have to save the customer record. By assigning it to the order record, it was automatically saved to generate the required primary key value. The related record is not saved if it already has been assigned a primary key, it is your responsiblity to save it if you changed an existing record.

Alternate Way To Set Related Records

You can always just assign the id's directly: $orderDetail->purchase_order_id = $purchase_order->purchase_order_id;. Saving the OrderDetail record is up to you.

Other Types Of Related Records

See Virtual Fields for information on how to impliment child or many to many relationships.

Multi Database Support

Related Records will always return a record from the currently selected database. Care must be taken when using multiple databases that any references to related records are done while the correct database instance is active. Cursors will continue to use the database in effect when they were created.

A future version of this libray may offer better multi database support.