Coder Social home page Coder Social logo

framework's Introduction

Darya Framework

Latest Stable Version Total Downloads Latest Unstable Version License Scrutinizer Code Quality

Darya is a PHP framework for web application development.

Its components include:

The framework is currently under development and the API is liable to change until v1.0.0.

Each component will eventually be split into its own repository.

Installation

Use Composer to install the darya/framework package.

Otherwise just clone this repository into a directory such as /vendor/darya/framework.

After this, you'll want to make use of a class autoloader to save you from manually including classes.

You can use Composer's autoloader or the autoloader that Darya provides.

Composer's autoloader

require_once 'vendor/autoload.php';

Darya's autoloader

Darya's autoloader.php includes Composer's autoload.php if it can find it.

require_once 'vendor/darya/framework/autoloader.php';

framework's People

Contributors

hexus avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar

Forkers

amnp76

framework's Issues

Schema building

Implement a schema builder and schema modification storage interfaces.

Maybe a Darya\Storage\Schematic interface and methods like createResource(), deleteResource(), etc.

Named routes

Implement optionally named routes within Router and/or Route so that their URIs can be generated (reverse-routed).

Eager relation loading

Implement loading model relations eagerly.

$pages = Page::eager('children');

foreach ($pages as $page) {
    $page->children; // already loaded, doesn't hit the database
}

Custom accessors and mutators for models

Model::mutable() could become Model::defined(), to determine whether the attribute has a defined type.

Model::mutable() could then check for a defined type using defined() and for a mutator method.

Model::accessible() could then check for a defined type using defined() and for an accessor method.

Unit test the Events package

There aren't any tests for the Events package, and it's fairly simple.

Routing doesn't need this because it's going to be refactored a lot in 0.5.2.

Event dispatcher for routing

Use an event dispatcher for controllers to respond to during specific parts of a route matching and dispatching process. This removes the dependency of specifically-named methods in controllers.

It helps remove the need for the Darya\Routing\Dispatcher class, which is essentially a decorator around Router that provides before/after hooks and dependency injection from the service container.

It would be nice to see the Router capable of doing all of these things, most likely optionally (this is probably best raised as another issue).

This could be hand-written or just Symfony's.

"Cheers" query builder

Something like

$storage->query('users')->where([
    'firstname' => 'Chris'
])->cheers();

Or

$storage->query('users')->update([
    'firstname' => 'Chris',
    'surname'   => 'Andrew'
])->where([
    'id' => 1
])->cheers();

Autoloader and Http API consolidation

Autoloader::registerNamespaces() might as well just be Autoloader::namespaces(). setBasePath() and getBasePath() can be consolidated to either basePath() or base(). The static classBaseName() could just become className() and not be public.

Request::session($key) would be helpful. Not sure whether to consolidate Request::setSession() and Request::getSession() into this same method; might be making a single method do far too many things at once, but I love single word methods! Oh the trade off.

Response::getStatus() and Response::setStatus() can easily just become Request::status(). Maybe the same for setCookie() and getCookie()? deleteCookie() should probably stay.

Removed Response::addContent(), consolidate Response::setContent() and Response::getContent(). Keep hasContent().

Session magic methods might be nice too!

Edit: Also improve View API.

  • View::setFile(), View::setDir(), View::setConfig() to View::file(), View::directory(), View::config()
  • View::getAssigned() and View::getShared() to View::assigned() and View::shared()

Storage interface

The Storage package needs a storage interface that can have Readable, Modifiable and other storage types plugged into it.

This would allow for behaviour like so:

$storage = new Storage([
    'create' => new SomeCreatableStorage(),
    'read'   => new SomeReadableStorage(),
    'modify' => new SomeModifiableStorage()
]);

$storage->readFrom(new SomeOtherReadableStorage());
$storage->searchFrom(new SomeSearchableStorage());

if (!$storage->canRead()) {
    throw new \RuntimeException('Storage is not readable!');
}

Perhaps by default the storage could assume everything capable from a single source, too:

$storage = new Storage(new DatabaseStorage($connection));

Sources could then be overridden afterwards if need be.

Maybe this needs a different name too, this is basically like a MultiStorage adapter. Or maybe the source interfaces should be renamed.

Work this out into a perfect set of interfaces and this will be one hell of an expressive system.

Model schema & persistent storage interfaces

Find the best way for a Record to expose its schema. It really might not matter if this is a static property in the long run.

Extract all the static load, save, and delete methods to a generic MySQL repository that is instantiated with a connection. Record can then have a sharedRepository property instead of a sharedConnection. These static methods can then simply use this repository, or maybe even a __callStatic magic method implementation would suffice.

This allows a Model instance to be passed to repositories for persistence at the same time as retaining the convenience methods on Record subclasses, without said methods containing messy conditions and hard-coded SQL.

Store the interfaces implemented by services in the container

With this you could then easily list all services registered that implement a given interface, even if one is only registered or aliased to the interface for type-hinting.

Would be useful from a plugin perspective; retrieving plugins without needing to know their namespace beforehand.

Improve Model & Controller API

Remove redundant methods. Implement attributes specifications.

Possibly make it easier to generate the current controller's URL:

return $this->request->route->url();

Rename Queryable::execute()

It sounds like... ๐Ÿ’ฅ ๐Ÿ”ซ

Queryable::query() is already taken for opening a new query builder. That's also how query() methods are used everywhere else in the API, so for consistency I don't feel like changing that.

Alternatives:

  • ->fetch()
  • ->send()
  • ->run()
  • ->get()

Default values for request data

It would be handy to provide default values for when request data is null.

For example:

$id = $request->get('id', 0);

In Symfony this is handled by parameter bags, but we don't need that. __call() is plenty powerful. :)

Don't forget to update the @method annotations!

Response cookies extraction

Maybe extract the cookies functionality of Darya\Http\Response to another class? This way it could be

$response->cookies->set(...);

instead of

$response->setCookie(...);

Request parameter key case-sensitivity

Request allows access its data thanks to its __call magic method implementation. While get, post, cookie and file data should be handled case-sensitively, server (environment) and header data does not need to be, but currently is.

Add some explicit case-insensitive processing for server and header data.

ORM readme

The ORM readme leaves a lot to be desired. Fill it out!

SQL Server Limit Offset

Implement this.

SELECT TOP {$limit} {$query_select} FROM (
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS row_number, {$query}...
) query_results WHERE row_number >= {$offset}

PSR-4

Update the file structure inside /src and the autoload configuration in composer.json to use PSR-4.

Do the same for tests.

Handle URI query string when instantiating Requests

GET requests can be created like this:

$request = new Request('/hello', 'GET', array(
    'GET' => array('this' => 'isdog')
);

But also like this:

$request = new Request('/hello?this=isnotdog', 'GET', array(
    'GET' => array('this' => 'isdog')
);

In this case, $request->uri() would evaluate to '/hello?this=isnotdog' and $request->get('this') would evaluate to 'isdog'.

Essentially, the query string of the request URI is not being handled in any way and just set as $this->data['server']['REQUEST_URI'] where $this is the Request instance.

The query string needs to be stripped and/or merged with the given GET array.

Edit: In Symfony's Request object, the URI always takes precedence.

Move Error and Result classes from Database to Storage namespace

If these are moved to the storage namespace it would be easy to ensure that the query builder returns an expected type and remains decoupled from databases.

Maybe some properties in Result would need to be renamed, and Error is absolutely fine as is because it's so simple.

Possibly keep unique Result in the database namespace that extends the storage equivalent.

Optionally define Record relationships using methods

Similar to the way Laravel does it, though this will bulk out the class even more.

class User extends Record
{
    public function roles() {
        return $this->belongsToMany('Role')->table('user_roles');
    }

    public function things() {
        return $this->hasMany('Thing')->foreignKey('owner_id');
    }
}

Extract model mutator/accessor logic to their own classes

Model::mutate() and Model::access() are rated critical by scrutinizer because of the switch statements.

Extract this logic to a couple of new classes:

Darya\Database\Model\Mutator
Darya\Database\Model\Accessor

Maybe also add interfaces for these so that they can be overridden/extended.

Improve Autoloader performance and reduce its complexity

The Autoloader checks a lot of paths for classes. Trim this down and do some method extraction in Autoloader::load(); maybe some protected methods like Autoloader::generatePaths($basePath, $class) and accepting an array of paths in Autoloader::attempt().

Smarter parameter argument resolution for the service container

Right now, Darya\Service\Container::mergeResolvedParameters() is begging for a smart implementation that merges user-provided arguments with those resolved from the container.

This will likely take into account numeric indexes of user-provided arguments and possibly the types of the resolved arguments.

Dynamic relation setters should replace instead of attach

Right now the dynamic relation setters attach.

$user->posts = $posts is the same as $user->posts()->attach($posts), which merges in with any existing related models.

The setter should probably replace everything that's there instead, so change Record::setRelated() to use Relation::replace() (which isn't public), or use Relation::clear() before attaching.

Container alias resolution

If an explicit container alias points to another explicit alias, it is not resolved from the container (only explicit services are checked and recursively resolved).

Either remove aliases altogether or allow these to be resolved recursively also.

Clean up Events interface names

DispatchableInterface, ListenableInterface, SubscribableInterface and SubscriberInterface seems all a bit too messy.

It also seems redundant having DispatchableInterface separate from ListenableInterface, I can't remember the reasoning behind this.

Try for the following interfaces:

Dispatchable, Subscribable, Subscriber.

Also while you're at it:

Darya\Http\Session becomes Darya\Http\Session\Php
Darya\Http\SessionInterface becomes Darya\Http\Session

PSR-2

Format all the code in a PSR-2ish style.

  • Database
  • Events
  • Foundation
  • HTTP
  • ORM
  • Routing
  • Service
  • Storage
  • View

Tests don't matter as much.

Reduce router complexity

Improve the simplicity of Router by once again extracting Dispatcher.

Instead of a dispatcher accepting a router, a router should be able to accept different dispatchers and also have a default implementation that it instantiates for itself (i.e. the current implementation).

Not only does this enhance the coherence of the framework, it also allows for custom dispatchers to be provided to the router.

Automatic strtotime() when setting cookie expiration

$response->cookies->set('key', 'value', strtotime('+1 day', time()));

This could be improved by adding a check for string expiration arguments, and if it is a string, using strtotime to automatically convert it to a timestamp.

$response->cookies->set('key', 'value', '1 day');

Doesn't that look much better?

Data Mappers

Pull out model & relation loading and saving from Record to a Mapper class that works in the same way.

This means the Mapper will access storage, and the Record will access the Mapper; another layer if you will.

This makes Active Record pattern optional, and the Data Mapper pattern what everything hinges on. It separates the concerns and means users won't have to extend Record to make use of relation loading, but if they do extend it then their relations can just be loaded in exactly the same way.

This one might take a bit of working out. Ultimately: class/method extraction yo!

Edit: EntityManager that contains a set of mappers and their relationships. Basically the Data Mapper pattern that Active Record can optionally sit on top of.

Edit edit: EntityManager that holds a Mapper for each Entity (and perhaps an EntityMap). Basically, Analogue but using storage interfaces instead of PDO.

HasMany::dissociate() reduces to dissociated IDs

Darya\ORM\Relation\HasMany::dissociate() uses the reduce() method to reduce the cached related models to those that have just been dissociated. It should do the inverse of this; reduce the cached models to all of those that haven't been dissociated.

Smarty adapter extraction

Extract SmartyView into its own repository, along with Smarty\ViewResolver and Smarty\Resource from the CMS project.

Relation attach() and detach()

I don't like how relations save automatically when setting them.

By default they should be attached and detached from the models without any storage operations, and saved by calling save() on the parent model.

The current behaviour could be replicated with $model->relation()->associate($related), which saves the parent model if need be, and then the relation. At least this way it's explicit and not so magic.

Readme files

  • Finish readme files for all packages
    • ORM
    • Service
    • View
  • Include a quick start section for detailed package readmes like Darya\Database
  • Simplify the framework readme with quick start snippets for each package

MySQL connection breaks when mysqlnd is missing

Darya\Database\Connection\MySql can't use mysqli_stmt::get_result without the mysqlnd extension installed.

Fatal error: Call to undefined method mysqli_stmt::get_result() in .../darya/framework/src/Darya/Database/Connection/MySql.php on line 121

Improve this situation by complaining as soon as the connection is instantiated if this method doesn't exist, or provide a runtime workaround using the following methods:

  1. mysql_stmt::bind_result
  2. mysql_stmt::fetch

http://stackoverflow.com/questions/18753262/example-of-how-to-use-bind-result-vs-get-result
http://stackoverflow.com/questions/8321096/call-to-undefined-method-mysqli-stmtget-result

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.