1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* CSVelte: Slender, elegant CSV for PHP |
4
|
|
|
* |
5
|
|
|
* Inspired by Python's CSV module and Frictionless Data and the W3C's CSV |
6
|
|
|
* standardization efforts, CSVelte was written in an effort to take all the |
7
|
|
|
* suck out of working with CSV. |
8
|
|
|
* |
9
|
|
|
* @version v0.2.1 |
10
|
|
|
* @copyright Copyright (c) 2016 Luke Visinoni <[email protected]> |
11
|
|
|
* @author Luke Visinoni <[email protected]> |
12
|
|
|
* @license https://github.com/deni-zen/csvelte/blob/master/LICENSE The MIT License (MIT) |
13
|
|
|
*/ |
14
|
|
|
namespace CSVelte; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* Library Functions |
18
|
|
|
* |
19
|
|
|
* @package CSVelte |
20
|
|
|
* @subpackage functions |
21
|
|
|
* @since v0.2.1 |
22
|
|
|
*/ |
23
|
|
|
|
24
|
|
|
use \Iterator; |
25
|
|
|
use CSVelte\Taster; |
26
|
|
|
use CSVelte\Flavor; |
27
|
|
|
use CSVelte\IO\Stream; |
28
|
|
|
use CSVelte\IO\Resource; |
29
|
|
|
use CSVelte\IO\IteratorStream; |
30
|
|
|
use CSVelte\Contract\Streamable; |
31
|
|
|
|
32
|
|
|
use \InvalidArgumentException; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Stream - streams various types of values and objects. |
36
|
|
|
* |
37
|
|
|
* You can pass a string, or an iterator, or an object with a __toString() |
38
|
|
|
* method to this function and it will find the best possible way to stream the |
39
|
|
|
* data from that object. |
40
|
|
|
* |
41
|
|
|
* @param mixed The item you want to stream |
42
|
|
|
* @return \CSVelte\IO\Stream A stream object |
43
|
|
|
* @since v0.2.1 |
44
|
|
|
*/ |
45
|
|
|
function streamize($obj = '') |
46
|
|
|
{ |
47
|
27 |
|
if ($obj instanceof Streamable) { |
48
|
1 |
|
return $obj; |
49
|
|
|
} |
50
|
|
|
|
51
|
27 |
|
if ($obj instanceof Resource) { |
52
|
1 |
|
return $obj(); |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
// @todo there needs to be a way to create a stream object from a resource |
56
|
|
|
// object (other than streamize($resource)). I'm thinking something like |
57
|
|
|
// $resource = new Resource(); $stream = $resource->toStream(); or $resource->stream(); |
|
|
|
|
58
|
|
|
// also possibly $resource = new Resource(); $stream = $resource(); |
|
|
|
|
59
|
|
|
// I kinda like the idea of passing around a $resource and then just invoking |
60
|
|
|
// it to get a stream from it... |
61
|
26 |
|
if (is_resource($obj) && get_resource_type($obj) == 'stream') { |
62
|
1 |
|
return new Stream(new Resource($obj)); |
63
|
|
|
} |
64
|
|
|
|
65
|
25 |
|
if ($obj instanceof Iterator) { |
66
|
4 |
|
return new IteratorStream($obj); |
67
|
|
|
} |
68
|
|
|
|
69
|
21 |
|
if (is_object($obj) && method_exists($obj, '__toString')) { |
70
|
2 |
|
$obj = (string) $obj; |
71
|
2 |
|
} |
72
|
21 |
|
if (is_string($obj)) { |
73
|
19 |
|
$stream = Stream::open('php://temp', 'r+'); |
74
|
19 |
|
if ($obj !== '') { |
75
|
16 |
|
$res = $stream->getResource(); |
76
|
16 |
|
fwrite($res->getHandle(), $obj); |
77
|
16 |
|
fseek($res->getHandle(), 0); |
78
|
16 |
|
} |
79
|
19 |
|
return $stream; |
80
|
|
|
} |
81
|
|
|
|
82
|
2 |
|
throw new InvalidArgumentException(sprintf( |
83
|
2 |
|
"Invalid argument type for %s: %s", |
84
|
2 |
|
__FUNCTION__, |
85
|
2 |
|
gettype($obj) |
86
|
2 |
|
)); |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
function stream_resource($uri, $mode = null, $context = null, $lazy = true) |
90
|
|
|
{ |
91
|
2 |
|
$res = (new Resource($uri, $mode)) |
92
|
2 |
|
->setContextResource($context); |
93
|
2 |
|
if (!$lazy) $res->connect(); |
94
|
2 |
|
return $res; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
function stream($uri, $mode = null, $context = null, $lazy = true) |
98
|
1 |
|
{ |
99
|
|
|
$res = stream_resource($uri, $mode, $context, $lazy); |
100
|
|
|
return new Stream($res); |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
/** |
104
|
|
|
* "Taste" a stream object. |
105
|
|
|
* |
106
|
|
|
* Pass any class that implements the "Streamable" interface to this function |
107
|
|
|
* to auto-detect "flavor" (formatting attributes). |
108
|
|
|
* |
109
|
|
|
* @param \CSVelte\Contract\Streamable Any streamable class to analyze |
110
|
|
|
* @return \CSVelte\Flavor A flavor representing str eam's formatting attributes |
111
|
|
|
* @since v0.2.1 |
112
|
|
|
*/ |
113
|
|
|
function taste(Streamable $str) |
114
|
|
|
{ |
115
|
13 |
|
$taster = new Taster($str); |
116
|
13 |
|
return $taster(); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* Does dataset being streamed by $str have a header row? |
121
|
|
|
* |
122
|
|
|
* @param \CSVelte\Contract\Streamable $str Stream object |
123
|
|
|
* @return boolean Whether stream dataset has header |
124
|
|
|
* @since v0.2.1 |
125
|
|
|
*/ |
126
|
|
|
function taste_has_header(Streamable $str) |
127
|
|
|
{ |
128
|
5 |
|
$taster = new Taster($str); |
129
|
5 |
|
$flv = $taster(); |
130
|
5 |
|
return $taster->lickHeader( |
131
|
5 |
|
$flv->delimiter, |
132
|
5 |
|
$flv->lineTerminator |
133
|
5 |
|
); |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* Collection factory. |
138
|
|
|
* |
139
|
|
|
* Simply an alias to (new Collection($in)). Allows for a little more concise and |
140
|
|
|
* simpler instantiation of a collection. Also I plan to eventually support |
141
|
|
|
* additional input types that will make this function more flexible and forgiving |
142
|
|
|
* than simply instantiating a Collection object, but for now the two are identical. |
143
|
|
|
* |
144
|
|
|
* @param array|Iterator $in Either an array or an iterator of data |
145
|
|
|
* @return \CSVelte\Collection A collection object containing data from $in |
146
|
|
|
* @see CSVelte\Collection::__construct() (alias) |
147
|
|
|
* ) |
148
|
|
|
*/ |
149
|
|
|
function collect($in = null) |
150
|
|
|
{ |
151
|
65 |
|
return new Collection($in); |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
/** |
155
|
|
|
* @param callable $callback |
156
|
|
|
* @param array ...$args |
157
|
|
|
* @return mixed |
158
|
|
|
*/ |
159
|
|
|
function getvalue(Callable $callback, ...$args) |
160
|
|
|
{ |
161
|
|
|
return $callback(...$args); |
162
|
|
|
} |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.