PHP - Is Inheritance Required When Injecting Entities?
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 NotionCommotionSimilar TutorialsI 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; } }
Hello. If you notice at this link: http://atomos.tumblr.com/post/1583437551 At the bottom there is a link labeled, "Show more notes.". I am trying to devise a way to make this automated using PHP. Heres the link, or javascript for "Show more users"... Code: [Select] <a class="more_notes_link" href="#" onclick="this.style.display='none';document.getElementById('notes_loading_1598703430').style.display = 'inline';if(window.ActiveXObject)var tumblrReq=new ActiveXObject('Microsoft.XMLHTTP');else if(window.XMLHttpRequest)var tumblrReq=new XMLHttpRequest();else return false;tumblrReq.onreadystatechange=function(){if(tumblrReq.readyState==4){var notes_html=tumblrReq.responseText.split('<!-- START '+'NOTES -->')[1].split('<!-- END '+'NOTES -->')[0]; if(window.tumblrNotesLoaded)if(tumblrNotesLoaded(notes_html)==false)return;var more_notes_link=document.getElementById('more_notes_1598703430');var notes=more_notes_link.parentNode;notes.removeChild(more_notes_link);notes.innerHTML+=notes_html;if(window.tumblrNotesInserted)tumblrNotesInserted(notes_html);}};tumblrReq.open('GET','/notes/1598703430/WpyI5vO1W?from_c=1289946513',true);tumblrReq.send();return false;">Show more notes</a> I am currently using a single entity called id for a key. I'm now wanting to use two entities as a key - id and size. I've tried using these two peices of code, but failed: foreach ($_SESSION['cart']['content'] as $key=>$product,$size) { if ($product['id'] == $id && $product['size'] == $size) { $item_found = $key; break; } } // do thing ... and foreach ($_SESSION['cart']['content'] as $key=>$product && $key=>$size) { if ($product['id'] == $id && $product['size'] == $size) { $item_found = $key; break; } } // do thing Am I going the right way about it? Can two entities even be used as a key? For user content validation, I built my own custom class which is injected with an array which specified how the data will be validated and how to respond to the user if invalid data. It has a method to validate server side as well as a method to produce the jQuery validation plugin's client configuration JSON. The configuration array is defined by one or more JSON file located on the server. I am trying to determine where I should define which files should be used to validate data for a given entity. The easiest location is to store them directly in the entity in question, however, I have heard people voice that the entity shouldn't be responsible for validation. It isn't directly responsible how I am doing this, but would like to know whether there are any specific reasons why doing so might have undesirable consequences. Alternately, I can have them defined in the repository, however, it requires more logic. public function update(int $idPublic, array $params): Entity { $entity=$this->read($idPublic); //Option 1 $validationFiles=$entity->getValidatorFiles(); //Option 2 $repo=$this->em->getRepository(get_class($entity)); $validationFiles=$repo->getValidatorFiles(); $rules=$this->filesToArr($files); $validator=$this->validator($rules); //Closure will create new object $validator->validateNameValue($params); //Update entity and save return $entity; }
I'm starting in Doctrine 2.4 and I'm developing a system where I separate the core files and application files, as follows:
/root |-- /Src |-- /App |-- /Model |-- ** (Application Entities) ** |-- /Core |-- /Model |-- ** (Core Entities) **In the Doctrine documentation shows the following form to set 1 directory for Esntitys: $config = Setup::createAnnotationMetadataConfiguration(array(__DIR__. "/src"), $isDevMode);But when I have to configure more than one directory that will contain the Entitys of my application, how to proceed? Thanks in advance! the above/attached image shows a table outputted using a 'for loop', it has the action column that should either edit or delete entity... I need help to be able to edit or delete each entity by clicking the action link... find attached image... I'm tearing my hair out trying to work with "simple" XML for the first time. I'm building a small CMS for a Flash based site and the content is held in an XML file. My problem is that many of the copy fields are XML CDATA fields. On the one hand, with: $xml = simplexml_load_file($file, 'SimpleXMLElement', LIBXML_NOCDATA); I can pull the data out of that node and the CDATA tags are stripped. My issues come with trying to save the data with: file_put_contents($file, $xml->asXML()); Problems a a) tags are interpreted with their HTML entity equivalents. I don't want this to happen as it's a CDATA field being read by Flash. I gather this is coming from the asXML method because even if I do an html_entity_decode on the $_POST data it's still being converted. b) because of the above, there's no way to add the CDATA tags because they also have their charachters converted. SimpleXML so far has been anything but simple for me Has anyone ever run into this? Is there a way to save the file back in a way that will just keep my data exactly as is and also allow me to add the CDATA tags back in? So I encode and decode html entities of my thread body variable in my script but now that I am working on the quote function I realize even after decode it prints the html entities instead of the regular character is there anyway to change this because if not it is going to print my font tag as characters instead of the font tag actually doing its job. Thanks! P.S. if this double posts I don't know what's going on...it happened last time but I didn't double post. It may be that I am using a mobile phone. I am using PHP and Doctrine to store and manipulate Highchart objects such as the following: { "chart": { "type": "bar" }, "xAxis": { "categories": ["Africa", "America", "Asia", "Europe", "Oceania"] } }, "series": [{ "name": "Year 1800", "data": [107, 31, 635, 203, 2] }, { "name": "Year 1900", "data": [133, 156, 947, 408, 6] }, { "name": "Year 2000", "data": [814, 841, 3714, 727, 31] }, { "name": "Year 2016", "data": [1216, 1001, 4436, 738, 40] }] } My DB schema is: BarChart -id (PK) -name (string) BarChartSerie -id (PK) -barChartId (FK) -name (string) -position (int) BarChartCategory -id (PK) -barChartId (FK) -name (string) -position (int) BarChartNode -barChartSerie (FK) -barChartCategory (FK) -value (decimal) The chart entity has a collection of serie and category, and the serie and category entities both contain a reference to the shared node. I wish to clone the chart entity and thus use __clone() to set the chart, category, and serie entity's' PK to NULL, however, am running into issues as the node entity still has the original entitiy's PKs. I think maybe I should be creating the entities differently. Any suggestions how these objects should be created? Maybe instead have my series contain a collection of nodes and have each of these nodes contain a reference to the applicable category? Thanks 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. Hey 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! 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 NotionCommotionHello, 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? 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 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! 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"]); ?> Trying 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! 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 |