Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 20 days ago.
Improve this question
I consider a slug property not being a part of my domain model. It's just a nice convenience for the view layer.
But still: I don't want to calculate it each time I retrieve it to the view.
So I decide to only define a private property with a getter on entities which eventually will be retrieved via an URL - through a Sluggable contract. The constructor doesn't touch it all. I delegate the slug's creation to an Infrastructure Service. The ORM deals with entities using reflections, so my solution kind of looks like how Doctrine would touch those.
I register the event lifecycle listener as a Symfony service.
<?php
namespace App\Common\Domain\Model;
interface Sluggable
{
public function slug();
}
<?php
namespace IMS\Registry\Domain\Model\Manufacturer;
use App\Common\Domain\Model\Sluggable;
class Manufacturer implements Sluggable
{
private ManufacturerId $id;
private ManufacturerName $name;
private string $slug;
public function __construct(ManufacturerId $anId, ManufacturerName $aName)
{
$this->id = $anId;
$this->name = $aName;
}
public function name(): ManufacturerName
{
return $this->name;
}
public function slug(): string
{
return $this->slug;
}
// other methods
}
<?php
namespace App\Common\Infrastructure\Domain\Model;
use App\Common\Domain\Model\Sluggable;
use Cocur\Slugify\SlugifyInterface;
use Doctrine\Persistence\Event\LifecycleEventArgs;
class NameSlugger
{
public function __construct(private readonly SlugifyInterface $slugger)
{
}
public function prePersist(LifecycleEventArgs $args): void
{
$this->preSlugged($args);
}
public function preUpdate(LifecycleEventArgs $args): void
{
$this->preSlugged($args);
}
private function preSlugged(LifecycleEventArgs $args): void
{
$entity = $args->getObject();
if (!$entity instanceof Sluggable) {
return;
}
$reflection = $args->getObjectManager()->getClassMetadata($entity::class)->getReflectionClass();
if (!$reflection->hasProperty('slug')) {
throw new \ReflectionException();
}
$reflectionProperty = $reflection->getProperty('slug');
if (!$reflectionProperty->hasType()) {
throw new \ReflectionException();
}
$reflectionPropertyType = $reflectionProperty->getType()->getName();
if ('string' !== $reflectionPropertyType) {
throw new \ReflectionException();
}
$reflectionProperty->setValue(
$entity,
// ManufacturerName VO has a __toString method
$this->slugger->slugify($entity->name())
);
}
}
My question is: is my reasoning valid in your opinion? From a DDD perspective. What different approach would you incorporate so it fits the DDD concept of a project?
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 20 days ago.
Improve this question
During some workaround with some architecture I faced a question and I am wondering if this implementation follows best practice or not.
Here we have a base abstract class:
abstract class A {
protected mixed $object;
public function __construct() {
$this->loadObject()
->fuc1();
}
abstract protected function loadObject(): self;
abstract public function fuc1(): bool;
abstract public function fuc3(): iterable;
}
In this case, I want to implement Class B and C. if I create each class separately everything is fine but as far as these 2 classes have the same functions I decided to create a base class for them (BC) so codes are now like this:
class BC extends A {
protected string x;
protected string y;
protected function loadObject(): self {
throw new \Exception('Child must implement loeadObject');
}
public function fuc1(): bool {
//Some Codes
}
public function fuc3(): iterable {
//Some Codes
}
}
And Class B and Class C are like this:
class B extends BC {
protected function loadObject(): self {
$this->object = new SomeObject();
return $this;
}
}
class C extends BC {
protected function loadObject(): self {
$this->object = new SomeObject2();
return $this;
}
}
We also can not move loadObject function to class BC cuz maybe class D wants to inherit directly from class A.
We can also rely on interfaces but I was wondering if some one forget to make class B/C implement an Interface then we will have problem in class A.
So is it a good practice that we throw exceptions in the class BC and force other developers to don't forget to overwrite the loadObject function?
This is not a good practice, if you doesn't need to implement the loadObject method in the BC class, you should keep it abstract.
abstract class BC extends A {
protected string $x;
protected string $y;
public function fuc1(): bool {
}
public function fuc3(): iterable {
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
So, I have this class that gets used over and over again throughout my app. This is just an example, not what's actually needed to be done:
File A:
class Names {
public function first() {
echo 'Bob';
}
}
That file is autoloaded into my app using spl_autoload_register and used all throughout in other pages/classes:
File B:
class LastNames {
public function __construct() {
$this->first = new Names();
}
public function last() {
echo $this->first->first().' Smith';
}
}
$names = new LastNames();
echo $names->last(); // Bob Smith
I have many files that instantiate the class Names inside the constructor.
Does this cause much of a hit on performance?
Should I be using static function instead of public function?
Is there a better way to reuse the functions inside Names over and over again inside different classes?
You have several options, using static function is one of them :
class LastNames {
public static function foo(){
// do stuff
}
}
Or you can use a singleton :
class LastNames {
private static $instance = null;
private function __construct(){
// do stuff
}
public function foo(){
// do stuff
}
public static function getInstance(){
if ( !self::$instance ){
self::$instance = new LastNames();
}
return self::$instance;
}
}
And then you can call it with :
$lastnames = LastNames::getInstance();
$lastnames->foo();
I have 2 tables in DB (question and answer). One question has many answers.
I get some Answers and depends on question.type I prepare results array.
In app without any framework I have Factory class which return specific object (SingleChoiceQuestion, OpenQuestion, MultipleChoiceQuestion) depends question.type from DB. All Questions extends abstract class Question which has declared abstract method getResults. All types have their own business logic to prepare results.
So in this situation when I have created object by factory I'm using method getResults and everything works well.
I would like to create it in Symfony and I read documentation. In my opinion I should create services for all my Question types.
I have created AggregatedResultsManager with method generate which returns results array. Depends on question.type it calls getResults method from specific service.
I would like to add, that I can't change DB structure.
My questions:
Am I creating and using services right? If I do it wrong, please help me understanding it and show me the right way.
I will have several services like AggregatedResultsManager and about 18 Question types.
In each service I will need to create switch with 18 choices, how to prevent that?
switch ($this->question->getType()) {
case Question::SINGLE:
$results = $this->container->get('app.single_choice_question')->getResults($answers);
break;
// other types
}
I have some idea to create array with types and service names:
$services = [
Question::SINGLE => 'app.single_choice_question',
Question::MULTIPLE => 'app.multiple_choice_question',
Question::OPEN => 'app.open_question',
];
and then use it in each service like that:
$results = $this->container->get($services[$this->question->getType()])->getResults($answers);
I think it's the best way to not use switch with 18 choices. But I will need to hardcode service names in array.
My code:
services.yml
app.question:
class: AppBundle\Questions\Question
abstract: true
arguments: ['#doctrine.orm.entity_manager']
app.single_choice_question:
class: AppBundle\Questions\SingleChoice
parent: app.question
app.agreggated_results_manager:
class: AppBundle\Results\AggregatedResultsManager
arguments: ['#doctrine.orm.entity_manager', '#service_container']
abstract Question
abstract class Question
{
/**
* #var EntityManager
*/
protected $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
abstract public function getResults($answers);
}
SingleChoice
class SingleChoice extends Question
{
public function getResults($answers)
{
$results = [];
// business logic
return $results;
}
}
Results
class AggregatedResultsManager
{
/**
* #var EntityManager
*/
private $em;
/**
* #var Question
*/
private $question;
/**
* #var ContainerInterface
*/
private $container;
public function __construct(EntityManager $em, ContainerInterface $container)
{
$this->em = $em;
$this->container = $container;
}
public function generate()
{
if (!$this->question) {
throw new \LogicException('Question is not set');
}
$answers = $this->em
->getRepository('AppBundle:Answer')
->findBy(['question' => $this->question]);
$results = [];
if (empty($answers)) {
return $results;
}
switch ($this->question->getType()) {
case Question::SINGLE:
$results = $this->container->get('app.single_choice_question')->getResults($answers);
break;
// other types
}
return $results;
}
public function setQuestion(Question $question)
{
$this->question = $question;
}
}
Controller
public function questionIdsAction(Question $question)
{
$resultsManager = $this->get('app.agreggated_results_manager');
$resultsManager->setQuestion($question);
$results = $resultsManager->generate();
return new JsonResponse($results);
}
I think you are saying that you have 18 QuestionTypes all extending an AbstractQuestion which needs the entity manager to do it's work? Instead of making 18 services and then using the container I would suggest making a question factory:
class QuestionFactory
public function __construct($entityManager)
$this->entityManager = $entityManager;
public function create($questionType)
switch($questionType) {
case Question::SINGLE: return new SingleQuestion($this->entityManager);
You would then inject the factory into the results manager.
This approach avoids the need to create a bunch of services and of needing to pass around the container. You still have a switch statement but that is okay.
The only problems that might arise is if some QuestionTypes need additional dependencies. In which case you might be back to using services.
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
I'm not 100% sure, but is this a correct way of defining a property:
class Product {
public $id;
public $name;
}
class LineItem {
public Product $product; //<------ this property
public $qty;
}
Or, is it best to leave it as $product with no type identifier?
Product should be defined this way:
public $product;
and create it as:
$product = new Product();
As #Jon already suggested in the comments. PHP doesn't indeed not support type identifiers. The best approach for this (or at least as I'd do it). Would be to just define $product and then create the constructor which instantiates a new Product object in that class variable. Or just pass in the object when you need it with a getter / setter method in the LineItem class.
edit: It does differ from the situation (you didn't gave a situation, so I tried to guess it and give an example).
Constructor:
public function __construct($product = new Product()) {
$this->product = $product;
}
Getter / setter work like same way:
public function getProduct() {
return $this->product;
}
//In arguments you're able to make sure it is of a class Product if I'm correct.
public function setProduct(Product $product) {
$this->product = $product;
//You might do a return of $this, dependent on your logic of course.
return $this;
}
edit: Added the below code for future users who might benefit of it.
In regular PHP file you can do for example the following:
$product = new Product();
//Set some price, description or something in your product...
//Pass product with constructor.
$lineItem = new LineItem($product);
//Get the product of the lineItem...
$product = $lineItem->getProduct();
//Set a product if constructor hasn't been used...
$lineItem->setProduct($product);
As Jon said, you can't have type identifiers in PHP.
You could do something like this and use the instanceof operator:
class LineItem {
protected $_product;
//...
public function setProduct($p) {
if($p instanceof Product) {
$this->_product = $p;
} else {
throw new Exception("...");
}
}
}
You can use Type Hinting on __construct():
class Product {
public $id;
public $name;
}
class LineItem {
public function __construct(Product $product) {
$this->product = $product;
}
public $qty;
}
you can set it in a constructor
class Product {
public $id;
public $name;
}
class LineItem {
public $product;
public $qty;
function __construct(){
$this->product = new Product();
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
How to create public php class object inside a another class?.
I have a class called
page.php
and also
Main.php
and
Content.php
I want to call Main.php and Content.php class inside the page.php class. What is the correct way to do this.
I tried this, but not working :( . Please help.
<?php
class Page
{
public $main;
public $content;
function __construct()
{
$main=new Main_Model();
$content=new Content_Model();
}
public function Menu()
{
$load_menu=$content->Load_Menu();
...
...
}
}
?>
I can only assume you are new to OOP.
But the issue resides within you needing to access the variables from the global scope.
I am also making the assumption that you are using a framework that provides auto-loading and that these classes are actually accessible.
class Page
{
private $main;
private $content;
function __construct()
{
$this->main=new Main_Model();
$This->content=new Content_Model();
}
public function Menu()
{
$load_menu=$this->content->Load_Menu();
...
...
}
}
That should solve everything for you. Also you should define your variables as private unless you plan on exposing them for use in other places as a public interface. And even then there is discussion on using methods to access private variables.
This should fix you're issue and I've changed/fixed a few other bits like public/private variables etc. As others have said you're missing the $this-> in your construct()
<?php
class Main_Model {
public function Load_Menu() {
return "This is the menu function";
}
}
class Content_Model {
public function Load_Content() {
return "This is the main content function";
}
}
class Page {
private $mainmenu;
private $content;
function __construct() {
$this->mainmenu = new Main_Model();
$this->content = new Content_Model();
}
function Menu() {
return $this->mainmenu->Load_Menu();
}
function Content() {
return $this->content->Load_Content();
}
}
$page = new Page();
echo $page->Menu();
echo "<br />";
echo $page->Content();
?>