Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


NotionCommotion last won the day on July 2

NotionCommotion had the most liked content!

Community Reputation

30 Good

About NotionCommotion

  • Rank
    Prolific Member

Contact Methods

  • Website URL

Profile Information

  • Gender
    Not Telling

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Fair enough. Sometimes a little more art than science...
  2. I found it helpful to configure all my objects in one or several bootstrap scripts. Before doing so, I would often find myself forgetting that I already had written some class which is located deep in some script and recreating it for some other need (granted, composer definitely helped in this regard, but using it wasn't always applicable). <?php $c=new Pimple\Container(getMySettings()); $c['pdo'] = function ($c) { $db = $c['settings']['mysql']; return new \PDO(bla); }; $c['foo'] = function ($c) { return new Foo( $c->get('pdo') ); }; $c['bar'] = function ($c) { return new Bar( $c->get('foo') ); }; It is all good until I find myself needing to create some new instance of some class instead of just passing some common instance to whoever needs it. class Foo { private $pdo; public function __construct(\PDO $pdo) { $this->pdo=$pdo; } public function getSomething():SomeClass { return new SomeClass($this->getAllDataFromDB($GET['id'])); } } class SomeClass { private $arr; public function __construct(array $records) { foreach($records as $record) { $arr[]=new SomeOtherClass($record); } } } I've read that one shouldn't create new objects in a given class's constructor, and while I could instead do so in some class's method and pass the object to the given class's constructor, to me it seems to really be the same thing. The three issues I have with this scenario are: Needing to remember that these classes exist as they are hidden deep in some classes. Makes it more difficult to replace one of the classes with some other class in the future. Some duplication of code. Are there other compelling reasons not to do so? Is it worth the effort to do differently? If so, how would you recommend doing so? My thoughts would either to use Pimple's factory() method are create my only factory which also relies on anonymous functions. Maybe something else? $c['someClass'] = $c->factory(function (array $record, Container $c) { return new SomeClass($record); }); Thanks
  3. Looks like Guzzle's approach is to either use CURLOPT_WRITEFUNCTION to write to a stream or CURLOPT_FILE to write to a file. if (isset($options['sink'])) { $sink = $options['sink']; if (!is_string($sink)) { $sink = \GuzzleHttp\Psr7\stream_for($sink); } elseif (!is_dir(dirname($sink))) { // Ensure that the directory exists before failing in curl. throw new \RuntimeException(sprintf( 'Directory %s does not exist for sink value of %s', dirname($sink), $sink )); } else { $sink = new LazyOpenStream($sink, 'w+'); } $easy->sink = $sink; $conf[CURLOPT_WRITEFUNCTION] = function ($ch, $write) use ($sink) { return $sink->write($write); }; } else { // Use a default temp stream if no sink was set. $conf[CURLOPT_FILE] = fopen('php://temp', 'w+'); $easy->sink = Psr7\stream_for($conf[CURLOPT_FILE]); }
  4. Are you thinking of something like the following? $obj = new Curl(); $iterator=$obj->query('bla'); $jsonMachine=new JsonMachine($iterator); foreach ($jsonMachine as $key => $value) { var_dump($value); } class Curl { public function query(string $url) { $iterator = new CurlBytes(); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, string $str) use ($iterator) { $iterator->append($str); return strlen($str); }); curl_exec($ch); curl_close($ch); return $iterator; } } class CurlBytes implements \IteratorAggregate { private $string = ''; private $chunkSize; public function __construct($chunkSize = 1024 * 8) { $this->chunkSize = $chunkSize; } public function append(string $string) { $this->string .= $string; } public function getIterator() { $len = strlen($this->string); for ($i=0; $i<$len; $i += $this->chunkSize) { yield substr($this->string, $i, $this->chunkSize); } } }
  5. Thanks Thanks, I will change paths and not try to force cURL to expose a stream. <?php class Curl implements DriverInterface, QueryDriverInterface { public function __construct($dsn, $options = []) { //... stream_wrapper_register("curl", "CurlStream") or die("Failed to register protocol wrapper"); } protected function execute($url, $curlOptions = []) { $this->lastRequestInfo = null; $ch = curl_init(); foreach ($curlOptions as $option => $value) { curl_setopt($ch, $option, $value); } $stream = fopen("curl://CurlStream", "r+"); curl_setopt($ch, CURLOPT_URL, $this->dsn . '/' . $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_BUFFERSIZE, 256); curl_setopt($ch, CURLOPT_FILE, $stream); curl_exec($ch); $this->lastRequestInfo = curl_getinfo($ch); if (fstat($stream)['size']) { // in case of total failure - socket/port is closed etc throw new Exception('Request failed! curl_errno: ' . curl_errno($ch)); } curl_close($ch); return $stream; } } class CurlStream //implements SomeInterface? { //Reference https://stackoverflow.com/questions/1342583/manipulate-a-string-that-is-30-million-characters-long/1342760#1342760 private $buffer, $position, $varname; //Not sure about $position, $varname public function stream_open($path, $mode, $options, &$opened_path) { //$path: curl://CurlStream, $mod: r+, $options: '', $opened_path: 0 $url = parse_url($path); //["scheme"=>"curl","host"=>"CurlStream"] $this->varname = $url["host"]; $this->position = 0; return true; } public function stream_write($data) { // Extract the lines ; on y tests, data was 8192 bytes long ; never more $lines = explode("\n", $data); // The buffer contains the end of the last line from previous time // => Is goes at the beginning of the first line we are getting this time $lines[0] = $this->buffer . $lines[0]; // And the last line os only partial // => save it for next time, and remove it from the list this time $nb_lines = count($lines); $this->buffer = $lines[$nb_lines-1]; unset($lines[$nb_lines-1]); // Here, do your work with the lines you have in the buffer //var_dump($lines); echo '<hr />'; return strlen($data); } //Not sure about the remaining methods. //Reference https://www.php.net/manual/en/stream.streamwrapper.example-1.php public function stream_stat() { return ['size'=>strlen($this->buffer)]; } public function stream_get_contents() { return $this->buffer; } public function stream_read($count) { $ret = substr($GLOBALS[$this->varname], $this->position, $count); $this->position += strlen($ret); return $ret; } public function stream_tell() { return $this->position; } public function stream_seek($offset, $whence) { switch ($whence) { case SEEK_SET: if ($offset < strlen($GLOBALS[$this->varname]) && $offset >= 0) { $this->position = $offset; return true; } else { return false; } break; case SEEK_CUR: if ($offset >= 0) { $this->position += $offset; return true; } else { return false; } break; case SEEK_END: if (strlen($GLOBALS[$this->varname]) + $offset >= 0) { $this->position = strlen($GLOBALS[$this->varname]) + $offset; return true; } else { return false; } break; default: return false; } } public function stream_metadata($path, $option, $var) { if($option == STREAM_META_TOUCH) { $url = parse_url($path); $varname = $url["host"]; if(!isset($GLOBALS[$varname])) { $GLOBALS[$varname] = ''; } return true; } return false; } }
  6. If a response is large, json-machine is used to decode the string instead of json_decode(). Based on the application's configuration, $this->stream can either be set using Guzzle or just PHP's cURL library. I've got the Guzzle version working, but not the cURL version. private function getParsedResults() { if(is_null($this->parsedResults)) { if(fstat($this->stream)['size'] > self::MAX_JSON_DECODE) { $this->parsedResults=[]; foreach (JsonMachine::fromStream($this->stream) as $key => $value) { $this->parsedResults[$key] = $value; } } else { $this->parsedResults=json_decode(stream_get_contents($this->stream), true); if (json_last_error() !== JSON_ERROR_NONE) { throw new \InvalidArgumentException('Invalid JSON'); } } $this->validate($this->parsedResults); } return $this->parsedResults; }
  7. The following will create a PHP stream. $response = $this->guzzleHttp->get($url); $stream = \GuzzleHttp\Psr7\StreamWrapper::getResource($response->getBody()); How can I return a stream using just PHP's native cURL library?
  8. I gave json-machine a try and it works great. You just pass it the steam and an optional json pointer and iterate over the elements.
  9. Thanks kicken, Not sure what will be enough memory, but will give it a try. It is for a one-time use application to fix some data. Thanks requnix, Ever try doing it? If so, did it work well and relativity simple? Looks like there might be a few other options. Haven't tried but will and will let you know if they work. https://github.com/pcrov/JsonReader/wiki/JsonReader-API#psr7streampsrhttpmessagestreaminterface-stream-void https://github.com/salsify/jsonstreamingparser with https://github.com/cerbero90/json-objects https://github.com/halaxa/json-machine Another one: https://github.com/MAXakaWIZARD/JsonCollectionParser. Also uses https://github.com/salsify/jsonstreamingparser
  10. I am using Guzzle as a HTTP client, and the following script results in the following error: $response = $this->httpClient->request('GET', "http://$this->host:$this->port/query", ['query' => $data]); $body = $response->getBody(); $rs=json_decode($body, true); Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 136956008 bytes) in /var/www/vendor/guzzlehttp/psr7/src/Stream.php on line 80 What are the work arounds? Instead of trying to convert it into an array all at once, how can I do so in pieces? I know the expected format so it seems I will need to read just the appropriate amount of bytes and then decode parts at a time. Seems like a pain. Are there any classes designed to do so, or can any of the following Guzzle built in methods be used? Thanks Guzzle Response methods: __construct getStatusCode getReasonPhrase withStatus getProtocolVersion withProtocolVersion getHeaders hasHeader getHeader getHeaderLine withHeader withAddedHeader withoutHeader getBody withBody Guzzle Body methods: __construct __destruct __toString getContents close detach getSize isReadable isWritable isSeekable eof tell rewind seek read write getMetadata
  11. I've never head the term "custom attributes", but suppose I do so. User A is named Bob, is 5 feet tall and 38 years old, and has special skills: has a hypnotism rate of 45 neurons per second, and a clairvoyance rating of 5 / 10. User B is named Jill, is 6 feet tall and 28 years old, and has special skills: has a rank of 3 of understanding of quantum physics and a shoe size of 25 and a half meters. User C is named Tom, is 4 feet tall and 12 years old, and has special skills: has fourteen years worth of towel folding experience User D is named Jane, is 5 feet tall and 18 years old, and has special skills: can eat twenty three beer battered brauttwerst in 48 seconds.
  12. Thank you Kicken, Your understanding is for the most part accurate. Did I correctly capture the reasons why you said "In general I'd say your common object should only contain the common properties"? Requires table inheritance if given common object is injected with specific object of different class/table or there is type of common object which doesn't require an injected object. Consistent with one:many Can easier be convert to a one:many
  13. Thanks Zane and maxxd, I am trying to keep track of user provided configuration settings of something. I might be wrong, but it seems like it could be just about anything, so I used cars and motors as an example, but did a poor job communicating that they were user settings. Keeping with my car example, user settings might be current mileage, serial number, color (not necessarily from the factory), and even spark plug torque (assuming cars still have spark plugs). The point is that the user provides settings for their particular something and these settings are saved (latest settings only and no audits required) in the DB. No issue yet and I have done this often. But then there are multiple variations of this something which require their own class and these classes have some properties common to all of them, but have other properties unique to their particular variation. In the past, I've used inheritance, but I am now trying to default to injection when possible, and thus created a single class which contains all the common properties and then inject some small object which represents the other properties unique to each particular variation. Data associated with each instance of this common object as well as the injected object is random user provided data, and therefore it seemed to me that I needed some one-to-one relationship between the two. Agree? Ditching the car/motor analogy, the same question is "If a common object contains a single unique specific object, what reasoning should one use to determine whether the common table should contain specific entity ID or whether the specific table should contain the common entity ID?" Thanks
  14. Yes, each GatewayDataSource gets its own unique gateway, and "linking" as you say was my intention. Would you agree this is a one-to-one relationship between source and gateway, and gateway to device? Is there some de facto standard where to locate the FK for these two links, or are there application specific details one must consider? For instance, to quote Zane, "Cars contain a motor. Motors do not contain cars. Therefore, put a column for motor in the Cars table and link through the various motor ids" makes sense, however, if some app was all about artificial brains, it might make more sense that a brain has a host (aka body), and one should do differently. PS. No, I am not creating a brain and maybe I should strike this obscure example! Modbus uses an 8 bit address to identify a device on the network and 16 bit registrars to locate some specific data in the device. Bacnet uses a 32 bit value to identify the device and another 32 bit value to represent something in the device (it actually uses ID and type, but I think this can be disregarded for this discussion). These 3rd party modbus and bacnet devices are not managed by my application and their associated identifying addresses are set outside of the application. A 3rd party modbus device is interfaced to by one of my ModbusGateways and a 3rd party bacnet device is similarly interfaced to by one of my BacnetGateways. Since ModbusGateways and BacnetGateways are also modbus devices and bacnet devices respectively and there are requirements to keep addresses for both unique on a given network, I created these ModbusDevice and BacnetDevice entities/tables which are used for both 3rd party devices and gateways alike. A device associated with a gateway can be deleted by the user and removed from the database, however, the devices in my application associated with some 3rd party controller should not be deleted from the database but only tagged as deleted. If a deleted 3rd party device is later added back as identified by its unique address, then the same PK associated with the specific data points in the device must be used as it is also used as a natural key by a historian. Hope I didn't totally confuse you (I certain confused myself ) Thank you
  15. Maxxd, where can I get a Honda with a Hemi or a V8? Been looking for one, but they don't seem to be available I see your and Barand's point and do not disagree for the common attributes, but it does not address the specific attributes such as the engine serial number or the torque I cinched down the spark plugs which make it unique. In hindsight my abstract example was flawed as all of the properties were common which should utilize a many-to-many except for the serial number, and apologize for the poor example. For my real application, I have device identifier, timeout settings, buffer size, etc, for some types of devices and other similar attributes for different types of devices, which are all specified by the user and used to configure each device. Maybe I should have included these attributes in some parent table/entity, however, injection brought some flexibility and simplification which leaves me with these one-to-ones.
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.