I often make small projects for friends or for people on forum I visit.
For instance, it's create a user space, or chat page, or stuff like that.
That's why I think Frameworks/ORM is not suitable for the size of these projects, the code is often less than 300 lines.
But in all cases, I use PDO, and it's really using to write the SQL string, check the docs to make a INSERT, .. So I was thinking of extending the PDO Class with a chaining approach, like this:
$pdo->create('users', array(
'id' => 'int',
'username' => 'text',
'password' => 'text'
));
$pdo->insert(array(
'username' => $user,
'password' => md5($password)
))->in('users');
$pdo->update(array(
'username' => $new_user
))->in('users')->where('id', $user_id);
$pdo->select()->from('users')->where('id', $user_id)->row();
$pdo->select('username')->from('users')->rows();
$pdo->drop('users');
$pdo->close();
And if PDO or the way of storing (mysql/sqlite/...) changes, I just have to edit the class and it's done.
So, does a similar class exist ?
And is it a good idea to make things like this ?
EDIT: I'm sorry to bump this thread, but I'm afraid that no-one has made a thing like this..
You are contradicting yourself... You are talking about writing a QueryBuilder and/or DBAL on top of PDO (which is a pretty complex thing to do in terms of the amount of code needed to support multiple DB vendors) Yet you shy away from a framework. Doesn't make much sense.
That said there are DBAL and QueryBuilders out there that can be used outside of a greater framework. Personally I'd say go with Doctrine DBAL. An example of using its QueryBuilder:
$conn = DriverManager::getConnection($connectionInfo);
$queryBuilder = $conn->createQueryBuilder();
$queryBuilder
->select('*')
->from('users')
->where('id = ?')
->setParameter(0, $user_id);
As for a framework there are also "micro frameworks" which serve as a simple MVC stack (when compared to something like Laravel, Cake, Symfony2, etc.). For projects of the nature you are talking I would in fact probably use Silex in combination with Doctrine DBAL.
Related
I have a simple website running Laravel Jetstream with Teams enabled. On this website, you can create different "to-do tasks", which are owned by a team. I have a model called Task.
I am trying to create a public facing API, so my users can query their tasks from their own applications. In my routes/api.php file, I have added this:
Route::middleware('auth:sanctum')->group(function(){
Route::apiResources([
'tasks' => \App\Http\Controllers\API\TaskController::class,
]);
});
And then in the TaskController, I have only begun coding the index method:
/**
* Display a listing of the resource.
* #queryParam team int The team to pull tasks for.
* #return \Illuminate\Http\Response
*/
public function index()
{
if(request()->team){
$tasks = Task::where('team_id', request()->team)->get();
return TaskResource::collection($tasks);
}
return response([
'status' => 'error',
'description' => "Missing required parameter `team`."
], 422);
}
Now this works fine. I can make a GET request to https://example.org/api/tasks?team=1 and successfully get all the tasks related to team.id = 1.
However, what if I want to include multiple query parameters - some required, others only optional. For example, if I want to let users access all tasks with a given status:
https://example.org/api/tasks?team=1&status=0
What is the best practices around this? As I can see where things are going now, I will end up with a lot of if/else statement just to check for valid parameters and given a correct error response code if something is missing.
Edit
I have changed my URL to be: https://example.org/api/teams/{team}/tasks - so now the team must be added to the URL. However, I am not sure how to add filters with Spatie's Query Builder:
public function index(Team $team)
{
$tasks = QueryBuilder::for($team)
->with('tasks')
->allowedFilters('tasks.status')
->toSql();
dd($tasks);
}
So the above simply just prints:
"select * from `teams`"
How can I select the relationship tasks from team, with filters?
The right way
The advanced solution, i have built a handful of custom ways of handling search query parameters. Which is what you basically wants to do, the best solution by far is the spatie package Query Builder.
QueryBuilder::for(Task::class)
->allowedFilters(['status', 'team_id'])
->get();
This operation will do the same as you want to do, and you can filter it like so.
?fields[status]=1
In my experience making team_id searchable by team and similar cases is not worth it, just have it one to one between columns and input. The package has rich opportunities for special cases and customization.
The simple way
Something as straight forward like your problem, does not need a package off course. It is just convenient and avoids you writing some boiler plate code.
This is a fairly simple problem where you have a query parameter and a column you need to search in. This can be represented with an array where the $key being the query parameter and $value being the column.
$searchable = [
'team' => 'team_id',
'status' => 'status',
];
Instead of doing a bunch of if statements you can simplify it. Checking if the request has your $searchables and if act upon it.
$request = resolve(Request::class);
$query = Task::query();
foreach ($this->seachables as $key => $value) {
if ($query->query->has($key)) {
$query->where($value, $query->query->get($key))
}
}
$tasks = $query->get();
This is a fairly basic example and here comes the problem not going with a package. You have to consider how to handle handle like queries, relationship queries etc.
In my experiences extending $value to an array or including closures to change the way the logic on the query builder works can be an option. This is thou the short coming of the simple solution.
Wrap up
Here you have two solutions where actually both are correct, find what suits your needs and see what you can use. This is a fairly hard problem to handle pragmatic, as the simply way often gets degraded as more an more explicit search functionality has to be implemented. On the other side using a package can be overkill, provide weird dependencies and also force you into a certain design approach. Pick your poison and hope at least this provides some guidance that can lead you in the right direction.
For a Web-Application with many Database related events I want to build a Changelog. That should log what users have done, so its a Userlog too.
The App is huge, has a complex role based user access system and there will be hundreds of different events (changes) that may occur.
This all should be Database-Driven, in PHP and needs at least a View to search the Logs.
But in short, I have totally no idea how to design that all and need some tips or inspirations, maybe what others have done.
I've done this in the past and found basically 2 approaches: Model-based and Controller-based.
Model-based within the model itself override the save and update methods (assuming an ActiveRecord pattern) to create a new entry in the ChangeLog table.
Controller-based add the ChangeLog record creation logic to each controller that you want to track.
I prefer the Controller-based approach since you have more control over what's going on and when. Also, you have full access to the user session so it's easier to add tracking for auditing purposes.
Have solved that much more easy as it appears with my first thoughts.
This should do it most times without a comment:
protected function log($comment = ''){
$user = $this->user();
ORM::factory('Changelog')->vaules(array(
'user_id' => $user->pk(),
'section_id' => $user->section->pk(),
'username' => $user->username.'#'.$user->section->name,
'time' => time(),
'uri' => $this->uri($this->request->param(), $this->request->query()),
'controller' => $this->request->controller(),
'action' => $this->request->action(),
'post' => serialize($this->request->post()),
'comment' => $comment,
))->save();
}
A simple $this->log() and all is done.
Result: http://charterix.sourceforge.net/log.jpg
99% of what REST API's do is serve as a controlled interface between client and DB, and yet I can't for the life of me find any libraries that do just that.
All libraries focus on providing a REST interface to the developer, who then sets up the communication with the database. It seems like a no-brainer to me to create a library that already interfaces with the database, and all the developer needs to do is define some ACL rules and plug in some logic here or there.
So, before I continue and put my thoughts into actions by actually creating this sort of library, may I just ask anyone with knowledge on the subject; has anyone implemented anything like this yet? Will I be re-inventing the wheel?
I'm talking strictly about a PHP based solutions by the way, I have nothing against other languages, PHP is simply my cup of tea. But for that matter, I haven't found any implementations in other languages either.
And in case my explanation doesn't make it very clear, this is essentially what I'd want:
<?php
class post_controller extends controller {
protected static $config = array(
'select' => true,
'insert' => true,
'update' => true,
'delete' => false,
'fields' => array(
'id' => array(
'select' => true,
'update' => false
),
'name' => array(
'select' => true,
'update' => true
),
'content' => array(
'select' => true,
'update' => true
)
)
);
/**
* GET, POST, DELETE are implemented already by the parent controller
* Just overriding PUT to modify the content entry
*/
function put($data) {
$data->content = htmlentities($data);
return parent::put($data);
}
}
?>
Thanks in advance for anyone giving their input and apologies if this is not a proper Stackoverflow question.
Edit:
To clarify, this type of service would be for specific use-cases, I don't imagine it to be a type of thing that anyone can use for any type of web service.
I have built a similar system for SOAP and must say it's very easy to do so. I haven't seen any prebuilt libraries that would help you do it (and I doubt they exist - see next paragraph), but it shouldn't take you more than a few hours to build your own solution (a day max - with testing and documentation writing included).
It is however a whole another question if you really want to do that. REST can be (mis)used for this purpose, but it is meant for manipulating resources. Records in a database only rarely have a one-to-one mapping with resources. If they do in your case (as they did in mine) then feel free to do it, otherwise it would be nicer to provide a proper REST API. Why expose your internal DB structure to the world? YMMV, of course.
I have recently begun working on a PHP/JS Form Class that will also include a SQL Form builder (eg. building simple forms from sql and auto inserts/updates).
I have tried several classes (zend_form, clonefish, PHP Form Builder Class, phorms etc) but as yet haven't come across a complete solution that is simple, customizable and complete (both server side and client side validation, covers all simple html elements and lots of dhtml elements: sorting, wysiwyg, mutli file upload, date picker, ajax validation etc)
My question is why do some "classes" implement elements via an array and others via proper OO class calls.
eg.
Clonefish (popular commercial php class):
$config = Array(
'username' => Array(
'type' => 'inputText',
'displayname' => 'Username',
validation => Array(
Array(
'type' => 'string',
'minimum' => 5,
'maximum' => 15,
),
),
));
$clonefish = new clonefish( 'loginform', 'test.php', 'POST' );
$clonefish->addElements( $config, $_POST );
Then others eg. Zend_Form
$form = new Zend_Form;
$username = new Zend_Form_Element_Text('username');
$username->addValidator(new Zend_Validate_Alnum());
$form->addElement($username);
I realise Zend_Form can pass elements in via an array similar to clonefish but why do this?
Is there any benefit? It seems to make things more complicated especially when using a proper IDE like Komodo.
Any thoughts would be appreciated as I dont want to get too far down the track and realize there was great benefit in using arrays to add elements (although this wouldn't be much of a task to add on).
Cheers
My question is why do some "classes" implement elements via an array and others via proper OO class calls.
For convenience. It's less verbose and it feels less like coding and more like configuration and you need less intimate knowledge of the API.
Btw, the reason you have not yet come across a complete solution that is simple, customizable and complete is because it is not simple. Forms, their validation and rendering is complex, especially if you want to have it customizable for any purpose. ZF's form components are a good example of how to properly decouple and separate all concerns to get the ultimate extensible form builder (including client side code through Zend_Dojo or ZendX_Jquery). But they are also a great example of the complexity required for this. Even with the convenient array configuration, it is damn difficult to make them bend to your will, especially if you need to depart from the default configuration and rendering.
Why to use objects? Becouase they are a much more complex types. Consider the following example (I never useed Zend_Form so I don't even know its architecture):
class MySuperAlnumValidator extends Zend_Validate_Alnum {
protected $forbiddenWords = array();
public function addForbiddenWord($word) {
$this->forbiddenWords[] = $word;
}
// Override Zend_Value_Alnum::validate() - I don't know whether such a method even exists
// but you know what's the point
public function validate() {
parent::validate();
if (in_array($this->value, $this->forbiddenWords) {
throw new Exception('Invalid value.');
}
return $this->value;
}
}
// -----------------------
$validator = new MySuperAlnumValidator();
$validator->addForbiddenWord('admin');
$validator->addForbiddenWord('administrator');
$username->addValidator($validator);
This is only a simple example but when you start writing more complex validators/form fields/etc. then objects are, in principle, the only meaningful tool.
I want to save an object or form to the database. Only I can't find the easiest (or normal) way for how to do this.
I found a lot of tutorials, but none seem to be easy or current. Can someone please help me with this?
I use version 1.9.3 of the Zend Framework.
The easiest way (aka the way using the smallest amount of code) to insert a row into a database table using Zend_Db is:
$data = array(
'created_on' => '2007-03-22',
'bug_description' => 'Something wrong',
'bug_status' => 'NEW'
);
$db->insert('bugs', $data);
The above code will insert a new row into the bugs table whereas $db is the Zend_Db_Adapter_Abstract-subclass you created with Zend_Db::factory(). Please see Writing Changes to the Database in the Zend Framework manual for more details and the whole spectrum of features Zend_Db provides.
For the sake of completeness, the above code will issue a query to the database similar to:
INSERT INTO bugs (created_on, bug_description, bug_status)
VALUES ('2007-03-22', 'Something wrong', 'NEW')
The next step would be a more sophisticated approach using Zend_Db_Table.
EDIT:
Given that you have a Zend_Form ($form) with the appropriate fields created_on, bug_description and bug_status and provided that you have the right filters and validators in place, adding a new row with values given in the form is as easy as
if ($form->isValid($_POST)) {
$db->insert('bugs', $form->getValues());
}
Storing a custom object is also very easy:
// $bug is your custom object representing a bug
$db->insert('bugs', array(
'created_on' => $bug->getCreatedOn(),
'bug_description' => $bug->getDescription(),
'bug_status' => $bug->getStatus()
));
Instantiate any object that you need and serialize it. Once serialized, you can store it or transmit it to pretty much any medium. Is this what you are referring to?