I have a class called Sharer, which accepts a Service interface in the construct method. Service can be FacebookService or TwitterService and so on. Each Service class has a post method, that posts whatever array data you pass to that method, using its own connection (either facebook, twitter in this example).
Now the Sharer class normalizes data before sending it to that service's post method. By normalizing, it checks whether the thing we are sending to that post method is just a simple array or a Model class. Model can be either Project model, or Image model, or Video model and so on.
If it is a model class, then it calls that specific model's transformer. Transformers are just helper classes, that accept the model instance and they have two methods - facebook and twitter in this case. And each method returns a formatted array, specific to the connection.
So for example, facebook method grabs the required fields (that are needed to post on facebook) from the model and sends that array back. And twitter method does the same for twitter's required fields.
Now the thing I am a bit stuck with, is calling that specific method on the transformer class. I want to do something like this:
if(we are sharing on facebook) {
then call the facebook method
}
if(we are sharing on twitter) {
then call the twitter method
}
but obviously I want to somehow make it dynamic and not have these if statements. What would be a better approach to this?
I solved it doing this:
$method = $this->resolveMethodToCall();
protected function resolveMethodToCall()
{
$reflection = new ReflectionClass($this->service); // service being either a FacebookService class or TwitterService
$shortName = $reflection->getShortName();
return strtolower(str_replace('Service', '', $shortName));
}
Probably not the best solution, but works well and after this I am checking if the resolved method actually exists on the transformer class and throw an exception if it doesn't.
Related
Project: Online Hotel Booking portal
Page: User dashboard. Here user can add property and details (basic details, rooms, amenities, etc.)
Problem:
In the User Dashboard page, we ave several pages (Basic details, policies, room details, images, etc). One controller for each controller. For each controller, I am using a middleware VerifyPropertyUserMiddleware. Now I require fetching Property model in every single controller.
$ppt = PropertyMaster::findOrFail($pID);
Solutions that I can think of
Create this instance in middleware and pass it to the controller. (but I think middlewares are not supposed to do this job)
Create a trait, inside that trait create a method getProperty (but code duplication is still a problem as I will have to call the method in every controller)
Use sessions. But still, code duplication is still there because in every controller I will have to check whether the laravel session has $ppt variable or not.
Here's an example of a trait used to enrich an object during construction. This particular mode of enrichment means when your upstream object is instantiated, you'll then have the property in all it's glory to work with downstream, or an exception to handle.
trait PropertyAware
{
private $property;
private function loadProperty(int $id): void
{
$this->property = PropertyMaster::findOrFail($id);
}
}
class PropertyFoo
{
use PropertyAware;
public function __construct(int $propertyId)
{
$this->loadProperty($propertyId);
}
}
As far as using the trait on a controller, I would tend to prefer a boundary operation and get the Property object fulfilled from the URL by contract:
Route::get('dashboard/properties/{property}', function (App\Property $property) {
// Use the hydrated $property.
});
That will make more sense than using a trait (or using a trait on a base controller, which seems odd to do), and then passing a trait method an id.
Generally I would recommend enrichment privately applied, bracketing an envelope process perhaps, where in transit it's an identifier, but when the message is opened or applied (as in a url request), it's enriched or enrichable by trait.
In this case, the enrichment happens in a url boundary operation, or when unwrapped to pass a message to a handler of some sort (a bus pattern). The attempt here is skinny objects that interpret by nature into known representations (controller pattern using Route Models, for instance), or a property dictionary object that can de-reference it's own relationships (an object of trait).
I have a service file that processes data and stores it in private fields. Many queries are executed, hence I'd like to instantiate the service file only once and access data from the fields when necessary in later stages of the request's lifecycle.
I've tried registering the service file in Laravel's service provider using the following snippet, but it did not seem to work as I expected.
$this->app->singleton('App\Services\UserService', function ($app) {
return new App\Services\UserService();
});
In my case, the first time I called the service methods was in my middleware class. The particular methods I called should've set many private fields in place which I could later use. Service file was loaded in using the "injection" method.
public function __construct(UserService $user_service) {
$this->user_service = $user_service;
}
However, once the request finally proceeded to the controller method, the fields in the service object had been nulled and I had to call the "heavy" methods once again.
Within the the controller constructor method, I resolved the service file using the resolve() helper method, however I don't think that would've made a difference.
Is there something I've missed or misunderstood?
Any help or pointers are appriciated!
I have a question about correct way of implementing factory pattern in PHP used for instantiating complex objects with their dependencies. Let's assume the factory class has a 'build' method, so that for example class User is created in following way:
$factory->build('User');
The class User needs to retrieve the user data from the repository (database), so it depends on Repository object - the constructor looks like:
public function __construct(Repository $repository);
This means that 'build' method of the factory needs to call something like this
$user = new User(new Repository());
Now let's assume I also need to instantiate HomeController object which displays content on the home page. It is retrieving a list of latest articles - to display them on the home page, so it needs repository object as well. So build method will call something like this:
$home = new HomeController(new Repository());
So it is clear now that we have two instances of Repository object, while in fact one instance would be probably enough in this case. So I was wondering if it is a good practise for factory pattern to actually register instantiated Repository object (store it in $registeredObjects array of Factory object) and return it from the table if it was instantiated before. So the object creation in build method would look then like so:
$user = new User($this->build('Repository')); // Here Repository is created first time.
$home = new HomeController($this->build('Repository')); //Here it is retrieved from list of already registered objects
Repository object act in fact as a singleton in this case. I am wondering whether this approach is correct or it is better to instantiate two independent Repository objects.
Suppose (as an example) that I have a class which I want to log all method calls to.
In PHP this can be accomplished quickly and easily with __call(), or in Python with decorators.
What would be the easiest way to accomplish the same thing in Actionscript 3?
Extend flash.utils.Proxy and use the flash.utils.flash_proxy namespace. There's methods similar to __get, __set and methods for delete methods as well. For example, the __call method is:
override flash_proxy function callProperty(name:*, ...rest):*;
so if have a class that extends Proxy, you do:
var test:MyObject = new MyObject();
test.myMethodThatIsntDefined("param");
then callProperty will be called and name will be set to "myMethodThatIsntDefined" and "param" will be in the ...rest array.
The link to the asdoc has a simple implementation that should get you going. I typically use the Proxy class for something like an API. For example, back in the day I had a Flickr API wrapper that translated the name of the function call to an API method name in the Flickr API. Something like:
flickr.galleriesGetPhotos();
and in the callProperty I'd split on the first word to get the API name "flickr.galleries.get_photos". The names were different back then I think.
You can try using the Proxy class.
dynamic class MyProxy extends Proxy {
flash_proxy override function callProperty(name:*, ...rest):* {
try {
// custom code here
}
catch (e:Error) {
// respond to error here
}
}
Refer:http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/utils/Proxy.html
Here is a quick overview of the controllers functionality in most of the application:
controller loads a specific model, gets data from it, formats the data and passes the formatted data to the view.
Now there is a search page, which needs to do a search query over entire database (all models). It needs to show each type of data in its particular formatted output on a single page as a list.
The problem:
The search controller can do the search, dynamically load model for each record type, and get the data from model. Problem comes when the data needs to be formatted. I am trying to load the specific controller from the search controller, which is causing problems.
What to do?
PS: I tried using the 'Wick' library, but it fails when the controller's format function tries to use its own model and session object, giving errors about call to a member on a non-object.
After much refactoring and trial/error, It appears that the best way to achieve the above is this way:
Keep the format function in the base controller from which all other controllers are derived. The format options are passed to the function along with the data object as arguments.
Make a static function in each derived controller, which returns the formatting options of the data.
Inside the search controller (which is itself derived from the base controller), for each data object, call the static function of its particular controller which returns the data formatting options, then use that to format the object for the view.
I guess I can say I will stick to using the model only for interaction with the database, and let everything else be done by controller. If anyone has a better solution still, I am all ears.
It sounds like you want to use the Factory design pattern
Make this a library:
class MyModelFactory {
static public function Factory($data) {
$type = key($data);
return new $type($data);
}
}
now, in your controller, you can do something like this:
$model = MyModelFactory::Factory(array($_REQUEST['model'] => $_REQUEST));
and now you have an object of whatever model was specified in $_REQUEST['model']. Be sure to take any security precautions you may need for your application to assure the user has permissions to use the model that they request
Now, since you want to be using common methods and stuff, your models should probably be based off an abstract class / interface.. so instead of
class MyModelOne extends Model {
// stuff
}
You probably want something like this, to ensure your required methods will always be available:
abstract class MyAbstractModel extends Model {
protected $search_params;
public function __construct($data = array()) {
$search_params = $data['search_params'];
}
protected function GetSearchParameters() {
return $this->search_params;
}
abstract public function GetData();
abstract public function GetColumns();
abstract public function DefineViewOptions();
}
class MyModelOne extends MyAbstractModel {
public function GetData() {
$params = array();
$params[] = $this->db->escape_str($this->GetSearchParameters());
// return whatever data you want, given the search parameter(s)
}
public function GetColumns() {
// return some columns
}
public function DefineViewOptions() {
// return some configuration options
}
}
In general you can't load another controller from within a controller in CodeIgniter (although there are mods that allow you to do something like this).
I would try creating a class for formatting your data and add it to the application/library folder. Then load, use and re-use this class throughout your various controllers.
Here is a page from the CodeIgniter documentation Creating Your Own Libraries that explains the details and conventions.
Also, if a class is overkill, creating helper functions is an even lighter approach.
The difference between libraries and helpers in CodeIgniter is that libraries are classes, helpers are just a group of php functions.
Once you have formatted your data, you can load any view from any controller, so you should still have all the re-usability you need so you DRY (don't repeat yourself)
There are a few simple approaches based on the principle of what's simpler (versus what's perfectly DRY). Here's one alternative approach I use with CodeIgniter:
Instead of trying to load multiple controllers, reuse the view fragments from your search controller (or search route, depending which you're using). This requires using the same naming conventions for your data elements so the views are interchangeable, but you should be doing this anyway.
Instead of using multiple models for search, add a single Search model that knows about the things that can be searched on. If you want to prevent duplicate SQL, reuse the SQL between models (this can be done using constants, or loading SQL from disk).
Controllers are not great candidates for reuse from your own PHP code: they route actions and requests for resources to the things themselves. They are intended to be called via HTTP, using the URI interface you've come up with. Calling them from code is a coupling you want to avoid. That said, reusing controllers from JavaScript (or via cURL) is a great, decoupled way to reuse things in any web framework.