Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring Sprunje Class #835

Closed
2 of 3 tasks
lcharette opened this issue Dec 29, 2017 · 7 comments
Closed
2 of 3 tasks

Refactoring Sprunje Class #835

lcharette opened this issue Dec 29, 2017 · 7 comments
Assignees
Labels
architecture Related to the framework architecture
Milestone

Comments

@lcharette
Copy link
Member

lcharette commented Dec 29, 2017

Tasks

  • Refactor constructor (see below)
  • Add built-in caching (at least for base query; to the whole result if possible)
  • Add properties feature

Current Sprunje Constructor is too complex. The problem is the query method is called inside the constructor. So if the query requires more info (eg. $foo relation model), you can't do this :

// Controller
$sprunje = new BarSprunje($classMapper, $params);
$sprunje->setFoo($foo);

// BarSprunje
protected function baseQuery()
{
    return $this->foo->bar();
}

Instead the ctor needs to be extended ($sprunje = new BarSprunje($classMapper, $params, $foo);), which in the long term can create issue if a new argument needs to be added to the core class.

Same goes if any additional services are required by the Sprunje and/or transform method.

@lcharette lcharette added the architecture Related to the framework architecture label Dec 29, 2017
@alexweissman
Copy link
Member

What do you propose?

In my Sprunjes, I've been creating a new method that allows me to access the underlying query object:

// Controller
$sprunje = (new StudentSprunje($classMapper, $params))->forWorker($worker);

// StudentSprunje
public function forWorker($worker)
{
    $this->query = $worker->currentStudents();

    return $this;
}

That being said, I've run into other issues with the Sprunje API that could indicate a need to refactor/rework it.

@lcharette
Copy link
Member Author

Your solution could also work in my case. But doesn't it makes the baseQuery abstract method useless? extendQuery can be useful when adding stuff to the base query, but not much setting the base relation...

Also, if you need to inject another service (Router, cache, etc.) to use with Transform for example, it won't be much of help.

And speaking of refactoring, caching is another issue when dealing with Sprunje...

@alexweissman
Copy link
Member

Yes, I agree, I'm starting to see a lot of structural issues with Sprunje. Maybe we should add this to the UF5 roadmap? I also want to add a properties feature to Sprunje, so that you can do something like this:

GET http://localhost/btoms/public/api/workers?size=10&page=0&sorts[info]=desc&properties[]=lastActivity&properties[]=institutions&properties[]=phones

This allows you to specify which relationships (and even direct properties) of a model to load. Maybe every Sprunje could have a set of default properties to load, and then additional properties could be specified in the parameters.

It would have to be integrated with our access control system somehow, I suppose.

@lcharette
Copy link
Member Author

Ok. Let's make this issue the Sprunje refactoring issue.

@lcharette lcharette added this to the 5.0 milestone Dec 29, 2017
@lcharette lcharette changed the title Simplify Sprunje Constructor to allow additionnal getter methods Refactoring Sprunje Class Dec 29, 2017
@lcharette lcharette self-assigned this Apr 27, 2022
lcharette added a commit to userfrosting/sprinkle-core that referenced this issue Apr 29, 2022
@lcharette
Copy link
Member Author

I've done part of the refactor in userfrosting/sprinkle-core@526bb8e.

The constructor have been simplified and an alternative to the option in the contractor have been added (sprunje::setOptions($options)). While custom sprunje will still require to extend the constructor to add new dependencies, modern dependency injection (PHP-DI) bypass the issue originally described, as long as options are not passed in the constructor. In essence:

  • Before :
public function getList(Request $request, Response $response)
{
    /** @var \UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */
    $classMapper = $this->ci->classMapper;

    $sprunje = $classMapper->createInstance('activity_sprunje', $classMapper, $params);
    
    return $sprunje->toResponse($response);
}
  • After :
public function getList(Request $request, Response $response, ActivitySprunje $sprunje)
{
    $sprunje->setOptions($params);
    
    return $sprunje->toResponse($response);
}

lcharette added a commit to userfrosting/sprinkle-core that referenced this issue May 1, 2022
@lcharette
Copy link
Member Author

I also want to add a properties feature to Sprunje

Done in userfrosting/sprinkle-core@7ce3e03 ! List of columns to show added as property (and not options; as theses proves difficult to default, and array are bad at type check).

@lcharette
Copy link
Member Author

As far as further rewrite goes, I propose to separate Sprunje between data definition (what we want to get) and what return the data :

class Sprunjer implement Sprunjer {
    public function __construct(SprunjeInterface $sprunje) { ... }
    public function toArray() { ... }
    public function getListable() { ... }
    //  etc.
}
class Sprunje implement SprunjeInterface, SortableSprunjeInterface, ListableSprunjeInterface, FilterableSprunjeInterface {
    protected array $filterable = [];
    protected array $listable = [];
    protected array $sortable = [];
    protected function baseQuery()
    // etc.
}

Big pro is Sprunjer can be extended : CsvSprunjer, ResponseSprunje, ExcelSprunjer, etc... One could add a feature globally to all Sprunje in a sprinkle (not possible right now), like caching. It will also enabled to better separate thing and declutter curent Sprunje class.

Sprunje (another name could be used to avoid confusion) itself could implement variable feature thought implemented interface. Sprunjer could check if Sprunje implement SortableSprunjeInterface before applying sort for example.

Finally the array of 'options' should be replaced with specific property (because array based options are bad at type check).


I'll probably target 5.1 for this fix, therefor create a new issue and move caching feature there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
architecture Related to the framework architecture
Projects
None yet
Development

No branches or pull requests

2 participants