Giter Club home page Giter Club logo

aura.marshal's People

Contributors

compwright avatar harikt avatar jakefolio avatar koriym avatar pborreli avatar sobstel avatar yutakachiba avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aura.marshal's Issues

Add some kind of a "clear" functionality.

In longer running processes or entity-heavy processes it may occur that you reach the memory_limit of PHP. Increasing it may not be an option, but I'd like to see some kind of clearance for the loaded entities to free some space (e.g., after a round of batch processing several thousand entities, remove everything that was loaded so far). As far as I could guess I think Marshal works similar to the Doctrine2 UnitOfWork, keeping references to generated object instances and reusing them. Doctrine2 has the same problem if you don't clear the UnitOfWork on a regular basis.

See the Doctrine2 UnitOfWork to get some sort of an idea:

I think this feature should be proposed for the 2.0 version of Marshal?

Document new use case: marshaling data from API sources

The examples are database-centric, it would be nice to have an example or documentation related to using this in an API context.

This does appear to be a use case that exists. Searching Packagist for terms such as api relationship or data relationship returns a small handful of libraries.

Most of these are unsuitable for some reason, such as lack of maintenance, poor documentation, or tight binding to a particular ORM (such as Doctrine) or framework (such as Laravel). However these two stand out as possibilities:

Neither of these are as elegant or well documented as Aura.Marshal.

As an aside, Aura.Marshal is the top hit for the search term data relationship. It would be nice for this to show up in the api relationship search results as well.

Officially support PHP 7-8

This probably works fine in later versions of PHP, but it would be helpful if this were proven and noted.

Problem with GenericLazy when using my own entity

I experienced some trouble when implementing my own entity because of the GenericLazy.

I figured out that \Aura\Marshal\Entity\MagicArrayAccessTrait make the "transformation" of the GenericLazy to the real class. But MagicArrayAccessTrait only works with an implementation of \ArrayAccess, that is made with \Aura\Marshal\Data.

So, I had to extends \Aura\Marshal\Data and use \Aura\Marshal\Entity\MagicArrayAccessTrait to make my entity works properly.

Should be good if MagicArrayAccessTrait makes the whole thing alone.
And it documented on README.md

'WiringAssertionsTrait' not found when running (php)unit tests

Aura.Marshal git:develop ❯ phpunit tests
PHP Fatal error:  Trait 'Aura\Framework\Test\WiringAssertionsTrait' not found in /Users/sobstel/Projects/Aura.Marshal/tests/WiringTest.php on line 8

Fatal error: Trait 'Aura\Framework\Test\WiringAssertionsTrait' not found in /Users/sobstel/Projects/Aura.Marshal/tests/WiringTest.php on line 8

Exception should not be raised

I have 3 posts , with ids 1, 2, 3 . If there is no summary for 3rd post

 post_id      read_sum
 1              4
 2                 2

trying to get $post->summary->read_sum will throw exception. I feel it should not throw the exception. Playing on develop branch with the same example in README.md .

Entity to array?

Lets say you have loaded data with relations and now wants to serialize / json your data

// get a collection of the post IDs we just loaded
$posts = $manager->posts->getCollection($post_ids);

print_r($posts[0]); //will throw me huge pile of code that kills my browser. 

Sure I could build an array by accessing individual properties like $posts[0]->name... And so on,but that's not convenient.

Support PSR-4

This package uses the old PSR-0 autoloader. It would be nice to upgrade that to the more common PSR-4.

Error in an example in docucmentation ?

I read this in the example of the "Loading Data" section :

// add the authors for the posts.  first, we need to know
// the author_id values for all the posts so far ...
$author_ids = $manager->posts->getFieldValues('author_id');

// ... then we can query and load.
$result = $db->fetchAll(
    'SELECT * FROM authors WHERE id IN (?)',
    [$author_ids]
);
$manager->comments->load($result);

I think the last line should be '$manager->authors->load($result);' instead of '$manager->comments->load($result);'.
Am I right ?

DataIterator should depend on ArrayAccess, not Data

The Aura\Marshal\DataIterator constructor expects an instance of Aura\Marshal\Data, but the only method it calls on the Data object is offsetGet(), which is part of the ArrayAccess interface. Is there any reason why the DataIterator constructor can't be modified to expect ArrayIterator rather than Data?

Fix Composer 2.x warning on install

Loading "aura/installer-default" which is a legacy composer-installer built for Composer 1.x, it is likely to cause issues as you are running Composer 2.x.

Allow protected/private properties without magic method

Currently https://github.com/auraphp/Aura.Marshal/blob/1.x/src/Aura/Marshal/Entity/Builder.php#L49 forces you to have public properties or using one of the provided traits which define __set magic method.

To allow having entities without this magic, I'd recommend to improve the Entity\Builder a bit to write into private/protected properties directly using a class bound setter function.

So instead of doing

foreach ($data as $field => $value) {
     $entity->$field = $value;
}

we could do

$writer = \Closure::bind(
    function ($object, $prop, $value) {
        $object->$prop = $value;
    },
    null,
    get_class($entity)
);

foreach ($data as $field => $value) {
     $writer($entity, $field, $value);
}

@pminnieur

Convert to array

Some use cases require using plain PHP arrays, but getCollection() returns an object.

A naive conversion fails:

$array = iterator_to_array(
    $manager->getCollection(...)->getIterator()
);

This fails because although $array is an array, its elements are objects of class Aura\Marshal\Entity\GenericEntity.

If this can be done with a custom builder, then a documentation example for that should be added.

Creating entities from different Builder

I was in an experiment to look how we can incorporate Marshal inside the SqlMapper bundle. Have noticed a few issues, may be I am wrong.

In advanced usage, we have Entity and Collection Builders . The only dependency was to make use of the BuilderInterface.

The example is taken from the same readme. Running it gives

PHP Notice:  Trying to get property of non-object in /var/www/github.com/harikt/marshal/marshal.php on line 169
PHP Notice:  Trying to get property of non-object in /var/www/github.com/harikt/marshal/marshal.php on line 170
PHP Notice:  Trying to get property of non-object in /var/www/github.com/harikt/marshal/marshal.php on line 170
PHP Notice:  Trying to get property of non-object in /var/www/github.com/harikt/marshal/marshal.php on line 171
The post titled  was written by . and has 0 comments. PHP Notice:  Trying to get property of non-object in /var/www/github.com/harikt/marshal/marshal.php on line 174
PHP Fatal error:  Call to a member function isEmpty() on a non-object in /var/www/github.com/harikt/marshal/marshal.php on line 174

Full example is below .

<?php
namespace Vendor\Package\Entity;

use Aura\Marshal\Entity\MagicPropertyTrait;

class PostCollection
{
    public $data;

    public function __construct($data)
    {
        $this->data = $data;
    }

    public function isEmpty()
    {
        return empty($this->data);
    }
}

<?php
namespace Vendor\Package\Entity;

use Aura\Marshal\Entity\MagicPropertyTrait;

class Post
{
    protected $id;

    protected $title;

    protected $author;

    protected $comments;

    protected $tags;

    use MagicPropertyTrait;

    public function __construct($data)
    {
        foreach ($data as $key => $value) {
            $this->{$key} = $value;
        }
    }
}

<?php
namespace Vendor\Package\Builder\Post;

use Aura\Marshal\Entity\BuilderInterface;
use Vendor\Package\Entity\Post;

class EntityBuilder implements BuilderInterface
{
    public function newInstance(array $data)
    {
        return new Post($data);
    }
}

<?php
namespace Vendor\Package\Builder\Post;

use Aura\Marshal\Collection\BuilderInterface;
use Vendor\Package\Entity\Post;
use Vendor\Package\Entity\PostCollection;

class CollectionBuilder implements BuilderInterface
{
    public function newInstance(array $data)
    {
        $instances = array();
        foreach ($data as $row) {
            $instances[] = new Post($row);
        }
        $collection = new PostCollection($instances);
        return $collection;
    }
}
<?php
require __DIR__ . '/vendor/autoload.php';

use Aura\Marshal\Manager;
use Aura\Marshal\Type\Builder as TypeBuilder;
use Aura\Marshal\Relation\Builder as RelationBuilder;
use Aura\Sql\ExtendedPdo;

$manager = new Manager(new TypeBuilder, new RelationBuilder, [
    'authors' => [
        'identity_field'                => 'id',
        'relation_names'                => [
            'posts'                     => [
                'relationship'          => 'has_many',
                'native_field'          => 'id',
                'foreign_field'         => 'author_id',
            ],
        ],
    ],

    'posts' => [
        'identity_field'                => 'id',
        'index_fields'                  => ['author_id'],
        'entity_builder'                => new \Vendor\Package\Builder\Post\EntityBuilder,
        'collection_builder'            => new \Vendor\Package\Builder\Post\CollectionBuilder,
        'relation_names'                => [
            'comments'                  => [
                'relationship'          => 'has_many',
                'native_field'          => 'id',
                'foreign_field'         => 'post_id'
            ],
            'author'                    => [
                'relationship'          => 'belongs_to',
                'foreign_type'          => 'authors',
                'native_field'          => 'author_id',
                'foreign_field'         => 'id',
            ],
            'tags'                      => [
                'relationship'          => 'has_many_through',
                'through_type'          => 'posts_tags',
                'native_field'          => 'id',
                'through_native_field'  => 'post_id',
                'through_foreign_field' => 'tag_id',
                'foreign_field'         => 'id'
            ],
        ],
    ],

    'comments' => [
        'identity_field'                => 'id',
        'index_fields'                  => ['post_id'],
        'relation_names'                => [
            'post'                      => [
                'relationship'          => 'belongs_to',
                'foreign_type'          => 'posts',
                'native_field'          => 'post_id',
                'foreign_field'         => 'id',
            ],
        ],
    ],

    'posts_tags' => [
        'identity_field'                => 'id',
        'index_fields'                  => ['post_id', 'tag_id'],
        'relation_names'                => [
            'post'                      => [
                'relationship'          => 'belongs_to',
                'foreign_type'          => 'posts',
                'native_field'          => 'post_id',
                'foreign_field'         => 'id',
            ],
            'tag'                       => [
                'relationship'          => 'belongs_to',
                'foreign_type'          => 'tags',
                'native_field'          => 'tag_id',
                'foreign_field'         => 'id',
            ],
        ],
    ],

    'tags' => [
        'identity_field'                => 'id',
        'relation_names'                => [
            'posts'                     => [
                'relationship'          => 'has_many_through',
                'native_field'          => 'id',
                'through_type'          => 'posts_tags',
                'through_native_field'  => 'tag_id',
                'through_foreign_field' => 'post_id',
                'foreign_field'         => 'id'
            ],
        ],
    ],
]);
/*
$manager->setType('posts', [
    // the field with the unique identifying value
    'identity_field' => 'id',

    // an object to build entities; default is a new instance of
    // Aura\Marshal\Entity\Builder
    'entity_builder' => new \Vendor\Package\Builder\Post\EntityBuilder,

    // an object to build collections; default is a new instance of
    // Aura\Marshal\Collection\Builder
    'collection_builder' => new \Vendor\Package\Builder\Post\CollectionBuilder,
]);
*/

$pdo = new ExtendedPdo(
    'mysql:host=localhost;dbname=marshal',
    'root',
    'mysqlroot',
    array(), // driver options as key-value pairs
    array()  // attributes as key-value pairs
);

$result = $pdo->fetchAll('SELECT * FROM posts LIMIT 10');

// load the results into the posts type object, and get back the
// identity (primary key) values for the loaded results.
$post_ids = $manager->posts->load($result);

// select and load all the comments on all the posts at once.
$result = $pdo->fetchAll(
    'SELECT * FROM comments WHERE post_id IN (:post_ids)',
    [
        'post_ids' => $post_ids,
    ]
);
$manager->comments->load($result);

// add the authors for the posts.  first, we need to know
// the author_id values for all the posts so far ...
$author_ids = $manager->posts->getFieldValues('author_id');

// ... then we can query and load.
$result = $pdo->fetchAll(
    'SELECT * FROM authors WHERE id IN (:author_ids)',
    [
        'author_ids' => $author_ids,
    ]
);
$manager->authors->load($result);

// query and load the association mapping type linking posts and tags
$result = $pdo->fetchAll(
    'SELECT * FROM posts_tags WHERE post_id IN (:post_ids)',
    [
        'post_ids' => $post_ids,
    ]
);
$manager->posts_tags->load($result);
$tag_ids = $manager->posts_tags->getFieldValues('tag_id');
// finally, query and load all tags regardless of posts
$result = $pdo->fetchAll('SELECT * FROM tags WHERE id IN (:tag_ids)',
    [
        'tag_ids' => $tag_ids,
    ]
);
$manager->tags->load($result);

// get a collection of the post IDs we just loaded
$posts = $manager->posts->getCollection($post_ids);

// loop through posts collection, getting a post entity each time
foreach ($posts as $post) {
    // address the native and foreign fields
    echo "The post titled {$post->title} "
       . "was written by {$post->author->name}. "
       . "and has " . count($post->comments) . " comments. ";

    // loop through the tags
    if ($post->tags->isEmpty()) {
        echo "It has no tags.";
    } else {
        echo "It has these tags: ";
        $tags = [];
        foreach ($post->tags as $tag) {
            $tags[] = $tag->name;
        }
        echo implode(', ', $tags);
    }

    echo PHP_EOL;
}

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.