Jump to content

NotionCommotion

Members
  • Content Count

    1,800
  • Joined

  • Last visited

  • Days Won

    8

Everything posted by NotionCommotion

  1. NotionCommotion

    Order of dependency injection

    I need to create an entity which models the connection between a PHP server and another device so that a web app can change the entity's properties which in turn will update the server DB as well as the other device. A little background information for context is as follows: When a socket clients connects to the PHP server, it will register by providing its GUID, and in turn the server will query its DB to identify the specific client. The client has various other properties associated with the socket connection such as reconnect_timeout, response_timeout, etc, and the associated values will also be stored in the server's DB. While all socket clients use the same approach to communicate to the PHP server, several "flavors" of socket clients exists which use a specific protocol (Modbus/RTU, Modbus/IP, ControlNet, BACnet/IP, BACnet/MSTP, KNX, DALI) to communicate to downstream devices. Based on the used protocol, there will be different properties as well as different methods (i.e. some protocols allow one to query the device to retrieve a list of available data). To create the entity using inheritance, I would likely do so where: class ModbusRtuSocketClient extends ModbusSocketClient (which extends SocketClient) class ModbusIpSocketClient extends ModbusSocketClient (which extends SocketClient) class ControlNetSocketClient extends SocketClient etc.. But instead of doing so by using inheritance, I am thinking that I should do so through injection. For instance, I create an object called SocketClient which just deals with that scope of work and is protocol agnostic. I also create a second object which deals with a given protocol such as ModbusRtuProtocol extends ModbusProtocol extends Protocol. I then do one of the following: $entity = new SocketClient(new ModbusRtuProtocol()); //or $entity = new ModbusRtuProtocol(new SocketClient()); //and do $entity->setSomeSocketClientProperty(123); $entity->getProperty()->setSomeSpecificProtocolProperty(321); $entity->updateEndDevice(); $entityManager->persist($entity); $entityManager->flush(); //or do $values=$entity->queryDevice(); The first approach "seems" right, but I am not sure. One concern is I cannot create a standard interface to govern all protocols because the methods are so protocol specific (maybe I need to think harder how to make a standard interface?). Any recommendations where I should be going on this? PS. If you think I shouldn't be doing so through injection but through inheritance, please advise.
  2. NotionCommotion

    Order of dependency injection

    Thanks requinx, Yes, I agree inheritance has its use regardless of what I do with injection. For instance, I showed ModbusRtuProtocol extends ModbusProtocol extends Protocol on the initial and was trying to imply that both ModbusProtocol and Protocol would be abstract superclasses. Also, agree some sort of factory will likely be beneficial. Do you agree that Protocol should likely be injected into ClientConnection instead of injecting ClientConnection into Protocol? What is your thought pattern when making these decisions?
  3. NotionCommotion

    Git, Windows, Linux, and end of line

    My IDE (Nusphere's PhpED) runs on Windows but is configured so that both the web server as well as all project files are located on a development Linux server. Since the project files are located on the Linux server, the git repository is located there as well and not on my PC. Every now again, my IDE complains that content was externally modified and whether I wish to reload the file. Also, I was recently asked to set git's core.autocrlf to true on a project I was collaborating on which prevented me from adding any changes to git (git complained that LF will be replaced by CRLF). The IDE allows file encoding to be changed (system default, UTF-8, Windows-1252, or ISO-8859-01) as well as the default file format (Unix, Windows, Mac, or autodetect). Any recommendations on how best to configure git and these ide settings? Thanks
  4. NotionCommotion

    Weak type declaration for integers

    I see now. I only experience the issue when the file includes declare(strict_types=1) which is what it should do. Thanks
  5. NotionCommotion

    Weak type declaration for integers

    Is it possible to perform type declaration which allows either an integer or a string digit (i.e. ctype-digit) instead of the following? function someFunction(int $id){} Looking at functions.arguments.type-declaration, I expect not. If not, would you recommend type casting before calling the function or removing type declaration from the function and performing the check manually within the function and throwing an applicable exception? Thanks
  6. NotionCommotion

    Passing variable post names with php

    You could POST the following. Be sure to validate. Array ( [text1] => foo [text2] => bar [otherField] => bla [fields] => Array ( [0] => text1 [1] => text2 ) )
  7. I can obtain either one or a collection of objects by executing the following. $product = $entityManager->find('Product', $id); $products = $entityManager->getRepository('Product')->findAll(); All products have many common properties, however, based on the type of product there are some differences. To implement this, I am using class table inheritance (side question - is there any difference between CTI and supertype/subtype modeling?). I will need to convert either a single product to JSON as well as a collection of products to JSON. When converting a collection, only a subset of the product's properties is desired, however, again most of these properties are common to each product type but there are some differences. One solution is to utilize the JsonSerializable interface. A shortcoming, however, is how to deal with both the detail view with all the properties and the collection view with only a subset of properties. To overcome this, I can potentially use jsonSerialize() to provide the detail view, and add another function index() to provide the subset results for the collection. Since this index() function will not recursively incorporate sub-objects, I will need to manually loop over the collection, however, it should not be too big of issue. Or should the entity not be responsible to convert to JSON? I am kind of mixed on this issue, but do agree using a separate class has merit. So, if a separate class is used, how does it deal with each subclass of Product which might have unique properties and getters? I suppose I can have the entities implement an interface which requires them to return their applicable properties, but doing so isn't very flexible and isn't this (almost) the same as having the entity responsible to provide the JSON? I "could" make this other class perform some switch operation based on the class name, but doing so goes against all good OOP principles. What is the "right" way to do this? Thanks
  8. NotionCommotion

    Converting collection of objects to JSON

    Not complete, but I definitely think I am on the right path. Appreciate the help. I am sure I am not doing the discriminator part correct, and if anyone has experience, would appreciate some additional direction. <?xml version="1.0" encoding="UTF-8" ?> <serializer> <class name="NotionCommotion\App\Domain\Entity\Chart\Chart" discriminator-field-name="dtype"> <xml-namespace prefix="atom" uri="http://www.w3.org/2005/Atom"/> <discriminator-class value="pie_chart">NotionCommotion\App\Domain\Entity\Chart\Pie\PieChart</discriminator-class> <discriminator-groups> <group>index</group> <group>detail</group> </discriminator-groups> <property name="account" exclude="true"/> <property name="id" exclude="true"/> <property name="name" groups="index, detail"/> <property name="id_public" serialized-name="id" groups="index, detail"/> <property name="series" groups="detail"/> <property name="dtype" exclude="true"/> </class> </serializer> <?xml version="1.0" encoding="UTF-8" ?> <serializer> <class name="NotionCommotion\App\Domain\Entity\Chart\Pie\PieChart" discriminator-field-name="dtype"> <xml-namespace prefix="atom" uri="http://www.w3.org/2005/Atom"/> <discriminator-class value="pie_chart">NotionCommotion\App\Domain\Entity\Chart\Pie\PieChart</discriminator-class> <discriminator-groups> <group>index</group> <group>detail</group> </discriminator-groups> <property name="dtype" exclude="true"/> </class> </serializer> <?php class ChartService { protected $em, $account; public function __construct(\Doctrine\ORM\EntityManager $em, \NotionCommotion\App\Domain\Entity\Account\Account $account) { $this->em = $em; $this->account = $account; } public function read(int $idPublic):Chart\Chart { return $this->em->getRepository(Chart\Chart::class)->findOneBy(['id_public'=>$idPublic, 'account'=>$this->account]); } } <?php class ChartResponderr { protected $serializer; public function __construct(\JMS\Serializer\Serializer $serializer) { $this->serializer = $serializer; } public function detail(Response $response, Entity\object $entity):Response { $json=$this->serializer->serialize($entity, 'json', SerializationContext::create()->setGroups(['Default','detail'])); $response->getBody()->write($json); return $response; } } <?php $c['serializer'] = function ($c) { return \JMS\Serializer\SerializerBuilder::create() ->setCacheDir(APP_ROOT.'/var/serializer/cache') ->setDebug(true) ->addMetadataDir(APP_ROOT.'/config/serializer') ->build(); }; $c['chartService'] = function ($c) { return new Api\Chart\ChartService( $c[EntityManager::class], $c['account'] //$c['validator'](['/chart/base.json']) ); }; $app->get('/chart/{chartId:[0-9]+}', function (Request $request, Response $response, $args) { return $this->chartResponder->detail($response, $this->chartService->read((int) $args['chartId'])); });
  9. NotionCommotion

    Converting collection of objects to JSON

    No, it is not because I am using XML metadata for my entities, but because my objects are too large and/or have too much recursion and PHP times out after 20+ seconds. Looks like I need to figure out how to instruct the serializer only to include the specific properties which I want.
  10. NotionCommotion

    Converting collection of objects to JSON

    Thanks gizmola, My model example very closely describes mine, and I think it works great for all the reasons you state. My only issue is determine how to act on an entity when the entity type is not known. For instance, it would be easy to serialize an array of vendorStreams or an array of channelStream, but not necessarily so for an array of streams which contain both vendorStreams and channelStream. While I was thinking of making the entities implement an interface which requires a method for each desired output, but it really doesn't belong there for multiple reasons which I finally understand. Maybe would be okay to making the entities implement an interface for one method which requires an argument which determines the serialization output. Or better yet, maybe your serializer suggestion is the answer. No, that was not my error and I of course tried it. I am pretty sure it is because my entities do not have annotation in the PHP class but in a separate XML file. Looking for documentation how to implement. If so, then the serialization specification is tied to the entity making the ability to serialize an array of mixed entities simple, yet does so in a way to make it more flexible that just adding individual serialization type methods to each entity. Well, at least I hope so!
  11. NotionCommotion

    Onclick in php loop

    Read gw1500se's post a couple times. Not necessarily the part about not being clear but the part about each operating in their own environment. Draw two circles and put Client (HTML/JavaScript) in one and Server (PHP) in the other. Then make an arrow from the client circle to the server circle and label it "request for HTML page" and then a return arrow and label it "HTML page". Then maybe make an arrow from the client to the server and label it "form submission" and an arrow back labeled "form results". You can do this for Ajax request as well. For all of these, the client initiates a request and the server responds. Do it until it is 100% clear in your head.
  12. NotionCommotion

    ELSE vs TWO "if" statements

    Your not going to get the results you are looking for. The server will not know whether the user submitted the form using the submit button or clicked the back button which caused it to be submitted. There are most likely better ways to do this, but something like the following might work. <?php session_start(); function display($counter) { $_SESSION["counter"]=$_SESSION["counter"]+1; //create your page and include $counter in a hidden input field. } if(!isset($_SESSION["counter"])) { $_SESSION["counter"]=0; } if(isset($_POST["SubmitButton"])) { if(isset($_POST["counter"])) { if($_POST["counter"]==$_SESSION["counter"]) { //Process your order } else { display(); } } else { echo('missing counter error'); } } else { display(); }
  13. NotionCommotion

    ELSE vs TWO "if" statements

    What is best is based on what you want your script to do. That being said, I would probably start with the session conditional first. if(isset($_SESSION["order_is_finalized"])){ if(isset($_POST["SubmitButton"])) { $_SESSION["order_is_finalized"]=null; } else { include('order_page.php'); exit; } }
  14. NotionCommotion

    Converting collection of objects to JSON

    Thanks gizmola, I certainly hope I am drinking the doctrine coolaid for a good reason! RDBs "kind of" support inheritance using supertype/subtype, don't you think? I was looking closer at your referenced serializer link. First of all, other than dealing with recursion, what is the point of using it instead of plain old json_encode()? Secondly, the documentation states that the most common use is serializing an object, but when I try the following, somehow the script just ends and returns nothing (I haven't totally tracked it down yet). Don't know if it matters but I am using xml to define my doctrine entities. Maybe I need to define what it returns? $serializer = \JMS\Serializer\SerializerBuilder::create()->build(); $serializer->serialize($someEntity, 'json')
  15. NotionCommotion

    Converting collection of objects to JSON

    @kicken As always, good advice. Thank you. @gizmola Yes, a REST api. No, I am not and haven't ever tried Symfony (well, I guess I use Twig). Using a formal ORM for the first time. While I like a lot of Doctrine's capabilities, I really don't know yet if I am glad I am trying to adapt it. Actually, I know I am not glad but hope/expect that will change. I probably should look into Symfony, but this Doctrine thing has taken me for a loop. Good news is doing so has allowed me to actually understand some previously foreign concepts that smart programmers on this forum believe are important. Thanks
  16. NotionCommotion

    Converting collection of objects to JSON

    I suppose I too don't understand why I am not just overriding getB(). My need is just to allow it to be flexible enough should two classes be slightly different. I thought the intent was for the JSON Schema to validate JSON documents. I will read in more detail. I actually wrote my own classes to validate JSON and wish I learned about this sooner. If I understand you correctly, I will need to have the entities responsible for obtaining the data included in the JSON but just should use a separate method instead of the JsonSerialize(). I got schooled a while back by ignace that a separate class should always be responsible to do so and was looking for ways to do so.
  17. NotionCommotion

    Converting collection of objects to JSON

    Thanks kicken, JSON Schema looks interesting, but I am not sure it is an answer. Let's say we have a collection (or array) containing 6 objects. Array ( [0] => ProjectC Object ( [c:protected] => 5 [g:protected] => 5 [h:protected] => 2 [a:protected] => 1 [b:protected] => 3 [d:protected] => 5 ) [1] => ProjectA Object ( [b:protected] => 4 [d:protected] => 2 [e:protected] => 7 [f:protected] => 8 [a:protected] => 1 [c:protected] => 2 ) [2] => ProjectB Object ( [bDiffName:protected] => 1 [c:protected] => 4 [d:protected] => 2 [g:protected] => 3 [a:protected] => 1 [b:protected] => 3 ) [3] => ProjectB Object ( [bDiffName:protected] => 1 [c:protected] => 4 [d:protected] => 2 [g:protected] => 3 [a:protected] => 1 [b:protected] => 3 ) [4] => ProjectC Object ( [c:protected] => 5 [g:protected] => 5 [h:protected] => 2 [a:protected] => 1 [b:protected] => 3 [d:protected] => 5 ) [5] => ProjectA Object ( [b:protected] => 4 [d:protected] => 2 [e:protected] => 7 [f:protected] => 8 [a:protected] => 1 [c:protected] => 2 ) ) $a should not be included in any of the JSON output. ProjectB uses $bDiffName instead of $b. Some objects provide have additional properties which should be included. As such, the desired output should be as shown. [ {"b":3,"c":5,"d":5,"g":5,"h":5}, {"b":4,"c":2,"d":2,"e":7,"f":8}, {"b":1,"c":4,"d":2,"g":3}, {"b":1,"c":4,"d":2,"g":3}, {"b":3,"c":5,"d":5,"g":5,"h":5}, {"b":4,"c":2,"d":2,"e":7,"f":8} ] Sure, I can write a class to present the results as needed. But if so, each object needs its own, no? And if i write a separate class for each, without making the entity responsible to identify the applicable class or without making some map between entity class name and serializing service, how can the script know which class to use? Reference code only... <?php abstract class Project implements JsonSerializable { protected $a=1, $b=3, $c=2, $d=5; public function getB(){return $this->b;} public function getC(){return $this->c;} public function getD(){return $this->d;} } class ProjectA extends Project { protected $b=4, $d=2, $e=7, $f=8; public function getE(){return $this->e;} public function getF(){return $this->f;} public function jsonSerialize() { return ['b'=>$this->getB(),'c'=>$this->getC(),'d'=>$this->getD(),'e'=>$this->getE(),'f'=>$this->getF()]; } } class ProjectB extends Project { protected $bDiffName=1, $c=4, $d=2, $g=3; public function getBDiffName(){return $this->bDiffName;} public function getG(){return $this->g;} public function jsonSerialize() { return ['b'=>$this->getBDiffName(),'c'=>$this->getC(),'d'=>$this->getD(),'g'=>$this->getG()]; } } class ProjectC extends Project { protected $c=5, $g=5, $h=2; public function getG(){return $this->g;} public function getH(){return $this->g;} public function jsonSerialize() { return ['b'=>$this->getB(),'c'=>$this->getC(),'d'=>$this->getD(),'g'=>$this->getG(),'h'=>$this->getH()]; } } $arr=[ new ProjectC, new ProjectA, new ProjectB, new ProjectB, new ProjectC, new ProjectA, ]; echo('<pre>'.print_r($arr,1).'</pre>'); echo('<pre>'.json_encode($arr).'</pre>');
  18. NotionCommotion

    Two Forms, One $_SESSION

    Since you are okay with your application relying on JavaScript, there is no need for PHP for this portion. Customer alters quantities on form_1 and when transitioning to form_2, just use JavaScript to copy the values you want to the hidden inputs. <script> function update(){ var quantity = document.getElementById("quantity"); var total = document.getElementById("total"); total.value = (quantity.value * 5); document.getElementById("q").value=quantity; document.getElementById("t").value=total; } </script> <form action="FINISHED.php" method="post"> <input type="submit" value="FINISHED"> <input type="hidden" name="q" id="q" value=""> <input type="hidden" name="t" id="t" value=""> </form> You need to get your head around what the client (i.e. your web browser) and server (i.e. PHP) is. The client always makes the request and the server only responds. The server cannot directly change anything on the client. If the client receives the code <?=$_POST["quantity"]?>, it will just be interpreted as this exact literal text. Only the server knows that it should replace this code with the value of $_POST['quantity']. Similarly, the server doesn't have access to the JavaScript variable "quantity" or "total". The only way data is shared is when the client sends some data to the server or the server responds to the client with some data. The client sends data to the server either by submitting the page or by submitting via an Ajax request, and for both cases the server responds with whatever it was instructed to do provide. You "could" make the client submit form_ and have the server respond with form_2 with certain inputs filled out using an echo statement. Or you can make the client under form_1 update form_2 with the correct values and submit form_2. And really "kind of" the same thing, you can make the client perform an Ajax request to send (and receive) data without submitting the form. Make extra, extra, extra sure you understand this.
  19. NotionCommotion

    Error connecting to database

    Not saying necessarily that your PHP doesn't have errors, but that error in particular wasn't a PHP error by a SQL error. Yes, I thought but wasn't positive that order and including all the fulltext indexes was required.
  20. NotionCommotion

    Error connecting to database

    I don't have too much experience with fulltext indexes. It isn't a PHP issue anymore but a SQL issue, and as such, I would recommend eliminating variables and running your query directly from the command line or through some SQL client if you wish. Maybe try the following? SELECT COUNT(*) as tot FROM television p WHERE MATCH(title,description,keywo´╗┐rds) AGAINST(? IN BOOLEAN MODE);
  21. NotionCommotion

    Error connecting to database

    What have you tried? SHOW INDEX FROM television; ALTER TABLE television ADD FULLTEXT(title,keywords);
  22. NotionCommotion

    Error connecting to database

    You are using PDO in your later code which is good. You next need to create a PDO connection. The docs give an example which was copied below. Obviously, you want to rename $dbh to $db. Note that if you simple searched "php pdo", the first result would be http://php.net/manual/en/book.pdo.php which doesn't give any examples. Instead of randomly going through each link (which isn't necessarily a waste of time), always check the __construct link first. PS. Get rid of all your constant definitions for your database connection values. At first you might think it is a good idea, but having too many constants gets complicated fast. I like to locate a file called config.ini in a secure location (i.e. not in your public root directory!) and use parse_ini_file() to convert it into an array. <?php /* Connect to a MySQL database using driver invocation */ $dsn = 'mysql:dbname=testdb;host=127.0.0.1'; $user = 'dbuser'; $password = 'dbpass'; try { $dbh = new PDO($dsn, $user, $password); } catch (PDOException $e) { echo 'Connection failed: ' . $e->getMessage(); } ?>
  23. NotionCommotion

    Creating new objects with sub-objects when using an ORM

    I think I answered half of my questions. If AggrPoint#aggrType should be an object (which I believe it should be), then I should use a factory pattern and have each factory retrieve the correct instance of AggrType and then either inject it in AggrPoint or use AggrPoint's setAggrType() method. I am not really sure whether TimeUnit should be an object, and still need to figure out how to prevent Doctrine from generating an object but still keep the foreign key constant.
  24. I have the following three tables (and also delta_point and hist_point which are purposely left out and just mentioned for context). Before going down the Doctrine ORM long curvy road, aggrType was just used to restrict possible values so that I didn't need to use MySQL's ENUM, but now I am thinking there may be value to making it an entity and include some methods (and a second reason because I still can't figure out how to make Doctrine create a FK constraint yet not populate the parent entity with a AggrType object). point -id (int PK) -data -dType /* descriminator. Options are AggregatePoint, DeltaPoint, and HistoricPoint */ aggr_point -id (int PK, FK to point) -aggrType (char FK to aggrType) -data aggrType -type (char PK) /* there are about five types */ I have a service to create a new point based on the provided desired type and user data. I don't like the switch statement to determine which type of point to create, but don't know a better way. Also my entity is responsible to provide the appropriate validation rules for the given point type which might not be considered proper but it seems to work for me. Any constructive criticism is welcomed. <?php namespace NotionCommotion\PointMapper\Api\Point; use NotionCommotion\PointMapper\Domain\Entity\Point; class PointService { public function create(string $type, array $params):integer { $class=[ 'aggr'=>'AggregatePoint', 'delta'=>'DeltaPoint', 'hist'=>'HistoricPoint', ][$type]; //$class='Point\\'.$class; //This doesn't seem to be possible and I needed to use the fully qualifed name without the short cut used namespace. $class='\\Greenbean\Datalogger\Domain\Entity\Point\\'.$class; $point=new $class(); $validator=$this->getValidator($point); $params=$validator->sanitize($params); $validator->validate($params); $point->setAccount($this->account); $point->populate($params, $this->em); //Will be addressed later $this->em->persist($point); $this->em->flush(); $point->setIdPublic($this->em->getRepository(Point\Point::class)->getPublicId($point->getId())); return $point->getIdPublic(); } } Now, this is the part I am struggling with the most. I only have one service to create any type of point, so I do wish to put a bunch of if/thens in it and instead move logic to the individual point type being created. The AggrPoint in question requires a sub-point and I don't think it is appropriate to inject the entity manager into a point entity and as an alternative solution find an existing point which is associated with the account which resides in the new AggrPoint. Maybe not appropriate, but it works. This type of point also has a sub-object AggrType as discussed at the very beginning of this post, so I first attempt to create a new one from scratch, but that doesn't work and I need to set $aggrType with an existing one. As an alternative, I passed the entity the entity manager, but as stated I think this is a bad idea. Any recommendations where to go from here? Thank you namespace NotionCommotion\PointMapper\Domain\Entity\Point; class AggregatePoint extends Point { public function populate(array $params, \Doctrine\ORM\EntityManager $em):\NotionCommotion\PointMapper\Domain\Entity\Entity{ $criteria = \Doctrine\Common\Collections\Criteria::create() ->where(\Doctrine\Common\Collections\Criteria::expr()->eq("id_public", $params['pointId'])); if(!$subpoint = $this->getAccount()->getPoints()->matching($criteria)->current()){ throw new \Exception("Invalid subpoint ID $params[pointId]"); } $this->setSubpoint($subpoint); //This won't work since I must use an existing AggregateType and not create a new one $aggrType=new AggregateType(); $aggrType->setType($params['aggrType']); //This just seems wrong and I shouldn't be passing the entity manager to an entity $aggrType=$em->getRepository(AggregateType::class)->findOneBy(['type'=>$params['aggrType']]); $this->setAggregateType($aggrType); unset($params['pointId'], $params['aggrType']); // parent::populate($params) not shown, but it basically calles appropriate setters based on the property name return parent::populate($params); } public function getValidatorRules():array { return $this->filesToArr(['/point/base.json', '/point/aggr.json']); } }
  25. NotionCommotion

    Creating new objects with sub-objects when using an ORM

    Another example of the same issue is TimeUnit. I have a table which contains only eight records which correspond to seconds, minutes, hours, days, weeks, months, quarters, and years. This table has two purposes: 1) Create the list of options to present to the user. 2) Provide referential integrity. I can make AggrPoint#timeUnit either a primitive type (integer or string) or an object. Both approaches seem to have merit. What would you do? If a string, how can Doctrine be used to generate the foreign key constraint? If an object, how should an instance of one of these eight TimeUnit objects be obtained when creating a new AggrPoint?
×

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.