Repository files navigation

Phaster

Phaster is a PSR-7 compatible library for easily making CRUD API endpoints. It enables mapping API fields to columns in the database or from a select query, and implementing custom validation or row modification logic. Built on top of PeachySQL.

Installation

composer require devtheorem/phaster

Usage

Create a class extending Entities, and implement the methods to map properties to columns and define the base SQL query (see example below). Pass the callable returned by the route handling functions to your Slim or other PSR-7 compatible framework.

<?phpuseDevTheorem\Phaster\{Entities, Prop, QueryOptions};
class Users extends Entities
{
// Return the table to insert/update/delete/select from.// If not implemented, the class name will be used as the table name.protectedfunctiongetTableName(): string
{
return'users';
}
// Return an array which maps properties to writable column names. Returns an// empty array by default, so no properties will be writable if not implemented.protectedfunctiongetMap(): array
{
return [
'username' => 'uname',
'firstName' => 'fname',
'lastName' => 'lname',
'isDisabled' => 'disabled',
'role' => [
'id' => 'role_id',
],
];
}
// Return a list of `Prop` objects, which map properties to readable columns and/or values,// and enable setting a type to cast the column value to, or defining a virtual property// which depends on other columns. See the Prop constructor for the full list of parameters// that can be set. Returns an empty array by default.protectedfunctiongetSelectProps(): array
{
return [
newProp('id', col: 'u.user_id'),
newProp('username', col: 'u.uname'),
newProp('firstName', col: 'u.fname'),
newProp('lastName', col: 'u.lname'),
newProp('isDisabled', col: 'u.disabled', type: 'bool'),
newProp('role.id', col: 'u.role_id'),
newProp('role.name', col: 'r.role_name'),
];
}
// Return a SELECT SQL query (without a WHERE clause) in order to join other tables when// selecting data. If not implemented, mapped columns will be selected from the table// returned by getTableName().protectedfunctiongetBaseQuery(QueryOptions$options): string
{
return"SELECT {$options->getColumns()} FROM users u INNER JOIN roles r ON r.role_id = u.role_id";
}
// Set the default column/direction for sorting selected results. If not implemented,// results will be sorted by the id property in ascending order by default.protectedfunctiongetDefaultSort(): array
{
return ['username' => 'asc'];
}
}

If it is necessary to bind parameters in the base query, use getBaseSelect() instead:

useDevTheorem\PeachySQL\QueryBuilder\SqlParams;
// ...protectedfunctiongetBaseSelect(QueryOptions$options): SqlParams
{
$sql = "WITH num_orders AS ( SELECT user_id, COUNT(*) as orders FROM Orders WHERE category_id = ? GROUP BY user_id ) SELECT {$options->getColumns()} FROM Users u INNER JOIN num_orders n ON n.user_id = u.user_id";
returnnewSqlParams($sql, [321]);
}
// ...
<?phpuseMy\DatabaseFactory;
useDevTheorem\Phaster\{Entities, EntitiesFactory};
class MyEntitiesFactory implements EntitiesFactory
{
publicfunctioncreateEntities($class): Entities
{
returnnew$class(DatabaseFactory::getDb());
}
}
<?phpuseDevTheorem\Phaster\RouteHandler;
$phaster = newRouteHandler(newMyEntitiesFactory());
$app->get('/users', $phaster->search(Users::class));
$app->get('/users/{id}', $phaster->getById(Users::class));
$app->post('/users', $phaster->insert(Users::class));
$app->put('/users/{id}', $phaster->update(Users::class));
$app->patch('/users/{id}', $phaster->patch(Users::class));
$app->delete('/users/{id}', $phaster->delete(Users::class));

Example API request/response

GET https://example.com/api/users?q[firstName]=Ted&q[isDisabled]=0&fields=id,username,role

{
"offset": 0,
"limit": 25,
"lastPage": true,
"data": [
{
"id": 5,
"username": "Teddy01",
"role": {
"id": 1,
"name": "Admin"
}
},
{
"id": 38,
"username": "only_tj",
"role": {
"id": 2,
"name": "Standard"
}
}
]
}

Author

Theodore Brown
https://theodorejb.me

License

MIT

About

A PSR-7 compatible library for easily making CRUD API endpoints

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Phaster

Phaster is a PSR-7 compatible library for easily making CRUD API endpoints. It enables mapping API fields to columns in the database or from a select query, and implementing custom validation or row modification logic. Built on top of PeachySQL.

Installation

composer require devtheorem/phaster

Usage

Create a class extending Entities, and implement the methods to map properties to columns and define the base SQL query (see example below). Pass the callable returned by the route handling functions to your Slim or other PSR-7 compatible framework.

<?phpuseDevTheorem\Phaster\{Entities, Prop, QueryOptions};
class Users extends Entities
{
// Return the table to insert/update/delete/select from.// If not implemented, the class name will be used as the table name.protectedfunctiongetTableName(): string
{
return'users';
}
// Return an array which maps properties to writable column names. Returns an// empty array by default, so no properties will be writable if not implemented.protectedfunctiongetMap(): array
{
return [
'username' => 'uname',
'firstName' => 'fname',
'lastName' => 'lname',
'isDisabled' => 'disabled',
'role' => [
'id' => 'role_id',
],
];
}
// Return a list of `Prop` objects, which map properties to readable columns and/or values,// and enable setting a type to cast the column value to, or defining a virtual property// which depends on other columns. See the Prop constructor for the full list of parameters// that can be set. Returns an empty array by default.protectedfunctiongetSelectProps(): array
{
return [
newProp('id', col: 'u.user_id'),
newProp('username', col: 'u.uname'),
newProp('firstName', col: 'u.fname'),
newProp('lastName', col: 'u.lname'),
newProp('isDisabled', col: 'u.disabled', type: 'bool'),
newProp('role.id', col: 'u.role_id'),
newProp('role.name', col: 'r.role_name'),
];
}
// Return a SELECT SQL query (without a WHERE clause) in order to join other tables when// selecting data. If not implemented, mapped columns will be selected from the table// returned by getTableName().protectedfunctiongetBaseQuery(QueryOptions$options): string
{
return"SELECT {$options->getColumns()} FROM users u INNER JOIN roles r ON r.role_id = u.role_id";
}
// Set the default column/direction for sorting selected results. If not implemented,// results will be sorted by the id property in ascending order by default.protectedfunctiongetDefaultSort(): array
{
return ['username' => 'asc'];
}
}

If it is necessary to bind parameters in the base query, use getBaseSelect() instead:

useDevTheorem\PeachySQL\QueryBuilder\SqlParams;
// ...protectedfunctiongetBaseSelect(QueryOptions$options): SqlParams
{
$sql = "WITH num_orders AS ( SELECT user_id, COUNT(*) as orders FROM Orders WHERE category_id = ? GROUP BY user_id ) SELECT {$options->getColumns()} FROM Users u INNER JOIN num_orders n ON n.user_id = u.user_id";
returnnewSqlParams($sql, [321]);
}
// ...
<?phpuseMy\DatabaseFactory;
useDevTheorem\Phaster\{Entities, EntitiesFactory};
class MyEntitiesFactory implements EntitiesFactory
{
publicfunctioncreateEntities($class): Entities
{
returnnew$class(DatabaseFactory::getDb());
}
}
<?phpuseDevTheorem\Phaster\RouteHandler;
$phaster = newRouteHandler(newMyEntitiesFactory());
$app->get('/users', $phaster->search(Users::class));
$app->get('/users/{id}', $phaster->getById(Users::class));
$app->post('/users', $phaster->insert(Users::class));
$app->put('/users/{id}', $phaster->update(Users::class));
$app->patch('/users/{id}', $phaster->patch(Users::class));
$app->delete('/users/{id}', $phaster->delete(Users::class));

Example API request/response

GET https://example.com/api/users?q[firstName]=Ted&q[isDisabled]=0&fields=id,username,role

{
"offset": 0,
"limit": 25,
"lastPage": true,
"data": [
{
"id": 5,
"username": "Teddy01",
"role": {
"id": 1,
"name": "Admin"
}
},
{
"id": 38,
"username": "only_tj",
"role": {
"id": 2,
"name": "Standard"
}
}
]
}

Author

Theodore Brown
https://theodorejb.me

License

MIT

About

A PSR-7 compatible library for easily making CRUD API endpoints

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Phaster

Phaster is a PSR-7 compatible library for easily making CRUD API endpoints. It enables mapping API fields to columns in the database or from a select query, and implementing custom validation or row modification logic. Built on top of PeachySQL.

Installation

composer require devtheorem/phaster

Usage

Create a class extending Entities, and implement the methods to map properties to columns and define the base SQL query (see example below). Pass the callable returned by the route handling functions to your Slim or other PSR-7 compatible framework.

<?phpuseDevTheorem\Phaster\{Entities, Prop, QueryOptions};
class Users extends Entities
{
// Return the table to insert/update/delete/select from.// If not implemented, the class name will be used as the table name.protectedfunctiongetTableName(): string
{
return'users';
}
// Return an array which maps properties to writable column names. Returns an// empty array by default, so no properties will be writable if not implemented.protectedfunctiongetMap(): array
{
return [
'username' => 'uname',
'firstName' => 'fname',
'lastName' => 'lname',
'isDisabled' => 'disabled',
'role' => [
'id' => 'role_id',
],
];
}
// Return a list of `Prop` objects, which map properties to readable columns and/or values,// and enable setting a type to cast the column value to, or defining a virtual property// which depends on other columns. See the Prop constructor for the full list of parameters// that can be set. Returns an empty array by default.protectedfunctiongetSelectProps(): array
{
return [
newProp('id', col: 'u.user_id'),
newProp('username', col: 'u.uname'),
newProp('firstName', col: 'u.fname'),
newProp('lastName', col: 'u.lname'),
newProp('isDisabled', col: 'u.disabled', type: 'bool'),
newProp('role.id', col: 'u.role_id'),
newProp('role.name', col: 'r.role_name'),
];
}
// Return a SELECT SQL query (without a WHERE clause) in order to join other tables when// selecting data. If not implemented, mapped columns will be selected from the table// returned by getTableName().protectedfunctiongetBaseQuery(QueryOptions$options): string
{
return"SELECT {$options->getColumns()} FROM users u INNER JOIN roles r ON r.role_id = u.role_id";
}
// Set the default column/direction for sorting selected results. If not implemented,// results will be sorted by the id property in ascending order by default.protectedfunctiongetDefaultSort(): array
{
return ['username' => 'asc'];
}
}

If it is necessary to bind parameters in the base query, use getBaseSelect() instead:

useDevTheorem\PeachySQL\QueryBuilder\SqlParams;
// ...protectedfunctiongetBaseSelect(QueryOptions$options): SqlParams
{
$sql = "WITH num_orders AS ( SELECT user_id, COUNT(*) as orders FROM Orders WHERE category_id = ? GROUP BY user_id ) SELECT {$options->getColumns()} FROM Users u INNER JOIN num_orders n ON n.user_id = u.user_id";
returnnewSqlParams($sql, [321]);
}
// ...
<?phpuseMy\DatabaseFactory;
useDevTheorem\Phaster\{Entities, EntitiesFactory};
class MyEntitiesFactory implements EntitiesFactory
{
publicfunctioncreateEntities($class): Entities
{
returnnew$class(DatabaseFactory::getDb());
}
}
<?phpuseDevTheorem\Phaster\RouteHandler;
$phaster = newRouteHandler(newMyEntitiesFactory());
$app->get('/users', $phaster->search(Users::class));
$app->get('/users/{id}', $phaster->getById(Users::class));
$app->post('/users', $phaster->insert(Users::class));
$app->put('/users/{id}', $phaster->update(Users::class));
$app->patch('/users/{id}', $phaster->patch(Users::class));
$app->delete('/users/{id}', $phaster->delete(Users::class));

Example API request/response

GET https://example.com/api/users?q[firstName]=Ted&q[isDisabled]=0&fields=id,username,role

{
"offset": 0,
"limit": 25,
"lastPage": true,
"data": [
{
"id": 5,
"username": "Teddy01",
"role": {
"id": 1,
"name": "Admin"
}
},
{
"id": 38,
"username": "only_tj",
"role": {
"id": 2,
"name": "Standard"
}
}
]
}

Author

Theodore Brown
https://theodorejb.me

License

MIT

About

A PSR-7 compatible library for easily making CRUD API endpoints

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Phaster

Phaster is a PSR-7 compatible library for easily making CRUD API endpoints. It enables mapping API fields to columns in the database or from a select query, and implementing custom validation or row modification logic. Built on top of PeachySQL.

Installation

composer require devtheorem/phaster

Usage

Create a class extending Entities, and implement the methods to map properties to columns and define the base SQL query (see example below). Pass the callable returned by the route handling functions to your Slim or other PSR-7 compatible framework.

<?phpuseDevTheorem\Phaster\{Entities, Prop, QueryOptions};
class Users extends Entities
{
// Return the table to insert/update/delete/select from.// If not implemented, the class name will be used as the table name.protectedfunctiongetTableName(): string
{
return'users';
}
// Return an array which maps properties to writable column names. Returns an// empty array by default, so no properties will be writable if not implemented.protectedfunctiongetMap(): array
{
return [
'username' => 'uname',
'firstName' => 'fname',
'lastName' => 'lname',
'isDisabled' => 'disabled',
'role' => [
'id' => 'role_id',
],
];
}
// Return a list of `Prop` objects, which map properties to readable columns and/or values,// and enable setting a type to cast the column value to, or defining a virtual property// which depends on other columns. See the Prop constructor for the full list of parameters// that can be set. Returns an empty array by default.protectedfunctiongetSelectProps(): array
{
return [
newProp('id', col: 'u.user_id'),
newProp('username', col: 'u.uname'),
newProp('firstName', col: 'u.fname'),
newProp('lastName', col: 'u.lname'),
newProp('isDisabled', col: 'u.disabled', type: 'bool'),
newProp('role.id', col: 'u.role_id'),
newProp('role.name', col: 'r.role_name'),
];
}
// Return a SELECT SQL query (without a WHERE clause) in order to join other tables when// selecting data. If not implemented, mapped columns will be selected from the table// returned by getTableName().protectedfunctiongetBaseQuery(QueryOptions$options): string
{
return"SELECT {$options->getColumns()} FROM users u INNER JOIN roles r ON r.role_id = u.role_id";
}
// Set the default column/direction for sorting selected results. If not implemented,// results will be sorted by the id property in ascending order by default.protectedfunctiongetDefaultSort(): array
{
return ['username' => 'asc'];
}
}

If it is necessary to bind parameters in the base query, use getBaseSelect() instead:

useDevTheorem\PeachySQL\QueryBuilder\SqlParams;
// ...protectedfunctiongetBaseSelect(QueryOptions$options): SqlParams
{
$sql = "WITH num_orders AS ( SELECT user_id, COUNT(*) as orders FROM Orders WHERE category_id = ? GROUP BY user_id ) SELECT {$options->getColumns()} FROM Users u INNER JOIN num_orders n ON n.user_id = u.user_id";
returnnewSqlParams($sql, [321]);
}
// ...
<?phpuseMy\DatabaseFactory;
useDevTheorem\Phaster\{Entities, EntitiesFactory};
class MyEntitiesFactory implements EntitiesFactory
{
publicfunctioncreateEntities($class): Entities
{
returnnew$class(DatabaseFactory::getDb());
}
}
<?phpuseDevTheorem\Phaster\RouteHandler;
$phaster = newRouteHandler(newMyEntitiesFactory());
$app->get('/users', $phaster->search(Users::class));
$app->get('/users/{id}', $phaster->getById(Users::class));
$app->post('/users', $phaster->insert(Users::class));
$app->put('/users/{id}', $phaster->update(Users::class));
$app->patch('/users/{id}', $phaster->patch(Users::class));
$app->delete('/users/{id}', $phaster->delete(Users::class));

Example API request/response

GET https://example.com/api/users?q[firstName]=Ted&q[isDisabled]=0&fields=id,username,role

{
"offset": 0,
"limit": 25,
"lastPage": true,
"data": [
{
"id": 5,
"username": "Teddy01",
"role": {
"id": 1,
"name": "Admin"
}
},
{
"id": 38,
"username": "only_tj",
"role": {
"id": 2,
"name": "Standard"
}
}
]
}

Author

Theodore Brown
https://theodorejb.me

License

MIT

About

A PSR-7 compatible library for easily making CRUD API endpoints

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Phaster

Phaster is a PSR-7 compatible library for easily making CRUD API endpoints. It enables mapping API fields to columns in the database or from a select query, and implementing custom validation or row modification logic. Built on top of PeachySQL.

Installation

composer require devtheorem/phaster

Usage

Create a class extending Entities, and implement the methods to map properties to columns and define the base SQL query (see example below). Pass the callable returned by the route handling functions to your Slim or other PSR-7 compatible framework.

<?phpuseDevTheorem\Phaster\{Entities, Prop, QueryOptions};
class Users extends Entities
{
// Return the table to insert/update/delete/select from.// If not implemented, the class name will be used as the table name.protectedfunctiongetTableName(): string
{
return'users';
}
// Return an array which maps properties to writable column names. Returns an// empty array by default, so no properties will be writable if not implemented.protectedfunctiongetMap(): array
{
return [
'username' => 'uname',
'firstName' => 'fname',
'lastName' => 'lname',
'isDisabled' => 'disabled',
'role' => [
'id' => 'role_id',
],
];
}
// Return a list of `Prop` objects, which map properties to readable columns and/or values,// and enable setting a type to cast the column value to, or defining a virtual property// which depends on other columns. See the Prop constructor for the full list of parameters// that can be set. Returns an empty array by default.protectedfunctiongetSelectProps(): array
{
return [
newProp('id', col: 'u.user_id'),
newProp('username', col: 'u.uname'),
newProp('firstName', col: 'u.fname'),
newProp('lastName', col: 'u.lname'),
newProp('isDisabled', col: 'u.disabled', type: 'bool'),
newProp('role.id', col: 'u.role_id'),
newProp('role.name', col: 'r.role_name'),
];
}
// Return a SELECT SQL query (without a WHERE clause) in order to join other tables when// selecting data. If not implemented, mapped columns will be selected from the table// returned by getTableName().protectedfunctiongetBaseQuery(QueryOptions$options): string
{
return"SELECT {$options->getColumns()} FROM users u INNER JOIN roles r ON r.role_id = u.role_id";
}
// Set the default column/direction for sorting selected results. If not implemented,// results will be sorted by the id property in ascending order by default.protectedfunctiongetDefaultSort(): array
{
return ['username' => 'asc'];
}
}

If it is necessary to bind parameters in the base query, use getBaseSelect() instead:

useDevTheorem\PeachySQL\QueryBuilder\SqlParams;
// ...protectedfunctiongetBaseSelect(QueryOptions$options): SqlParams
{
$sql = "WITH num_orders AS ( SELECT user_id, COUNT(*) as orders FROM Orders WHERE category_id = ? GROUP BY user_id ) SELECT {$options->getColumns()} FROM Users u INNER JOIN num_orders n ON n.user_id = u.user_id";
returnnewSqlParams($sql, [321]);
}
// ...
<?phpuseMy\DatabaseFactory;
useDevTheorem\Phaster\{Entities, EntitiesFactory};
class MyEntitiesFactory implements EntitiesFactory
{
publicfunctioncreateEntities($class): Entities
{
returnnew$class(DatabaseFactory::getDb());
}
}
<?phpuseDevTheorem\Phaster\RouteHandler;
$phaster = newRouteHandler(newMyEntitiesFactory());
$app->get('/users', $phaster->search(Users::class));
$app->get('/users/{id}', $phaster->getById(Users::class));
$app->post('/users', $phaster->insert(Users::class));
$app->put('/users/{id}', $phaster->update(Users::class));
$app->patch('/users/{id}', $phaster->patch(Users::class));
$app->delete('/users/{id}', $phaster->delete(Users::class));

Example API request/response

GET https://example.com/api/users?q[firstName]=Ted&q[isDisabled]=0&fields=id,username,role

{
"offset": 0,
"limit": 25,
"lastPage": true,
"data": [
{
"id": 5,
"username": "Teddy01",
"role": {
"id": 1,
"name": "Admin"
}
},
{
"id": 38,
"username": "only_tj",
"role": {
"id": 2,
"name": "Standard"
}
}
]
}

Author

Theodore Brown
https://theodorejb.me

License

MIT

About

A PSR-7 compatible library for easily making CRUD API endpoints

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Phaster

Phaster is a PSR-7 compatible library for easily making CRUD API endpoints. It enables mapping API fields to columns in the database or from a select query, and implementing custom validation or row modification logic. Built on top of PeachySQL.

Installation

composer require devtheorem/phaster

Usage

Create a class extending Entities, and implement the methods to map properties to columns and define the base SQL query (see example below). Pass the callable returned by the route handling functions to your Slim or other PSR-7 compatible framework.

<?phpuseDevTheorem\Phaster\{Entities, Prop, QueryOptions};
class Users extends Entities
{
// Return the table to insert/update/delete/select from.// If not implemented, the class name will be used as the table name.protectedfunctiongetTableName(): string
{
return'users';
}
// Return an array which maps properties to writable column names. Returns an// empty array by default, so no properties will be writable if not implemented.protectedfunctiongetMap(): array
{
return [
'username' => 'uname',
'firstName' => 'fname',
'lastName' => 'lname',
'isDisabled' => 'disabled',
'role' => [
'id' => 'role_id',
],
];
}
// Return a list of `Prop` objects, which map properties to readable columns and/or values,// and enable setting a type to cast the column value to, or defining a virtual property// which depends on other columns. See the Prop constructor for the full list of parameters// that can be set. Returns an empty array by default.protectedfunctiongetSelectProps(): array
{
return [
newProp('id', col: 'u.user_id'),
newProp('username', col: 'u.uname'),
newProp('firstName', col: 'u.fname'),
newProp('lastName', col: 'u.lname'),
newProp('isDisabled', col: 'u.disabled', type: 'bool'),
newProp('role.id', col: 'u.role_id'),
newProp('role.name', col: 'r.role_name'),
];
}
// Return a SELECT SQL query (without a WHERE clause) in order to join other tables when// selecting data. If not implemented, mapped columns will be selected from the table// returned by getTableName().protectedfunctiongetBaseQuery(QueryOptions$options): string
{
return"SELECT {$options->getColumns()} FROM users u INNER JOIN roles r ON r.role_id = u.role_id";
}
// Set the default column/direction for sorting selected results. If not implemented,// results will be sorted by the id property in ascending order by default.protectedfunctiongetDefaultSort(): array
{
return ['username' => 'asc'];
}
}

If it is necessary to bind parameters in the base query, use getBaseSelect() instead:

useDevTheorem\PeachySQL\QueryBuilder\SqlParams;
// ...protectedfunctiongetBaseSelect(QueryOptions$options): SqlParams
{
$sql = "WITH num_orders AS ( SELECT user_id, COUNT(*) as orders FROM Orders WHERE category_id = ? GROUP BY user_id ) SELECT {$options->getColumns()} FROM Users u INNER JOIN num_orders n ON n.user_id = u.user_id";
returnnewSqlParams($sql, [321]);
}
// ...
<?phpuseMy\DatabaseFactory;
useDevTheorem\Phaster\{Entities, EntitiesFactory};
class MyEntitiesFactory implements EntitiesFactory
{
publicfunctioncreateEntities($class): Entities
{
returnnew$class(DatabaseFactory::getDb());
}
}
<?phpuseDevTheorem\Phaster\RouteHandler;
$phaster = newRouteHandler(newMyEntitiesFactory());
$app->get('/users', $phaster->search(Users::class));
$app->get('/users/{id}', $phaster->getById(Users::class));
$app->post('/users', $phaster->insert(Users::class));
$app->put('/users/{id}', $phaster->update(Users::class));
$app->patch('/users/{id}', $phaster->patch(Users::class));
$app->delete('/users/{id}', $phaster->delete(Users::class));

Example API request/response

GET https://example.com/api/users?q[firstName]=Ted&q[isDisabled]=0&fields=id,username,role

{
"offset": 0,
"limit": 25,
"lastPage": true,
"data": [
{
"id": 5,
"username": "Teddy01",
"role": {
"id": 1,
"name": "Admin"
}
},
{
"id": 38,
"username": "only_tj",
"role": {
"id": 2,
"name": "Standard"
}
}
]
}

Author

Theodore Brown
https://theodorejb.me

License

MIT

About

A PSR-7 compatible library for easily making CRUD API endpoints

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Phaster

Phaster is a PSR-7 compatible library for easily making CRUD API endpoints. It enables mapping API fields to columns in the database or from a select query, and implementing custom validation or row modification logic. Built on top of PeachySQL.

Installation

composer require devtheorem/phaster

Usage

Create a class extending Entities, and implement the methods to map properties to columns and define the base SQL query (see example below). Pass the callable returned by the route handling functions to your Slim or other PSR-7 compatible framework.

<?phpuseDevTheorem\Phaster\{Entities, Prop, QueryOptions};
class Users extends Entities
{
// Return the table to insert/update/delete/select from.// If not implemented, the class name will be used as the table name.protectedfunctiongetTableName(): string
{
return'users';
}
// Return an array which maps properties to writable column names. Returns an// empty array by default, so no properties will be writable if not implemented.protectedfunctiongetMap(): array
{
return [
'username' => 'uname',
'firstName' => 'fname',
'lastName' => 'lname',
'isDisabled' => 'disabled',
'role' => [
'id' => 'role_id',
],
];
}
// Return a list of `Prop` objects, which map properties to readable columns and/or values,// and enable setting a type to cast the column value to, or defining a virtual property// which depends on other columns. See the Prop constructor for the full list of parameters// that can be set. Returns an empty array by default.protectedfunctiongetSelectProps(): array
{
return [
newProp('id', col: 'u.user_id'),
newProp('username', col: 'u.uname'),
newProp('firstName', col: 'u.fname'),
newProp('lastName', col: 'u.lname'),
newProp('isDisabled', col: 'u.disabled', type: 'bool'),
newProp('role.id', col: 'u.role_id'),
newProp('role.name', col: 'r.role_name'),
];
}
// Return a SELECT SQL query (without a WHERE clause) in order to join other tables when// selecting data. If not implemented, mapped columns will be selected from the table// returned by getTableName().protectedfunctiongetBaseQuery(QueryOptions$options): string
{
return"SELECT {$options->getColumns()} FROM users u INNER JOIN roles r ON r.role_id = u.role_id";
}
// Set the default column/direction for sorting selected results. If not implemented,// results will be sorted by the id property in ascending order by default.protectedfunctiongetDefaultSort(): array
{
return ['username' => 'asc'];
}
}

If it is necessary to bind parameters in the base query, use getBaseSelect() instead:

useDevTheorem\PeachySQL\QueryBuilder\SqlParams;
// ...protectedfunctiongetBaseSelect(QueryOptions$options): SqlParams
{
$sql = "WITH num_orders AS ( SELECT user_id, COUNT(*) as orders FROM Orders WHERE category_id = ? GROUP BY user_id ) SELECT {$options->getColumns()} FROM Users u INNER JOIN num_orders n ON n.user_id = u.user_id";
returnnewSqlParams($sql, [321]);
}
// ...
<?phpuseMy\DatabaseFactory;
useDevTheorem\Phaster\{Entities, EntitiesFactory};
class MyEntitiesFactory implements EntitiesFactory
{
publicfunctioncreateEntities($class): Entities
{
returnnew$class(DatabaseFactory::getDb());
}
}
<?phpuseDevTheorem\Phaster\RouteHandler;
$phaster = newRouteHandler(newMyEntitiesFactory());
$app->get('/users', $phaster->search(Users::class));
$app->get('/users/{id}', $phaster->getById(Users::class));
$app->post('/users', $phaster->insert(Users::class));
$app->put('/users/{id}', $phaster->update(Users::class));
$app->patch('/users/{id}', $phaster->patch(Users::class));
$app->delete('/users/{id}', $phaster->delete(Users::class));

Example API request/response

GET https://example.com/api/users?q[firstName]=Ted&q[isDisabled]=0&fields=id,username,role

{
"offset": 0,
"limit": 25,
"lastPage": true,
"data": [
{
"id": 5,
"username": "Teddy01",
"role": {
"id": 1,
"name": "Admin"
}
},
{
"id": 38,
"username": "only_tj",
"role": {
"id": 2,
"name": "Standard"
}
}
]
}

Author

Theodore Brown
https://theodorejb.me

License

MIT

About

A PSR-7 compatible library for easily making CRUD API endpoints

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Phaster

Phaster is a PSR-7 compatible library for easily making CRUD API endpoints. It enables mapping API fields to columns in the database or from a select query, and implementing custom validation or row modification logic. Built on top of PeachySQL.

Installation

composer require devtheorem/phaster

Usage

Create a class extending Entities, and implement the methods to map properties to columns and define the base SQL query (see example below). Pass the callable returned by the route handling functions to your Slim or other PSR-7 compatible framework.

<?phpuseDevTheorem\Phaster\{Entities, Prop, QueryOptions};
class Users extends Entities
{
// Return the table to insert/update/delete/select from.// If not implemented, the class name will be used as the table name.protectedfunctiongetTableName(): string
{
return'users';
}
// Return an array which maps properties to writable column names. Returns an// empty array by default, so no properties will be writable if not implemented.protectedfunctiongetMap(): array
{
return [
'username' => 'uname',
'firstName' => 'fname',
'lastName' => 'lname',
'isDisabled' => 'disabled',
'role' => [
'id' => 'role_id',
],
];
}
// Return a list of `Prop` objects, which map properties to readable columns and/or values,// and enable setting a type to cast the column value to, or defining a virtual property// which depends on other columns. See the Prop constructor for the full list of parameters// that can be set. Returns an empty array by default.protectedfunctiongetSelectProps(): array
{
return [
newProp('id', col: 'u.user_id'),
newProp('username', col: 'u.uname'),
newProp('firstName', col: 'u.fname'),
newProp('lastName', col: 'u.lname'),
newProp('isDisabled', col: 'u.disabled', type: 'bool'),
newProp('role.id', col: 'u.role_id'),
newProp('role.name', col: 'r.role_name'),
];
}
// Return a SELECT SQL query (without a WHERE clause) in order to join other tables when// selecting data. If not implemented, mapped columns will be selected from the table// returned by getTableName().protectedfunctiongetBaseQuery(QueryOptions$options): string
{
return"SELECT {$options->getColumns()} FROM users u INNER JOIN roles r ON r.role_id = u.role_id";
}
// Set the default column/direction for sorting selected results. If not implemented,// results will be sorted by the id property in ascending order by default.protectedfunctiongetDefaultSort(): array
{
return ['username' => 'asc'];
}
}

If it is necessary to bind parameters in the base query, use getBaseSelect() instead:

useDevTheorem\PeachySQL\QueryBuilder\SqlParams;
// ...protectedfunctiongetBaseSelect(QueryOptions$options): SqlParams
{
$sql = "WITH num_orders AS ( SELECT user_id, COUNT(*) as orders FROM Orders WHERE category_id = ? GROUP BY user_id ) SELECT {$options->getColumns()} FROM Users u INNER JOIN num_orders n ON n.user_id = u.user_id";
returnnewSqlParams($sql, [321]);
}
// ...
<?phpuseMy\DatabaseFactory;
useDevTheorem\Phaster\{Entities, EntitiesFactory};
class MyEntitiesFactory implements EntitiesFactory
{
publicfunctioncreateEntities($class): Entities
{
returnnew$class(DatabaseFactory::getDb());
}
}
<?phpuseDevTheorem\Phaster\RouteHandler;
$phaster = newRouteHandler(newMyEntitiesFactory());
$app->get('/users', $phaster->search(Users::class));
$app->get('/users/{id}', $phaster->getById(Users::class));
$app->post('/users', $phaster->insert(Users::class));
$app->put('/users/{id}', $phaster->update(Users::class));
$app->patch('/users/{id}', $phaster->patch(Users::class));
$app->delete('/users/{id}', $phaster->delete(Users::class));

Example API request/response

GET https://example.com/api/users?q[firstName]=Ted&q[isDisabled]=0&fields=id,username,role

{
"offset": 0,
"limit": 25,
"lastPage": true,
"data": [
{
"id": 5,
"username": "Teddy01",
"role": {
"id": 1,
"name": "Admin"
}
},
{
"id": 38,
"username": "only_tj",
"role": {
"id": 2,
"name": "Standard"
}
}
]
}

Author

Theodore Brown
https://theodorejb.me

License

MIT

About

A PSR-7 compatible library for easily making CRUD API endpoints

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages