PHP Integrated Query, a real LINQ library for PHP

Overview

PHP Integrated Query - Official site

Build status Code quality Coverage Status Stable Release License

What is PINQ?

Based off the .NET's LINQ (Language integrated query), PINQ unifies querying across arrays/iterators and external data sources, in a single readable and concise fluent API.

An example

$youngPeopleDetails = $people
        ->where(function ($row) { return $row['age'] <= 50; })
        ->orderByAscending(function ($row) { return $row['firstName']; })
        ->thenByAscending(function ($row) { return $row['lastName']; })
        ->take(50)
        ->indexBy(function ($row) { return $row['phoneNumber']; })
        ->select(function ($row) { 
            return [
                'fullName'    => $row['firstName'] . ' ' . $row['lastName'],
                'address'     => $row['address'],
                'dateOfBirth' => $row['dateOfBirth'],
            ]; 
        });

More examples

Installation

PINQ is compatible with >= PHP 7.3

Install the package via composer:

composer require timetoogo/pinq
Comments
  • Naming convention

    Naming convention

    Hi, your project is still young so it's the best time to choose and use a naming convention. By there I mean that you should not, for example, call your function Where but where (you can see here that quite all frameworks work this way) (The only one I found to use PascalCase is ... Apache, whose style guide link is dead

    Check here for more informations and great stuff : http://www.phptherightway.com/

    Greetings, PunKeel

    opened by punkeel 17
  • Implement new static analysis tools and infrastructure for expression trees

    Implement new static analysis tools and infrastructure for expression trees

    This provides the tools necessary to analyse a given expression tree.

    This branch currently supports:

    • Getting type and reflection information from almost all types of expressions.
    • Emulating PHP's native type system for all operators as of PHP 5.6
    • Extendable type system implementation with type data for date for date time classes, native interfaces (eg ArrayAccess), string / array / math internal functions and the ITraversable query API.

    Unsupported:

    • Dynamic language features such as variable function / method calls, variable class types...
    • Proper handling of references for all use cases (this is almost impossible in a language such as PHP)
    • Only a small subset of internal classes or functions type data is implemented.
    • User defined classes type data. Possible through utilising docblocks via phpDocumentor/ReflectionDocBlock
    opened by TimeToogo 9
  • An actual use-example

    An actual use-example

    Hey.

    I am working with Yii's 1.1.x version and I would like to extend CActiveRecord to implement Pinq.

    So I looked into the documentation but all I find is either a very long class list, or examples where the original classes with their implementation is not shown - or at least a pseudo implementation. There also seems to be no detail how Pinq is actually used by the developer.

    I am aware of this one: http://elliotswebsite.com/Pinq/api.html ...but it is just a method listing and an explanation of what is for what, but i can't make up an implementation from this.

    Could you maybe give a short example for a possible implementation? Thanks!

    Kind regards, Ingwie

    opened by IngwiePhoenix 7
  • Converting to different DSL

    Converting to different DSL

    Different data-sources, such as RDBMSs or MongoDB, use different DSLs (SQL/JS queries, etc).

    What I found out so far is this page in the docs, which seems to simulate usage of a visitor on different types of filtering/aggregation requests.

    It is really hard for newcomers to understand how to use the visitors to lazily evaluate Pinq expressions to convert them into, for example, SQL.

    A simplified SQL that appends conditionals to a given SQL string would probably be useful in those examples.

    opened by Ocramius 7
  • Hint on groupBy and select

    Hint on groupBy and select

    Hi there,

    I am trying to do some grouping on a dataset by "author" and would return a new dataset with "author" and its relevant count.

    The code is something like this:

    $filter1 = $data
            ->where(function($row)
            {
                return $row['price'] > 90 && $row['price'] < 99;
            })
            ->orderByDescending(function($row)
    {
        return $row['id'];
    });
    

    $filter1 returns the results where its price is between 90 and 99, perfect.

    Next:

    $filter2 = $filter1
            ->groupBy(function($row)
            {
                return $row['author'];
            })
            ->select(
            function(ITraversable $filter1)
    {
        return ['Author' => $filter1['author'], 'Count' => $filter1->count()];
    }
    );
    

    I would like to group the filtered dataset ($filter1) by "author" and get the count for each "author".

    I have some problem to set the select function body:

    return ['Author' => $filter1['author'], 'Count' => $filter1->count()];
    

    I am expecting to return an array with two keys ('Author' and 'Count') with respective author name and count, like:

    author1 12 author2 15 ...

    How can I achieve this?

    opened by taylorren 5
  • Need help on a mimic facet search implementation using Pinq

    Need help on a mimic facet search implementation using Pinq

    Hi,

    I am trying to use Pinq to mimic a facet search and created a repo here: https://github.com/taylorren/pinq.

    The issue is that after creating a facet result, I am not able to display it as in my "demo1" route.

    Error message:

    Catchable fatal error: Argument 1 passed to pinqDemo{closure}() must be an instance of pinqDemo\ITraversable, instance of Pinq\Traversable given, called in F:\www\pinq\vendor\timetoogo\pinq\Source\Iterators\ProjectionIterator.php on line 40 and defined in F:\www\pinq\web\pinqDemo.php on line 17

    The function in question:

    function facetauthor($data)
        {
            $filter = $data
                    ->groupBy(function($row)
                    {
                        return $row['author'];
                    })
                    ->select(
                            function(ITraversable $data)
                    {
                        return ['author' => $data->first()['author'], 'count' => $data->count()];
                    }
                    );
    
            return $filter;
        }
    
    opened by taylorren 4
  • Performance of join and groupJoin methods is abnormally bad

    Performance of join and groupJoin methods is abnormally bad

    Your competitor here. :grinning:

    Pinq queries containing join and groupJoin can be thousands of times slower than native implementation, or any other LINQ library, when long arrays are joined (thousands of items). I have no idea what is going on, as I have trouble navigating your immense code base, but you should probably look into it.


    I've run the tests, your code is often an order of magnitude slower than YaLinqo, sometimes less, sometimes much more (like in the cases above). See gist with benchmark results (master branch). I've significantly improved performance of sorting thanks to your implementation. I didn't know array_multisort is so much faster than usort — the difference caused Pinq to be the fastest of the major LINQ libraries in the sorting test (well, no longer so, but it was).

    Considering your library is the only one providing LINQ to databases, I think it's critical to avoid performance traps in the basic functionality, even if the library is the slowest of the bunch.

    Technically, we aren't even competitors, considering YaLinqo is designed to be fast and expressive LINQ to objects and Pinq is designed to be LINQ to both objects and databases. Functionality and performance is so different that there isn't much to compete over. I'm still surprised by the lack of functionality in the basic methods of Pinq though, but I guess limiting expressiveness is required to make implementing query providers actually possible.

    What is the current state of MySQL query provider? Your website and readme say that it's a "demo", so I'm curious what plans you have on implementing production-ready query providers.

    By the way, how did you manage to receive more than 200 stars on GitHub? Did SitePoint cause so much traffic or is it something else?

    Anyway, thanks for writing your library. Ginq and Pinq forced me to update my own library: add missing methods, improve peformance, add integartion with CI and code quality tools. :grinning:

    opened by Athari 3
  • Document/Provide Functionality Without Expression Parsing

    Document/Provide Functionality Without Expression Parsing

    Forgive me if I've missed something big, but it seems that IQueryable has a lot of methods that let you pass functions, and provides a nice eloquent interface. I would like to implement it in such a way that I can guarantee that no function parsing happens in userland php at runtime. Is there a reason why this would not be possible or why the lazy evaluation must use parsing at runtime? If not, is there a set of classes from which I should extend, or do I just satisfy the interfaces without inheriting?

    From what I can tell, the requests/filters/etc all need to be passed a function of a given spec, and then they should be able to just call the darn thing without needing to parse it and make a decision about what it means.

    opened by winmillwill 3
  • Replace hard coded classes with factories or DI container

    Replace hard coded classes with factories or DI container

    I want to use own Traversable class that adds a custom method, but it's impossible. It would be useful to have a environment object that can be passed to each iterator:

    $pinq = new Environment(['Traversable' => 'Vendor\Traversable', 'GroupedTraversable' => ...]);
    $pinq->traversable($data);
    
    opened by hason 2
  • Generate SQL query

    Generate SQL query

    Has there been a way/method to generate SQL using PINQ? If not, I will have to go and code one. But I would like to know beforehand so I do not re-invent the wheel. :)

    opened by IngwiePhoenix 1
  • Only variable references should be returned by reference

    Only variable references should be returned by reference

    I get en error in IteratorGenerator, method &getIterator: Only variable references should be returned by reference. This should fix the problem. The error first occurred when I updated my server from php 5.6.7 to 5.6.8...

    $generator = $this->iteratorGenerator($this->iterator);
    return $generator;
    

    I'm not really sure what exactly is the problem here and if this is a good fix. Otherwise I could create a pullrequest.

    opened by sidneywidmer 1
  • Treat instances of DateTimeInterface as a value type throughout the API

    Treat instances of DateTimeInterface as a value type throughout the API

    For instance:

    $traversable = Traversable::from([
        ['date' => new \DateTime('1/1/2000'), 'message' => '...'],
        ['date' => new \DateTime('1/1/2000'), 'message' => '...'],
        ['date' => new \DateTime('2/1/2000'), 'message' => '...'],
    ]);
    
    $results = $traversable
        ->groupBy(function ($row) { return $row['date']; })
        ->select(function (ITraversable $group, \DateTime $key) {
            return $key->format('d/m/Y') . ':' . $group->count(); 
        })
        ->asArray();
    

    Due to strict comparisons on the group by this would yield some rather unexpected results:

    ['01/01/2000:1', '01/01/2000:1', '02/01/2000:1']
    

    When what is actually wanted is:

    ['01/01/2000:2', '02/01/2000:1']
    

    This PR changes the Identity::hash behaviour such that DateTimes are treated as a value type based on their timestamps (and class name) which would solve this problem.

    enhancement 
    opened by TimeToogo 4
  • Documentation should also be in the repository (to keep in sync with versions)

    Documentation should also be in the repository (to keep in sync with versions)

    The documentation is currently only in the gh-pages branch, which makes it quite easy for problems to popup if there are API breakages and the documentation isn't updated in sync.

    Instead, the doc should probably be put into the master branch (with the repo itself) and deployed into the gh-pages branch via a script.

    opened by Ocramius 0
Releases(3.0.0)
  • 3.0.0(Sep 21, 2014)

    • Query functions are passed each value with their associated key as the second parameter while maintaining support for single parameter internal functions.

    • Proper support for non scalar keys:

      • Non scalar keys will be automatically converted to integers when foreach'd or converted to an array.
      • Added ITraversable::iterate to iterate all unaltered values and keys
      • Added ITraversable::keys select the keys and ITraversable::reindex to reindex the values by their 0-based position
      • Added ITraversable::getTrueIterator to get the iterator for all values and unaltered keys.
    • Refactored iterator structure:

      • Abstracted iterator implementations under Iterators\IIteratorScheme.
      • Now supports generators for performance improvement and reduced memory usage for >= PHP 5.5.0
      • Will fall back to iterators for <= PHP 5.5.0
        • Native iterators have also been improved with regards to performance.
    • Implemented new ITraversable source semantics:

      • A source ITraversable is the instance containing the original underlying elements.

      • Added ITraversable::isSource, returns whether the instance is the source ITraversable.

        $elements = Traversable::from(range(1, 100));
        $elements->isSource(); //true
        $someElements = $elements->where(function ($i) { return $i > 50; });
        $someElements->isSource(); //false
        
      • Added ITraversable::getSource, returns the source ITraversable or itself if it is the source.

      • Removed unnecessary caching in Traversable queries.

        • Traversable can be used with nondeterministic/mutable sources and query parameters.
        • Traversable classes can longer be serialized when queried with closures.
        • Because of this combined with covariant return types, ICollection has new and improved mutable query API:
        $collection = Collection::from(range(1, 10));
        $collection
                ->where(function ($i) { return $i >= 5; })
                ->apply(function (&$i) { $i *= 10; });
        
        $collection->asArray();//[1, 2, 3, 4, 50, 60, 70, 80, 90, 100]
        
        $collection
                /* ... */
                ->clear();
        //Is equivalent to:
        $collection
                ->removeRange(/* ... */);
        
    • Removed ITraversable::asQueryable, ITraversable::asRepository, updated interfaces annotations with covariant return types. ITraversable, ICollection, IQueryable, IRepository should all return their respective types for each query method.

    • Moved/Implemented Necessary interfaces (IOrdered*, IJoiningOn*, IJoiningTo*) with covariant return types under Interfaces namespace.

    • Removed IGroupedTraversable, use ITraversable::groupBy returning an array instead.

    • ITraversable::groupBy implicitly indexes each group by the group key.

    • Changed ITraversable::exists in favour of ITraversable::isEmpty.

    • Traversable/Collection are now extendable.

    • IJoiningOnTraversable::onEquality will not match nulls as equal as in C#.

    • Implemented optional default value for ITraversable::join/ITraversable::groupJoin:

      • The following join query:
      Traversable::from(range(1, 6))
          ->join(range(1, 20))
          ->on(function ($outer, $inner) { return $outer % 2 === 0 && $outer * 2 === $inner; })
          ->withDefault('<Odd>')
          ->to(function ($outer, $inner) { 
              return $outer . ':' . $inner;
          });
      

      Will produce: ['1:<Odd>', '2:4', '3:<Odd>', '4:8', '5:<Odd>', '6:12']

    • Added join(...)->apply(...) operation for ICollection/IRepository

    • Added ICollection::remove to remove all occurrences of the supplied value from the collection.

    • Made order by Direction constants interchangeable with native SORT_ASC/SORT_DESC.

    • Shorten expression getter names by removing redundant ...Expression.

    • Restructured and improved function parsing

      • New function reflection API
      • Correctly handle resolving magic constants (__DIR__...) and scopes (self::...).
      • Largely improved signature matching using all reflection data to resolve to the correct function. Functions now have to be defined on the same line with identical signatures to cause an ambiguity.
      • Fixed fully qualified namespace detection in AST parsing.
      • Upgraded to nikic/php-parser V1.0.0 with compatibility for 5.6 syntax features.
      • Updated namespace: Parsing\PHPParser to Parsing\PhpParser.
    • Improved query representations (Queries namespace)

      • New builder API (under Builders) to build query objects from expression trees. Queryable/Repository now only construct the query expression tree. These classes parse the expression tree into the equivalent query structure.
      • Query parameters are now externalized from the query object. Under a IParameterRegistry instance.
      • New common ISource interface for a another sequence inside a query: ->intersect(...)
      • Removed FunctionExpressionTree in favour of dedicated function types (under Queries\Functions namespace) for all types of functions in a query:
        • ElementProjection: ->select(function ($value, $key) { return ... })
        • ElementMutator: ->apply(function (&$value, $key) { ... })
        • ConnectorProjection: ->join(...)->to(function ($outerValue, $innerValue, $outerKey, $innerKey) { return ... })
        • ConnectorMutator: ->join(...)->apply(function (&$outerValue, $innerValue, $outerKey, $innerKey) { ... })
        • Aggregator: ->aggregate(function ($aggregate, $value) { return ... })
      • New ISourceInfo to store source information of a IQueryable.
      • Refactored Segments\OrderBy query segment by representing each function and direction as an Queries\Segments\OrderFunction class.
      • Renamed Segments\Operation::getTraversable to getValues
      • Refactored Join query segments / operations.
        • Refactored inheritance to composition, extracted join filtering to interface Queries\Common\Join\IFilter.
        • Created class containing common join options: Queries\Common\Join\Options.
      • Extracted interfaces from Request/Operation/Segment visitor classes.
    • Removed obsolete query providers (Loadable, Caching) in favour of a new integrated helper Providers\Utilities\IQueryResultCollection

    • Implemented new DSL query provider under Providers\DSL.

    • Implemented new static analysis tools and infrastructure for expression trees under the Analysis namespace.

    • New structure of query providers

      • RepositoryProvider decorates the QueryProvider
      • New configuration classes (under Providers\Configuration namespace)
      • Integrated with Caching\IQueryCache and Queries\Builders\*.
    • New expression classes: UnsetExpression, StaticFieldExpression, ConstantExpression, ClassConstantExpression

    • Refactored ArrayExpression by creating ArrayItemExpression representing each element.

    • Refactored ClosureExpression by creating ClosureUsedVariableExpression representing each used variable and supports references.

    • Updated expression simplification to use compilation + eval with an IEvaluationContext, integrated into reflection and query API.

    • Ensure PSR-2 code guidelines adherence.

    • Fixed binary operation instanceof compilation bug with literal class names.

    • Refactored caching implementation:

      • Caching\Provider renamed to Caching\CacheProvider
      • Caching\IQueryCache now acts as a wrapper to Caching\ICacheAdapter.
      • Any type of value can be cached and retrieved through the cache adapter.
      • Implemented cache namespacing API.
    • Fixed issue with ITraversable::union not reindexing keys.

    • Fixed issue with Iterators\Common\Set not detecting null values.

    Source code(tar.gz)
    Source code(zip)
`LINQ to Object` inspired DSL for PHP

Ginq Array handling in PHP? Be happy with Ginq! Ginq is a DSL that can handle arrays and iterators of PHP unified. Ginq is inspired by Linq to Object,

Atsushi Kanehara 191 Dec 19, 2022
A Collections library for PHP.

A Library of Collections for OO Programming While developing and helping others develop PHP applications I noticed the trend to use PHP's arrays in ne

Levi Morrison 629 Nov 20, 2022
🗃 Array manipulation library for PHP, called Arrayy!

?? Arrayy A PHP array manipulation library. Compatible with PHP 7+ & PHP 8+ \Arrayy\Type\StringCollection::create(['Array', 'Array'])->unique()->appen

Lars Moelleken 430 Jan 5, 2023
Collections Abstraction library for PHP

Collections Collections Abstraction library for PHP The Collection library is one of the most useful things that many modern languages has, but for so

Ítalo Vietro 62 Dec 27, 2021
Library for (de-)serializing data of any complexity (supports JSON, and XML)

jms/serializer Introduction This library allows you to (de-)serialize data of any complexity. Currently, it supports XML and JSON. It also provides yo

Johannes 2.2k Jan 1, 2023
:lipstick: Scalable and durable all-purpose data import library for publishing APIs and SDKs.

Porter Scalable and durable data imports for publishing and consuming APIs Porter is the all-purpose PHP data importer. She fetches data from anywhere

null 594 Jan 1, 2023
[READ-ONLY] Collection library in CakePHP. This repo is a split of the main code that can be found in https://github.com/cakephp/cakephp

CakePHP Collection Library The collection classes provide a set of tools to manipulate arrays or Traversable objects. If you have ever used underscore

CakePHP 85 Nov 28, 2022
True asynchronous PHP I/O and HTTP without frameworks, extensions, or annoying code. Uses the accepted Fibers RFC to be implemented into PHP 8.1

PHP Fibers - Async Examples Without External Dependencies True asynchronous PHP I/O and HTTP without frameworks, extensions, or annoying code behemoth

Cole Green 121 Jan 6, 2023
Map nested JSON structures onto PHP classes

JsonMapper - map nested JSON structures onto PHP classes Takes data retrieved from a JSON web service and converts them into nested object and arrays

Christian Weiske 1.4k Dec 30, 2022
A repository with implementations of different data structures and algorithms using PHP

PHP Data Structures and Algorithms Data structure and Algorithm is always important for any programming language. PHP, being one of the most popular l

Mizanur Rahman 610 Jan 2, 2023
Leetcode for PHP, five questions a week and weekends are updated irregularly

✏️ Leetcode for PHP why do you have to sleep for a long time ,and naturally sleep after death 联系 说明 由于目前工作主要是 golang,我又新起了一个LeetCode-Go-Week项目,- Leetc

吴亲库里 370 Dec 29, 2022
Missing data types for PHP. Highly extendable.

Neverending data validation can be exhausting. Either you have to validate your data over and over again in every function you use it, or you have to rely it has already been validated somewhere else and risk potential problems.

SmartEmailing 82 Nov 11, 2022
JsonMapper - map nested JSON structures onto PHP classes

Takes data retrieved from a JSON web service and converts them into nested object and arrays - using your own model classes.

Netresearch 9 Aug 21, 2022
All Algorithms implemented in Php

The Algorithms - PHP All algorithms implemented in Php (for education) These implementations are for learning purposes. They may be less efficient tha

The Algorithms 1k Dec 27, 2022
A community driven collection of sorting algorithms in PHP

algorithms A community driven collection of sorting algorithms This repository includes a comma separated file that includes 10k numbers between 1 and

Andrew S Erwin 0 May 16, 2022
Iterators - The missing PHP iterators.

PHP Iterators Description The missing PHP iterators. Features CachingIteratorAggregate ClosureIterator: ClosureIterator(callable $callable, array $arg

(infinite) loophp 24 Dec 21, 2022
Yet Another LINQ to Objects for PHP [Simplified BSD]

YaLinqo: Yet Another LINQ to Objects for PHP Online documentation GitHub repository Features The most complete port of .NET LINQ to PHP, with many add

Alexander Prokhorov 436 Jan 3, 2023
`LINQ to Object` inspired DSL for PHP

Ginq Array handling in PHP? Be happy with Ginq! Ginq is a DSL that can handle arrays and iterators of PHP unified. Ginq is inspired by Linq to Object,

Atsushi Kanehara 191 Dec 19, 2022
MOP is a php query handling and manipulation library providing easy and reliable way to manipulate query and get result in a fastest way

Mysql Optimizer mysql optimizer also known as MOP is a php query handling and manipulation library providing easy and reliable way to manipulate query

null 2 Nov 20, 2021
MOP is a php query handling and manipulation library providing easy and reliable way to manipulate query and get result in a fastest way. ( WEBSITE VERSION )

Mysql Optimizer mysql optimizer also known as MOP is a php query handling and manipulation library providing easy and reliable way to manipulate query

null 3 Feb 14, 2022