Collection|array|object->mixed|null * @method static callable|mixed propOr( ...$default, ...$key, ...$obj ) - Curried :: mixed->string->Collection|array|object->mixed|null * @method static callable|array props( ...$keys, ...$obj ) - Curried :: [keys] → Collection|array|object → [v] * @method static callable|array|\stdClass addProp( ...$key, ...$transformation, ...$obj ) - Curried :: string->callable->object|array->object->array * @method static callable|array|\stdClass removeProp( ...$key, ...$obj ) - Curried :: string->object|array->object->array * @method static callable|array|\stdClass renameProp( ...$key, ...$newKey, ...$obj ) - Curried :: string->string->object|array->object->array * @method static callable|mixed path( ...$path, ...$obj ) - Curried :: array->Collection|array|object->mixed|null * @method static callable|mixed pathOr( ...$default, ...$path, ...$obj ) - Curried :: mixed → array → Collection|array|object → mixed * @method static callable assoc( ...$key, ...$value, ...$item ) - Curried :: string->mixed->Collection|array|object->mixed|null * @method static callable assocPath( ...$path, ...$value, ...$item ) - Curried :: array->mixed->Collection|array|object->mixed|null * @method static callable lens( ...$getter, ...$setter ) - Curried :: callable->callable->callable * @method static callable lensProp( ...$prop ) - Curried :: string->callable * @method static callable lensPath( ...$path ) - Curried :: array->callable * @method static callable lensMapped( ...$toFunctorFn ) - Curried :: callable->callable * @method static callable lensMappedProp( ...$prop ) - Curried :: string->callable * @method static callable view( ...$lens, ...$obj ) - Curried :: callable->Collection|array|object->mixed * @method static callable set( ...$lens, ...$value, ...$obj ) - Curried :: callable->mixed->Collection|array|object->mixed * @method static callable over( ...$lens, ...$transformation, ...$obj ) - Curried :: callable->callable->Collection|array|object->mixed * @method static callable pick( ...$props, ...$obj ) - Curried :: array->Collection|array->Collection|array * @method static callable pickAll( ...$props, ...$obj ) - Curried :: array->Collection|array->Collection|array * @method static callable pickBy( ...$predicate, ...$obj ) - Curried :: ( ( v, k ) → bool ) → Collection|array->Collection|array * @method static callable pickByKey( ...$predicate, ...$obj ) - Curried :: ( ( k ) → bool ) → Collection|array->callable|Collection|array|object * @method static callable project( ...$props, ...$target ) - Curried :: array->Collection|array->Collection|array * @method static callable where( array $condition ) - Curried :: [string → ( * → bool )] → bool * @method static callable|bool has( ...$prop, ...$item ) - Curried :: string → a → bool * @method static callable|bool hasPath( ...$path, ...$item ) - Curried :: array → a → bool * @method static callable|mixed evolve( ...$transformations, ...$item ) - Curried :: array → array → array * * @method static callable|array objOf( ...$key, ...$value ) - Curried :: string->mixed->array * * Creates an object containing a single key:value pair. * * @method static callable|array keys( ...$obj ) - Curried :: object|array->array * * Returns * - keys if argument is an array * - public properties' names if argument is an object * - keys if argument is Collection * * ``` * $this->assertEquals( [ 0, 1, 2 ], Obj::keys( [ 'a', 'b', 'c' ] ) ); * $this->assertEquals( [ 'a', 'b', 'c' ], Obj::keys( [ 'a' => 1, 'b' => 2, 'c' => 3 ] ) ); * * $this->assertEquals( [ 0, 1, 2 ], Obj::keys( \wpml_collect( [ 'a', 'b', 'c' ] ) ) ); * $this->assertEquals( [ 'a', 'b', 'c' ], Obj::keys( \wpml_collect( [ 'a' => 1, 'b' => 2, 'c' => 3 ] ) ) ); * * $this->assertEquals( [ 'a', 'b', 'c' ], Obj::keys( (object) [ 'a' => 1, 'b' => 2, 'c' => 3 ] ) ); * ``` * * @method static callable|array values( ...$obj ) - Curried :: object|array->array * * Returns * - values if argument is an array * - public properties' values if argument is an object * - values if argument is Collection * * ``` * $this->assertEquals( [ 'a', 'b', 'c' ], Obj::values( [ 'a', 'b', 'c' ] ) ); * $this->assertEquals( [ 1, 2, 3 ], Obj::values( [ 'a' => 1, 'b' => 2, 'c' => 3 ] ) ); * * $this->assertEquals( [ 'a', 'b', 'c' ], Obj::values( \wpml_collect( [ 'a', 'b', 'c' ] ) ) ); * $this->assertEquals( [ 1, 2, 3 ], Obj::values( \wpml_collect( [ 'a' => 1, 'b' => 2, 'c' => 3 ] ) ) ); * * $this->assertEquals( [ 1, 2, 3 ], Obj::values( (object) [ 'a' => 1, 'b' => 2, 'c' => 3 ] ) ); * ``` * * @method static callable|array replaceRecursive( array ...$newValue, ...$target ) - Curried :: array->array->array * * @method static callable|array toArray( Collection|Object ...$item ) - Curried :: Collection|Object->array */ class Obj { use Macroable; /** * @return void */ public static function init() { self::macro( 'prop', curryN( 2, function ( $key, $item ) { return self::propOr( null, $key, $item ); } ) ); self::macro( 'propOr', curryN( 3, function ( $default, $key, $item ) { if ( $item instanceof Collection ) { return $item->get( $key, $default ); } if ( is_array( $item ) ) { return array_key_exists( $key, $item ) ? $item[ $key ] : $default; } if ( is_object( $item ) ) { if ( property_exists( $item, $key ) || isset( $item->$key ) ) { return $item->$key; } elseif ( is_numeric( $key ) ) { return self::propOr( $default, $key, (array) $item ); } else { return $default; } } if ( is_null( $item ) ) { return null; } throw( new \InvalidArgumentException( 'item should be a Collection or an array or an object' ) ); } ) ); self::macro( 'props', curryN( 2, function ( array $keys, $item ) { return Fns::map( Obj::prop( Fns::__, $item ), $keys ); } ) ); self::macro( 'addProp', curryN( 3, function ( $key, $transformation, $data ) { return Obj::assoc( $key, $transformation( $data ), $data ); } ) ); self::macro( 'removeProp', curryN( 2, function ( $key, $data ) { if ( is_array( $data ) ) { unset( $data[ $key ] ); return $data; } elseif ( is_object( $data ) ) { $newData = clone $data; unset( $newData->$key ); return $newData; } return $data; } ) ); self::macro( 'renameProp', curryN( 3, function ( $key, $newKey, $data ) { $data = self::addProp( $newKey, self::prop( $key ), $data ); return self::removeProp( $key, $data ); } ) ); self::macro( 'path', curryN( 2, function ( $path, $item ) { return array_reduce( $path, flip( self::prop() ), $item ); } ) ); self::macro( 'pathOr', curryN( 3, function ( $default, $path, $item ) { $result = Either::of( $item ) ->tryCatch( Obj::path( $path ) ) ->getOrElse( null ); return is_null( $result ) ? $default : $result; } ) ); self::macro( 'assocPath', curryN( 3, function ( $path, $val, $item ) { $split = [ $item ]; for ( $i = 0; $i < count( $path ) - 1; $i ++ ) { $split[] = self::prop( $path[ $i ], $split[ $i ] ); } $split = array_reverse( $split ); $reversePath = array_reverse( $path ); $split[0] = self::assoc( $reversePath[0], $val, $split[0] ); for ( $i = 1; $i < count( $reversePath ); $i ++ ) { $key = $reversePath[ $i ]; $split[ $i ] = self::assoc( $key, $split[ $i - 1 ], $split[ $i ] ); } return array_pop( $split ); } ) ); self::macro( 'assoc', curryN( 3, function ( $key, $value, $item ) { if ( $item instanceof Collection ) { $item = clone $item; return $item->put( $key, $value ); } if ( is_array( $item ) ) { $item[ $key ] = $value; return $item; } if ( is_object( $item ) ) { $item = clone $item; $item->$key = $value; return $item; } if ( is_null( $item ) ) { return null; } throw( new \InvalidArgumentException( 'item should be a Collection or an array or an object' ) ); } ) ); self::macro( 'lens', curryN( 2, function ( $getter, $setter ) { return function ( $toFunctorFn ) use ( $getter, $setter ) { return function ( $target ) use ( $toFunctorFn, $getter, $setter ) { $result = $getter( $target ); return Fns::map( function ( $focus ) use ( $setter, $target ) { return $setter( $focus, $target ); }, $toFunctorFn( $result ) ); }; }; } ) ); self::macro( 'lensProp', curryN( 1, function ( $prop ) { return self::lens( self::prop( $prop ), self::assoc( $prop ) ); } ) ); self::macro( 'lensPath', curryN( 1, function ( $path ) { return self::lens( self::path( $path ), self::assocPath( $path ) ); } ) ); self::macro( 'lensMapped', curryN( 1, function ( $toFunctorFn ) { return function ( $target ) use ( $toFunctorFn ) { return IdentityFunctor::of( Logic::isMappable( $target ) ? Fns::map( pipe( $toFunctorFn, invoke( 'get' ) ), $target ) : $target ); }; } ) ); self::macro( 'lensMappedProp', curryN( 1, function ( $prop ) { return compose( Obj::lensProp( $prop ), Obj::lensMapped() ); } ) ); self::macro( 'view', curryN( 2, function ( $lens, $obj ) { $view = $lens( [ ConstFunctor::class, 'of' ] ); return $view( $obj )->get(); } ) ); self::macro( 'set', curryN( 3, function ( $lens, $value, $obj ) { return self::over( $lens, Fns::always( $value ), $obj ); } ) ); self::macro( 'over', curryN( 3, function ( $lens, $transformation, $obj ) { $over = $lens( function ( $value ) use ( $transformation ) { return IdentityFunctor::of( $transformation( $value ) ); } ); return $over( $obj )->get(); } ) ); self::macro( 'pick', curryN( 2, function ( array $props, $item ) { $find = curryN( 3, function ( $item, $result, $prop ) { $value = self::propOr( new Undefined(), $prop, $item ); if ( ! $value instanceof Undefined ) { $result[ $prop ] = $value; } return $result; } ); $result = Fns::reduce( $find( $item ), [], $props ); return self::matchType( $result, $item ); } ) ); self::macro( 'pickAll', curryN( 2, function ( array $props, $item ) { $find = curryN( 3, function ( $item, $result, $prop ) { $result[ $prop ] = self::prop( $prop, $item ); return $result; } ); $result = Fns::reduce( $find( $item ), [], $props ); return self::matchType( $result, $item ); } ) ); self::macro( 'project', curryN( 2, function ( array $props, $items ) { return Fns::map( Obj::pick( $props ), $items ); } ) ); self::macro( 'where', curryN( 2, function ( array $conditions, $items ) { foreach ( $conditions as $prop => $condition ) { $filter = pipe( Obj::prop( $prop ), Logic::both( Logic::isNotNull(), $condition ) ); $items = Fns::filter( $filter, $items ); } return $items; } ) ); self::macro( 'pickBy', curryN( 2, function ( callable $predicate, $item ) { $result = array_filter( self::toArray( $item ), $predicate, ARRAY_FILTER_USE_BOTH ); return self::matchType( $result, $item ); } ) ); self::macro( 'pickByKey', curryN( 2, function ( callable $predicate, $item ) { return self::pickBy( pipe( Fns::nthArg( 1 ), $predicate ), $item ); } ) ); self::macro( 'hasPath', curryN( 2, function ( $path, $item ) { $undefinedValue = new Undefined(); $currentElement = $item; foreach ( $path as $pathProp ) { $currentElement = Either::of( $currentElement ) ->tryCatch( self::propOr( $undefinedValue, $pathProp ) ) ->getOrElse( $undefinedValue ); if ( $undefinedValue === $currentElement ) { return false; } } return true; } ) ); self::macro( 'has', curryN( 2, function ( $prop, $item ) { if ( $item instanceof Collection ) { return $item->has( $prop ); } if ( is_array( $item ) ) { return isset( $item[ $prop ] ); } if ( is_object( $item ) ) { return property_exists( $item, $prop ); } throw( new \InvalidArgumentException( 'item should be a Collection or an array or an object' ) ); } ) ); self::macro( 'evolve', curryN( 2, function ( $transformations, $item ) { $temp = self::toArray( $item ); foreach ( $transformations as $prop => $transformation ) { if ( isset( $temp[ $prop ] ) ) { if ( is_callable( $transformation ) ) { $temp[ $prop ] = $transformation( $temp[ $prop ] ); } elseif ( is_array( $transformation ) ) { $temp[ $prop ] = self::evolve( $transformation, $temp[ $prop ] ); } } } return self::matchType( $temp, $item ); } ) ); self::macro( 'keys', curryN( 1, function ( $obj ) { if ( is_array( $obj ) ) { return array_keys( $obj ); } elseif ( $obj instanceof Collection ) { return $obj->keys()->toArray(); } elseif ( is_object( $obj ) ) { return array_keys( get_object_vars( $obj ) ); } throw new \InvalidArgumentException( 'obj should be either array or object' ); } ) ); self::macro( 'values', curryN( 1, function ( $obj ) { if ( is_array( $obj ) ) { return array_values( $obj ); } elseif ( $obj instanceof Collection ) { return $obj->values()->toArray(); } elseif ( is_object( $obj ) ) { return array_values( get_object_vars( $obj ) ); } throw new \InvalidArgumentException( 'obj should be either array or object' ); } ) ); self::macro( 'objOf', curryN( 2, function ( $key, $value ) { return [ $key => $value ]; } ) ); self::macro( 'replaceRecursive', curryN( 2, flip( 'array_replace_recursive' ) ) ); self::macro( 'toArray', curryN( 1, function ( $item ) { $temp = $item; if ( $temp instanceof Collection ) { $temp = $temp->toArray(); } if ( is_object( $temp ) ) { $temp = (array) $temp; } return $temp; } ) ); } /** * @param object|Collection $item * @param object|Collection $reference * * @return object|Collection */ private static function matchType( $item, $reference ) { if ( $reference instanceof Collection ) { return wpml_collect( $item ); } if ( is_object( $reference ) ) { return (object) $item; } return $item; } /** * Curried :: mixed → array|object|Collection → array|object|Collection * function to remove an item by key from an array. * * @param string|int $key * @param array|object|Collection|null $item * * @return callable|array|object|Collection */ static function without( $key = null, $item = null ) { $without = function ( $key, $item ) { $temp = self::toArray( $item ); unset( $temp[ $key ] ); return self::matchType( $temp, $item ); }; return call_user_func_array( curryN( 2, $without ), func_get_args() ); } /** * Curried :: array|object -> array|object -> array|object * * It merges the new data with item. * * @param array|object $newData * @param array|object $item * * @return array|object */ public static function merge( $newData = null, $item = null ) { $merge = function ( $newData, $item ) { $isNested = Logic::anyPass( [ 'is_array', 'is_object' ] ); foreach ( (array) $newData as $key => $value ) { if ( $isNested( $newData ) && Obj::has( $key, $item ) && $isNested( Obj::prop( $key, $item ) ) ) { $item = Obj::assoc( $key, self::merge( $value, Obj::prop( $key, $item ) ), $item ); } else { $item = Obj::assoc( $key, $value, $item ); } } return $item; }; return call_user_func_array( curryN( 2, $merge ), func_get_args() ); } } Obj::init();