Skip to content

Instantly share code, notes, and snippets.

@deathlyfrantic
Created March 21, 2016 16:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save deathlyfrantic/8c93addb6ed3b46597ce to your computer and use it in GitHub Desktop.
Save deathlyfrantic/8c93addb6ed3b46597ce to your computer and use it in GitHub Desktop.
the start of a mini-framework for object<->db abstraction that i will not finish because it's reinvention of the wheel
<?php
function coerceToCamelCase($string)
{
$camel = "";
$i = 0;
$upper = false;
while($i < mb_strlen($string)) {
$char = $string[$i];
if($char === "_") {
$upper = true;
} elseif($upper) {
$camel .= mb_strtoupper($char);
$upper = false;
} else {
$camel .= mb_strtolower($char);
}
$i++;
}
return $camel;
}
function coerceToSnakeCase($string)
{
$snake = "";
$i = 0;
while($i < mb_strlen($string)) {
$char = $string[$i];
if(mb_strtolower($char) === $char) {
$snake .= $char;
} elseif($i === 0) {
$snake .= mb_strtolower($char);
} else {
$snake .= "_".mb_strtolower($char);
}
$i++;
}
return $snake;
}
abstract class Base
{
protected $properties = [];
protected function table()
{
return coerceToSnakeCase(get_class($this));
}
public function __construct($id = null)
{
foreach($this->properties as $name => $fieldType) {
$prop = new $fieldType();
$prop->setName($name);
$this->properties[$name] = $prop;
}
$idField = new IntegerField();
$idField->setName("id");
$this->properties["id"] = $idField;
if(is_numeric($id)) {
$this->id = $id;
$this->load();
}
return $this;
}
public function __call($name, $args)
{
if(mb_stripos($name, "get") === 0) {
$prop = mb_substr($name, 3);
$prop[0] = mb_strtolower($prop[0]);
return $this->getter($prop);
}
if(mb_stripos($name, "set") === 0) {
$prop = mb_substr($name, 3);
$prop[0] = mb_strtolower($prop[0]);
return $this->setter($prop, $args[0]);
}
}
public function __get($name)
{
return $this->getter($name);
}
public function __set($name, $value)
{
$this->setter($name, $value);
return $this;
}
protected function setter($name, $value)
{
if(array_key_exists($name, $this->properties)) {
$this->properties[$name]->setValue($value);
} else {
$this->$name = $value;
}
return $this;
}
protected function getter($name)
{
if(array_key_exists($name, $this->properties)) {
return $this->properties[$name]->getValue();
} elseif(property_exists($this, $name)) {
return $this->$name;
} else {
$thisObject = get_class($this);
throw new InvalidPropertyException("`$name` is not a valid property of this object ($thisObject)");
}
}
public function save()
{
$params = [];
foreach($this->properties as $prop) {
if($prop->changed && $prop->getName() !== "id") {
$params[$prop->getSnakeCaseName()] = $prop->getValue();
}
}
if(count($params) > 0) {
if(is_numeric($this->id)) {
// update query
$cols = array_map(
function ($col) {
return "$col = ?";
},
array_keys($params)
);
$colsString = implode(", ", $cols);
$params["id"] = $this->id;
$query = "UPDATE `{$this->table()}` SET $colsString WHERE id = ?;";
} else {
// insert query
$colsString = implode(", ", array_keys($params));
$marks = implode(", ", array_fill(0, count($params), "?"));
$query = "INSERT INTO `{$this->table()}` ($colsString) VALUES ($marks)";
}
} else {
$query = "no changed properties, nothing to do";
}
$this->resetPropertyChangedFlags();
return [$query, $params];
}
public function resetPropertyChangedFlags()
{
foreach($this->properties as $prop) {
$prop->changed = false;
}
return $this;
}
public function load()
{
$query = "SELECT * FROM `{$this->table()}` WHERE id = ?";
$param = $this->id;
// $result = someFetchRowFunction();
$result = [
// for testing
"first_name" => "Jimmy",
"last_name" => "Smith",
"age" => 20
];
$this->setProperties($result);
return $this;
}
public function delete()
{
$query = "DELETE FROM `{$this->table()}` WHERE id = ?";
$param = $this->id;
// $success = someDeleteRowFunction();
return $success;
}
public function setProperties(array $data)
{
foreach($data as $field => $value) {
$prop = $this->properties[coerceToCamelCase($field)];
$prop->setValue($value);
}
$this->resetPropertyChangedFlags();
return $this;
}
}
class Person extends Base
{
protected $properties = [
"firstName" => "StringField",
"lastName" => "StringField",
"age" => "IntegerField",
];
public function getFullName()
{
$fullName = [];
foreach([$this->firstName, $this->lastName] as $name) {
if(mb_strlen($name) > 0) {
$fullName[] = $name;
}
}
return implode(" ", $fullName);
}
}
abstract class Field
{
protected $name;
protected $value;
public $changed = false;
public function getName()
{
return $this->name;
}
public function getSnakeCaseName()
{
return coerceToSnakeCase($this->getName());
}
public function setName($name)
{
$this->name = $name;
return $this;
}
public function getValue()
{
return $this->value;
}
public function setValue($value)
{
if($this->validate($value)) {
$this->value = $this->coerce($value);
} elseif(is_null($value)) {
$this->value = null;
} else {
$thisType = get_class($this);
throw new InvalidValueException("`$value` is not a valid value for a property of this type ($thisType)");
}
$this->changed = true;
return $this;
}
public abstract function coerce($value);
public abstract function validate($value);
}
class StringField extends Field
{
public function coerce($value)
{
return $value;
}
public function validate($value)
{
return true;
}
}
class IntegerField extends Field
{
public function validate($value)
{
return is_int($value);
}
public function coerce($value)
{
return (int)$value;
}
}
class FloatField extends Field
{
public function validate($value)
{
return is_float($value);
}
public function coerce($value)
{
return (float)$value;
}
}
class BooleanField extends Field
{
public function validate($value)
{
return is_bool($value) || (is_int($value) && in_array($value, [0, 1]));
}
public function coerce($value)
{
return (bool)$value;
}
}
class InvalidPropertyException extends \Exception {}
class InvalidValueException extends \Exception {}
$p = new Person();
$p->firstName = "John";
$p->lastName = "Doe";
$p->age = 30;
print_r($p);
echo "{$p->firstName}'s age is {$p->age}\n";
print_r($p->save());
$p->id = 1;
$p->age = 31;
print_r($p->save());
$p->firstName = "Johnathan";
$p->lastName = "Doeson";
print_r($p->save());
$p2 = new Person(1);
print_r($p2);
echo print_r($p2->getFullName(), true)."\n";
print_r($p2->save());
try {
echo $p2->flibberty;
} catch(InvalidPropertyException $e) {
echo "exception caught: {$e->getMessage()}\n";
}
try {
$p2->age = "spam";
} catch(InvalidValueException $e) {
echo "exception caught: {$e->getMessage()}\n";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment