Ankündigung

Einklappen
Keine Ankündigung bisher.

Daten gezielt aus Repository laden

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Daten gezielt aus Repository laden

    Hallo leute,

    mittlerweile habe ich ein wenig weiter mit Clean Code Architektur experementiert und bin auf folgendes Gestoßen:

    UseCase:
    Zeige listen von objekten an die weitere objekte beinhalten, filtere die liste nach bestimmten Kriterien und Sortiere die ausgabe nach bestimmten feldern.

    Mögliche Lösung 1:
    Repository klasse mit allen notwendigen methoden ausstatten.

    PHP-Code:
    $repository->findByNameAndLoadWithFooAndOrderByBar($name,$order); 
    Problem: repository wird viel zu viele methoden haben die teilweise immer das gleiche machen nur ein wenig anders.

    Mögliche Lösung 2:
    PHP-Code:
    $objects $repository->findByName($name); 
    und das sortieren wird PHP Seitig geregelt und weitere objekte werden mit ProxyPattern nachgeladen

    Problem: größere listen die auch noch große objekte nachladen kann auch performance fressen

    Mögliche Lösung 3:

    ein mix aus 1 und 2, alles normal laden und an den stellen, wo man performance probleme sieht, eine extra methode implementieren die das Problem wegschaft.

    Irgendwie gefällt mir keiner der lösungen. Was ich mir gut vorstellen könnte, wäre zb

    PHP-Code:
    $repository->findByCriteria(RepositoryCreteria $criteria); 
    glaub es hieß filter pattern oder ähnlich, wo bei den Creterias ein And und Or drangehängt wird.. das Problem ist, dass in den beispielen, meist bereits eine komplette liste gefiltert wird, ich möchte aber schon die fertige liste(inklusive unterklassen) kriegen.

    Vielleicht kennt jemand von euch, einen sauberen weg wie ich gezielt daten aus einem Repository laden könnte inclusive weitere objekte bei bedarf, dabei soll dieser weg auf alle möglichen spechermedien übertragbar sein, sei es DB / Datei oder PUT Requests auf einer API.

    Hoffe jemand kann mir da weiter helfen

    LG BlackScorp
    apt-get install npm -> npm install -g bower -> bower install <package> YOLO [URL]https://www.paypal.me/BlackScorp[/URL] | Mein Youtube PHP Kanal: [url]https://www.youtube.com/c/VitalijMik[/url]

  • #2
    Dein letzter Ansatz dürfte der sinnvollste sein.
    Ich habe sowas Ähnliches mal mittels QueryObject umgesetzt, um von der Datenschicht komplett unabhängig zu sein.
    Dabei wurden dann Bedingungen beliebig verschachtelt definiert (um z.B. auch komplexe SQL-Queries zu realisieren) und dann erst im jeweiligen Mapper auf die nötige Syntax (z.B. SQL) umgesetzt.
    Mit spezialisierten Methoden habe ich auch schon gearbeitet, wie du aber bereits festgestellt hast ist das schrecklich, insbesondere wenn man bei sprechenden Namen bleiben will.
    VokeIT GmbH & Co. KG - VokeIT-oss @ github

    Kommentar


    • #3
      Hi,
      ich habe mir darüber schon Gedanken machen müssen.
      Meine Umsetzung ist bestimmt nicht perfekt und es ist viel Code für einen Post, aber es vermittelt einen besseren Gesamteindruck meines Models.

      Die unwichtigeren Dinge habe ich raus gelassen.

      Vielleicht habt ihr ja sogar noch ein paar Tipps für mich.
      Quellcode ist durch die Kommentare hoffentlich selbsterklärend. Sonst Schande über mich.

      Service (Repository nennt ihr es immer)
      PHP-Code:
      <?php

      /**
       * Service class for profiles.
       *
       * @author Carpenter
       */
      class ProfileService extends AbstractService {

          
      /**
           * @var IProfileDao
           */
          
      private $profileDao;

          
      /**
           * Constructor.
           *
           * @author Carpenter
           * @param IProfileDao $profileDao
           * @return void
           */
          
      public function __construct(IProfileDao $profileDao) {
              
      $this->profileDao $profileDao;
          }

          
      /******************************************************************************
           * START Profile
          ******************************************************************************/

          /**
           * Returns a new Profile.
           *
           * @author Carpenter
           * @return Profile
           */
          
      public function createProfile() {
              
      $profile = new Profile();
              return 
      $profile;
          }
          
          
      /**
           * Returns the profile with the given id.
           *
           * @author Carpenter
           * @param int $id
           * @return Profile
           */
          
      public function fetchProfileById($id) {
              return 
      $this->profileDao->findById($id);
          }

          
      /**
           * Returns the profiles that apply to the filter as paged result.
           *
           * @author Carpenter
           * @param ProfileFilter $filter
           * @return PagedResult
           */
          
      public function fetchProfileByFilter(ProfileFilter $filter) {
              return 
      $this->profileDao->findByFilter($filter);
          }

          
      /**
           * Returns the profiles that apply to the example profile entity.
           *
           * @author Carpenter
           * @param Profile $filter
           * @return array of Profile
           */
          
      public function fetchProfileByExample(Profile $profile) {
              return 
      $this->profileDao->findByExample($profile);
          }

          
      /**
           * Saves the given profile.
           *
           * @author Carpenter
           * @param Profile $profile
           */
          
      public function saveProfile(Profile $profile) {
              
      $this->profileDao->save($profile);
          }

          
      /**
           * Deletes the given profile.
           *
           * @author Carpenter
           * @param Profile $profile
           */
          
      public function deleteProfile(Profile $profile) {
              
      $this->profileDao->delete($profile);
          }

          
      /******************************************************************************
           * END Profile
          ******************************************************************************/
      }
      Dazu die Entity:
      PHP-Code:
      <?php

      /**
       * Profile entity.
       *
       * @author Carpenter
       * @Entity
       * @Table(name="profile")
       */
      class Profile extends AbstractEntity {

          
      /**
           * @var int
           * @Column(type="bigint", name="id", nullable=FALSE, length="20")
           */
          
      protected $id;

          
      /**
           * @var string
           * @Column(type="text", name="name", nullable=FALSE, length="255")
           */
          
      protected $name;

          
      /**
           * @var string
           * @Column(type="string", name="password", nullable=FALSE, length="255")
           */
          
      protected $password;
          
          
      /**
           * Returns the $id value.
           *
           * @author Carpenter
           * @return int
           */
          
      public function getId() {
              return 
      $this->id;
          }

          
      /**
           * Sets the $id value.
           *
           * @author Carpenter
           * @param int $id
           * @return void
           */
          
      public function setId($id) {
              
      $this->id $id;
          }

          
      /**
           * Returns the $name value.
           *
           * @author Carpenter
           * @return string
           */
          
      public function getName() {
              return 
      $this->name;
          }

          
      /**
           * Sets the $name value.
           *
           * @author Carpenter
           * @param string $name
           * @return void
           */
          
      public function setName($name) {
              
      $this->name $name;
          }

          
      /**
           * Returns the $password value.
           *
           * @author Carpenter
           * @return string
           */
          
      public function getPassword() {
              return 
      $this->password;
          }

          
      /**
           * Sets the $password value.
           *
           * @author Carpenter
           * @param string $password
           * @return void
           */
          
      public function setPassword($password) {
              
      $this->password $password;
          }

      }
      Dazu meine PDO Klasse:
      PHP-Code:
      <?php

      /** 
       * PDO dao for the Profile entity.
       * 
       * @author Carpenter
       */
      class PDOProfileDao extends AbstractPDODao implements IProfileDao {

          private static function 
      log() {
              return 
      Log::getLogger(__FILE____CLASS__);
          }

          
      /**
           * Constructor.
           *
           * @author Carpenter
           */
          
      public function __construct() {}

          
      /**
           * (non-PHPdoc)
           * @see IDao::save()
           * @author Carpenter
           */
          
      public function save($entity) {
              try {
                  if (
      $entity instanceof Profile) {
                      
      $sql 'INSERT INTO `profile`
                                  (
                                      `id`,
                                      `name`,
                                      `password`
                                  )
                              VALUES 
                                  (
                                      :id,
                                      :name,
                                      :password
                                  ) 
                              ON DUPLICATE KEY UPDATE
                                  `id` = :id,
                                  `name` = :name,
                                  `password` = :password
                              '
      ;
                      
                      
      $stmt $this->getDatabase()->prepareQuery($sql);
                      
      $stmt->bindValue(':id'$entity->getId());
                      
      $stmt->bindValue(':name'$entity->getName());
                      
      $stmt->bindValue(':password'$entity->getPassword());
                      
      $stmt->execute();
                      
                      if (
      $entity->getId() <= 0) {
                          
      $entity->setId($this->getDatabase()->getLastInsertId());
                      }
                  }
              } catch (
      Exception $e) {
                  
      self::log()->error('Error while saving Profile');
                  
      self::log()->errorEx($e);
                  throw new 
      DatabaseException('Error while saving Profile!');
              }
          }

          
      /**
           * (non-PHPdoc)
           * @see AbstractPDODao::findByCondition()
           * @author Carpenter
           */
          
      protected function findByCondition($condition$conditionValues) {
              try {
                  
      $sql 'SELECT     
                                  `p`.`id` AS `id`,
                                  `p`.`name` AS `name`,
                                  `p`.`password` AS `password`
                          FROM
                              `profile` AS `p` 
                          ' 
      $condition;
                  
                  
      $stmt $this->getDatabase()->prepareQuery($sql);
                  foreach (
      $conditionValues as $paramName => $paramValue) {
                      
      $stmt->bindValue($paramName$paramValue);
                  }
                  
      $stmt->setFetchMode(PDO::FETCH_CLASS PDO::FETCH_PROPS_LATE'Profile');
                  
      $stmt->execute();
                  return 
      $stmt->fetchAll();
              } catch (
      Exception $e) {
                  
      self::log()->error(sprintf('Error while fetching Profile by condition %s:'$condition));
                  
      self::log()->errorEx($e);
                  throw new 
      DatabaseException(sprintf('Error while fetching Profile by condition %s!'$condition));
              }
          }
          
          
      /**
           *
           * Counts Profile by condition.
           *
           * @author Carpenter
           * @param stringe $condition
           * @param array $conditionValues
           * @throws DatabaseException
           * @return int
           */
          
      protected function countByCondition($condition$conditionValues) {
              try {
                  
      $sql 'SELECT COUNT(*)
                              FROM
                          `profile` AS `p`
                              ' 
      $condition;
          
                  
      $stmt $this->getDatabase()->prepareQuery($sql);
                  foreach (
      $conditionValues as $paramName => $paramValue) {
                      
      $stmt->bindValue($paramName$paramValue);
                  }
                  
      $stmt->execute();
                  return 
      $stmt->fetchColumn(0);
              } catch (
      Exception $e) {
                  
      self::log()->error(sprintf('Error while counting Profile by condition %s:'$condition));
                  
      self::log()->errorEx($e);
                  throw new 
      DatabaseException(sprintf('Error while counting Profile by condition %s!'$condition));
              }
          }
          
          
      /**
           * (non-PHPdoc)
           * @see IProfileDao::findByFilter()
           */
          
      public function findByFilter(ProfileFilter $filter) {
              
      $condition = array();
              
      $conditionValues = array();
              
              
      // create conditions by example
              
      $this->buildExampleConditionAndValues($filter->getExampleObj(), $condition$conditionValues);
              
              
      // just include ids set in filter.
              
      if (is_array($filter->getProfileIds()) && count($filter->getProfileIds()) > 0) {
                  
      $condition[] = 'AND `p`.`id` IN (' $this->getListParameterString($filter->getProfileIds(), 'includeProfileIds') . ') ';
                  
      $this->addListParameters($conditionValues$filter->getProfileIds(), 'includeProfileIds');
              }
              
          
              
      // Create the order sql
              
      $orderDirSql FilterBase::ORDER_DIRECTION_ASC;
              if (
      $filter->getOrderDirection() === FilterBase::ORDER_DIRECTION_DESC) {
                  
      $orderDirSql FilterBase::ORDER_DIRECTION_DESC;
              }
          
              
      $orderSql '';
              switch (
      $filter->getOrderColumn()) {
                  case 
      ProfileFilter::ORDER_COLUMN_NAME:
                      
      $orderSql 'ORDER BY `p`.`name` ' $orderDirSql;
                      break;
              }
              
              
      // Create limit string
              
      if ($filter->getLimitStart() !== null && $filter->getLimitCount() !== null) {
                  
      $limitString ' LIMIT ' $filter->getLimitStart() . ',' $filter->getLimitCount();
              }
          
              
      // Create the condition statement
              
      $conditionString implode("\n"$condition);
              
              
      // count results
              
      $count $this->countByCondition($conditionString$conditionValues);
              
              
      // Concat the search condition
              
      $conditionString.= $orderSql $limitString;

              
      // Do the search and return the result
              
      $data $this->findByCondition($conditionString$conditionValues);

              
      // paged result is just a container
              
      return new PagedResult($data$count$filter->getLimitCount());
          }

          
      /**
           * (non-PHPdoc)
           * @see IDao::findById()
           * @author Carpenter
           * @return Profile
           */
          
      public function findById($id) {
              
      $conditionStrings 'WHERE `p`.`id` = :id';
              
      $condition = array(':id' => $id);
              return 
      $this->takeFirstObjectFromList($this->findByCondition($conditionStrings$condition), 'Profile');
          }

          
      /**
           * (non-PHPdoc)
           * @see IDao::findAll()
           * @author Carpenter
           */
          
      public function findAll() {
              return 
      $this->findByCondition('', array());
          }

          
      /** 
           * (non-PHPdoc)
           * @see IDao::delete()
           * @author Carpenter
           * @param Profile $entity
           */
          
      public function delete($entity) {
              try {
                  
      $sql 'DELETE FROM 
                              `profile`
                          WHERE 
                              `id` = :id
                          '
      ;
                  
                  
      $stmt $this->getDatabase()->prepareQuery($sql);
                  
      $stmt->bindValue(':id'$entity->getId());
                  
      $stmt->execute();
              } catch (
      Exception $e) {
                  
      self::log()->error(sprintf('Error while deleting Profile with id %s:'$entity->getId()));
                  
      self::log()->errorEx($e);
                  throw new 
      DatabaseException(sprintf('Error while deleting Profile with id %s!'$entity->getId()));
              }
          }

          
      /** 
           * (non-PHPdoc)
           * @see IDao::findByExample()
           * @author Carpenter
           */
          
      public function findByExample($entity) {
              try {
                  
      $condition '';
                  
      $conditionValues = array();
                  
      $this->buildExampleConditionAndValues($entity$condition$conditionValues);
                  
                  return 
      $this->findByCondition($condition$conditionValues);
              } catch (
      Exception $e) {
                  
      self::log()->error('Error while fetching Profile by example:');
                  
      self::log()->errorEx($e);
                  throw new 
      DatabaseException('Error while fetching Profile by example!');
              }
          }
          
          
      /**
           * Build the example condition and values for the given entity.
           *
           * @author Carpenter
           * @param Profile $entity
           * @param string $condition
           * @param array $conditionValues
           */
          
      protected function buildExampleConditionAndValues(Profile $entity, &$condition, array &$conditionValues) {
              if (empty(
      $condition)) {
                  
      $condition 'WHERE 1=1 ';
              }
              if (
      $entity->getId() !== NULL) {
                  
      $condition .= ' AND `p`.`id` = :id ';
                  
      $conditionValues[':id'] = $entity->getId();
              }
              if (
      $entity->getAssessmentDayId() !== NULL) {
                  
      $condition .= ' AND `p`.`name` LIKE :name ';
                  
      $conditionValues[':name'] = $entity->getName();
              }
              if (
      $entity->getProfileId() !== NULL) {
                  
      $condition .= ' AND `p`.`password` LIKE :password ';
                  
      $conditionValues[':password'] = $entity->getPassword();
              }
          }
      }
      Und jetzt die Filterklasse:
      PHP-Code:
      <?php

      /**
       * Filter for Profile.
       *
       * @author Carpenter
       */
      class ProfileFilter extends FilterBase {

          const 
      ORDER_COLUMN_NAME 1;
          
          
      /**
           * @var Profile
           */
          
      private $exampleObj;
          
      /**
           * @var array of int
           */
          
      private $profileIds;

          
      /**
           * Returns the $profileIds value.
           *
           * @author Carpenter
           * @return array of int
           */
          
      public function getProfileIds() {
              return 
      $this->profileIds;
          }

          
      /**
           * Sets the $profileIds value.
           *
           * @author Carpenter
           * @param array of int $profileIds
           */
          
      public function setProfileIds(array $profileIds) {
              
      $this->profileIds $profileIds;
          }
          
          
      /**
           * Adds the $profileId value.
           *
           * @author Carpenter
           * @param array of int $profileId
           */
          
      public function addProfileId($profileId) {
              if (! 
      is_array($this->profileIds)) {
                  
      $this->profileIds = array();
              }
              
      $this->profileIds[] = $profileId;
          }

          
      /**
           * Returns the $exampleObj value.
           *
           * @author Carpenter
           * @return Profile
           */
          
      public function getExampleObj() {
              return 
      $this->exampleObj;
          }

          
      /**
           * Sets the $exampleObj value.
           *
           * @author Carpenter
           * @param Profile $exampleObj
           */
          
      public function setExampleObj(Profile $exampleObj) {
              
      $this->exampleObj $exampleObj;
          }

          
      /**
           * Constructor.
           *
           * @author Carpenter
           * @return void
           */
          
      public function __construct() {
              
      parent::__construct();
              
      $this->setLimitStart(NULL);
              
      $this->setLimitCount(NULL);
              
      $this->setExampleObj(new Profile());
          }
          
      }
      Ein Beispiel zur Filterfunktion:
      PHP-Code:
      $profileService $coreService->getProfileService();

      $profileFilter = new ProfileFilter();
      $profileFilter->setOrderColumn(ProfileFilter::ORDER_COLUMN_NAME);
      $profileFilter->addProfileId(1);
      $profileFilter->addProfileId(2);
      $profileFilter->addProfileId(3);
      $profileFilter->getExampleObj()->setName('Carpenter');

      $profiles $profileService->fetchProfileByFilter($profileFilter); 
      Ich hoffe es hilft dir bei deinem Problem oder gibt dir zumindest einen Ansatz.

      Viele Grüße
      Carpenter

      PS: Mit Doctrine2 habe ich noch nicht viel gemacht. Ich überlege aber darauf umzusteigen.

      Kommentar


      • #4
        Ein Service ist kein Repository und was du da als Service darstellst ist schlicht ein ungeeigneter Wrapper.
        Ein DAO sollte niemals mit Entities in Berührung kommen, für ein ganzheitliches Konzept fehlt dir ein Mapper.
        Nach meinem Verständnis sieht die gesamte Kette so aus:
        Client (z.B. ein Controller) erhält per DI einen Service, welcher widerum n Repositories bedienen kann.
        Jedes Repository arbeitet mit n Mappern zusammen (DB, XML, Webservice ...), welche, je nach Anwendungsfall, die Entities auf DAOs abbilden.
        Die einzelnen Glieder dieser Kette sind in PoEAA sehr ausführlich erklärt und man erkennt nach intensivem Lesen auch durchaus die Zusammenhänge - zumindest meiner Meinung nach.
        VokeIT GmbH & Co. KG - VokeIT-oss @ github

        Kommentar


        • #5
          Gut, danke für den Hinweis. Habs bestellt und schaue es mir an.

          Viele Grüße
          Carpenter

          Kommentar


          • #6
            Wieso spezialisierte Methoden schrecklich sein sollen, kann ich nicht ganzheitlich nachvollziehen. Methoden im Sinne von findById($id) oder findByName($name) halte ich persönlich für gelungen, wohingegen bei einer Vielzahl von Bedingungen ziemlich schnell Ungetüme entstehen können. Hierbei hat eine Methode wie findByCriteria(Criteria $criteria) ihre Vorzüge. In der Summe befürworte ich beide Varianten im Verbund.

            Einen anderen Punkt, welchen BlackScorp anspricht, ist die Frage nach Lazy Loading oder Eager Loading. Dies würde ich vom konkreten Anwendungsfall abhängig machen. Es gilt zu überlegen, in welchem Kontext welche Daten mit welcher Wahrscheinlichkeit benötigt werden. Ein weiteres Kriterium ist wohl auch die Datenmenge.

            Kommentar


            • #7
              Hallöchen,

              noch eine kurze Anmerkung: meiner Meinung nach sollte man versuchen redundante Methodennamen möglichst zu vermeiden. Besonders dann wenn der Kontext eindeutig ist. In deinem Beispiel wäre das: ProfileService->saveProfile(...);. Man spart sich damt nicht nur ein wenig Schreibarbeit:

              PHP-Code:
              $profileRepository->saveProfile(...); 
              vs
              PHP-Code:
              $profileRepository->save(...); 
              sondern erhöht damit die Wiederverwandbarkeit des bestehenden Codes enorm. Außerdem können auf diese Weise Basisfunktionalitäten in ein Interface gepackt werden um eine einheitliche Schnittstelle für den Zugriff auf die vorhandenen Daten zu bieten:

              PHP-Code:
              interface IRepository{
                  function 
              get($id);
                  function 
              store(Entity $entity);
                  function 
              remove(Entity $entity);
                  function 
              find(EntityFilter $filter);

              Viele Grüße,
              lotti
              [SIZE="1"]Atwood's Law: any application that can be written in JavaScript, will eventually be written in JavaScript.[/SIZE]

              Kommentar


              • #8
                @Trainmaster, findById und findByName müssen vorhanden sein und werde immer in den allgemeinen fällen verwenden, es geht hier darum, bei den Speziallfällen zu unterscheiden.

                Simples Beispiel:

                Ich habe eine Veranstaltungs software, als Administrator muss ich eine Liste aller Veranstaltungen in einem Zeitraum von X sehen, als informationen, soll die Veranstaltungsnummer, Veranstaltungsname, Anzahl Teilnehmer, Veranstaltungsleiter, Raum der Veranstaltung angezeigt werden. Dabei soll man nach einem der Felder auf und absteigenden sortieren.

                ich habe in dem Fall mindestens 3 Repositories
                1) CourseRepository
                2) RoomRepository
                3) UserRepository

                wobei bei den usern zwischen Leiter und Teilnehmer noch zusätzlich unterschieden wird.

                Angenommen Proxy Pattern und Lazy Loading würde ich hier einsetzen, dann wird jeder user und jeder raum mit allen weiteren Informationen geladen, die ich nicht brauchen werde bei der darstellung.

                Angenommen Specification Pattern, dann hätte ich viele weitere interfaces und am ende müsste ich sowieso konkrete specifications erstellen.

                Aktuell habe ich mir überlegt, ob ich nicht extra für solche spezial fälle dann Entities anlege, die datenbank Views mappen und ein Repository über setter methoden verändern kann..

                ala:

                PHP-Code:
                class PDOAdminCourseRepository{

                protected 
                $orderRow 'courseID';
                protected 
                $oderDirection 'ASC';
                public function 
                setOrderBy()
                public function 
                findInRange(DateTime $start,DateTime $end){
                //simples select from view
                }
                public function 
                findByName($name){

                }

                füllt sich nach einem "Hack" bzw. "Quick und Dirty" way an, würde aber mein Problem nicht unnötig verkomplezieren und dennoch flexibel machen.. was mein ihr?
                apt-get install npm -> npm install -g bower -> bower install <package> YOLO [URL]https://www.paypal.me/BlackScorp[/URL] | Mein Youtube PHP Kanal: [url]https://www.youtube.com/c/VitalijMik[/url]

                Kommentar


                • #9
                  Mein bisheriger Ansatz ist sicherlich auch nicht perfekt. Ich will ihn trotzdem mal vorstellen.

                  Mein Ansatz besteht um einfachsten Fall aus 4 Klassen pro Tabelle:

                  Code:
                  Repository < AbstractRepository
                  Query < AbstractQuery
                  Entity < AbstractEntity
                  Model < AbstractModel
                  Bislang mache ich im Bezug auf Entities und Models viel Gebrauch von Magic. Allerdings bleibt dabei die IDE-Unterstützung bestehen:

                  Ein Repository hat bei mir in der Regel diese Methoden:

                  Code:
                  ->find(): Query
                  ->create(array $data): Entity
                  ->get(int $id): Entity
                  ->getModel(int $id): Model
                  ->validate(Entity $entity, ValidationResult $result=null): bool
                  ->save(Entity $entity): bool
                  ->remove(Entity $entity): bool
                  Ein Query sieht beispielsweise so aus:

                  Code:
                  where<UserDefinedExt>($value): $this
                  where(string $field, scalar|array $arg, scalar|array $arg, ...): $this
                  limit(int $count, int $offset=0): $this
                  order(string $field, string $field, ...): $this
                  getAll(): Model[]
                  getFirst(): Model
                  getCountAll(): int (~ SQL_CALC_FOUND_ROWS)
                  Bislang erlaube ich string-based expressions in den where- und order-Methoden. Dadurch sind meine Queries u.U. DB-spezifisch. Ich koennte mir vorstellen, dass man hier durch ADO (oder so) einen Gemeinsamen Nenner einbringen könnte. Wichtig ist vor allem aber die Idee hinter dieser Methode. Ich habe keine whereNameAndPasswordAndOrderByAge Funktionen, sondern kann die Filter beliebig zusammenstellen. Das ist wichtig, wenn man mit dynamisch filter- und sortierbaren Grids arbeitet.

                  Entities:

                  Code:
                  __construct(array $data)
                  asArray(): array
                  Durch Magic kann man auf alle Felder über properties zugreifen. Die Properties werden im PHPDoc genannt:
                  Code:
                  @property int id
                  @property string zipCode (~ zip_code)
                  Models:
                  Models bekommen Entities und den ServiceLocator über constructor injection. Sie sind (eigentlich) immutable Entities mit erweitertem Funktionsumfang. Beispiel: $user->getGroups() ruft intern das Repository "UserGroups" ab und führt damit dessen Query aus. Vorher setzt es aber noch den Filter "user_id < $user->id". Diese Verknüpfung kann man auch an einen externen Manager übergeben, wenn man hier eine Verletzung des SRP sieht.

                  Models haben über einen intern durchgeschleiften "ServiceLocator" Zugriff auf alle anderen Repositories.

                  So ziemlich alle Methoden aller 4 Klassen kann man in abstrakte Klassen auslagern. In PHP muss ich sie nur deswegen überschreiben, weil PHP keine Generics kann...

                  Diese Methode ist aus meiner Sicht (abgesehen von den lockeren Query-Methoden und abhängig von der Implementation) SOLID kompatibel.

                  Kommentar


                  • #10
                    hm.. mir ist bei allen beispiele aufgefallen dass ihr save(Entity $entity) methoden habt, sollte aber die datenpersistenz nicht in der anwendung stattfinden? also in der Geschäftslogik ein add(Entity $entity) dabei werden entities in eigenschaften hinterlegt und erst später mit save() in den speicher gepackt werden?
                    apt-get install npm -> npm install -g bower -> bower install <package> YOLO [URL]https://www.paypal.me/BlackScorp[/URL] | Mein Youtube PHP Kanal: [url]https://www.youtube.com/c/VitalijMik[/url]

                    Kommentar


                    • #11
                      Zitat von BlackScorp Beitrag anzeigen
                      hm.. mir ist bei allen beispiele aufgefallen dass ihr save(Entity $entity) methoden habt, sollte aber die datenpersistenz nicht in der anwendung stattfinden? also in der Geschäftslogik ein add(Entity $entity) dabei werden entities in eigenschaften hinterlegt und erst später mit save() in den speicher gepackt werden?
                      Collection vs. Factory/Repository

                      Kommentar


                      • #12
                        Zitat von rkr Beitrag anzeigen
                        Collection vs. Factory/Repository
                        wieso vs? verstehe die aussage nicht ganz
                        apt-get install npm -> npm install -g bower -> bower install <package> YOLO [URL]https://www.paypal.me/BlackScorp[/URL] | Mein Youtube PHP Kanal: [url]https://www.youtube.com/c/VitalijMik[/url]

                        Kommentar

                        Lädt...
                        X