Yet Another LINQ to Objects for PHP [Simplified BSD]

Overview

YaLinqo: Yet Another LINQ to Objects for PHP

Travis CI Status Coveralls Coverage Scrutinizer Code Quality SensioLabs Insight Check VersionEye Dependencies
Packagist Downloads VersionEye References Packagist Version GitHub License

Features

  • The most complete port of .NET LINQ to PHP, with many additional methods.
  • Lazy evaluation, error messages and other behavior of original LINQ.
  • Detailed PHPDoc and online reference based on PHPDoc for all methods. Articles are adapted from original LINQ documentation from MSDN.
  • 100% unit test coverage.
  • Best performance among full-featured LINQ ports (YaLinqo, Ginq, Pinq), at least 2x faster than the closest competitor, see performance tests.
  • Callback functions can be specified as closures (like function ($v) { return $v; }), PHP "function pointers" (either strings like 'strnatcmp' or arrays like array($object, 'methodName')), string "lambdas" using various syntaxes ('"$k = $v"', '$v ==> $v+1', '($v, $k) ==> $v + $k', '($v, $k) ==> { return $v + $k; }').
  • Keys are as important as values. Most callback functions receive both values and the keys; transformations can be applied to both values and the keys; keys are never lost during transformations, if possible.
  • SPL interfaces Iterator, IteratorAggregate etc. are used throughout the code and can be used interchangeably with Enumerable.
  • Redundant collection classes are avoided, native PHP arrays are used everywhere.
  • Composer support (package on Packagist).
  • No external dependencies.

Implemented methods

Some methods had to be renamed, because their names are reserved keywords. Original methods names are given in parenthesis.

  • Generation: cycle, emptyEnum (empty), from, generate, toInfinity, toNegativeInfinity, matches, returnEnum (return), range, rangeDown, rangeTo, repeat, split;
  • Projection and filtering: cast, ofType, select, selectMany, where;
  • Ordering: orderBy, orderByDescending, orderByDir, thenBy, thenByDescending, thenByDir;
  • Joining and grouping: groupJoin, join, groupBy;
  • Aggregation: aggregate, aggregateOrDefault, average, count, max, maxBy, min, minBy, sum;
  • Set: all, any, append, concat, contains, distinct, except, intersect, prepend, union;
  • Pagination: elementAt, elementAtOrDefault, first, firstOrDefault, firstOrFallback, last, lastOrDefault, lastOrFallback, single, singleOrDefault, singleOrFallback, indexOf, lastIndexOf, findIndex, findLastIndex, skip, skipWhile, take, takeWhile;
  • Conversion: toArray, toArrayDeep, toList, toListDeep, toDictionary, toJSON, toLookup, toKeys, toValues, toObject, toString;
  • Actions: call (do), each (forEach), write, writeLine.

In total, more than 80 methods.

Example

Process sample data:

// Data
$products = array(
    array('name' => 'Keyboard',    'catId' => 'hw', 'quantity' =>  10, 'id' => 1),
    array('name' => 'Mouse',       'catId' => 'hw', 'quantity' =>  20, 'id' => 2),
    array('name' => 'Monitor',     'catId' => 'hw', 'quantity' =>   0, 'id' => 3),
    array('name' => 'Joystick',    'catId' => 'hw', 'quantity' =>  15, 'id' => 4),
    array('name' => 'CPU',         'catId' => 'hw', 'quantity' =>  15, 'id' => 5),
    array('name' => 'Motherboard', 'catId' => 'hw', 'quantity' =>  11, 'id' => 6),
    array('name' => 'Windows',     'catId' => 'os', 'quantity' => 666, 'id' => 7),
    array('name' => 'Linux',       'catId' => 'os', 'quantity' => 666, 'id' => 8),
    array('name' => 'Mac',         'catId' => 'os', 'quantity' => 666, 'id' => 9),
);
$categories = array(
    array('name' => 'Hardware',          'id' => 'hw'),
    array('name' => 'Operating systems', 'id' => 'os'),
);

// Put products with non-zero quantity into matching categories;
// sort categories by name;
// sort products within categories by quantity descending, then by name.
$result = from($categories)
    ->orderBy('$cat ==> $cat["name"]')
    ->groupJoin(
        from($products)
            ->where('$prod ==> $prod["quantity"] > 0')
            ->orderByDescending('$prod ==> $prod["quantity"]')
            ->thenBy('$prod ==> $prod["name"]'),
        '$cat ==> $cat["id"]', '$prod ==> $prod["catId"]',
        '($cat, $prods) ==> array(
            "name" => $cat["name"],
            "products" => $prods
        )'
    );

// Alternative shorter syntax using default variable names
$result2 = from($categories)
    ->orderBy('$v["name"]')
    ->groupJoin(
        from($products)
            ->where('$v["quantity"] > 0')
            ->orderByDescending('$v["quantity"]')
            ->thenBy('$v["name"]'),
        '$v["id"]', '$v["catId"]',
        'array(
            "name" => $v["name"],
            "products" => $e
        )'
    );

// Closure syntax, maximum support in IDEs, but verbose and hard to read
$result3 = from($categories)
    ->orderBy(function ($cat) { return $cat['name']; })
    ->groupJoin(
        from($products)
            ->where(function ($prod) { return $prod["quantity"] > 0; })
            ->orderByDescending(function ($prod) { return $prod["quantity"]; })
            ->thenBy(function ($prod) { return $prod["name"]; }),
        function ($cat) { return $cat["id"]; },
        function ($prod) { return $prod["catId"]; },
        function ($cat, $prods) {
            return array(
                "name" => $cat["name"],
                "products" => $prods
            );
        }
    );

print_r($result->toArrayDeep());

Output (compacted):

Array (
    [hw] => Array (
        [name] => Hardware
        [products] => Array (
            [0] => Array ( [name] => Mouse       [catId] => hw [quantity] =>  20 [id] => 2 )
            [1] => Array ( [name] => CPU         [catId] => hw [quantity] =>  15 [id] => 5 )
            [2] => Array ( [name] => Joystick    [catId] => hw [quantity] =>  15 [id] => 4 )
            [3] => Array ( [name] => Motherboard [catId] => hw [quantity] =>  11 [id] => 6 )
            [4] => Array ( [name] => Keyboard    [catId] => hw [quantity] =>  10 [id] => 1 )
        )
    )
    [os] => Array (
        [name] => Operating systems
        [products] => Array (
            [0] => Array ( [name] => Linux       [catId] => os [quantity] => 666 [id] => 8 )
            [1] => Array ( [name] => Mac         [catId] => os [quantity] => 666 [id] => 9 )
            [2] => Array ( [name] => Windows     [catId] => os [quantity] => 666 [id] => 7 )
        )
    )
)

Requirements

  • Version 1 (stable): PHP 5.3 or higher.
  • Version 2 (stable): PHP 5.5 or higher.
  • Version 3 (pre-alpha): PHP 7.0 or higher.

Usage

Add to composer.json:

{
    "require": {
        "athari/yalinqo": "^2.0"
    }
}

Add to your PHP script:

require_once 'vendor/autoloader.php';
use \YaLinqo\Enumerable;

// 'from' can be called as a static method or via a global function shortcut
Enumerable::from(array(1, 2, 3));
from(array(1, 2, 3));

License

Simplified BSD License
Copyright © 2012–2018, Alexander Prokhorov
All rights reserved.

Links

YaLinqo Articles

Related projects

  • linq.js — LINQ for JavaScript. The one and only complete port of .NET LINQ to JavaScript.
  • Underscore.js — library for functional programming in JavaScript. Similar to LINQ, but different method names and no lazy evaluation.
  • Underscore.php — port of Underscore.js to PHP.
  • RxPHP — reactive (push) counterpart of the active (pull) LINQ, port of Rx.NET.
  • YaLinqoPerf — collection of performance tests comparing raw PHP, array functions, YaLinqo, YaLinqo with string lambdas, Ginq, Ginq with property accessors, Pinq.
Comments
  • Iterating through two arrays of objects with same ids

    Iterating through two arrays of objects with same ids

    Hello, is it possible to iterate through this two arrays of objects using the library?, and how do I get the $obj->id property so I can check using it inside the ->where() and retrieve an array with the objects where the id's are equal. It would be great if you can provide an example.

    //json_encode($arr) output:
    [{"id":0,"name":"","surname":""},{"id":1,"name":"","surname":""},{"id":2,"name":"","surname":""},{"id":3,"name":"","surname":""},{"id":4,"name":"","surname":""}]
    //json_encode($arr1) output:
    [{"id":1,"name":"","surname":""},{"id":2,"name":"","surname":""},{"id":3,"name":"","surname":""},{"id":4,"name":"","surname":""},{"id":5,"name":"","surname":""}]
    

    Thanks in advance!!!

    resolved:done type:support 
    opened by eebanos 6
  • 'Cannot traverse an already closed generator' when running benchmarks from YaLinqoPerf

    'Cannot traverse an already closed generator' when running benchmarks from YaLinqoPerf

    After playing around with YaLinqoPerf, I ran composer update to get the latest versions of the libraries and YaLinqo began to throw exceptions 'Cannot traverse an already closed generator' on some of the benchmarks.

    Here is some sample output:

    Iterating over 100 ints .....
    -----------------------
      PHP     [for]               0.00001 sec   x1.0 (100%)
      PHP     [array functions]   0.00002 sec   x2.0 (+100%)
      YaLinqo                     0.00003 sec   x3.0 (+200%)
      Ginq                        0.00021 sec   x21.0 (+2000%)
      Pinq                        0.00016 sec   x16.0 (+1500%)
    
    Generating array of 100 integers .....
    --------------------------------
      PHP     [for]               0.00003 sec   x1.0 (100%)
      PHP     [array functions]   0.00003 sec   x1.0 (+0%)
      YaLinqo                     0.00007 sec   x2.3 (+133%)
      Ginq                        0.00022 sec   x7.3 (+633%)
      Pinq                        0.00008 sec   x2.7 (+167%)
    
    Generating lookup of 100 floats, calculate sum .....
    ----------------------------------------------
      PHP                         0.00031 sec   x1.0 (100%)
      YaLinqo                     0.00086 sec   x2.8 (+177%)
      YaLinqo [string lambda]     0.00078 sec   x2.5 (+152%)
      Ginq                        0.00558 sec   x18.0 (+1701%)
      Pinq                        * Not implemented
    
    Counting values in arrays ......
    -------------------------
      PHP     [for]               0.00003 sec   x1.0 (100%)
      PHP     [array functions]   0.00007 sec   x2.3 (+133%)
      YaLinqo                     0.00010 sec   x3.3 (+233%)
      YaLinqo [string lambda]     0.00010 sec   x3.3 (+233%)
      Ginq                        0.00021 sec   x7.0 (+600%)
      Pinq                        0.00035 sec   x11.7 (+1067%)
    
    Counting values in arrays deep .....
    ------------------------------
      PHP     [for]               0.00007 sec   x1.0 (100%)
      PHP     [array functions]   0.00051 sec   x7.3 (+629%)
      YaLinqo                     0.00092 sec   x13.1 (+1214%)
      Ginq                        0.00173 sec   x24.7 (+2371%)
      Pinq                        0.00442 sec   x63.1 (+6214%)
    
    Filtering values in arrays ......
    --------------------------
      PHP     [for]               0.00004 sec   x1.0 (100%)
      PHP     [array functions]   0.00008 sec   x2.0 (+100%)
      YaLinqo                     * Cannot traverse an already closed generator
      YaLinqo [string lambda]     * Cannot traverse an already closed generator
      Ginq                        0.00036 sec   x9.0 (+800%)
      Pinq                        0.00032 sec   x8.0 (+700%)
    
    Filtering values in arrays deep ......
    -------------------------------
      PHP     [for]               0.00039 sec   x1.0 (100%)
      PHP     [array functions]   0.00069 sec   x1.8 (+77%)
      YaLinqo                     * Cannot traverse an already closed generator
      YaLinqo [string lambda]     * Cannot traverse an already closed generator
      Ginq                        0.00428 sec   x11.0 (+997%)
      Pinq                        0.00529 sec   x13.6 (+1256%)
    
    Sorting arrays ......
    --------------
      PHP                         0.00002 sec   x1.0 (100%)
      YaLinqo                     0.00008 sec   x4.0 (+300%)
      YaLinqo [string lambda]     0.00007 sec   x3.5 (+250%)
      Ginq                        0.00023 sec   x11.5 (+1050%)
      Ginq    [property path]     0.00068 sec   x34.0 (+3300%)
      Pinq                        0.00023 sec   x11.5 (+1050%)
    
    Joining arrays ......
    --------------
      PHP                         0.00002 sec   x1.0 (100%)
      YaLinqo                     * Cannot traverse an already closed generator
      YaLinqo [string lambda]     * Cannot traverse an already closed generator
      Ginq                        0.00016 sec   x8.0 (+700%)
      Ginq    [property path]     0.00029 sec   x14.5 (+1349%)
      Pinq                        0.00109 sec   x54.5 (+5348%)
    
    Aggregating arrays .......
    ------------------
      PHP     [for]               0.00008 sec   x1.0 (100%)
      PHP     [array functions]   0.00024 sec   x3.0 (+200%)
      YaLinqo                     0.00027 sec   x3.4 (+238%)
      YaLinqo [string lambda]     0.00031 sec   x3.9 (+288%)
      Ginq                        0.00088 sec   x11.0 (+1000%)
      Ginq    [property path]     0.00507 sec   x63.4 (+6238%)
      Pinq                        0.00186 sec   x23.3 (+2225%)
    
    Aggregating arrays custom .....
    -------------------------
      PHP                         0.00001 sec   x1.0 (100%)
      YaLinqo                     0.00007 sec   x7.0 (+600%)
      YaLinqo [string lambda]     0.00008 sec   x8.0 (+700%)
      Ginq                        0.00007 sec   x7.0 (+600%)
      Pinq                        0.00054 sec   x54.0 (+5301%)
    
    Process data from ReadMe example .....
    --------------------------------
      PHP                         0.00060 sec   x1.0 (100%)
      YaLinqo                     * Cannot traverse an already closed generator
      YaLinqo [string lambda]     * Cannot traverse an already closed generator
      Ginq                        0.00780 sec   x13.0 (+1200%)
      Pinq                        0.00340 sec   x5.7 (+467%)
    
    resolved:wontfix type:support 
    opened by TimeToogo 6
  • Version 3 doesn't exist

    Version 3 doesn't exist

    The documentation claims: Add to composer.json: "athari/yalinqo": "^3.0". However, version 3 does not exist.

    • The requested package athari/yalinqo ^3 exists as athari/yalinqo[dev-master, 2.x-dev, v1.0.0.0, v1.0.1.0, v1.0.1.1, v1.0.x-dev, v1.1.0.0, v1.1.1, v1.1.2, v2.0.0.0, v2.0.x-dev, v2.1.0.0, v2.2.0.0, v2.3.0.0, v2.3.1, v2.4.0, v2.4.1] but these are rejected by your constraint.
    type:bug resolved:done 
    opened by Bilge 5
  • Joining multiple arrays

    Joining multiple arrays

    Hello thank you for such awesome script! I want to join 4 arrays. But honestly I coudn't undersand the documentation. Right now I have an sql query:

    $ZoneID = '1';
    $TillageID = '2';
    $rs = mySQLquery("SELECT
            CR.CropID AS CropID,
            CP.OperID AS OperID,
            CP.ParentOperID AS ParentOperID,
            A.ActionID AS ActionID,
            A.WorkloadUnit AS WorkloadUnit,
            A.WorkpayUnit AS WorkpayUnit,
            AT.ActionTypeID AS ActionTypeID,
            A.Labor_prod AS LaborProd,
            A.Labor_rate AS LaborRate,
            A.Mech_rate AS ServiceRate,
            AT.Category AS WorkCategory,
            CP.Feature AS Feature,
            CP.StartYear AS StartYear,
            CP.StartMonth AS StartMonth,
            CP.StartDay AS StartDay,
            CP.EndYear AS EndYear,
            CP.EndMonth AS EndMonth,
            CP.EndDay AS EndDay
            FROM
            ((mlp_cropplan CP
            INNER JOIN mlp_crops CR ON CP.CropID = CR.CropID)
            INNER JOIN mlp_actions A ON CP.ActionID = A.ActionID)
            INNER JOIN mlp_actiontypes AT ON A.ActionTypeID = AT.ActionTypeID
            WHERE (CP.TillageID = 0 OR CP.TillageID = " . $TillageID . ")
            AND (CP.ZoneID = 0 OR CP.ZoneID = " . $ZoneID . ")          
            ORDER BY CR.CropID ASC, CP.OperID ASC");
    

    But I want to use yalinqo instead of mysql. I dumped all the date from these table and made php arrays. Here is the code:

    $rs2 = from( $mlp_cropplan )
            ->where(function( $mlp_cropplan ) { 
                global $TillageID, $ZoneID;
                return ( ( $mlp_cropplan['TillageID'] == 0 || $mlp_cropplan['TillageID'] == $TillageID ) && ( $mlp_cropplan['ZoneID'] == 0 || $mlp_cropplan['ZoneID'] == $ZoneID ) ); 
            } )
            ->orderBy( function( $mlp_cropplan ) { return $mlp_cropplan['CropID']; } )
            ->thenBy( function( $mlp_cropplan ) { return $mlp_cropplan['CropID']; } )
            ->join( from( $mlp_crops ), 
                function( $mlp_cropplan ) { return $mlp_cropplan['CropID']; }, 
                function( $mlp_crops ) { return $mlp_crops['CropID']; }, 
                function( $mlp_cropplan, $mlp_crops ) {
                    return array(
                        'CropID' => $mlp_cropplan['CropID'],
                        'OperID' => $mlp_cropplan['OperID'],
                        'ParentOperID' => $mlp_cropplan['ParentOperID'],
                        'Feature' => $mlp_cropplan['Feature'],
                        'StartYear' => $mlp_cropplan['StartYear'],
                        'StartMonth' => $mlp_cropplan['StartMonth'],
                        'StartDay' => $mlp_cropplan['StartDay'],
                        'EndYear' => $mlp_cropplan['EndYear'],
                        'EndMonth' => $mlp_cropplan['EndMonth'],
                        'EndDay' => $mlp_cropplan['EndDay'],
                        'ActionID' => $mlp_cropplan['ActionID'],
                    );
                } )
            ->join( from( $mlp_actions ), 
                function( $mlp_cropplan ) { return $mlp_cropplan['ActionID']; }, 
                function( $mlp_actions ) { return $mlp_actions['ActionID']; }, 
                function( $mlp_cropplan, $mlp_actions ) {
                    return array(
                        'CropID' => $mlp_cropplan['CropID'],
                        'OperID' => $mlp_cropplan['OperID'],
                        'ParentOperID' => $mlp_cropplan['ParentOperID'],
                        'ActionID' => $mlp_cropplan['ActionID'],
                        'WorkloadUnit' => $mlp_actions['WorkloadUnit'],
                        'WorkpayUnit' => $mlp_actions['WorkpayUnit'],
                        'LaborProd' => $mlp_actions['Labor_prod'],
                        'LaborRate' => $mlp_actions['Labor_rate'],
                        'ServiceRate' => $mlp_actions['Mech_rate'],
                        'Feature' => $mlp_cropplan['Feature'],
                        'StartYear' => $mlp_cropplan['StartYear'],
                        'StartMonth' => $mlp_cropplan['StartMonth'],
                        'StartDay' => $mlp_cropplan['StartDay'],
                        'EndYear' => $mlp_cropplan['EndYear'],
                        'EndMonth' => $mlp_cropplan['EndMonth'],
                        'EndDay' => $mlp_cropplan['EndDay'],
                        'ActionTypeID' => $mlp_actions['ActionTypeID'],  
                    );
                } )
            ->join( from( $mlp_actiontypes ), 
                function( $mlp_cropplan ) { return $mlp_cropplan['ActionTypeID']; }, 
                function( $mlp_actiontypes ) { return $mlp_actiontypes['ActionTypeID']; }, 
                function( $mlp_cropplan, $mlp_actiontypes ) {
                    return array(
                        'CropID' => $mlp_cropplan['CropID'],
                        'OperID' => $mlp_cropplan['OperID'],
                        'ParentOperID' => $mlp_cropplan['ParentOperID'],
                        'ActionID' => $mlp_cropplan['ActionID'],
                        'WorkloadUnit' => $mlp_cropplan['WorkloadUnit'],
                        'WorkpayUnit' => $mlp_cropplan['WorkpayUnit'],
                        'ActionTypeID' => $mlp_actiontypes['ActionTypeID'],
                        'LaborProd' => $mlp_cropplan['Labor_prod'],
                        'LaborRate' => $mlp_cropplan['Labor_rate'],
                        'ServiceRate' => $mlp_cropplan['Mech_rate'],
                        'WorkCategory' => $mlp_actiontypes['Category'],
                        'Feature' => $mlp_cropplan['Feature'],
                        'StartYear' => $mlp_cropplan['StartYear'],
                        'StartMonth' => $mlp_cropplan['StartMonth'],
                        'StartDay' => $mlp_cropplan['StartDay'],
                        'EndYear' => $mlp_cropplan['EndYear'],
                        'EndMonth' => $mlp_cropplan['EndMonth'],
                        'EndDay' => $mlp_cropplan['EndDay'],
                    );
                } );
    

    The code is working, bu after second join the data of the first join is disappearing, please help me :-(

    resolved:done type:support 
    opened by anvarulugov 5
  • Examples?

    Examples?

    Why aren't there any examples? I get that this is a port of LINQ and many people may be familiar, but I am not and would like to use this lib. I appreciate the elegance of LINQ in filtering datasets, and PHP doesn't really have anything natively or other libs much for this.

    I'm trying to pass from a Doctrine Collection object. Then call first(). However, I'm getting Sequence contains no matching elements.. Why?

    resolved:done type:support 
    opened by oojacoboo 4
  • Can I employ the 'use' language construct when using a string predicate?

    Can I employ the 'use' language construct when using a string predicate?

    Let's say I have something like this:

    $foo = ['hello' => true];
    $bar = ['hello' => 'candy canes'];
    

    I can echo 'candy canes' like this:

    foreach (Enumerable::from($foo)
                ->where('$v ==> $v')
                ->select(function ($v, $k) use ($bar) {return $bar[$k];}) as $baz) {
        echo $baz;
    }
    

    Is it possible to do something like this though?

    foreach (Enumerable::from($foo)
                ->where('$v ==> $v')
                ->select('($v, $k) use ($bar) ==> $bar[$k]') as $baz) {
        echo $baz;
    }
    

    Obviously it throws an exception, I'm just wondering if it's possible.

    type:feature resolved:wontfix 
    opened by BrandonLegault 4
  • Using with PDO MySQL - a datetime example

    Using with PDO MySQL - a datetime example

    hi there,

    Im using it also to 'query' date/datetime field, in example an array from PDO MySQL, works flawless... :) not optimized the manual dates (2017-02-12/2017-02-15) should be stored on vars, out of the loop.

    $result3 = from($rows)
    ->where(function ($x) { return
    strtotime($x['datecreated']) >= strtotime("2017-02-12") && 
    strtotime($x['datecreated']) < strtotime("2017-02-15"); })
    ->select(function($res){ return array(
                "country" => $res['country'],
                "datecreated" => $res['datecreated']
            ); })
    ->toArray();
    

    and also advise that can be used without composer :

    require_once('/YaLinqo/Utils.php');
    require_once('/YaLinqo/Functions.php');
    require_once('/YaLinqo/Linq.php');
    require_once('/YaLinqo/EnumerablePagination.php');
    require_once('/YaLinqo/EnumerableGeneration.php');
    require_once('/YaLinqo/Enumerable.php');
    require_once('/YaLinqo/Errors.php');
    require_once('/YaLinqo/OrderedEnumerable.php');
    

    for groupby - check also - https://gist.github.com/mcaskill/baaee44487653e1afc0d

    thanks for your time!

    resolved:done type:support 
    opened by pipiscrew 4
  • GroupBy Deep works for groupBy('$v[

    GroupBy Deep works for groupBy('$v["A"]', '$v["B"]') but crashes for groupBy('$v["A"]', '$v["B"]', '$v["C"]')

    Hi!

    Beautiful package, but I have probably an easy roadblock to solve since this morning, please let me explain my scenario, I am gathering the following array result (Role/Area/Permissions) from a Laravel Builder Query:

    array
      0 => 
        array
          'RoleName' => string 'Root'
          'AreaName' => string 'Global'
          'PermissionName' => string 'Post'
      1 => 
        array (size=3)
          'RoleName' => string 'Root'
          'AreaName' => string 'Global'
          'PermissionName' => string 'Delete'
      3 => 
        array (size=3)
          'RoleName' => string 'Editor'
          'AreaName' => string 'Europe'
          'PermissionName' => string 'Index'
      4 => 
        array (size=3)
          'RoleName' => string 'Editor'
          'AreaName' => string 'Europe'
          'PermissionName' => string 'Post'
    

    and I was wondering how to produce the following array result using your groupBy method:

    Root
        Global
            Post
            Delete
            ...
    
    ...
    
    Editor
        Europe
            Index
            Area
            ...
    

    This what I am currently using right now:

            $roles = from($permissions)
                ->groupBy('$v["RoleName"]', '$v["AreaName"]', '$v["PermissionName"]')
                ->toArray();
    

    Thanks in advance!

    resolved:done type:support 
    opened by josoroma-zz 3
  • Memory consumption of create_function()

    Memory consumption of create_function()

    I have noticed a lot of memory leaks if using the short syntax like

    from($array)->select("explode(', ', $v)")->toArray();
    

    But it's ok with closures

    from($array)->select(function($var) { return explode(', ', $var); })->toArray();
    

    proceeding first loop at one runtime with a big amount of data will cause to overhead of memory.

    Not sure if this bottleneck is reason of lib implementation, or PHP's create_function(), but if you suggest me, I'll write a test samples of this issue.

    type:bug resolved:done 
    opened by cursedcoder 3
  • Enumerable::getIterator fails silently

    Enumerable::getIterator fails silently

    For some reason, when calling toArray, which called getIterator, the script is failing silently. I've confirmed the array being passed to from is okay. It is a fairly deeply nested array with many objects.

    I guess the real question here is... what's preventing exceptions?

    type:bug resolved:invalid 
    opened by oojacoboo 2
  • Two conditions within where clause

    Two conditions within where clause

    While I'm trying to iterate through the WP users table to check meta option where ID and meta_key are the where clause conditions used in the following code:

    $db_usermeta = $wpdb->get_results('SELECT * FROM ' . $wpdb->usermeta );
    foreach ($db_users as $key => $row) {
    	  $usermeta = from($db_usermeta)
    	  ->where(function($db_usermeta) {
          return $db_usermeta["user_id"] === $row->ID && 
    	  $db_usermeta["meta_key"] === "co_dateofbirth" ;})
    	  ->toString();
    	 echo 'co_dateofbirth value is : ' . $usermeta . '<br/>';
    }
    
    resolved:done type:support 
    opened by wpplumber 2
  • Custom comparer in orderBy is ignored if key selector is cached

    Custom comparer in orderBy is ignored if key selector is cached

    Using latest "composer require athari/yalinqo", v2.4.2

    <?php
    
    require 'vendor/autoload.php';
    
    $qwe = [
        'key3' => 3,
        'key2' => 1,
        'key1' => 2
    ];
    
    $asd =
        from($qwe)->
        orderBy(
            // #1
            function($v, $k) {
                return $k;
            },
    
            // #2
            // '$k',
    
            // #3
            // YaLinqo\Functions::$key,
        function($a, $b) {
            echo "in\n";
            return $b <=> $a;
        })->
        toArray();
    
    var_dump($asd);
    
    

    Hi Alexander. If I run code like shown, with key_selector#1, I can see "echo in\n" executed, like expected. But If I run code with key_selector#2 or key_selector#3, I never see "echo in\n" executed, $comparer is never executed. Sorting still works, but not with my custom comparer, just by alphabet.

    I've digged into the sources, and I've found vendor\athari\yalinqo\YaLinqo\OrderedEnumerable.php:127

    trySortBySingleField:
      elseif ($this->keySelector === Functions::$key)
        elseif ($this->sortOrder == SORT_ASC) {
          ksort($array, $this->sortFlags);
    

    If your code found current key selector function is the one from the cache, it never even tries to run provided custom comparer function.

    I expect orderBy to always run comparer function if it is present. Thank you.

    type:bug 
    opened by dima-stefantsov 0
  • OrderedEnumerable::thenBy() expects...

    OrderedEnumerable::thenBy() expects...

    YaLinqo\OrderedEnumerable::thenBy() expects (callable(): mixed)|null, '$v->getTitle()' given.
    

    Similar to https://github.com/Athari/YaLinqo/pull/55

    opened by umpirsky 0
  • $keySelector of method Enumerable::orderBy()

    $keySelector of method Enumerable::orderBy()

    Code:

    Enumerable::from($arr)->orderBy('$v->getDisplayOrder()');
    

    Error:

    Parameter #1 $keySelector of method YaLinqo\Enumerable::orderBy() expects (callable(): mixed)|null, '$v->getDisplayOrder…' given. 
    
    opened by umpirsky 0
  • ReadMe: update syntax, sensible intro for newbies, FAQ

    ReadMe: update syntax, sensible intro for newbies, FAQ

    Update ReadMe to a more sensible state:

    1. Get rid of obsolete string lambda garbage. Cast arrays to objects. Make the code pretty, not scary mess it is now.
    2. Explain basics like what from does, how to chain, how to iterate (come on man, you copypasted that on StackOverflow 10 times already). Literally anything is better than what ReadMe contains now.
    3. Add FAQ with common mistakes like trying to replace ORM with YaLinqo, multiple iterations over a sequence, comparisions etc. Check issues here and on SO.
    4. Links to SO maybe? That stupid "opinionated" question would be a good fit.
    type:improvement 
    opened by Athari 0
  • Replace Functions::compareStrict and compareLoose with spaceship operator

    Replace Functions::compareStrict and compareLoose with spaceship operator

    Remove compareStrict and compareLoose functions in Functions. Add compare function which is implemented using spaceship operayor (<=>).

    compareStrict is unstable anyway (1 < '1' == false, 1 > '1' == false).

    type:improvement 
    opened by Athari 0
Releases(v2.4.0)
  • v2.4.0(Jan 15, 2016)

    • Switched to PSR-4 autoloader.
    • Improved performance of sorting in oderBy*, thenBy*: now uses specific array functions when possible instead of just usort.
    • Added support for Traversable which does not implement Iterator or IteratorAggregate in from.
    • Fixed toString in case of same keys.
    • Added build integration with online tool SensioLabs.
    Source code(tar.gz)
    Source code(zip)
  • v2.3.0.0(Jun 7, 2015)

    • Added set functions: except, intersect, union.
    • Added cast function.
    • Improved performance of some functions by inlining code: range, rangeTo, max, min, sum.
    • Changed iterator wrapping from closure to directly wrapping iterator.
    • Fixed integration with Coveralls.
    • Fixed builds for PHP 7 and HHVM on Travis CI.
    • Code cleanup: short array syntax everywhere.
    Source code(tar.gz)
    Source code(zip)
  • v2.2.0.0(Jun 3, 2015)

    • Added integration with online tools:
      • Travis CI
      • Coveralls
      • Scrutinizer
    • Added string lambda caching to Utils::createLambdaFromString. Should drastically improve performance when queries are performed multiple times.
    • Completed YaLinqoPerf benchmarks, see ReadMe.
    Source code(tar.gz)
    Source code(zip)
  • v1.1.0.0(Jun 3, 2015)

  • v2.1.0.0(Jun 3, 2015)

  • v2.0.0.0(Jul 12, 2014)

    Code upgraded from PHP 5.3 to 5.5. Big performance improvements thanks to new PHP features and removal of unnecessary classes.

    • Dropped support for PHP 5.3.
    • Replaced collections (Dictionary and Lookup) with standard arrays.
    • Replaced Enumerator class with with new yield operator.
    • Replaced call_user_func and call_user_func_array with direct variable function calls.
    • Major code cleanup.
    Source code(tar.gz)
    Source code(zip)
  • v1.0.1.1(Jul 12, 2014)

  • v1.0.1.0(Jul 12, 2014)

  • v1.0.0.0(Jul 12, 2014)

Owner
Alexander Prokhorov
C# & PHP developer
Alexander Prokhorov
`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
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 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
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
StrongShop 是一款免费开源的跨境电商商城网站。基于 PHP Laravel6 框架开发,遵循 BSD-3-Clause 开源协议,免费商用。支持多语言,多货币,多种国际配送方式。PayPal 支付,国际信用卡支付。PC Web 端和移动端自适应。

跨境电商独立站的理想选择之一 StrongShop 简介 StrongShop 是一款免费开源的跨境电商商城网站。 StrongShop 是基于 PHP Laravel 框架开发的一款 Web 商城系统。 开发缘起是公司的一套跨境商城系统,原先公司使用的系统是基于 Ecshop 二次开发的,后来因为

OpenStrong 38 Dec 9, 2022
PHP Integrated Query, a real LINQ library for PHP

PHP Integrated Query - Official site What is PINQ? Based off the .NET's LINQ (Language integrated query), PINQ unifies querying across arrays/iterator

Elliot Levin 465 Dec 30, 2022
`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
YAPS - Yet Another PHP Shell

YAPS - Yet Another PHP Shell Yeah, I know, I know... But that's it. =) As the name reveals, this is yet another PHP reverse shell, one more among hund

Nicholas Ferreira 60 Dec 14, 2022
Simple and minimal yet another PHP 7 Framework

DemirApp Minimal PHP Framework Introduction Simple and minimal yet another PHP 7 Framework Features Simple routing Simple container (Dependency Inject

yidemir 12 Sep 19, 2022
Yet another PHP Microframework.

ρ Yet another PHP Microframework. The premise of this framework is to be backwards-compatible (PHP <= 5.6) with powerful utilities (Like caching and l

null 0 Apr 6, 2022
Here you have yet another framework for writing RESTful web services in PHP

PHP-Rocker Here you have yet another framework for writing RESTful web services in PHP, jay! What sets this framework apart from many of the others is

Victor Jonsson 43 May 19, 2022