Custom setters and getters in Laravel - php

Here's a tricky question.
I am building a framework in Laravel and I want my objects to interact with Rackspace in a transparent way.
From now on I made it possible to upload/delete objects without having in mind Rackspace
$model->file = Input::file('thing'); // and it uploads to Rackspace.
The next step I want to achieve is to get the route using my config file. The behaviour would be something like $route = $file->source (with source with hello.jpg in the database for instance) and get $route as rackspace.com/WHATEVER/hello.jpg. The part rackspace.com/WHATEVER is in my config file, so the only thing I need is how to make this behaviour.
I have been searching extensively and I only found the __call() method to do so.
The fields I want to behave like this are dynamic and are setted from an array such as:
public static $rackspaceable = array('source' => 'images-demo');
Where images-demo is a Rackspace container.
Does anyone knows to achieve that and if it is even possible?

This might be what you are looking for:
class Model extends Eloquent {
public static $rackspaceable = array('source' => 'images-demo');
public function __get($key)
{
if (isset(static::$rackspaceable[$key]))
{
return static::$rackspaceable[$key];
}
return parent::__get($key);
}
public function __set($key, $value)
{
if (isset(static::$rackspaceable[$key]))
{
static::$rackspaceable[$key] = $value;
}
else
{
parent::__set($key, $value);
}
}
}
To use it:
$model = new Model;
var_dump( $model->source );
$model->source = 'new value';
var_dump( $model->source );

Related

Use instance of child class instead of parent class given a condition

I'm working on breaking up a large, monolithic class into several subclasses, but it's too much to do all at once so I'm looking to split them out one by one over several releases as time permits. It's an authentication class that authorizes some channel, so currently it looks like this:
$auth = new Auth($user, $data);
$output = $auth->authChannel($channelName);
Inside Auth, it basically looks like this:
public function __construct($user, $data)
{
$this->user = $user;
$this->data = $data;
}
public function authChannel($channel)
{
$this->setUserData();
if (isset(self::CHANNEL_AUTH_FUNCTIONS[$channel])) {
$authFunction = self::CHANNEL_AUTH_FUNCTIONS[$channel];
return $this->$authFunction();
} else {
// invalid channel
}
}
So self::CHANNEL_AUTH_FUNCTIONS is basically ['channelA' => 'authChannelA', 'channelB' => 'authChannelB'], etc., and all those functions are in this one class.
Now what I want to do, one at a time, is if $legacyChannel => callLegacyFunction() / else $newChannel => instantiate its own class and call auth().
So I put Auth.php into its own namespace and have the new Channel.php class in that same namespace. And Channel extends Auth.
Currently I have this:
public function authChannel($channel)
{
$this->setUserData();
if (isset(self::CHANNEL_AUTH_LEGACY_FUNCTIONS[$channel])) {
$authFunction = self::CHANNEL_AUTH_LEGACY_FUNCTIONS[$channel];
if ($authFunction) {
return $this->$authFunction();
} else {
$authClassName = __NAMESPACE__ . '\\' . ucwords($channel);
$authClass = new $authClassName($user, $data);
return $authClass->auth();
}
} else {
// invalid channel
}
}
Is there a better way to do this? Currently it seems a bit wasteful since two different objects are created and the setUserData() function for example would need to be called again I believe. I'm also wondering if there's a better way to get the dynamic class name other than through __NAMESPACE__ . / . $className.
You'll have to work quite a bit until that code starts looking better. I'll try to suggest as few changes as possible, to make "migration" as painless as possible, although you are a few steps removed from a clean design.
To start with, you can create an AuthStrategyInterface for your new authentication classes.
interface AuthStrategyInterface
{
public function supports(string $channel): bool;
public function auth($user, $data);
}
Each of your new authentication classes should implement this interface. The method supports($channel) is easy enough to understand: if a authentication class can deal with certain channel, it should return true.
Your Auth class would need a way to get these strategies injected. Usually you would do that in the constructor... but to leave your API unchanged we'll just create a setter method for that.
When executing authChannel(), it will first check on the injected strategies to see if any supports the used $channel, and use that if possible. If not, goes back to check your old implementations.
This way you do not need to touch any of the old code as you add new authentication strategies. As you add new implementations, you are gradually strangling the legacy system. At one point no of the old implementations are used, and you can move on to a new code refactoring phase.
class Auth {
private iterable $strategies = [];
public function __construct($user, $data)
{
$this->user = $user;
$this->data = $data;
}
public function setAuthStrategies(iterable $strategies)
{
$this->strategies = $strategies;
}
public function authChannel($channel)
{
$this->setUserData();
// check if any of the new strategies supports
foreach ($this->strategies as $strategy) {
if ($strategy->supports($channel) {
return $strategy->auth($this->user, $this->data);
}
}
// check "legacy" authentication methods.
if (isset(self::CHANNEL_AUTH_FUNCTIONS[$channel])) {
$authFunction = self::CHANNEL_AUTH_FUNCTIONS[$channel];
return $this->$authFunction($this->user, $this->data);
}
// no valid authentication method
return false;
}
}
To use it, you would do something like this:
$fooAuthStrategy = new FooAuthStrategy();
$barAuthStrategy = new BarAuthStrategy();
$bazAuthStrategy = new BazAuthStrategy();
$auth = new Auth($user, $data);
$auth->setAuthStrategies(
[
$fooAuthStrategy,
$barAuthStrategy,
bazAuthStrategy
]
);
$auth->authChannel($channel);
The specifics would change according to how exactly your application is set-up, but something like this would take you further in a good direction than your current approach.
I don't know if I understood the question correctly, but you couldn't do it like that?
public function authChannel($channel)
{
$this->setUserData();
if (!isset(self::CHANNEL_AUTH_LEGACY_FUNCTIONS[$channel])) {
// Invalid channel
return;
}
return self::CHANNEL_AUTH_LEGACY_FUNCTIONS[$channel]
? $this->$authFunction()
: parent::auth();
}

PHP Classes function inside function?

I'm self-studying the PHP language. And I'm focused on the latest PHP OOP language.
I search for some "ready-to-install" PHP software and as I scan for some references to search and know, I saw lines of code with a structure like this (can't remember so I'll create my own):
$myapp->settings->getValue('openforum');
$myapp->settings->setValue('closeformaintenance', '1');
So my question is, how can I reproduce the code above? I don't know what term to use that line of code (objects, I guess?).
Something like this:
$newLogin->search($uid)->setLogin($dateToday);
Like that. I really need to do that way so I can organize my coding structure. Thanks by the way.
And also for the final question, IS THAT POSSIBLE?
Here's a fairly straight forward way of looking at it, using dependency injection.
Try it out: https://3v4l.org/iSJgL
Note, the below requires PHP 7 due to the string type hint. Remove that and I believe it should work in 5.6 just fine.
<?php
$myapp = new MyApp(new SettingsBag([
'works' => false,
'random' => rand(),
]));
var_dump($myapp->settings()->get('random'));
var_dump($myapp->settings()->get('works'));
// Let's change it up...
$myapp->settings()->set('works', true);
// Now it should be true.
var_dump($myapp->settings()->get('works'));
These would normally have namespaces like \App and/or \App\Configuration, but I ignore that here so it's easier to follow:
class MyApp {
private $settings_bag = null;
function __construct(SettingsBag $settings_bag)
{
$this->settings_bag = $settings_bag;
}
public function settings()
{
return $this->settings_bag;
}
}
class SettingsBag {
private $settings = null;
function __construct(array $settings = [])
{
$this->settings = $settings;
}
public function set(string $key, $value)
{
return $this->settings[$key] = $value;
}
public function get(string $key)
{
return $this->settings[$key];
}
}
What you try to achieve is called method chaining. You can get this by the following:
<?php
class TestClass {
private $val = '';
public function test1($val) {
$this->val = $val;
return $this;
}
public function test2() {
echo 'Hello '.$this->val;
}
}
$test->test1('World')->test2(); // Hello World
You have simply to return the instance of the object on the method to allow the method chaining.
You can read more here.
It's method chaining.
See code below:
class T {
public function test() {
// do something
return $this;
}
}
$x = new T;
$x->test()->test();

Access control architecture in a PHP application

I'm trying to figure out how to limit access to specific resources in a PHP project I'm currently working on. I've looked for existing solutions, but none of them really fit what I need (for example, Zend_Acl).
Now I've come up with something like this: (Of course, this is very, very simplified. No exceptions or whatever. Just enough to get the point across)
class Access {
protected $_context;
protected $_handlers;
public function __construct($context) {
$this->_context = $context;
}
public static function registerHandler(Access_Handler $handler) {
$key = $handler->getContextType().'/'.$handler->getResourceType();
self::$_handlers[$key] = $handler;
}
public function isAllowed($resource) {
return $this->getHandler($resource)->isAllowed($this->_context, $resource);
}
public function getHandler($resource) {
// Look for and return the appropriate handler for the combination of
// $context and $resource
}
}
abstract class Access_Handler {
$_contextType;
$_resourceType;
abstract public function isAllowed();
}
class Access_Handler_UserInvoice extends Access_Handler {
$_contextType = 'User';
$_resourceType = 'Invoice';
public function isAllowed($user, $invoice) {
if($invoice->user_id === $user->id) {
return true;
}
return false;
}
}
I would then do something like this in my Application Bootstrap:
protected function $_initAccessHandlers() {
Access::registerHandler(new Access_Handler_UserInvoice());
}
And in my controller (because I've heard that's where you should put your access control) I'd have something like this:
class InvoiceController {
public function viewAction() {
// $this->me is of type User
$access = new Access($this->me);
if($access->isAllowed($this->invoice)) {
// ...
}
}
}
I haven't tested the code, so there might be typos or other errors, but I think you get the gist. Also, in reality I'd probably implement Access as a Singleton or a Multiton, but that's not what my question is about.
Is this the right way to do it? It seems so natural to me, but then I'm wondering why nobody else is doing it in this fashion.
My development stack is PHP/MySQL/Zend Framework/Doctrine.
With Zend_Acl you will perform the basic control, like:
$acl = new Zend_Acl();
$acl->add(new Zend_Acl_Resource('article'));
$acl->addRole(new Zend_Acl_Role('author'));
$acl->deny();
$acl->allow('author', 'article', array('list'));
Then you can use assertions to do what you want:
$user = Zend_Auth::getInstance()->getIdentity();
$assertion = new My_Acl_Assertion_ArticleEditCheck($user);
$acl->allow('author', 'article', 'edit', $assertion);
You can instead of pass the user object to the assertion, implement it as a internal property and also work on the request parameters if necessary.
References:
http://framework.zend.com/manual/en/zend.acl.advanced.html
Dynamic custom ACL in zend framework?
For more advanced use of assertions, look at:
http://www.aviblock.com/blog/2009/03/19/acl-in-zend-framework/
http://ralphschindler.com/2009/08/13/dynamic-assertions-for-zend_acl-in-zf

Global variable inside multiple classes

Let's say I have something like this:
<?php
namespace Twitter;
class Twitter {
function __construct()
{
$config = array ('api' => 'something', 'api_url' => 'something2');
}
// some code goes here
}
class TwitterConnection {
function __construct()
{
$config = array ('api' => 'something', 'api_url' => 'something2');
}
// some code goes here
}
?>
and so on - there will be more classes that uses $config variables.
Now, the question is: how can I define config only once, and make it accessible across all classes?
Thanks
You could create a configuration object that reads from your data source (ini, db, php file ...) and populates itself. Then give it a getter so you can get the configuration properties stored within.
Something along the lines of Config::get('someProperty')
Once you have this object setup, you can pass it to the constructor of your classes so it can be used in inside.
class Twitter {
function __construct($config) {
$state = $config->get('someState');
}
}
You could also simply use it within your classes without injecting it by making it a static class (You could also just as easily create a new instance).
class Twitter {
function __construct() {
//Don't recommend this, better to inject it.
$state = Config::get('someState');
}
}
EDIT
The simplest config class that uses your hardcoded array would look something like this. Again, I suggest you move out your configuration out of your code.
class Config {
private $opts = array();
public function __construct() {
/**
* Ideally opts should be coming from some kind of easy to
* access configuration file
*
*/
$this->opts = array ('api' => 'something', 'api_url' => 'something2');
}
public function get($key) {
if (isset($this->opts[$key])) {
return $this->opts[$key];
}
return false;
}
}
class Twitter {
function __construct($config) {
echo $config->get('api');
}
}
$config = new Config();
new Twitter($config);
You could also change the class a bit so that it works without needing an instance of itself.
There are a couple of different things in play here - config data storage, and config data representation and use.
For storage, as martswite commented above, you could have a config file. You could also have config data stored in a database.
For data representation, you could have an array, like you've shown in your question, or a separate full-fledged object.
Usually, if you have objects that have a dependency on certain data in order to work, you pass (inject) that dependency into the object through its constructor. So, roughly, something like this:
class Example
{
private $dependency;
public function __construct($dependency)
{
$this->dependency = $dependency;
}
public function doSomething()
{
// do something with $this->dependency
}
}
This would be tedious to do manually if you had many objects which required the same dependency. Thankfully, there are dependency injection containers which automate a lot of the process. Where do you find these containers? A Google search should yield results. That said, Symfony seems like a popular option: http://components.symfony-project.org/dependency-injection/
All that said, there's a bit of a learning curve to understanding and using a DI container. Still, it's probably the best way to go without introducing globals into your code.
Finally, just to give you an idea of how to use it, here's some pseudo-code:
// Load config data from file/db/some other source. Use it to populate an object (most likely) or array
// Set up the DI container to automatically inject the config data into the objects which require it
// Profit
Try:
namespace Twitter;
$config = array ('api' => 'something', 'api_url' => 'something2');
class Twitter {
function __construct()
{
global $config;
}
}
class TwitterConnection {
function __construct()
{
global $config;
}
}
?>

Determine MySQL query type in Zend Framework

Can anyone tell me how to determine query type i.e. select, update, delete or insert before it is executed over MySQL.
I strongly believe internally Zend Framework might be using mysql*_query function to execute them.
I need a centralized function which will return the query type before the execution.
I am using three files for every database table
I am giving you the example.
Say I want to create model for categories table.
So I will create following files
DbTable/Categories.php
class Application_Model_DbTable_Categories extends Zend_Db_Table_Abstract {
protected $_name = 'categories';
protected $_dependentTables = array('Application_Model_DbTable_Videos');
}
Categories.php
class Application_Model_Categories extends Application_Model_CommonGetterSetter {
protected $_type = array('id' => 'int', 'name' => 'string', 'slug' => 'string', 'status' => 'int');
public function __construct(array $options = null) {
parent::__construct($options, __CLASS__);
}
}
CategoriesMapper.php
class Application_Model_CategoriesMapper {
protected $_dbTable;
public function setDbTable($dbTable) {
if (is_string($dbTable)) {
$dbTable = new $dbTable();
}
if (!$dbTable instanceof Zend_Db_Table_Abstract) {
throw new Exception('Invalid table data gateway provided');
}
$this->_dbTable = $dbTable;
return $this;
}
public function getDbTable() {
if (null === $this->_dbTable) {
$this->setDbTable('Application_Model_DbTable_Categories');
}
return $this->_dbTable;
}
public function save(Application_Model_Categories $categories) {
$data = array(
'name' => $categories->name,
'slug' => $categories->slug,
'status' => $categories->status,
);
if (#$categories->id <= 0) {
return $this->getDbTable()->insert($data);
} else {
$this->getDbTable()->update($data, array('id = ?' => $categories->id));
return $categories->id;
}
}
CommonGetterSetter.php
class Application_Model_CommonGetterSetter {
protected $_data = array();
private $_class_name;
public function __construct(array $options = null, $class_name = null) {
if (is_array($options)) {
foreach ($options as $key => $value) {
$this->$key = $value;
}
$this->_class_name = $class_name;
}
}
public function __set($name, $value) {
if (!array_key_exists($name, $this->_type)) {
throw new Exception("Invalid {$this->_class_name} property". $name);
}
else {
settype($value, $this->_type[$name]);
$this->_data[$name] = $value;
}
}
public function __get($name) {
if (!array_key_exists($name, $this->_type)) {
throw new Exception("Invalid {$this->_class_name} property". $name);
}
else {
return $this->_data[$name];
}
}
}
So I want to find out which query was executed , where and what should i write?
Mny thanks in advance.
I know the code is bit long but that was to give a complete idea.
I strongly believe internally Zend Framework might be using mysql*_query function to execute them.
ZF's Database class does not have support for the decrepit mysql extension. It has adapters for PDO and mysqli. You'll know which of these you are using because you have to expressly specify one in your code or configuration.
So I want to find out which query was executed
I think that you're going to be better served by rethinking your design. It's not entirely clear what is going on here, nor is it clear why you think you need to know the query type, nor is it clear where you expect to need to know the query type.
Please review the Zend_Db_Table documentation, as it looks like you might have missed the point somewhere along the way.
In specific, there are already methods provided by Zend_Db_Table for inserts, deletes and updates. If you need to change the behavior of the appropriate method, you should do so by simply overriding it in your class.
Further, it looks like you're trying to build some sort of smart column type definition system. You don't need to do that, as again, Zend_Db_Table already provides this information to you, and even lets you hard-code it if you'd rather it not determine this information automatically.
ZF is a complicated beast. If you're going to use it, I suggest that you fully understand everything it can do. Building non-standard, redundant architecture is only going to complicate things for you later on.
EDIT : I was looking at the code for the Zend_Db_Table and Zend_Db_Table_Abstract and my second solution seems much more difficult now.
Hey guys,
If you want to give yourself a bit of a headache, what you can do is keep using the multidb resource to create two connections, one to the slave and one for the master.
Set the default connection to the one that will be used the most.
Then, with the other connection you can fetch it manually every time you need to use it and deal directly with the adapter instead of going through the DbTable class.
For example, create another method for the mapper classes called getOtherDbAdapter() that gets the other adapter. Then you can use the adapter from there to perform selects or inserts.
OH!
Another solution is that you can extend extend the class Zend_Db_Table or Zend_Db_Table_Abstract and create another variable for the second db connection.
Then, copy and paste the implementation code for all the fetch/select/insert/update methods from the Zend_Db_Table_Abstract class and have it use the the other adapter whenever you see the code performing the operations you want to have redirected to the other db.

Categories