I am using the ZendDebugToolbar and it displays fine on the app, however, how do I send custom debug data to it? For example if I want to dump some key session information to it or a simple var_dump ?
I assume you are referring to the ZFDebug.
Since ZFDebug operates as a front-controller plugin that fires only on dispatchLoopShutdown(), it really only has access to variables that are available there, typically long-lived singleton instances from classes like Zend_Registry, Zend_Controller_Front (so you can get the request and response objects), etc. There is really no mechanism for direct communication between internal processes - like models and controllers - and the ZFDebug plugin.
So, for the kind of debugging about which you ask - var_dump() of your own custom variables and introspecting session data, presumably in other parts of system like services, controllers, models, etc - it might be easiest to simply add that data to Zend_Registry and then examine it later in ZFDebug under the Variables tab.
However, if you really want to add something new to the ZFDebug interface itself, then you can use its own internal plugin system to add tabs/panels to its interface.
It looks like you can simply create a class that implements the interface ZFDebug_Controller_Plugin_Debug_Plugin_Interface (link) and then register your custom plugin with the main $debug object during bootstrap.
Something like this:
/**
* See some of the other plugin implementations for examples of what could go into each of
* these methods.
*/
class My_ZFDebug_Controller_Plugin_SomePlugin implements ZFDebug_Controller_Plugin_Debug_Plugin_Interface
{
/**
* Has to return html code for the menu tab
*
* #return string
*/
public function getTab()
{
// #todo
}
/**
* Has to return html code for the content panel
*
* #return string
*/
public function getPanel()
{
// #todo
}
/**
* Has to return a unique identifier for the specific plugin
*
* #return string
*/
public function getIdentifier()
{
// #todo
}
/**
* Return the path to an icon
*
* #return string
*/
public function getIconData()
{
// #todo
}
}
Then in Bootstrap:
protected function _initZFDebug()
{
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->registerNamespace('ZFDebug');
$options = array(
'plugins' => array('Variables',
'Database' => array('adapter' => $db),
'File' => array('basePath' => '/path/to/project'),
'Cache' => array('backend' => $cache->getBackend()),
'Exception')
);
$debug = new ZFDebug_Controller_Plugin_Debug($options);
// register your custom sub-plugin
$debug->registerPlugin(new My_ZFDebug_Controller_Plugin_SomePlugin());
$this->bootstrap('frontController');
$frontController = $this->getResource('frontController');
$frontController->registerPlugin($debug);
}
As usual, you will have to have autoloading in place for the namespace My_ or whatever you use for your custom class.
Remember, the same constraint as before applies: the only data available to your plugins are the long-lived instances that you can statically pull out of the ether; things like Zend_Registry, Zend_Controller_Front (hence request/response), etc.
#vinygarcia87 is the right answer.
Could not select it as the right answer because you typed it as a comment.
Related
I'm working on my HMVC project.
First: I have a list of helper/utilities classes, used to accomplish specific tasks: Arrays, Classes, Files, Log, Messages, Images, Encryption, etc.
For example, in the Arrays class I defined a function to read an array value in a multidimensional array by a given keypath (ex: get 'app/paths/modules' value).
For some classes, some of them are required dependencies, therefore beeing mandatory to be injected in constructors. Like, the Array class is a mandatory dependency of the Config class, used to read the values from the application configurations array.
For other classes they are not required dependencies. Like the Log class. It's used sometimes in controller actions, or in QueryBuilder methods, for logging purposes.
I would like to know, how the instances of this type of classes should be injected.
As setter dependencies, or
as arguments in the methods which are using them?
Second: Should I consider a Request class as a required, e.g. constructor dependency in controllers?
I'm also using a dependency injection container.
Thank you.
Edit
Removed bullet lists from "For some classes..." and "For other classes...".
EDIT 2
Here is an example of using Arrays class inside ConnectionConfiguration:
/*
* Connection configuration.
*/
namespace [...]\Database;
use PDO;
use [...]\Config;
use [...]\Utils\Arrays;
/**
* Connection configuration.
*/
class ConnectionConfiguration {
/**
* Config.
*
* #var Config
*/
private $config;
/**
* Arrays.
*
* #var Arrays
*/
private $arrays;
/**
* Connection name.
*
* #var string
*/
private $connectionName;
/**
* Default connection attributes.
*
* #var array
*/
private $defaultConnectionAttributes = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => FALSE,
PDO::ATTR_PERSISTENT => TRUE
);
/**
*
* #param Config $config Config.
*/
public function __construct(Config $config, Arrays $arrays) {
$this
->setConfig($config)
->setArrays($arrays);
}
/**
* Get the connection attributes (merged over the default ones).
*
* #return array
*/
public function getConnectionAttributes() {
$defaultAttributes = $this->getDefaultConnectionAttributes();
$connectionAttributes = $this->getConnectionAttributes();
return $this->getArrays()->mergeArrays($defaultAttributes, $connectionAttributes);
}
}
I personally use Request as dependency of controller's method, that actually needs it.
As for the rest of your code, it seem that you are attempting to shove too much within controller. I would recommend for you to add a "service layer", that handles the application logic, with each controller only depending on those services as requirements in constructor.
To add anything more, you will have to show some code.
I'm working on a Symfony (2.7.4) website where some users have their own language resources for their own locales. For example, a user might have two locales (for example fr and en) and another user could also have one or all of these locales.
Each user has the ability to edit its own translations in a third party app, so translations are not shared between users.
I would like to be able to load the appropriate (YML or XLIFF) resources file when accessing a user's page, based on the locale (which is defined in the URL) and the user (could be its ID or anything that identifies it).
For example, when visiting user99.my-domain.ext/fr/ I'd like to add [base_directory]/user99/messages.fr.yml to the resources loaded by the Translator so it overrides the keys in the base messages.fr.yml.
I've tried to inject the Translator in my service, but I can only use it for reading translations, not adding any. What would be the best way to do that? Or is doing it in a service is too late? Maybe the Kernel is a better place?
Any help is appreciated!
Note: I'm using the YAML format in my examples, but any of the Symfony-known formats is eligible.
In order to "override" translations you should decorate the translator service. That way your own translator logic will be executed when trans() is called somewhere.
http://symfony.com/doc/current/components/dependency_injection/advanced.html#decorating-services
By decorating the service other bundles will also start using the logic you did describe above. You can inject the active user (eg. token_storage service) and some caching services (eg. https://github.com/doctrine/DoctrineCacheBundle) to make sure your user gets the right translations.
This isn't related to the request or hostname, your translation logic for the user should happen after the firewall / authorization logic was executed.
See Symfony's LoggingTranslator PR to find out how the decorator pattern was used to let the translator log missing translations: https://github.com/symfony/symfony/pull/10887/files
I chose to use a custom Twig filter, so I can decide when I want user specific translations and when I want generic ones.
Here's my extension (my users are in fact Domain instances):
<?php
// src/AppBundle/Twig/DomainTranslationExtension
namespace AppBundle\Twig;
use AppBundle\Document\Domain;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Translation\Loader\YamlFileLoader;
use Symfony\Component\Translation\Translator;
class DomainTranslationExtension extends \Twig_Extension {
/**
* #var ContainerInterface
*/
protected $container;
/**
* #var Translator
*/
protected $translator;
/**
* #var string
*/
protected $locale;
/**
* #var Domain
*/
protected $domain;
public function setContainer(ContainerInterface $container) {
$this->container = $container;
$this->locale = $this->container->get('request_stack')->getMasterRequest()->getLocale();
$domainService = $this->container->get('app.domain_service');
$this->domain = $domainService->getDomain();
// TODO: File loading error check
$this->translator = new Translator($this->locale);
$this->translator->addLoader('yaml', new YamlFileLoader());
$this->translator->addResource('yaml', 'path/to/domain-translations/' . $this->domain->getSlug() . '/messages.' . $this->locale . '.yml', $this->locale);
}
public function getFilters() {
return array(
new \Twig_SimpleFilter('transDomain', array($this, 'transDomain')),
);
}
public function transDomain($s) {
$trans = $this->translator->trans($s);
// Falling back to default translation if custom isn't available
if ($trans == $s) {
$trans = $this->container->get('translator')->trans($s);
}
return $trans;
}
public function getName() {
return 'app_translation_extension';
}
}
Declared like that in app/config/services.yml:
app.domain_service:
class: AppBundle\Services\DomainService
arguments: [ #request_stack, #doctrine_mongodb, #translation.loader ]
And used like that in a Twig file:
{{ 'my.translation.key'|transDomain }}
I hope this helps, thanks!
I was developing codeigniter app for last 2 years and since i started my mvc pattern styling from codeigniter itself, now i'm not a heavy command line user so at first i did had some learning curve with codeigniter but i crossed it and started developing apps with code igniter because we don't need to configure a lot and everything was inside one zip file but now as unfortunately codeigniter is dead and i'm just one person in my team i have to rely on other third party tools which are trusted by others so i decided to switch to laravel, now at starting it was way way tough to migrate from codeigniter because composer and every other stuff, but somehow i crossed that too, but i'm now confused with routing and other stuff and i've tried many tutorials but i'm still not able to see how can i migrate from application where i'm managing students, where they can change email, change phone number updated stuff, in codeigniter it was easy but i don't how to approach this stuff in routing of laravel, now this question sounds way to dumb for community who is already working on laravel but if you see from my point of view it is going to affect my bread and butter. This is how i use to approach in codeigniter
class Student extends CI_Controller{
// usual piece of code of constructor
function update_email()
{
// piece of code to update email
}
}
but now with laravel routing system and all i've no idea how to approach this a resource controller looks like this
<?php
class StudentController extends \BaseController {
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
}
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* #return Response
*/
public function store()
{
//
}
/**
* Display the specified resource.
*
* #param int $id
* #return Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param int $id
* #return Response
*/
public function update($id)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return Response
*/
public function destroy($id)
{
//
}
}
now every part is okay but how can i approach things where i've to update only email address or only phone number and stuff
Actually, in your question you have a RESTful controller which could be confusing for you at this time because you are new to Laravel and used CI, so probably you are very so much used with automating URL mapping without route. In this case, for ease, I suggest you to use a plain controller and that is almost same thing that you've did in CI but here in Laravel you have to declare route for every action. So, just create two routes like these:
Rouite::get('something/edit/{id}', array('uses' => 'StudentController#edit', 'as' => 'edit.record'));
Rouite::post('something/update/{id}', array('uses' => 'StudentController#update', 'as' => 'update.record'));
Then create a class/Controller and declare these methods:
class StudentController extends baseController {
// URL: http://example.com/something/edit/10 and it'll listen to GET request
public function edit($id) {
// $record = Load the record from database using the $id/10
// retuen View::make('editform')->with('record', $record);
}
// URL: http://example.com/something/update/10 and it'll listen to POST request
public function update($id) {
// Update the record using the $id/10
}
}
In your form, you need to use http://example.com/something/update/10 as action and you may use route('update.record') or url('something/update/10') to generate the action in the form. Read more on Laravel Documentation.
What you have created (or maybe rather generated) here is called Restful controller. It is some 'standard way' to manage CRUD actions (create/read/update/delete). However there is no need to do it this way. You can add in your controller whatever methods you want and not use Restful Controllers at all. That's your choice.
You can create in your function new method
function updateEmail()
{
// do here whatever you want
}
and in your routes.php file add new route:
Route::match(array('GET', 'POST'), '/changegemail', 'StudentController#updateEmail');
Now you can write your code for this method and it will work.
I'm practicing a little of PHP OO, I don't work actively with it, so I am sort of creating my own API to create websites. I'm a big fan of Laravel and I've been using it as reference to develop it and learn more of PHP and OO in the process, however now I've hit the wall.
I'm trying to build an Exception Handler in my "API" to handle 404 errors and such. I looked into Laravel and this is how you do it:
App::missing(function($exception)
{
return Response::view('errors.missing', array(), 404);
});
So, it's using a callback, and I went to see what Laravel was doing with it, and here is the thing: I can't understand how this works.
The code can be found here: https://github.com/laravel/framework/blob/master/src/Illuminate/Foundation/Application.php
I'll just put what I was looking into:
/**
* Register a 404 error handler.
*
* #param \Closure $callback
* #return void
*/
public function missing(Closure $callback)
{
$this->error(function(NotFoundHttpException $e) use ($callback)
{
return call_user_func($callback, $e);
});
}
So far I can understand, but then there is the $this->error(....); so let's see that:
/**
* Register an application error handler.
*
* #param \Closure $callback
* #return void
*/
public function error(Closure $callback)
{
$this['exception']->error($callback);
}
This I cannot understand. $this is an object, referencing itself, but it's referenced by an index, like in an array? And more, it's calling a method.
I'm sorry, but it's the first time I see this. How do you make the $this work as an array? And even further, call a method with it? I've been googling it around but I can't find a name for this, or what is it.
I believe, further in this class, there is something related to $this['exception']->error($callback);:
/**
* Register the core class aliases in the container.
*
* #return void
*/
public function registerCoreContainerAliases()
{
$aliases = array(
'...' => '...', // other stuff
'exception' => 'Illuminate\Contracts\Exception\Handler',
'...' => '...', // other stuff
);
foreach ($aliases as $key => $aliases)
{
foreach ((array) $aliases as $alias)
{
$this->alias($key, $alias);
}
}
}
But then, if I look at 'Illuminate\Contracts\Exception\Handler', it's just an interface. As far as I know, you implement an interface and then use the implementation, you don't call the interface directly. So that's kinda confusing too.
Link for the Handler class: https://github.com/laravel/framework/blob/master/src/Illuminate/Contracts/Exception/Handler.php
As you can see in the source code, Application extends Container which in turn implements ArrayAccess:
Interface to provide accessing objects as arrays.
Instances of a class implementing this interface can be accessed as if they were arrays, which is what happens in $this['exception'].
That is because Application class in which you have found the confusing line is inherited from Container.
Container class implements ArrayAccess interface which is used to provide accessing objects as arrays.
I need to cache some info about a user who is logged in (such as security groups, name, username, etc.)
Currently I have a separate class to achieve just this, lets call it CurrentUserHelper. Given a user object, it will cache the appropriate data and save store info in the $_SESSION variable.
The issue is I'm finding a bunch of classes relying just on CurrentUserHelper because they only need a couple of common fields. In fact, most of the functions have the same name as my User class. There's a couple of functions in CurrentUserHelper, such as getSecurityGroupsNames(), that contains a cache of all security group names, but there is no reason this function name could not be in the user class also.
Instead, should I create a CachedUser class and pass this around? This class can extend User, but then I can override getName(), getSecurityGroups(), etc, and returned the cached data, and not preform db requests to get the data.
The downside of passing around a CachedUser object is that this kind of hides the fact the data isn't really up to date if a constructor/function is accepting a type User. I also need to find way to handle merging the entity with Doctrine 2, and making sure entities associating themselves with a CachedUser won't break. If I decide to cache some temporary data (such as # of page views since logged in), this property shouldn't be part of the User class, it's more about the current user's session.
If I continue using the CurrentUserHelper class, maybe I should create an interface and have both CurrentUserHelper and User for the common functionality the two classes would share?
Preface: Extension isn't the best way for these sorts of things.. I'm sure you've heard composition over inheritance shouted at you over and over again. In fact, you can even gain inheritance without using extends!
This sounds like a good use-case for the decorator pattern. Basically, you wrap your existing object with another one that implements the same interface, so it has the same methods as the inner object, but this object's method adds the extra stuff around the method call to the inner object, like caching, for example.
Imagine you have a UserRepository:
/**
* Represents an object capable of providing a user from persistence
*/
interface UserProvider
{
/**
* #param int $id
*
* #return User
*/
public function findUser($id);
}
/**
* Our object that already does the stuff we want to do, without caching
*/
class UserRepository implements UserProvider
{
/**
* #var DbAbstraction
*/
protected $db;
/**
* #var UserMapper
*/
protected $mapper;
/**
* #param DbAbstraction $db
* #param UserMapper $mapper
*/
public function __construct(DbAbstraction $db, UserMapper $mapper)
{
$this->db = $db;
$this->mapper = $mapper;
}
/**
* {#inheritDoc}
*/
public function findUser($id)
{
$data = $this->db->find(['id' => $id]);
/** Data mapper pattern - map data to the User object **/
$user = $this->mapper->map($data);
return $user;
}
}
The above is a really simple example. It'll retrieve the user data from it's persistence (a database, filesystem, whatever), map that data to an actual User object, then return it.
Great, so now we want to add caching. Where should we do this, within the UserRepository? No, because it's not the responsibility of the repository to perform caching, even if you Dependency Inject a caching object (or even a logger!).. this is where the decorator pattern would come in useful.
/**
* Decorates the UserRepository to provide caching
*/
class CachedUserRepository implements UserProvider
{
/**
* #var UserRepository
*/
protected $repo;
/**
* #var CachingImpl
*/
protected $cache;
/**
* #param UserRepository $repo
*/
public function __construct(UserRepository $repo, CachingImpl $cache)
{
$this->repo = $repo;
$this->cache = $cache;
}
/**
* {#inheritDoc}
*
* So, because this class also implements UserProvider, it has to
* have the same method in the interface. We FORWARD the call to
* the ACTUAL user provider, but put caching AROUND it...
*/
public function findUser($id)
{
/** Has this been cached? **/
if ($this->cache->hasKey($id))
{
/**
* Returns your user object, or maps data or whatever
*/
return $this->cache->get($id);
}
/** Hasn't been cached, forward the call to our user repository **/
$user = $this->repo->findUser($id);
/** Store the user in the cache for next time **/
$this->cache->add($id, $user);
return $user;
}
}
Very simply, we've wrapped the original object and method call with some additional caching functionality. The cool thing about this is that, not only can you switch out this cached version for the non-cached version at any time (because they both rely on the same interface), but you can remove the caching completely as a result, just by changing how you instantiate this object (you could take a look at the factory pattern for that, and even decide which factory (abstract factory?) depending on a configuration variable).