Since my lastquestion related to this I have managed to create a working base and to understand how MVC works.
I'm writingRESTful APIS in PHP, they serve the purpose but I see that my code is repeating.
For example, for each action, I have acontroller, aservice... etc and a lot of that code can be reused not that I write a ton of code for one simple route.
I have tried a few of my ideas but I end up having spaghetti code and it does not look clean.
Here is folder the structure in one of my APIS.
.├── README.md├── apache_default├── composer.json├── composer.lock├── config│ ├── config-development.yml│ ├── config-production.yml│ ├── dependencies│ │ ├── common│ │ │ ├── cashing.yml│ │ │ ├── components.yml│ │ │ ├── controllers.yml│ │ │ ├── domains.yml│ │ │ ├── middleware.yml│ │ │ ├── objmap.yml│ │ │ ├── repositories.yml│ │ │ └── services.yml│ │ ├── development│ │ │ └── db.yml│ │ ├── general-production.yml│ │ ├── general.yml│ │ └── main.yml│ ├── parameters│ │ └── development│ │ └── tables.yml│ └── routing.yml├── phpunit.xml├── public│ ├── Bootstrap.php│ ├── Kernel.php│ ├── index.php│ └── monolog.log├── resources│ ├── git│ │ ├── diagram.png│ │ ├── schema.png│ │ └── schema_1.png│ └── loggs│ └── monolog.txt├── src│ └── Spartan│ ├── Core│ │ ├── Component│ │ │ ├── Collection.php│ │ │ ├── Controller.php│ │ │ ├── DataMapper.php│ │ │ ├── Exception.php│ │ │ ├── MapperFactory.php│ │ │ └── Service.php│ │ ├── Database│ │ │ ├── ES.php│ │ │ └── PDOCompat.php│ │ ├── Entities│ │ │ ├── CanPersistMapper.php│ │ │ ├── HasId.php│ │ │ └── ResponseBootstrap.php│ │ ├── Logger│ │ │ └── Logger.php│ │ └── Mapper│ │ └── CanCreateMapper.php│ ├── Models│ │ ├── Adapters│ │ ├── Cashing│ │ │ └── WorkoutCashing.php│ │ ├── Collections│ │ │ ├── DescriptionCollection.php│ │ │ ├── ExerciseCollection.php│ │ │ ├── NameCollection.php│ │ │ ├── RoundCollection.php│ │ │ ├── TagCollection.php│ │ │ ├── WorkoutCollection.php│ │ │ └── WorkoutListCollection.php│ │ ├── Domains│ │ │ ├── AddWorkoutDomain│ │ │ │ └── AddWorkoutDomain.php│ │ │ ├── DeleteWorkoutDomain│ │ │ │ └── DeleteWorkoutDomain.php│ │ │ ├── EditWorkoutDomain│ │ │ │ └── EditWorkoutDomain.php│ │ │ ├── GetWorkoutDomain│ │ │ │ └── GetWorkoutDomain.php│ │ │ ├── GetWorkoutIdsDomain│ │ │ │ └── GetWorkoutIdsDomain.php│ │ │ ├── GetWorkoutListDomain│ │ │ │ └── GetWorkoutListDomain.php│ │ │ ├── ReleaseWorkoutDomain│ │ │ │ └── ReleaseWorkoutDomain.php│ │ │ └── WorkoutExsistsDomain│ │ │ └── WorkoutExsistsDomain.php│ │ ├── Entities│ │ │ ├── Description.php│ │ │ ├── Exercise.php│ │ │ ├── Name.php│ │ │ ├── Round.php│ │ │ ├── Tag.php│ │ │ ├── Version.php│ │ │ ├── Workout.php│ │ │ └── WorkoutList.php│ │ ├── Exceptions│ │ │ ├── BaseError.php│ │ │ ├── DescriptionConfliect.php│ │ │ ├── ESError.php│ │ │ ├── NameConflict.php│ │ │ ├── RoundError.php│ │ │ └── TagError.php│ │ ├── Facades│ │ ├── Helpers│ │ ├── Interfaces│ │ │ └── CanPersistWorkout.php│ │ ├── Mappers│ │ │ ├── VersionMapper.php│ │ │ ├── WorkoutBase.php│ │ │ ├── WorkoutDescription.php│ │ │ ├── WorkoutListMapper.php│ │ │ ├── WorkoutName.php│ │ │ ├── WorkoutRound.php│ │ │ └── WorkoutTag.php│ │ ├── Middlewares│ │ │ ├── CreateWorkoutMiddleware.php│ │ │ ├── DeleteWorkoutMiddleware.php│ │ │ ├── EditWorkoutMiddleware.php│ │ │ ├── GetWorkoutByIdsMiddleware.php│ │ │ ├── GetWorkoutListMiddleware.php│ │ │ ├── GetWorkoutMiddleware.php│ │ │ └── ReleaseWorkoutMiddleware.php│ │ ├── Repositories│ │ │ └── WorkoutRepository.php│ │ └── Services│ │ └── WorkoutService.php│ └── Presentation│ ├── Controller│ │ ├── LogController.php│ │ └── WorkoutController.php│ └── Mappers│ └── WorkoutMapp.php└── tests ├── bootstrap.php ├── fixture ├── integration ├── mock │ ├── Entity.php │ ├── Factory.php │ ├── Mapper.php │ ├── RepoEntity.php │ └── RepoMapper.php ├── report └── unit └── Spartan ├── Cashing │ └── WorkoutCashingTest.php ├── Component │ ├── CollectionTest.php │ ├── DataMapperTest.php │ └── MapperFactoryTest.php ├── Controller │ └── MappTest.php ├── Domains ├── Entities │ ├── DescriptionTest.php │ ├── ExerciseTest.php │ ├── NameTest.php │ ├── RoundTest.php │ ├── TagTest.php │ ├── VersionTest.php │ ├── WorkoutListTest.php │ └── WorkoutTest.php ├── Mappers │ ├── VersionTest.php │ ├── WorkoutBaseTest.php │ ├── WorkoutDescriptionTest.php │ ├── WorkoutListTest.php │ ├── WorkoutNameTest.php │ ├── WorkoutRoundTest.php │ └── WorkoutTagTest.php ├── Repositories │ └── WorkoutTest.php └── Services └── WorkoutTest.phpFor each activity I have a controller, that controller has a service injected into it via DI over yml.
When the service loads I have a domain folder where I keep my logic and over a factory, I create mappers there which I need(if I need them).
Each domain does one action, for example version workout(I need this for auditing of my data in MySQL).
Than I have a middleware in my service which does cashing(I'm working to change)
And thats basically how each of my routes works a lot of repeated code.
It looks very boring to write code now and I need a push into another direction.
Here is a part of my code:
index.php
<?php//Display errorsini_set('display_errors', 1);ini_set('display_startup_errors', 1);error_reporting(E_ALL);use Symfony\Component\HttpFoundation\Request;// load vendorrequire __DIR__.'/../vendor/autoload.php';require_once __DIR__.'/../public/Kernel.php';require_once __DIR__.'/../public/Bootstrap.php';// new kernel$kernel = new Kernel('dev');$bootstrap = new Bootstrap;// new request$request = Request::createFromGlobals();// loader interface$config = $kernel->registerContainerConfiguration();// response from$response = $bootstrap->handle($request,$config,null);bootstrap.php
<?phpclass Bootstrap{ public function handle($request,$config,$ipRange) { // Configuration $locator = new FileLocator(__DIR__ . '/../config'); $data = new ResponseBootstrap(); // Create a log channel $log = new Logger('spartan_workouts_ms'); $log->pushHandler(new StreamHandler('monolog.log')); $log->pushHandler(new LogglyHandler('55920048-11f0-4b7e-a203-e90083d6962d/tag/monolog', Logger::INFO)); // Dependency Injection Container $container = new DependencyInjection\ContainerBuilder; $loader = new DependencyInjection\Loader\YamlFileLoader($container, $locator); $loader->load($config); $container->compile(); // Routing $loader = new Routing\Loader\YamlFileLoader($locator); $context = new Routing\RequestContext(); $context->fromRequest($request); $matcher = new Routing\Matcher\UrlMatcher( $loader->load('routing.yml'), $context ); try{ $parameters = $matcher->match($request->getPathInfo()); foreach ($parameters as $key => $value) { $request->attributes->set($key, $value); } $command = $request->getMethod() . $request->get('action'); $resource = "controller.{$request->get('controller')}"; $controller = $container->get($resource); $data = $controller->{$command}($request); } // log custom thrown exceptions catch (\Exception $e) { /** * This is to slow it takes to much time to log */// // log errors// $log->addWarning(// json_encode([// "date"=> date("Y-m-d h:i:s"),// "code"=> $e->getCode(),// "message"=> $e->getMessage(),// "file"=> $e->getFile(),// "line"=> $e->getLine()// ])// ); $data->setData([ "date"=> date("Y-m-d h:i:s"), "code"=> $e->getCode(), "message"=> $e->getMessage(), "file"=> $e->getFile(), "line"=> $e->getLine() ]); if($e->getCode() == 0){ // TODO log data $data->setStatus(404); }else{ // TODO log data $data->setStatus($e->getCode()); } $data->setMessage($e->getMessage()); //echo "log to monolog"; } catch (\TypeError $error) { // TODO log data $data->setStatus(404); $data->setMessage(new Response("Invalid dependency: {$error->getMessage()}")); die(print_r(new Response("Invalid dependency: {$error->getMessage()}"))); } // Check if json in array from if(!empty($data->getData())){ $response = new JsonResponse($data->getData()); }else{ // Not json $response = new Response; } //Set custom headers $response->setStatusCode( (int)$data->getStatus(), empty($data->getMessage()) ? $data->getMessage() : null ); // preflighted request handle if($request->getMethod() === 'OPTIONS'){ // set status $response->setStatusCode((int)200); } // headers $response->headers->set('Access-Control-Allow-Origin', '*'); $response->headers->set('Access-Control-Allow-Methods', 'GET,HEAD,OPTIONS,POST,PUT,DELETE'); $response->headers->set('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization'); $response->headers->set('Access-Control-Allow-Credentials', 'true'); $response->headers->set("Access-Control-Max-Age", "1728000"); // return response $response->send(); return $response; }}Kernel.php
<?phpclass Kernel{ protected $env; public function __construct($env = null) { if (is_null($env)) { $this->env = is_null($env) ? 'prod' : 'dev'; }else{ $this->env = $env; } } /** * Loads the container configuration. */ public function registerContainerConfiguration() { if((string)$this->env === (string)'dev'){ $configuration = 'config-development.yml'; }else{ $configuration = 'config-production.yml'; } return $configuration; }}WorkoutController.php
<?phpclass WorkoutController extends Controller{ private $workoutService; private $workoutMapp; public function __construct(WorkoutService $workoutService, WorkoutMapp $workoutMapp){ $this->workoutService = $workoutService; $this->workoutMapp = $workoutMapp; // construct the parent parent::__construct(); } /** * Get workout * Get workouts by id * Get workout list * * @param Request $request * @return ResponseBootstrap */ public function get(Request $request):ResponseBootstrap { $workout = $this->workoutMapp->getWorkoutUniversal($request); // list if(!is_null($workout->getOffset()) && !is_null($workout->getLimit()) && !is_null($workout->getState())){ return $this->workoutService->getWorkoutList($workout); } // get workout by id if($workout->getId() && $workout->getState()){ return $this->workoutService->getWorkout($workout); } // get workout ids if($workout->getIds()){ return $this->workoutService->getWorkoutIds($workout); } return $this->badRequest(); } /** * Create workout * * @param Request $request * @return ResponseBootstrap */ public function post(Request $request) { // raw data $data = json_decode($request->getContent(), true); // map raw data to workout object $workout = $this->workoutMapp->addWorkout($data); // check if the name, description, tags and rounds are not empty if(!empty($workout->getNames()->toArray()) && !empty($workout->getDescriptions()->toArray()) && !empty($workout->getTags()->toArray()) && !empty($workout->getRounds()->toArray())){ return $this->workoutService->addWorkout($workout); } // when empty return a response from the base controller return $this->badRequest(); }....WorkoutService.php
<?phpclass WorkoutService extends Service{ ...... /** * Add Workout * * @param Workout $workout * @return ResponseBootstrap */ public function addWorkout(Workout $workout):ResponseBootstrap { // middleware for handling cashing $this->createWorkoutMiddleware->handle( $this->addWorkoutDomain, $workout, $this->getWorkoutDomain); return $this->formResponse($workout, true); } /** * Delete Workout * * @param Workout $workout * @return ResponseBootstrap */ public function deleteWorkout(Workout $workout):ResponseBootstrap { // middleware for handling cashing $this->deleteWorkoutMiddleware->handle( $this->deleteWorkoutDomain, $workout); return $this->formResponse($workout, false); } /** * Edit Workout * * @param Workout $workout * @return ResponseBootstrap */ public function editWorkout(Workout $workout):ResponseBootstrap { // middleware for handling cashing $this->editWorkoutMiddleware->handle( $this->editWorkoutDomain, $workout, $this->getWorkoutDomain); return $this->formResponse($workout, false); }WorkoutRepository.php
<?php class WorkoutRepository implements CanPersistWorkout{ private $mapperFactory; private $list = [ Workout::class => WorkoutBase::class, Round::class => WorkoutRound::class, Name::class => WorkoutName::class, Version::class => VersionMapper::class, Description::class => WorkoutDescription::class, Tag::class => WorkoutTag::class, RoundCollection::class => WorkoutRound::class, NameCollection::class => WorkoutName::class, DescriptionCollection::class => WorkoutDescription::class, TagCollection::class => WorkoutTag::class, WorkoutListCollection::class => WorkoutListMapper::class ]; public function __construct(CanCreateMapper $mapperFactory) { $this->mapperFactory = $mapperFactory; } /*********************************************************************************************/ /************************************ Store **************************************/ /*********************************************************************************************/ public function storeDescription(Description $description, string $override = null) { $mapper = $this->retrieveMapper(get_class($description), $override); $mapper->store($description); } public function storeBase(Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($workout), $override); $mapper->store($workout); } public function storeRound(Round $round, string $override = null) { $mapper = $this->retrieveMapper(get_class($round), $override); $mapper->store($round); } public function storeName(Name $name, string $override = null) { $mapper = $this->retrieveMapper(get_class($name), $override); $mapper->store($name); } public function versionUp(Version $version, string $override = null) { $mapper = $this->retrieveMapper(get_class($version), $override); $mapper->versionUp($version); } public function storeTag(Tag $tag, string $override = null) { $mapper = $this->retrieveMapper(get_class($tag), $override); $mapper->store($tag); } /*********************************************************************************************/ /************************************ Delete **************************************/ /*********************************************************************************************/ public function deleteWorkout(Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($workout), $override); $mapper->delete($workout); } public function deleteRounds(Round $round, Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($round), $override); $mapper->delete($round,$workout); } public function deleteDescriptions(Description $description, Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($description), $override); $mapper->delete($description,$workout); } public function deleteNames(Name $name, Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($name), $override); $mapper->delete($name,$workout); } public function deleteTags(Tag $tag, Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($tag), $override); $mapper->delete($tag,$workout); } /*********************************************************************************************/ /************************************ Fetch **************************************/ /*********************************************************************************************/ public function getDescriptions(DescriptionCollection $description, Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($description), $override); $mapper->fetch($description, $workout); } public function getRounds(RoundCollection $round, Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($round), $override); $mapper->fetch($round, $workout); } public function getNames(NameCollection $name, Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($name), $override); $mapper->fetch($name,$workout); } public function getWorkout(Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($workout), $override); $mapper->fetch($workout); } public function getTags(TagCollection $tag, Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($tag), $override); $mapper->fetch($tag, $workout); } public function getWorkoutList(WorkoutListCollection $list, Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($list), $override); $mapper->fetch($list, $workout); } public function getTotalWorkotus(Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($workout), $override); $mapper->total($workout); } /*********************************************************************************************/ /*********************************** Update ********************************************/ /*********************************************************************************************/ public function updateNameState(NameCollection $name, Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($name), $override); $mapper->update($name, $workout); } public function updateRoundState(RoundCollection $round, Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($round), $override); $mapper->update($round,$workout); } public function updateBaseState(Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($workout), $override); $mapper->update($workout); } public function updateDescriptionState(DescriptionCollection $description, Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($description), $override); $mapper->update($description,$workout); } /*********************************************************************************************/ /*********************************** Audit ********************************************/ /*********************************************************************************************/ public function auditRound(Round $round,Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($round), $override); $mapper->storeToAudit($round, $workout); } public function auditDescription(Description $description,Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($description), $override); $mapper->storeToAudit($description, $workout); } public function auditBase(Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($workout), $override); $mapper->storeToAudit($workout); } public function auditName(Name $name,Workout $workout, string $override = null) { $mapper = $this->retrieveMapper(get_class($name), $override); $mapper->storeToAudit($name,$workout); } /*********************************************************************************************/ /*********************************** Helpers ********************************************/ /*********************************************************************************************/ public function begginTransaction() { $mapper = $this->mapperFactory->create(WorkoutBase::class); $mapper->begginTransaction(); } public function commitTransaction() { $mapper = $this->mapperFactory->create(WorkoutBase::class); $mapper->commit(); } private function computeKey(string $key, string $override = null): string { if ($override !== null) { $key = $override; } if (array_key_exists($key, $this->list) === false) { throw new \RuntimeException("No mapper for class '{$key}' has been defined!"); } return $key; } private function retrieveMapper(string $name, string $override = null) { $key = $this->computeKey($name, $override); $entry = $this->list[$key]; return $this->mapperFactory->create($entry); } public function define(string $entity, string $mapper) { if (class_exists($entity) === false) { throw new \RuntimeException("Entity class '{$entity}' was not found!"); } if (class_exists($mapper) === false) { throw new \RuntimeException("Mapper class '{$mapper}' was not found!"); } $this->list[$entity] = $mapper; } public function load($identity, string $override = null) { $mapper = $this->retrieveMapper(get_class($identity), $override); $mapper->fetch($identity); }}VersionMapper.php
<?php class VersionMapper extends DataMapper{ /** * Version Up * * @param Version $version */ public function versionUp(Version $version) // TODO handle exceptions { $sql = "INSERT INTO version VALUES(null)"; $statement = $this->connection->prepare($sql); $statement->execute(); $version->setVersion($this->connection->lastInsertId()); }}AddWorkoutDomain.php
<?php class AddWorkoutDomain{ private $repository; public function __construct(Repository $repository) { $this->repository = $repository; } /*********************************************************************************************/ /***************************** Visible functions to children ******************************/ /*********************************************************************************************/ /** * Handle * * @param Workout $workout * @return array */ public function handle(Workout $workout):array { // beggin transaction $this->repository->begginTransaction(); $messages = []; $messages = array_merge($messages, $this->storeBase($workout)); $messages = array_merge($messages, $this->storeNames($workout)); $messages = array_merge($messages, $this->storeDescriptions($workout)); $messages = array_merge($messages, $this->storeRounds($workout)); $messages = array_merge($messages, $this->storeTags($workout)); // commit transaction $this->repository->commitTransaction(); return $messages; } /** * Get Total * * @param Workout $workout */ public function getTotal(Workout $workout):void { $this->repository->getTotalWorkotus($workout); } /*********************************************************************************************/ /************************************* Executors ******************************************/ /*********************************************************************************************/ /** * Store Base * * @param Workout $workout * @return array */ private function storeBase(Workout $workout):array { // version up $workout->setVersion($this->versionUp()->getVersion()); $workout->setState('P'); $this->repository->storeBase($workout); return ['success'=>'Base']; } /** * Store Names * * @param Workout $workout * @return array */ private function storeNames(Workout $workout):array { foreach($workout->getNames()->toArray() as $name){ // set workout parent $name->setParent($workout->getId()); $name->setState('P'); $this->repository->storeName($name); } return ['success'=>'Names']; } /** * Store Descriptions * * @param Workout $workout * @return array */ private function storeDescriptions(Workout $workout):array { foreach($workout->getDescriptions()->toArray() as $description){ // set workout parent $description->setParent($workout->getId()); $description->setState('P'); $this->repository->storeDescription($description); } return ['success'=>'Descriptions']; } /** * Store Rounds * * @param Workout $workout * @return array */ private function storeRounds(Workout $workout):array { foreach($workout->getRounds()->toArray() as $round){ // set workout parent $round->setParent($workout->getId()); $round->setState('P'); $this->repository->storeRound($round); } return ['success'=>'Rounds']; } /** * Store Tags * * @param Workout $workout * @return array */ private function storeTags(Workout $workout):array { foreach($workout->getTags()->toArray() as $tag){ // set workout parent $tag->setParent($workout->getId()); $this->repository->storeTag($tag); } return ['success'=>'Rounds']; } /** * Version Up * * @return Version */ private function versionUp():Version { $version = new Version(); $this->repository->versionUp($version); return $version; }}Any comment and advice are welcome, I'm seeking to expand my knowledge.
Credits toTereško for helping me out.
2 Answers2
Take the followingKernel class:
class Kernel{ protected $env; const ENV_TYPE_DEV = 'dev'; const ENV_TYPE_PROD = 'prod'; public function __construct($env = null) { $this->env = $env ?? self::ENV_TYPE_DEV; } /** * Loads the container configuration. */ public function registerContainerConfiguration() { if ($this->env === self::ENV_TYPE_DEV) { $configuration = 'config-development.yml'; } else { $configuration = 'config-production.yml'; } return $configuration; }}The changes I made are as follows:
- Defined two constants so you can reference them rather than passing a direct string as the
$env. This also gives you the option to change the values in the future without having to consider hardcoded versions of the values - Simplified your
ifstatement (via thenull coalescing operator) in your__constructto set the$envproperty to whatever is passed toENV_TYPE_DEVas a default - In
registerContainerConfigurationI removed your casts as they were redundant and turned the hard-coded string into the respectiveconst
Then yourindex.php file:
use Symfony\Component\HttpFoundation\Request;// load vendorrequire __DIR__.'/../vendor/autoload.php';// autoloading done through composer// error handling based on kernel env// type that is passed.// new kernel$kernel = new Kernel(Kernel::ENV_TYPE_DEV);$bootstrap = new Bootstrap;// new request$request = Request::createFromGlobals();// loader interface$config = $kernel->registerContainerConfiguration();// response from$response = $bootstrap->handle($request, $config, null);The changes I made / suggest are as follows:
- You should have your error reporting work in conjunction with your environment that is defined in your
Kernel - You should autoload your classes through composer
- I changed the hardcoded
devstring to the defined constant
In yourAddWorkoutDomain class, I'd simplify the handle function:
/** * Handle * * @param Workout $workout * @return array */ public function handle(Workout $workout):array { // beggin transaction $this->repository->begginTransaction(); $messages = array_merge($messages, $this->storeBase($workout), $this->storeNames($workout), $this->storeDescriptions($workout), $this->storeRounds($workout), $this->storeTags($workout)); // commit transaction $this->repository->commitTransaction(); return $messages; }- Merged the
array_mergecalls into one (pun intended...), as per the documentation, the second parameter can be a list of variables to merge, doesn't have to be one per function call
Miscellaneous
- Opinionated but, you seem to have quite a few blank lines within your classes, I would reduce that down
In various places you check for
nullvariables in long, drawn out, if statements:if(!is_null($workout->getOffset()) && !is_null($workout->getLimit()) && !is_null($workout->getState())){ return $this->workoutService->getWorkoutList($workout);}
Consider the following:
if (isset($workout->getOffset(), $workout->getLimit(), $workout->getState())) {}- \$\begingroup\$I have implemented your changes, thank you! I won't accept your answer but I will upvote it. If you could go through the whole code and give me full feedback on my code and classes and how it can be reduced I will accept it then.\$\endgroup\$DaAmidza– DaAmidza2019-04-03 06:41:48 +00:00CommentedApr 3, 2019 at 6:41
Since nobody answered my question probably because I have not explained what I want here is an answer which satisfied my needs.
I have been wondering in the dark than I have found thisanswer which expanded my knowledge regarding programming.
I have seen some of those methods but I have never taught of the level of abstraction which they can bring.
As the accepted answer states:
Programming: Writing a program that creates, transforms, filters, aggregates and otherwise manipulates data.
Metaprogramming: Writing a program that creates, transforms, filters, aggregates and otherwise manipulates programs.
Generic Programming: Writing a program that creates, transforms, filters, aggregates and otherwise manipulates data, but makes only the minimum assumptions about the structure of the data, thus maximizing reuse across a wide range of data types.
I saw that I have been typing code which can be easily avoided.
Long story short here is my implementation to the issue I had.
My controller is still not there where I want it to be but I have managed to call my actions like this:
return $this->baseService->actionHandler($exercise, [ BaseService::ACT_GET_NAME, BaseService::ACT_GET_DESC, BaseService::ACT_GET_BASE, BaseService::ACT_GET_OBJ ], $queryParams );And my service looks something like this:
class BaseService{ // vars private $domainRepository; private $responseBootstrap; private $versionDomain; private $nameDomain; private $tagDomain; private $planDomain; private $packageDomain; private $roundDomain; private $auditDomain; private $deleteDomain; private $languageDomain; //actions create const ACT_VERSION = 'versionUp'; const ACT_CREATE = 'createObject'; const ACT_SINGLE_OBJ = 'returnSingleObject'; const ACT_CRE_NAME = 'createName'; const ACT_CRE_DESC = 'createDescription'; const ACT_CRE_TAG = 'createTags'; const ACT_CRE_BODY = 'createBody'; const ACT_CRE_PKG_PLAN = 'createPackagePlan'; const ACT_CRE_WRK_PLN_DAY = 'createWorkoutPlanDay'; const ACT_CRE_ROUND = 'createRound'; const ACT_RELEASE = 'releaseContent'; const ACT_DELETE = 'delete'; // actions delete const ACT_ED_NAME = 'editName'; const ACT_ED_OBJ = 'editObject'; const ACT_ED_DESC = 'editDescription'; const ACT_ED_TAG = 'editTag'; const ACT_ED_ROUND = 'editRound'; const ACT_ED_BODY = 'editBody'; const ACT_ED_DAY = 'editDay'; const ACT_ED_PKG_PLAN = 'editPackagePlan'; // actions get const ACT_GET_NAME = 'getName'; const ACT_GET_DESC = 'getDescription'; const ACT_GET_BODY = 'getBody'; const ACT_GET_OBJ = 'getObjectResponse'; const ACT_GET_BASE = 'getBase'; // system actions const SYS_ACT_BEG_TRANS = 'begginTransaction'; const SYS_ACT_COM_TRANS = 'commitTransaction'; const SYS_ACT_ROLB_TRANS = 'rollbackTransaction'; private $responseArray = []; /** * Constructor * * @param DomainRepository $domainRepository * @param ResponseBootstrap $responseBootstrap * @param VersionDomain $versionDomain * @param NameDomain $nameDomain * @param NameDomain $descriptionDomain */ public function __construct( DomainRepository $domainRepository, ResponseBootstrap $responseBootstrap, VersionDomain $versionDomain, NameDomain $nameDomain, TagDomain $tagDomain, PlanDomain $planDomain, PackageDomain $packageDomain, RoundDomain $roundDomain, AuditDomain $auditDomain, DeleteDomain $deleteDomain, LanguageDomain $languageDomain) { $this->domainRepository = $domainRepository; $this->responseBootstrap = $responseBootstrap; $this->versionDomain = $versionDomain; $this->nameDomain = $nameDomain; $this->tagDomain = $tagDomain; $this->planDomain = $planDomain; $this->packageDomain = $packageDomain; $this->roundDomain = $roundDomain; $this->auditDomain = $auditDomain; $this->deleteDomain = $deleteDomain; $this->languageDomain = $languageDomain; } /** * Action Handler * * @param object $object * @param array $actions * @return object */ public function actionHandler(object $object, array $actions = [], QueryParams $queryParams = null):object { try{ // beggin transaction $this->domainRepository->begginTransaction(); foreach($actions as $action){ // on create return object if($action == BaseService::ACT_SINGLE_OBJ){ // commit transaction $this->domainRepository->commitTransaction(); return $this->{$action}($object); } // on get return object else if($action == BaseService::ACT_GET_OBJ){ // commit transaction $this->domainRepository->commitTransaction(); return $this->{$action}(); }else{ $this->{$action}($object, $queryParams); } } }catch(\PDOException $e){ // handle rollback of sql action $this->domainRepository->rollbackTransaction($e); } } /*********************************************************************************************/ /*********************************** Executors *********************************/ /*********************************************************************************************/ /** * Version Up * * @param object $object */ private function versionUp(object $object):void { // version up $this->versionDomain->handle($object); } ...........TheBaseService class has all the actions and it calls the DAO layer which is flexible enough to construct the query I need.
I need to add a caching layer to it and a few more things but this is the answer which I have been asking for(at least I think so if somebody else had a better version of it feel free to post your answer.
You mustlog in to answer this question.
Explore related questions
See similar questions with these tags.

