Implementation, that I use - http://symfony.com/blog/cross-application-links
// apps/backend/config/backendConfiguration.class.php
class backendConfiguration extends sfApplicationConfiguration
{
protected $frontendRouting = null;
public function generateFrontendUrl($name, $parameters = array())
{
return 'http://frontend.example.com'.$this->getFrontendRouting()->generate($name, $parameters);
}
public function getFrontendRouting()
{
if (!$this->frontendRouting)
{
$this->frontendRouting = new sfPatternRouting(new sfEventDispatcher());
$config = new sfRoutingConfigHandler();
$routes = $config->evaluate(array(sfConfig::get('sf_apps_dir').'/frontend/config/routing.yml'));
$this->frontendRouting->setRoutes($routes);
}
return $this->frontendRouting;
}
}
All work fine, but first call generateFrontendUrl function execute approximately 1-2 second.
How to correct this?
Related
I'm making a Laravel package, which is a basic API Wrapper to practice. I want my code completely re-usable and neat, well that's the reason we learn OOP I think :P
Let me first attach my code, and I'll explain what I'm trying to achieve via comments.
// This is how I'm calling my class
Shiprocket::
withCredential('other-than-default') // this is optional
->order(203504661) // pass order id
->details() // finally fetch the details
// This is my main class it's behind a Larvel Facade Accessor
class Shiprocket
{
protected $credentials;
protected $token;
// I'm using it as a constructor to initilize with a different credentil pair.
public function withCredential($credential_id)
{
$this->credentials = config('shiprocket.credentials')[$credential_id];
$this->token = $this->getToken();
return $this;
}
public function __construct()
{
$this->credentials = config('shiprocket.credentials')[config('shiprocket.default_credentials')];
$this->token = $this->getToken();
}
public function order($order_id = null)
{
return new OrderResource($order_id);
// Here my doubt starts
// I want to return another class (OrderResource) for Order related methods
// so that we can call Order related methods like:
// Shiprocket::withCredential('my-credential')->order()->getAll()
// and those methods will also use methods & properties of this Main class
// like the token, get(), post()
}
public function shipment($shipment_id = null)
{
return new ShipmentResource($shipment_id);
// and maybe I can also have more child classes like OrderResource
// So that I can call similar methods as OrderResource for shipments like ... ->getAll()
// or ... ->status()
// but these methods won't be reusable - they'll be completely different, just sometimes
// might have same names.
}
public function getToken(): string
{
$duration = config('shiprocket.token_cache') ? config('shiprocket.token_cache_duration') : 0;
return cache()->remember("shiprocket-{$this->credentials['email']}", $duration, function () {
return Http::post("https://apiv2.shiprocket.in/v1/external/auth/login", [
'email' => $this->credentials['email'],
'password' => $this->credentials['password'],
])->json()['token'];
});
}
public function get($url, $data = null)
{
return Http::withToken($this->token)->get($url, $data)->json();
}
public function post($url, $data = null)
{
return Http::withToken($this->token)->post($url, $data)->json();
}
}
It's okay even if you don't attach any code, maybe just guide me a bit what would be the best way to achieve something like this.
The chain methods that you want to apply it's called the Builder pattern
Builder is a creational design pattern that lets you construct complex objects step by step. The pattern allows you to produce different types and representations of an object using the same construction code.
you can learn and find snippets from here https://refactoring.guru/design-patterns/builder
back to your case, I cant agree that we need the builder pattern here, but let's try to have the small steps with your code, let's say you want to build Shiprocket object that contains the Order and the Shipment
the simple change you need is to return the Shiprocket so the code should look like this
<?php
class Shiprocket
{
protected $credentials;
protected $token;
private $order;
private $shipment;
public function withCredential($credential_id)
{
$this->credentials = config('shiprocket.credentials')[$credential_id];
$this->token = $this->getToken();
$this->order = null;
$this->shipment = null;
return $this;
}
public function __construct()
{
$this->credentials = config('shiprocket.credentials')[config('shiprocket.default_credentials')];
$this->token = $this->getToken();
$this->order = null;
$this->shipment = null;
}
public function order($order_id = null)
{
$this->order = new OrderResource($order_id);
return $this;
}
public function shipment($shipment_id = null)
{
$this->shipment = new ShipmentResource($shipment_id);
return $this;
}
public function getOrder(){
return $this->order;
}
public function getShipment(){
return $this->shipment;
}
public function getToken(): string
{
$duration = config('shiprocket.token_cache') ? config('shiprocket.token_cache_duration') : 0;
return cache()->remember("shiprocket-{$this->credentials['email']}", $duration, function () {
return Http::post("https://apiv2.shiprocket.in/v1/external/auth/login", [
'email' => $this->credentials['email'],
'password' => $this->credentials['password'],
])->json()['token'];
});
}
public function get($url, $data = null)
{
return Http::withToken($this->token)->get($url, $data)->json();
}
public function post($url, $data = null)
{
return Http::withToken($this->token)->post($url, $data)->json();
}
}
Note: the code could not be perfect when it comes to the standard and the best practice I just change it to follow your idea
I hope it's helpful
I have a controller in laravel, AppExportController. In one of my functions on that controller, I iterate over many records and return a file download. I decided I wanted to create a little function so I could cache a certain thing, a Zone Name in this instance.
This was my first attempt at writing a function to cache the zone names (the getZoneName function obviously):
<?php
namespace App\Http\Controllers;
class AppExportController extends Controller {
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct() {
$this->middleware('auth');
$this->middleware('client.approved');
}
public function prices(Request $request) {
$user = Auth::user();
...
$zoneNameCache = [];
function getZoneName($zoneId) use (&$zoneNameCache) {
try {
if (!empty($zoneNameCache[$zoneId])) {
return $zoneNameCache[$zoneId];
} else {
$zone = ServiceZone::find($zoneId);
$zoneNameCache[$zoneId] = $zone->name;
return $zone->name;
}
} catch(Exception $e) {
return '';
}
};
$prices = []; // I actually do a database query here, don't worry about that
$records = [];
foreach($prices as $price) {
// output to $records here
$records[] = [
...
getZoneName($price->service_zone_id),
...
];
}
return response();
}
}
This was making that route 500 error, and I tracked it down to being for sure the closure aspect of the function -- when I took out the use (&$zoneNameCache) part, it worked (but didn't cache anything of course).
So I tried another thing -- assigning the function to a variable instead. And that worked! With the closure, and caching was working!
<?php
namespace App\Http\Controllers;
class AppExportController extends Controller {
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct() {
$this->middleware('auth');
$this->middleware('client.approved');
}
public function prices(Request $request) {
$user = Auth::user();
...
$zoneNameCache = [];
$getZoneName = function ($zoneId) use (&$zoneNameCache) {
try {
if (!empty($zoneNameCache[$zoneId])) {
return $zoneNameCache[$zoneId];
} else {
$zone = ServiceZone::find($zoneId);
$zoneNameCache[$zoneId] = $zone->name;
return $zone->name;
}
} catch(Exception $e) {
return '';
}
};
$prices = []; // I actually do a database query here, don't worry about that
$records = [];
foreach($prices as $price) {
// output to $records here
$records[] = [
...
$getZoneName($price->service_zone_id),
...
];
}
return response();
}
}
I don't know why the second one should work but not the first one. Can anyone shed light on this?
Without assigning it to a variable, or returning it, it is not a closure.
This way you have function declaration, within another function or method in this case.
Which is not allowed, and therefore will give you a 500 for sure.
If you check your php error_log and probably your laravel log. It will tell you that.
If your do not want to assign it to a variable at that point, you could return it immediately
return function().......
I want to use a private method in a class called by public methods from the same class.
class Foo
{
private $updateAll = true;
private $updateA = false;
private $updateB = false;
public function updateA()
{
$this->updateAll = false;
$this->updateA = true;
$this->updateB = false;
$this->update();
}
public function updateB()
{
$this->updateAll = false;
$this->updateA = false;
$this->updateB = true;
$this->update();
}
private function update()
{
// Code here...
if ($this->updateAll) {
// set all api call params
}
if ($this->updateA) {
// set api call param
}
if ($this->updateB) {
// set api call param
}
// Code here...
}
}
Is this a proper use of class properties as arguments?
It works but I don't know whether there is a better way to do this. My purpose is to kinda use dynamic method arguments without the need to pass 3 arguments to update().
Your code is not wrong and should work just fine as you say, but it does feel a bit weird... I think any of the following approaches is cleaner and more flexible than your code. I'm sure there will be lots of other options perfectly valid, these are just some ideas...
Multiple method arguments
As it's been suggested to you in the comments, I think the normal way to do that is actually just adding the arguments to the update() method...
class Updater
{
public function update($all = true, $a = false, $b = false)
{
// Code...
}
}
One constant method argument
However, in your example, the options seem to be mutually exclusive (any combination of 2 options is redundant), so you can do perfectly fine with just one parameter!
class Updater
{
const UPDATE_ALL = 'all';
const UPDATE_A = 'a';
const UPDATE_B = 'b';
public function update($updateMode = self::UPDATE_ALL)
{
// Code...
}
}
Command pattern
If your example is not realistic, and you have a scenario with lots of options that are not mutually exclusive, I'd use something similar to a command pattern, where the class in charge to define the options of the operations is different from the class that performs the operation...
class Updater
{
public function update(UpdateCommand $command)
{
// Code...
}
}
class UpdateCommand
{
public $paramA = false;
public $paramB = false;
// ...
public $paramZ = false;
}
Fluent interface
Or you could also use a fluent interface. Although that's a bit harder to test...
class Updater
{
private $paramA = false;
private $paramB = false;
// ...
private $paramZ = false;
public function withA()
{
$this->paramA = true;
return $this;
}
public function withB()
{
$this->paramB = true;
return $this;
}
// ...
public function withZ()
{
$this->paramZ = true;
return $this;
}
public function run()
{
// Code...
}
}
I have a string of data that will be written to a file as a log of events, so I need this string available from the time the page begins to load to the time it is completed loading, at which time the contents of the string are written to the log file.
I am able to add to this string across some classes, but not others so it has me confused. When it doesn't work I get an 'allowed memory size of ... exhausted' error.
FILE: index.php
spl_autoload_register(function($class) {
if (file_exists(dirname(__FILE__).'/classes/'.$class.'.class.php')) {
include dirname(__FILE__).'/classes/'.$class.'.class.php';
}
});
$App = new Core();
$App->Visitor->getIP(); // This will exhaust memory...why?
$App->Settings->hello(); // Works
$App->writeLog('in my index file...'); // Works
$App->viewLog();
FILE: /classes/Core.class.php
class Core {
public static $logContent;
public function __construct() {
$this->initialize();
}
private function initialize() {
self::$logContent = 'Lets start...';
$this->Visitor = new Visitor($this);
$this->Settings = new Settings($this);
$this->Cache = new Cache($this);
}
public function writeLog($action) {
self::$logContent .= $action;
}
public function viewLog() {
echo self::$logContent;
}
}
FILE: /classes/Visitor.class.php
class Visitor {
private $App;
public function __construct($App) {
$this->App = $App;
}
public function getIP() {
$this->App->writeLog('getting ip...'); // Exhausts memory
if (isset($_SERVER['REMOTE_ADDR'])) {
return $_SERVER['REMOTE_ADDR'];
} else {
return false;
}
}
}
FILE: /classes/Settings.class.php
class Settings {
private $App;
public function __construct($App) {
$this->App = $App;
}
public function hello() {
$this->App->writeLog('getting ip...');
return 'hello';
}
}
What I can't figure out is that both Visitor.class.php and Settings.class.php are setup the same way with the same constructor and yet one will work and the other won't.
So as you can see, I made a static string that everything throughout the app can add to, then later this string will be written to a file one time. Am I going about this the wrong way?
The flow:
CreateNewTaskRequest -> CreateNewTaskService -> Task::writeFromNew() -> NewTaskWasCreated(domain event) -> DomainEventPublisher calls handle on subscribers.
Following the flow above, I'm wondering where do you add subscribers for domain events?
I'm currently reading the book DDD in PHP, but I'm unable to grasp where this should be done?
This is the code I have but feels wrong to me
public static function writeNewFrom($title)
{
$taskId = new TaskId(1);
$task = new static($taskId, new TaskTitle($title));
DomainEventPublisher::instance()->subscribe(new MyEventSubscriber());
$task->recordApplyAndPublishThat(
new TaskWasCreated($taskId, new TaskTitle($title))
);
return $task;
}
Task extends Aggregate root:
class AggregateRoot
{
private $recordedEvents = [];
protected function recordApplyAndPublishThat(DomainEvent $domainEvent)
{
$this->recordThat($domainEvent);
$this->applyThat($domainEvent);
$this->publishThat($domainEvent);
}
protected function recordThat(DomainEvent $domainEvent)
{
$this->recordedEvents[] = $domainEvent;
}
protected function applyThat(DomainEvent $domainEvent)
{
$modifier = 'apply' . $this->getClassName($domainEvent);
$this->$modifier($domainEvent);
}
protected function publishThat(DomainEvent $domainEvent)
{
DomainEventPublisher::instance()->publish($domainEvent);
}
private function getClassName($class)
{
$class = get_class($class);
$class = explode('\\', $class);
$class = end($class);
return $class;
}
public function recordedEvents()
{
return $this->recordedEvents;
}
public function clearEvents()
{
$this->recordedEvents = [];
}
}
The DomainEventPublisher class is a singleton, and you can add a subscriber with
DomainEventPublisher::instance()->subscribe(new YourSubscriber());
where YourSubscriber implements DomainEventSubscriber.