PHP - Iteration Over $this And Inheritance
Hello, I have two classes:
Code: [Select] abstract class Serializable { public function serialize() { foreach($this as $member => $value) { $publicObject->$member = $value; } return $publicObject } } class ToSerialize extends Serializable { public function otherSerialize() { foreach($this as $member => $value) { $publicObject->$member = $value; } return $publicObject } } $foo = new ToSerialize(); $foo->serialize(); //This will return one thing $foo->otherSerialize(); //This will return something different Why does this happen? Similar Tutorialshi I'm coding a page and I was trying to iterate an iteration. but it doesn't seem to work. is this possible in php? Code: [Select] $pageTpl->setIteration('iPlaylist'); // loop all collections and output them foreach ($playlists as $playlist) { // assign collection & urls in template $pageTpl->assignIteration('playlist', $playlist['Title']); $pageTpl->refillIteration(); $pageTpl->setIteration('iMusic'); foreach ($songs as $song){ $pageTpl->assignIteration('path', STREAMING_PREFIX.substr($song['Filename'], 7)); $pageTpl->assignIteration('songId', $song['SongId']); $pageTpl->assignIteration('title', $song['Title']); $pageTpl->assignIteration('artist', $song['Artist']); $pageTpl->assignIteration('time', FYMFunctions::Sec2hms($song['Length'])); $pageTpl->assignIteration('genre', $song['Genre']); $pageTpl->assignIteration('delete', 'removeSong('.$song['SongId'].')'); $pageTpl->refillIteration('iMusic'); } // parseIteration $pageTpl->parseIteration('iMusic'); } // refillIteration $pageTpl->refillIteration(); // parseIteration $pageTpl->parseIteration('iPlaylist'); this is the piece of code... did I do anything wrong? To solve a bigger issue I'm having in WordPress, I have thrown together this basic script in PHP script to help me get to the bottom of it. Basically, I am trying to add a <hr /> tag after every 3rd paragraph: http://www.mattpealing-server.co.uk/~freshmat/wp-content/themes/match2move/test.php With the following code: <?php $count = 0; ?><?php while($count < 20) : ?><span><p><strong><?php echo $count; ?>:</strong> Lorem ipsum dolor sit amet, consectetuer adipiscing.</p></span><?php if ($count % 3) : ?><hr /><?php endif; ?><?php $count ++; ?><?php endwhile; ?>() However if you notice, this output just doesn't turn out like this! Does the operator I'm using not test if $count is a multiple of 3? Hello,
Here is my code:
<?php require 'vendor/autoload.php'; $client = new Elasticsearch/Client(); $root = realpath('~/elkdata/for_elk_test_2014_11_24/Agencies'); $iter = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($root, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD); $paths = array($root); foreach ($iter as $path => $dir) { if ($dir -> isDir()) { $paths[] = $path; } } //Create the index and mappings $mapping['index'] = 'rvuehistoricaldocuments2009-2013'; //mapping code $mapping['body'] = array ( 'mappings' => array ( 'documents' => array ( '_source' => array ( 'enabled' => true ), 'properties' => array( 'doc_name' => array( 'type' => 'string', 'analyzer' => 'standard' ), 'description' => array( 'type' => 'string' ) ) ) ) ); $client ->indices()->create($mapping) //Now index the documents for ($i = 0; $i <= count($paths); $i++) { $params ['body'][] = array( 'index' => array( 'type' => 'documents' 'body' => array( 'foo' => 'bar' //Document body goes here ) ) ); //Every 1000 documents stop and send the bulk request. if($1 % 1000) { $responses = $client->bulk($params); // erase the old bulk request $params = array(); // unset the bulk response when you are done to save memory unset($responses); } } ?>I am looking to index a large amount of documents using elastic search and php. I have a very complex directory filled with other directories that i need to index into an array. I wanted to see if my code looked right, and if not what am I doing wrong? Thanks, Austin Harmon So I have a very simple for loop that I am populating a list with levels and exp required to achieve the next level. I have been using a sandbox to test my output and have also created an excel sheet to replicate the data to verify the content. This code was not mine from the beginning and in creating the spreadsheet I discovered the flaw. Below is the code I am trying to fix: function experience($L, $pres = 0) { $a = 0; $end = 0; for ($x = 1; $x < $L; ++$x) { $a += $x * round($x + 5 * pow(4, ($x / 300))); } if ($x > 199) { $a += $x * round($x + 7 * pow(4, ($x / 290))); } if ($x > 399) { $a += $x * round($x + 11 * pow(4, ($x / 280))); } if ($x > 599) { $a += $x * round($x + 19 * pow(4, ($x / 270))); } if ($x > 799) { $a += $x * round($x + 35 * pow(4, ($x / 260))); } if ($x > 999) { $a += $x * round($x + 67 * pow(4, ($x / 250))); } return round($a / 1.25); } Below is the troubleshooting I am attempting to do (Modified and simplified for and while loop): //for loop $no = 200; $a = 0; for ($x = 1; $x < $no; ++$x) { $a += $x + 1; } if ($no > 199) { $a += $x + 2; } echo $a; //while loop $no = 200; $a = 0; $x = 1; while (($x - 1) < $no) { $a += $x * round($x + 5 * pow(4, ($x / 300))); $x++; if ($x > 199) { $a += $x * round($x + 7 * pow(4, ($x / 290))); } } echo $a; Upon request I can also provide snipets of the excel sheet. So the gist of what the issue I am having is this. Between level 199 and 200 the iteration of the loop is running one extra time through the initial formula. As you can tell at level 200, 400, 600, 800 and 1000 I want this formula to change so that it simplifies the amount of exp required to achieve the next level. I can not for the life of me figure out how to restrict the loop while still allowing the values 200 up to run through it for the first 199 iterations. The output I should get from the primary code for levels 199 through 201 are as follows: 199 = 200 = 201 = At level 199 I am good but for whatever reason it runs one additional iteration at the level 1-199 formula and then moves on to the 200 level formula messing up the values. Any and all help is much appreciated. I am a novice hobbyist at best and have been doing this for many, many years now but sometimes I get stumped. I chalk it up to lack of proper training and time to really be serious with it. Thanks in advance....NICON I'm not entirely sure how to phrase the title, so I hope it's appropriate... I have an array which looks like the following.. Code: [Select] Array ( [contact] => Array ( [0] => Array ( [name] => Someone Cool [number] => 1234567890 ) ) [messages] => Array ( [0] => Array ( [message] => A message that was recieved [date] => 1234567890 [type] => 1 ) [1] => Array ( [message] => A message which was sent [date] => 1322175702616 [type] => 2 ) ) [calls] => Array ( [0] => Array ( [datetime] => 1320674980836 [type] => 1 [duration] => 7 [number] => 1234567890 ) [1] => Array ( [datetime] => 1320675327541 [type] => 2 [duration] => 638 [number] => 1234567890 ) ) ) [messages] can have anywhere between 40 and 3000 children [calls] can have anywhere from 0 to 200ish children ** These are generals, but realistically, either can have any number. What I'm trying to do is dump all messages and calls. The catch is this: When dumping a call, a check needs to be run against datestamps and only dump the next call coming out where the datestamp of the call is NEWER than the LAST message dumped, AND OLDER than the message that is to be dump in this cycle of the loop. What I have so far is the following... Code: [Select] foreach($vardump['messages'] as $message) { // So we have a reference point for the first call we're going to dump if(!is_numeric($last_message_stamp)) { $last_message_stamp = $message['date']; } if( trim($vardump['calls'][$calls_counter]['datetime']) > trim($last_message_stamp) && trim($vardump['calls'][$calls_counter]['datetime']) < trim($message['date'])) { // Dump the calls row! echo(" <div class=\"chatbubble-call\"> <div class=\"chatbubble-person\">".$vardump['contact'][0]['name']."</div> <p>".$vardump['calls'][$calls_counter]['number']."</p> <p>".date("h:i:s", $vardump['calls'][$calls_counter]['number'])."</p> <div class=\"chatbubble-datetime\">".date("l, j F, Y -- h:i:s", $vardump['calls'][$calls_counter]['datetime'] / 1000)."</div> </div> "); // Increase our calls index $calls_counter++; } // Begin dumping Texts out :D // Let's see which style type we're dumping out... if($message['type'] == 2) { // Message Sent echo(" <div class=\"chatbubble-sent\"> <div class=\"chatbubble-person\">Pat Litke</div> <p>".$message['message']."</p> <div class=\"chatbubble-datetime\">".date("l, j F, Y -- h:i:s", $message['date'] / 1000)."</div> </div> "); } else { // Message Recieved echo(" <div class=\"chatbubble-recieved\"> <div class=\"chatbubble-person\">".$vardump['contact'][0]['name']."</div> <p>".$message['message']."</p> <div class=\"chatbubble-datetime\">".date("l, j F, Y -- h:i:s", $message['date'] / 1000)."</div> </div> "); } // Reset our $last_messge_stamp variable $last_message_stamp = $message['date']; } I should also add that I am using the following queries to pull this date out of my database... Code: [Select] $sql_get_messages = "SELECT * FROM messages WHERE thread_number LIKE '%$the_thread%' ORDER BY epoch_date ASC"; $sql_get_calls = "SELECT * FROM calls WHERE number LIKE '%$the_thread%' ORDER BY datetime ASC"; $sql_get_contact = "SELECT * FROM contacts WHERE number LIKE '%$the_thread%' LIMIT 1"; But, I feel that this is horribly inefficient, and it doesn't work right... I only ever get a single call dumped. What am I doing wrong? Specific question with general application here. i am having some trouble with a loop and am getting some odd timing results specifically this is a WMI query on a hyper-v server retrieving disk information but im not sure the context of the query is relevant here. The main question is how come the first iteration of the loop is so much slower than the other iterations, it just doesnt seem to make sense to me unless ive done something stupid here i cannot see. any ideas ? Code: [Select] <?php $diskstart = microtime(true); // get the hard disk size try { $resultDisk = $wmi->ExecQuery("SELECT BlockSize,NumberOfBlocks FROM msvm_LogicalDisk where systemname like '%" . $guid . "%' and name='Hard Disk Image'"); $ct=0; $start1 = microtime(true); $start = microtime(true); foreach($resultDisk as $itemDisk) { $end = microtime(true); echo "<BR>FOREACH: [" . Round($end-$start,3) . "] seconds"; $vm[$name]['disks'][$ct] = ($itemDisk->BlockSize * $itemDisk->NumberOfBlocks)/1024; // format the disk size into KB $ct++; $start = microtime(true); } $end1 = microtime(true); echo "<br> ALLLOOP: [" . Round($end1-$start1,3) . "] "; } catch(exception $e) { } $diskend = microtime(true); echo "<br>DISK: [" . ($diskend-$diskstart) . "] seconds"; ?> and here are the results Code: [Select] FOREACH: [1.236] seconds FOREACH: [0.001] seconds FOREACH: [0.001] seconds FOREACH: [0.001] seconds FOREACH: [0.002] seconds FOREACH: [0.001] seconds FOREACH: [0.001] seconds FOREACH: [0.001] seconds FOREACH: [0.001] seconds FOREACH: [0.001] seconds FOREACH: [0.001] seconds ALLLOOP: [2] DISK: [2.1837468147278] seconds Evening everyone and Merry X-Mas (Happy Holidays) or whatever fits you best.... I have been trying over and over for about 12 hours to figure out how to get data from a specific JSON response and assign the specific values to a new array key/value pair. The various ways I have tried to figure this out are numerous so i'm going to avoid the runnig list of "I trieid this...and this...and this... etc etc." just understand I have reached a dead end point where I need help badly.
Here is what our end goal is:
"The company" is a "service industry" provider (plumbing, electrical etc. etc.) who wants to dispatch its technicians to new jobs based on which technician has the shortest travel time from any existing address where they already have a scheduled appointment that day and has available time in there schedule. Thus the dispatching system when a new service call is entered is going to give "recommended" technicians (up to 4) to be assigned the new service call based on the above mentioned criteria. (Efficient routing to save company gas cost)
1.) We have a "New service" street address assigned to the $to variable: $to = "4813 River Basin Dr S, Jacksonville FL 32207"; 2.) We will have "records" array which containes a series of records, each record consists of a ticket# a technician id# and a street address: $records = array( array("DV1012","30453423","9890 Hutchinson Park Dr Jacksonville, FL 32225"), array("DB3434","30404041","821 Orange Ave Crescent City, FL 32112"), array("DB3434","30605060","1972 Wells Road, Orange Park FL 32073"), array("DB4578","30605060","2 Independent Drive, Jacksonville FL 32202"), array("DB7841","30605060","5000 Norwood Avenue, Jacksonville FL 32208"), array("DB3235","30605060","9501 Arlington Expressway, Jacksonville FL 32225"), array("DB7894","30605060","Massey Avenue, Jacksonville, FL 32227"), array("DB2020","30121212","11200 Central Pkwy Jacksonville, FL 32224") ); 3.) We are going to prepare the records array for submission to Google's Distance Matrix API by URL encoding each array value into a single variable and then submit it: foreach ($records as $key => $value) {$from = $from.urlencode($value[2])."|";} $to = urlencode($to); $data = file_get_contents("//maps.googleapis.com/maps/api/distancematrix/json?origins=$from&destinations=$to&language=en-EN&units=imperial&mode=driving&sensor=false"); $res=json_decode($data) or die("Error: Cannot read object"); You may look at the ACTUAL live Google response from this he http://tiny.cc/i6eerx (We have applied <pre> and var_dump($res) to the output) We are looking to get the following information back: The distance and travel time between the "New Service" address ($to) and each of the address' in the $records array ($from), now once that information is returned from Google (JSON response) we need to parse the response and narrow it down to 4 or less (Based on the 4 lowest drive times) to form a new array which ends like this: $results = array( array("DV1012","30453423","2.3 Miles","8 mins"), array("DB3434","30404041","2.8 Miles","9 mins"), array("DB3434","30605060","4.6 Miles","13.8 mins"), array("DB4578","30605060","5.7 Miles","15.2 min") ); OUR PROBLEM: Everything up until the the Google API response is fine, but iterating over the multidimensional arrays within multidimensional arrays of the JSON response is just not coming together in my head (or 2 dozen code attempts). I am able to ECHO an individual value like ( echo $res->rows[0]->elements[0]->distance->text; ) but this has no value for the end result i need to get to. My last thoughts and efforts was that that I was going to have to embed foreach statements within foreach statements to drill down through the various arrays but that hasn't worked very well and it seems like it shouldn't be how it has to be done. I would appreciate any help in showing me how the iteration code should be written and any explanation about the code so i can wrap my head around it. I have an array of property details that prints to the page. Later on that same page, I would like to use one of the array's values as part of a mailto script, but I can't seem to figure out how to recall it. could someone point me in the direction of how I can make the array's values available for later use? I hope this is clear enough. Thanks I am doing some study on using time() and date() and i just wrote this simple for loop to add one day to each iteration with +$i and its echoing the unix timestamp as opposed to the correctly formated date as it should be based on my code. Anyone have any idea why this is not working as expected? for($i=0; $i < 50; $i++) { echo $time = time()+$i . "<br />"; // add a day on each iteration echo date('y-m-d', $time) . "<br />"; // should echo 10-12-02, 10-12-03, 10-12-04, etc.. } what am i doing wrong here? arrgggg! maybe its too late for this s$%^#!
$start = 0; I have
class MyProductClass { function computeProductA() { doSometing(); } function computeProductB() { doSometingElse(); $this->computeProductCommon(); } function computeProductC() { $this->computeProductCommon(); } function computeProductCommon() { } }And I was wondering ... does it make sense to move out product-specific functions into their own classes and then have them extend MyProductClass. While I think it makes sense to me from an aesthetic point of view, and that I get to use object oriented principles, I could not answer myself as to "Why" I would do that. So, why? Why would I do that, and should I? Right now in the code, various product specific classes instantiate MyProductClass and just use their specific and generic functions, as needed. Edited by dennis-fedco, 15 December 2014 - 09:55 AM. Context. Class AbstractTenantEntity's purpose is to restrict access to data to the tenant (i.e. account, owner, etc) that owns the data. Any entity which extends it will have the TenantId added when created and the TenantId in the WHERE clause for all other requests. Tenant typically does not have collections of the various entities which extend AbstractTenantEntity, but does for a few of them do. When using annotation, I handled it by applying Doctrine's AssociationOverride annotation to the extended classes which should have a collection in Tenant. use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity() */ class Tenant { /** * @ORM\OneToMany(targetEntity=Asset::class, mappedBy="tenant") */ private $assets; // Other properties and typical getters and setters }
use Doctrine\ORM\Mapping as ORM; abstract class AbstractTenantEntity implements TenantInterface { /** * inversedBy performed in child where required * @ORM\ManyToOne(targetEntity=Tenant::class) * @ORM\JoinColumn(nullable=false) */ protected ?Tenant $tenant = null; // Typical getters and setters }
use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity() * @ORM\AssociationOverrides({ * @ORM\AssociationOverride(name="tenant", inversedBy="assets") * }) */ class Asset extends PublicIdTenantEntity { // Various properties and typical getters and setters }
So, now I am changing from annotations to attributes, and modified AbstractTenantEntity as follows: use Doctrine\ORM\Mapping\ManyToOne; use Doctrine\ORM\Mapping\JoinColumn; abstract class AbstractTenantEntity implements TenantInterface { /** * inversedBy performed in child where required */ #[ManyToOne(targetEntity: Tenant::class)] #[JoinColumn(nullable: false)] protected ?Tenant $tenant = null; // Typical getters and setters } Next I went to modify Asset and realized that there didn't appear to be an attribute for AssociationOverride. I found a little discussion on the topic on github but couldn't find any resolution. Question Can inheritance be used with PHP 8 attributes where the property is defined in the parent class and the attribute is applied in the child class? Googling php 8 attributes inheritance didn't provide anything and thus I expect the answer is no but thought I'd ask. Thanks
EDIT. Maybe Doctrine does have an attribute version: https://github.com/doctrine/orm/blob/2.9.x/lib/Doctrine/ORM/Mapping/AttributeOverride.php EDIT2. Actually don't think so Edited July 30 by NotionCommotionHey again, I hope you guys don't get annoyed with my noob questions. I was reading the guide here on the site about OOP, and on the section related to inheritance it makes a "Dog" class, after giving it an attribute and a method it then creates the "Animal" class using "extends" and expands on the methods. Then after that here is the paragraph I'm looking at now. "Class Animal is unaware of the fact that it is being extended; there are no references to Dog whatsoever. Say Animal extended another class called LifeForm, and I instantiated Animal, only methods and properties of Animal and LifeForm would be included in the object." To me, this sounds like if I were to create this "LifeForm" class by further extending the "Animal" class, I would not be able to access any of the attributes and methods that were in "Dog," only the ones that were in Animal and any that I put in LifeForm itself. But, I was playing with the code and I can call an attribute from Dog in LifeForm. So, am I reading the post wrong or am I coding wrong? Code: (php) [Select] <?php //Class Dog// class Dog{ public $hungry = 'Hell yeah!'; public $test = 'Affirmative!'; function eat($food){ $this->hungry = 'not so much.'; } } //Class Animal// class Animal extends Dog{ function eat($food){ if($food === 'cookie'){ $this->hungry = 'not so much'; }else{ echo 'Barf! I only like cookies!'; } } } //Class LifeForm// class LifeForm extends Animal{ function eat($food){ } } //Program Variables// $dog = new Dog; $LifeForm = new LifeForm; //Program Code// echo $LifeForm->test; ?> My assumption was that I am able to call that attribute because of the 'public' in front of it, but all the attributes in the examples are also public. Thanks guys! Hello, I'm attempting to build a Model View Controller and I've run into some issues with inheriting objects / extending classes. The application is focused around a "SuperObject", which contain instantiated libraries, helpers, controllers, models and views. I current have a Base class, which is effectively the "SuperObject". Previously I called the function GetInstance() within my model to get an instance of the SuperObject and assign it to a variable. So, $this->Instance->(The Object)->(The Method)(); However, I want to remove the need for that variable $this->Instance and just have $this->(The Object)->(TheMethod)(); And so, If you see my Controller class, libraries are instantiated as $this->Object which works perfectly. If from, within my controller I was to load the Model class. For example, $this->Loader->Library('Model'); when that model becomes instantiated, even though an extension of the Base class, I cannot use the libraries I instantiated in my controller. And of course there is a Fatal Error: Fatal error: Call to a member function UserAgent() on a non-object Code: [Select] <?php class Base { private static $Instance; public function Base() { self::$Instance =& $this; } public static function &GetInstance() { return self::$Instance; } } function &GetInstance() { return Base::GetInstance(); } Code: [Select] <?php class Controller extends Base { function Controller() { parent::Base(); $this->Initialize(); } function Initialize() { $Array = array( 'Uri', 'Loader', 'Router', 'Database', ); foreach($Array as $Object) { $this->$Object = loadClass($Object); } } } Code: [Select] <?php class Model extends Base { function Model() { parent::Base(); echo $this->Input->UserAgent(); } } Code: [Select] <?php class Home extends Controller { function Home() { parent::Controller(); } function index() { $this->Loader->Library('Session'); $this->Loader->Library('Model'); $Data = array( 'Controller' => $this->Router->FetchClass(), 'Title' => ucfirst($this->Router->FetchClass()) ); $this->Loader->View('meta',$Data); $this->Loader->View('header',$Data); $this->Loader->View('home'); $this->Loader->View('footer'); } } Any input would be appreciated! I am using API-Platform, Doctrine, and Symfony with entities that utilize class type inheritance to extend an abstract entity. I've been running into one issue after another primarily related to the serialization process (serialization groups, parent annotations not propagated to the child, etc), and while I am sure user error on my part is part of the culprit, it appears that API-Platform and potentially Symfony and Doctrine don't fully support entity inheritance. My reason for thinking so is the incredibly sparse amount of documentation on the subject and remarks on quite a few github issues posts and other blogs how it is "bad practice". For instance, say I have Mouse, Cat, and Dog which all extend AbstractAnimal, and each has a bunch of common properties such as birthday, weight, etc, and methods such as eats(), sleeps(), etc. Sorry in advance for using hypothetical entities but I don't think doing so distracts. I like how inheritance allows me to keep all common properties in a single table, but can let that go. More importantly, the subset mouse, cat, and dog table shares an ID from the animal table allowing me to associate all animals to some other table (i.e. many-to-one to person whether they are their pet or many-to-many to country whether they are native to a country), and to retrieve a list of animals and filter by some property or type as needed without a bunch of unions. To me, this sounds like inheritance, but if the products I am using don't support it very well, it doesn't matter. First question. Is entity inheritance considered bad practice? And even if not, is it common for frameworks to limit their level of support for them? If so, what can I do about it? Maybe favor composition over inheritance? Okay, great, I now have a single animal table which makes all my SQL concerns issues go away and I am pretty confident that my serialization issues will also go away. All I need to do is inject each animal with some "thing" to make them a mouse, cat, or dog. But what do I call this thing? I've struggled with this topic for a while and asked the same question regarding how to deal with BarCharts, PieCharts, GaugeCharts, LineCharts, etc all being charts but all acting slightly differently, and never really came to any conclusion. For a non-hypothetical scenario, I have BacnetGateway and ModbusGateway which extend AbstractGateway. Okay, this one is easy and I change to just having a Gateway and inject either BacnetProtocol or ModbusProtocol. For another non-hypothetical scenario, I have PhysicalPoint which represents some real environmental parameter, VirtualPoint which represents combining one or more PhysicalPoints or VirtualPoints, and TransformedPoint (feel free to provide a better name) which represents performing some time function such as integrating over a given time. Currently, they all extend AbstractPoint, but if I was trying to do so with composition, I could inject PointType but don't think doing so makes sense. For my hypothetical scenario, do I make a DNA interface and inject an Animal with DogDNA to get a dog? I really need to get my head around this once and for all. Thanks Hi, After a long time I start php again to do some stuff and using OOP concept for the first time and getting this below error Code: [Select] PHP Fatal error: Class 'SystemConfig' not found in /home/tanveer/Workspace/EmailTest/webapp/classes/MailParser.class.php on line 12, referer: http://localhost/EmailTest/public_html/index.php My project directory structure is as follows: Code: [Select] \webapp: |- classes |- MailParser.class.php |-DatabaseConnect.class.php |-SystemConfig.class.php \public_html: |-header.php |-footer.php |-gencsv.php |-stat.php \css |-style.css \images index.php And the php code file that I am trying to make work is as follows: class MailParser extends SystemConfig { /* Reads the files passed line-by-line * @param $fileName */ public function readFiles($fileName){ $fileHandler = fopen($fileName,'r'); while ($line = fgets($fileHandler)) { echo $line."<br />"; } fclose($fileHandler); } /* Traverse the user specified directory * @param $dirPath */ public function traverseDirectory($dirPath) { echo $dirPath; $sentFolderPath = new SystemConfig(); $sentFolderPath->getSentMailFolder(); $totalDirPath = $dirPath."/".$sentFolderPath; echo $totalDirPath; $io=0; if ($handle = @opendir($dirPath)) { while (false !== ($file = readdir($handle))) { if ($file != "." && $file != "..") { $newdir = ""; $filetext = ""; if (!is_file($dirPath."/".$file) or is_dir($dirPath) ) { $io++; $newdir.= $dirPath."/".$file."/"; print $newdir."<br />"; $this->traverseDirectory($newdir); if(is_file($dirPath.$file)) { $text = str_replace('//','/',"".$dirPath.$file."\n"); } } } } closedir($handle); } } } $rmf = new MailParser(); $rmf->traverseDirectory($_POST["dirpath"]); ?> I wish to create and store in a DB three objects which are created using injection; $myAObject=new BaseEntity(new InjectedThingA()); $myBObject=new BaseEntity(new InjectedThingB()); $myCObject=new BaseEntity(new InjectedThingC()); BaseEntity is defined by SQL table base_entity and my three injected objects InjectedThingA, InjectedThingB, and InjectedThingC are each defined by SQL tables injected_thing_a, injected_thing_b, injected_thing_c, respectively. Each of these injected tables has autoincrement column id plus whatever other columns, and base_entity includes a column injected_thing_id. But this won't work since this ID is not unique across InjectedThings and also poor since there is no foreign key, so instead I do the following. InjectedThingA extends AbstractInjectedThing InjectedThingB extends AbstractInjectedThing InjectedThingC extends AbstractInjectedThing Then I add an autoincrement id column to AbstractedInjectedThing and place a one-to-one constraint from column id in InjectedThingA, InjectedThingB, and InjectedThingC to column id in AbstractedInjectedThing. So, I still need to use inheritance, right? I don't think that this type of inheritance brings the baggage which MyInheritedEntity extends BaseEntity does and I am okay with it, but just want to make sure I am doing this right. Thanks Edited October 4, 2019 by NotionCommotionTrying to create a model where Parent1 and Parent2 extend Grandparent, and Child1_1 and Child1_2 extend Parent1 as well as Child2_1 and Child2_2 extend Parent2. I set up my definitions: Grandparent: type: entity table: grandparent_table inheritanceType: JOINED discriminatorColumn: name: discriminator_column_grandparent type: string repositoryClass: GrandParent id: id: type: integer generator: strategy: AUTO fields: GrandParent_Item1: type: string GrandParent_Item2: type: string Parent1: type: entity table: parent_table1 extends: Grandparent inheritanceType: JOINED discriminatorColumn: name: discriminator_column_parent1 type: string id: id: associationKey: true fields: Parent1_Item1: type: string Parent1_Item2: type: string Parent2: type: entity table: parent_table2 extends: Grandparent inheritanceType: JOINED discriminatorColumn: name: discriminator_column_parent2 type: string id: id: associationKey: true fields: Parent2_Item1: type: string Parent2_Item2: type: string Child1_1: extends: Parent1 type: entity table: child1_1_table id: id: associationKey: true fields: Child1_1_Item1: type: string Child1_1_Item2: type: string Child1_2: extends: Parent1 type: entity table: child1_2_table id: id: associationKey: true fields: Child1_2_Item1: type: string Child1_2_Item2: type: string Child2_1: extends: Parent2 type: entity table: child2_1_table id: id: associationKey: true fields: Child2_1_Item1: type: string Child2_1_Item2: type: string Child2_2: extends: Parent2 type: entity table: child2_2_table id: id: associationKey: true fields: Child2_2_Item1: type: string Child2_2_Item2: type: string And then generate my entities: $ vendor/bin/doctrine orm:generate-entities -vvv src Processing entity "Child1_1" Processing entity "Child1_2" Processing entity "Child2_1" Processing entity "Child2_2" Processing entity "Grandparent" Processing entity "Parent1" Processing entity "Parent2" [OK] Entity classes generated to "/var/www/doctrine/src" Note that I needed to manually edit the Parent1 and 2 classes to extend Grandparent as well as the individual Child classes to extend their applicable Parent. Next, I create the schema: $ vendor/bin/doctrine orm:schema-tool:create --dump-sql The following SQL statements will be executed: CREATE TABLE child1_1_table (id INT NOT NULL, Child1_1_Item1 VARCHAR(255) NOT NULL, Child1_1_Item2 VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB; CREATE TABLE child1_2_table (id INT NOT NULL, Child1_2_Item1 VARCHAR(255) NOT NULL, Child1_2_Item2 VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB; CREATE TABLE child2_1_table (id INT NOT NULL, Child2_1_Item1 VARCHAR(255) NOT NULL, Child2_1_Item2 VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB; CREATE TABLE child2_2_table (id INT NOT NULL, Child2_2_Item1 VARCHAR(255) NOT NULL, Child2_2_Item2 VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB; CREATE TABLE grandparent_table (id INT AUTO_INCREMENT NOT NULL, GrandParent_Item1 VARCHAR(255) NOT NULL, GrandParent_Item2 VARCHAR(255) NOT NULL, discriminator_column_grandparent VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB; CREATE TABLE parent_table1 (id INT NOT NULL, Parent1_Item1 VARCHAR(255) NOT NULL, Parent1_Item2 VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB; CREATE TABLE parent_table2 (id INT NOT NULL, Parent2_Item1 VARCHAR(255) NOT NULL, Parent2_Item2 VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB; ALTER TABLE child1_1_table ADD CONSTRAINT FK_3445750EBF396750 FOREIGN KEY (id) REFERENCES grandparent_table (id) ON DELETE CASCADE; ALTER TABLE child1_2_table ADD CONSTRAINT FK_5AD6F93BF396750 FOREIGN KEY (id) REFERENCES grandparent_table (id) ON DELETE CASCADE; ALTER TABLE child2_1_table ADD CONSTRAINT FK_DC849CBBF396750 FOREIGN KEY (id) REFERENCES grandparent_table (id) ON DELETE CASCADE; ALTER TABLE child2_2_table ADD CONSTRAINT FK_3C205356BF396750 FOREIGN KEY (id) REFERENCES grandparent_table (id) ON DELETE CASCADE; ALTER TABLE parent_table1 ADD CONSTRAINT FK_5386E15BBF396750 FOREIGN KEY (id) REFERENCES grandparent_table (id) ON DELETE CASCADE; ALTER TABLE parent_table2 ADD CONSTRAINT FK_CA8FB0E1BF396750 FOREIGN KEY (id) REFERENCES grandparent_table (id) ON DELETE CASCADE; I see how Grandparent has discriminatorColumn discriminator_column_grandparent as expected. But why doesn't Parent1 and Parent2 have discriminatorColumn's discriminator_column_parent1 and discriminator_column_parent2? Note that I've also tried making Grandparent, Parent1, and Parent2 abstract but get the same results. I've also messed around with Mapped Superclasses, but I don't think they are applicable for my use (correct me if you think I am wrong). Thanks! I am doing something stupid, and just can't see it and hoping someone has better eyes than mine. I have two Doctrine entities which extend another class using single class inheritance, but when retrieving the collection of either of the two child classes, I get the collection of the parent (i.e. combination of both child classes). I've experimented with making the parent abstract and not including it in the discriminator map but no change. In hopes to identifying my mistake, I created a new Symfony project with just the relevant classes and show all steps below. Initial install by running the following: symfony new test composer update composer require doctrine/orm composer require migrations composer require maker --dev composer require security Using "php bin/console make:user", I created three users: AbstractUser, OwnerUser, VendorUser. I then edited all three entities and the owner and vendor repositories as follows: <?php namespace App\Entity; use App\Repository\AbstractUserRepository; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Security\Core\User\UserInterface; /** * @ORM\Entity(repositoryClass=AbstractUserRepository::class) * @ORM\InheritanceType("SINGLE_TABLE") * @ORM\DiscriminatorColumn(name="discr", type="string") * @ORM\DiscriminatorMap({"owner" = "OwnerUser", "vendor" = "VendorUser", "abstract" = "AbstractUser"}) */ class AbstractUser implements UserInterface { // No changes made }
<?php namespace App\Entity; use App\Repository\OwnerUserRepository; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity(repositoryClass=OwnerUserRepository::class) */ class OwnerUser extends AbstractUser { }
<?php namespace App\Entity; use App\Repository\VendorUserRepository; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity(repositoryClass=VendorUserRepository::class) */ class VendorUser extends AbstractUser { } No change to AbstractUserRepository. <?php namespace App\Repository; class OwnerUserRepository extends AbstractUserRepository { }
<?php namespace App\Repository; class VendorUserRepository extends AbstractUserRepository { } Then I migrated the DB. php bin/console doctrine:schema:drop --full-database --force rm migrations/* php bin/console make:migration php bin/console doctrine:migrations:migrate Next I created two OwnerUsers and one VendorUser using a command script I wrote shown at the end of this post. # php bin/console app:tester create OwnerUser roles=[] # php bin/console app:tester create OwnerUser roles=[] # php bin/console app:tester create VendorUser roles=[] Checked the PostSQL database. facdocs=> \d List of relations Schema | Name | Type | Owner --------+-----------------------------+----------+--------- public | abstract_user | table | facdocs public | abstract_user_id_seq | sequence | facdocs public | doctrine_migration_versions | table | facdocs (3 rows) facdocs=> select * from abstract_user; id | email | roles | password | discr ----+-------------+-------+----------------+-------- 1 | setEmail158 | [] | setPassword146 | owner 2 | setEmail87 | [] | setPassword101 | owner 3 | setEmail62 | [] | setPassword20 | vendor (3 rows) facdocs=>
Next, I retrieved the entities using Doctrine along with the beforementioned test script. [michael@devserver test]$ php bin/console app:tester read VendorUser Test Entity Manager ============ command: read entity: VendorUser class: \App\Entity\VendorUser properties: [] array(3) { [0]=> object(stdClass)#293 (5) { ["__CLASS__"]=> string(20) "App\Entity\OwnerUser" ["id:App\Entity\AbstractUser:private"]=> int(1) ["email:App\Entity\AbstractUser:private"]=> string(11) "setEmail158" ["roles:App\Entity\AbstractUser:private"]=> string(8) "Array(0)" ["password:App\Entity\AbstractUser:private"]=> string(14) "setPassword146" } [1]=> object(stdClass)#294 (5) { ["__CLASS__"]=> string(20) "App\Entity\OwnerUser" ["id:App\Entity\AbstractUser:private"]=> int(2) ["email:App\Entity\AbstractUser:private"]=> string(10) "setEmail87" ["roles:App\Entity\AbstractUser:private"]=> string(8) "Array(0)" ["password:App\Entity\AbstractUser:private"]=> string(14) "setPassword101" } [2]=> object(stdClass)#358 (5) { ["__CLASS__"]=> string(21) "App\Entity\VendorUser" ["id:App\Entity\AbstractUser:private"]=> int(3) ["email:App\Entity\AbstractUser:private"]=> string(10) "setEmail62" ["roles:App\Entity\AbstractUser:private"]=> string(8) "Array(0)" ["password:App\Entity\AbstractUser:private"]=> string(13) "setPassword20" } } [michael@devserver test]$ [michael@devserver test]$ php bin/console app:tester read OwnerUser Test Entity Manager ============ command: read entity: OwnerUser class: \App\Entity\OwnerUser properties: [] array(3) { [0]=> object(stdClass)#293 (5) { ["__CLASS__"]=> string(20) "App\Entity\OwnerUser" ["id:App\Entity\AbstractUser:private"]=> int(1) ["email:App\Entity\AbstractUser:private"]=> string(11) "setEmail158" ["roles:App\Entity\AbstractUser:private"]=> string(8) "Array(0)" ["password:App\Entity\AbstractUser:private"]=> string(14) "setPassword146" } [1]=> object(stdClass)#294 (5) { ["__CLASS__"]=> string(20) "App\Entity\OwnerUser" ["id:App\Entity\AbstractUser:private"]=> int(2) ["email:App\Entity\AbstractUser:private"]=> string(10) "setEmail87" ["roles:App\Entity\AbstractUser:private"]=> string(8) "Array(0)" ["password:App\Entity\AbstractUser:private"]=> string(14) "setPassword101" } [2]=> object(stdClass)#358 (5) { ["__CLASS__"]=> string(21) "App\Entity\VendorUser" ["id:App\Entity\AbstractUser:private"]=> int(3) ["email:App\Entity\AbstractUser:private"]=> string(10) "setEmail62" ["roles:App\Entity\AbstractUser:private"]=> string(8) "Array(0)" ["password:App\Entity\AbstractUser:private"]=> string(13) "setPassword20" } } [michael@devserver test]$
As seen, when requesting a collection of either OwnerUsers or VendorUsers, I am retrieving the combination of both collections. I am sure it is totally user (i.e. me) error, but just don't see it. Are you able to see my stupid mistake? Thanks
<?php namespace App\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; use Doctrine\ORM\EntityManagerInterface; use Doctrine\Common\Util\Debug; class Tester extends Command { // the name of the command (the part after "bin/console") protected static $defaultName = 'app:tester'; private $entityManager; public function __construct(EntityManagerInterface $entityManager) { $this->entityManager = $entityManager; parent::__construct(); } protected function configure() { $this ->setDescription('Doctrine Object Tester. --help') ->setHelp('This command allows you to query a single entity...') ->addArgument('cmd', InputArgument::REQUIRED, 'The command name [create, read].') ->addArgument('entity', InputArgument::REQUIRED, 'The name of the entity.') ->addArgument('properties', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'properies (foo=foo bla=[]') ; } private function getProperties($input) { $properties=[]; foreach($input as $property) { $property=explode('=', $property); $name = trim($property[0]); $value = trim($property[1]); if($value === '[]') { $value = []; } elseif($value === 'null') { $value = null; } elseif(substr($value, 0, 1) === '/') { $value = explode('/', substr($value, 1)); $class = ucfirst(substr($value[0], 0, -1)); $class = '\App\Entity\\'.$class; if(count($value)===1) { $value = $this->entityManager->getRepository($class)->findAll(); } else { $value = $this->entityManager->getRepository($class)->find($value[1]); } } $properties[$name] = $value; } return $properties; } protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln([ 'Test Entity Manager', '============', '', ]); // retrieve the argument value using getArgument() $cmd = $input->getArgument('cmd'); $output->writeln('command: '.$cmd); $entity = $input->getArgument('entity'); $output->writeln('entity: '.$entity); $class = '\App\Entity\\'.$entity; $output->writeln('class: '.$class); $properties = $this->getProperties($input->getArgument('properties')); $output->writeln('properties: '.json_encode($properties)); switch($cmd) { case 'create': $entity = new $class; foreach(get_class_methods($entity) as $method) { if(substr($method, 0, 3)==='set') { $m = lcfirst(substr($method, 3)); $entity->$method(array_key_exists($m, $properties)?$properties[$m]:$method.rand(0,200)); } } $this->entityManager->persist($entity); $this->entityManager->flush(); $output->writeln('entity created'); break; case 'read': Debug::dump($this->entityManager->getRepository($class)->findAll()); break; default: $output->writeln('INVALID COMMAND: '.$cmd.'. Only create and read are supported.'); } return Command::SUCCESS; } }
For solely to reduce duplicated code and when injection isn't applicable, should one use inheritance or traits? <?php abstract class BaseClass { private $id, $name; public function __construct(int $id, string $name) { $this->id=$id; $this->name=$name; } public function getId():int { return $this->id; } public function getName():string { return $this->name; } } <?php class A extends BaseClass{} class B extends BaseClass{} class C extends BaseClass { private $foo; public function __construct(int $id, string $name, Foo $foo) { parent::__construct($id, $name); $this->foo=$foo; } public function getFoo():Foo { return $this->foo; } } <?php trait MyTrait { private $id, $name; public function __construct(int $id, string $name) { $this->id=$id; $this->name=$name; } public function getId():int { return $this->id; } public function getName():string { return $this->name; } } <?php class A { use MyTrait; } class B { use MyTrait; } class C { use MyTrait; private $foo; public function __construct(int $id, string $name, Foo $foo) { $this->id=$id; $this->name=$name; $this->foo=$foo; } public function getFoo():Foo { return $this->foo; } } Edited January 2, 2020 by NotionCommotion |