I have a forum I've put in the public directory and I want to make a SSO with the site and the forum. The problem is, when I try to get a user session using Zend's AuthenticationService class, it gives the following error :
Class 'Zend\Authentication\AuthenticationService' not found in C:\Users\Milen\Documents\site\public\forum\admin\sources\classes\session\ssoPublicSessions.php
What am I doing wrong ?
The code:
<?php
use Zend\Authentication\AuthenticationService;
class ssoPublicSessions extends publicSessions {
public function __construct() {
parent::__construct();
if (self::$data_store['member_id'] OR $this->_member->is_not_human) {
return;
}
$auth = new AuthenticationService();
$member = $auth->getIdentity();
if (!$member) {
return;
}
self::setMember($member['member_id']);
$this->_updateMemberSession();
return;
}
}
Related
I'm looking for a way to have a single base class that can be extended by several child classes, only one of which would be active at a time. A very basic example:
class API_Base {
public $context;
public function __construct() {
$this->init()
}
}
class Mailchimp_API extends API_Base {
public function init() {
$this->context = 'mailchimp';
$this->enabled = false;
}
public function add_contact($email_address) {
// mailchimp API for adding contact
}
}
class Infusionsoft_API extends API_Base {
public function init() {
$this->context = 'infusionsoft';
$this->enabled = true;
}
public function add_contact($email_address) {
// infusionsoft API for adding contact
}
}
Each child initializes itself and registers as an option for the user to select. After the user has chosen which integration to use, this is saved to the database. I'd like future access to the API_Base to look something like:
$api = new API_Base();
$api->context; // should be "infusionsoft"
$api->add_contact($email_address);
So when $api->add_contact() is run, it only runs the add_contact() function for the active API integration.
Eventually I'd like to somehow use get_class_methods(); to return the capabilities of just the active API, so functions accessing the API can know what is possible (i.e. some API's support email lists while others don't, or support creating custom fields, etc.).
I've had some success with calling parent::set_context($context); from the enabled class, but I still can't figure out how to get the parent to only execute the methods in the "enabled" child class.
This is not how inheritance works. Child subclasses inherit from their parent class.
To solve your problem you can add a factory method to API_Base which will create API implementation by its type:
class API_Base {
public static function createByType($type)
{
switch ($type) {
case 'mailchimp': return new Mailchimp_API();
case 'infusionsoft': return new Infusionsoft_API();
default: throw new \InvalidArgumentException(spintf('Invalid API type "%s"', $type));
}
}
// other methods
}
and use it like this:
$api = API_Base::createByType($user->selectedApi);
$api->context; // should be "infusionsoft"
$api->add_contact($email_address);
You can consider Abstract Class Implementation . The abstract class works as the , who ever is extending the abstract class can execute the methods it have .
abstract class Something{
function __construct(){
// some stuff
}
function my_func(){
$this->myTest ;
}
abstract function my_func();
}
class Some extends Something{
function __construct(){
parent::__construct() ;
}
function my_test(){
echo "Voila" ;
}
}
I got it working in a way works perfectly for me, thanks to Ihor's advice. Here's what I ended up doing:
In the main plugin file, there's a filterable function where other devs can add new integrations if they need. The first parameter is the slug (for my autoloader) and the second is the class name.
public function get_apis() {
return apply_filters( 'custom_apis', array(
'infusionsoft-isdk' => 'MYPLUGIN_Infusionsoft_iSDK',
'infusionsoft-oauth' => 'MYPLUGIN_Infusionsoft_oAuth',
'activecampaign' => 'MYPLUGIN_ActiveCampaign'
) );
}
Each integration contains the slug and the class name. Then in my API_Base class I have this in the constructor:
class API_Base {
public $available_apis = array();
public $api;
public function __construct() {
$configured_apis = main_plugin()->get_apis();
foreach( $configured_apis as $slug => $classname ) {
if(class_exists($classname)) {
$api = new $classname();
$api->init();
if($api->active == true)
$this->api = $api;
$this->available_apis[$slug] = array( 'name' => $api->name );
if(isset($api->menu_name)) {
$this->available_apis[$slug]['menu_name'] = $api->menu_name;
} else {
$this->available_apis[$slug]['menu_name'] = $api->name;
}
}
}
}
}
And in my main file, after all the includes, I run:
self::$instance->api_base = new API_Base();
self::$instance->api = self::$instance->api_base->api;
Now I can call self::$instance->api->add_contact($email); and it will trigger whichever is the current active API.
It seems to be the best approach as this way I can spin up the API only once when the plugin loads, instead of having to create a new instance each time I want to use it.
I have to parse a huge csv files in a Yii 1.1 Application.
Each row has to be validated and saved to the database.
I decided to use Multi Threading for this task.
So here is my code in the Controller action:
public function parseData($) {
$this->content = explode("\n", $this->content);
$thread_1 = new DatalogThread(array_slice($this->content, 0, 7000));
$thread_2 = new DatalogThread(array_slice($this->content, 7001));
$thread_1->start();
$thread_2->start();
}
And the Thread (I put it in models folder):
class DatalogThread extends Thread {
public $content;
public function __construct($content) {
$this->content = $content;
}
public function run() {
foreach ($this->content as $value) {
$row = str_getcsv($value);
$datalog = new Datalog($row);
$datalog->save();
}
}
}
The problem is that the Thread does not get access to the model file:
Fatal error: Class 'Datalog' not found in C:\xampp...\protected\models\DatalogThread.php
I tried Yii::autoload("Datalog"), but got The following error:
Fatal error: Cannot access property Yii::$_coreClasses in ...\YiiMain\framework\YiiBase.php on line 402
Yii uses a LOT of statics, this is not the best kind of code for multi-threading.
What you want to do is initialize threads that are not aware of Yii and reload it, I do not use Yii, but here's some working out to give you an idea of what to do:
<?php
define ("MY_YII_PATH", "/usr/src/yii/framework/yii.php");
include (MY_YII_PATH);
class YiiThread extends Thread {
public $path;
public $config;
public function __construct($path, $config = array()) {
$this->path = $path;
$this->config = $config;
}
public function run() {
include (
$this->path);
/* create sub application here */
}
}
$t = new YiiThread(MY_YII_PATH);
$t->start(PTHREADS_INHERIT_NONE);
?>
This will work much better ... I should think you want what yii calls a console application in your threads, because you don't want it trying to send any headers or anything like that ...
That should get you started ...
I currently have a manual method for registering helpers into my base connection class which goes pretty much as follows:
class db_con
{
// define the usual suspect properties..
public $helpers; // helper objects will get registered here..
public function __construct()
{
// fire up the connection or die trying
$this->helpers = (object) array();
}
public function __destruct()
{
$this->helpers = null;
$this->connection = null;
}
// $name = desired handle for the helper
// $helper = name of class to be registered
public function register_helper($name, $helper)
{
if(!isset($this->helpers->$name, $helper))
{
// tack on a helper..
$this->helpers->$name = new $helper($this);
}
}
// generic DB interaction methods follow..
}
Then a helper class such as..
class user_auth
{
public function __construct($connection){ }
public function __destruct(){ }
public function user_method($somevars)
{
// do something with user details
}
}
So after creating the $connection object, i would then manually register a helper like so:
$connection->register_helper('users', 'user_auth');
Now my question is, could I somehow autoload helper classes inside the base connection class? (within the register_helper() method or similar) Or am I limited to loading them manually or via an external autoloader of some form?
My apologies if this question has been answered elsewhere, but I just haven't found it (not for lack of trying) and I haven't any real experience autoloading anything yet.
Any help or pointers greatly appreciated, thanks in advance! :)
EDIT: As per Vic's suggestion this is the working solution I came up with for the register method..
public function register_handlers()
{
$handler_dir = 'path/to/database/handlers/';
foreach (glob($handler_dir . '*.class.php') as $handler_file)
{
$handler_bits = explode('.', basename($handler_file));
$handler = $handler_bits[0];
if(!class_exists($handler, false))
{
include_once $handler_file;
if(!isset($this->handle->$handler, $handler))
{
$this->handle->$handler = new $handler($this);
}
}
}
}
This appears to include and register the objects absolutely fine for now, whether this solution is a "good" one or not, I can't know without more input or testing.
The code could look something like below, but why would you need this?
public function register_helper($name, $helper)
{
if(!isset($this->helpers->$name, $helper))
{
$this->load_class($helper);
// tack on a helper..
$this->helpers->$name = new $helper($this);
}
}
private function load_class($class)
{
if( !class_exists($class, false) ) {
$class_file = PATH_SOME_WHERE . $class . '.php';
require $class_file;
}
}
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
I'm working through Practical Web 2.0 Appications currently and have hit a bit of a roadblock. I'm trying to get PHP, MySQL, Apache, Smarty and the Zend Framework all working correctly so I can begin to build the application. I have gotten the bootstrap file for Zend working, shown here:
<?php
require_once('Zend/Loader.php');
Zend_Loader::registerAutoload();
// load the application configuration
$config = new Zend_Config_Ini('../settings.ini', 'development');
Zend_Registry::set('config', $config);
// create the application logger
$logger = new Zend_Log(new Zend_Log_Writer_Stream($config->logging->file));
Zend_Registry::set('logger', $logger);
// connect to the database
$params = array('host' => $config->database->hostname,
'username' => $config->database->username,
'password' => $config->database->password,
'dbname' => $config->database->database);
$db = Zend_Db::factory($config->database->type, $params);
Zend_Registry::set('db', $db);
// handle the user request
$controller = Zend_Controller_Front::getInstance();
$controller->setControllerDirectory($config->paths->base .
'/include/Controllers');
// setup the view renderer
$vr = new Zend_Controller_Action_Helper_ViewRenderer();
$vr->setView(new Templater());
$vr->setViewSuffix('tpl');
Zend_Controller_Action_HelperBroker::addHelper($vr);
$controller->dispatch();
?>
This calls the IndexController. The error comes with the use of this Templater.php to implement Smarty with Zend:
<?php
class Templater extends Zend_View_Abstract
{
protected $_path;
protected $_engine;
public function __construct()
{
$config = Zend_Registry::get('config');
require_once('Smarty/Smarty.class.php');
$this->_engine = new Smarty();
$this->_engine->template_dir = $config->paths->templates;
$this->_engine->compile_dir = sprintf('%s/tmp/templates_c',
$config->paths->data);
$this->_engine->plugins_dir = array($config->paths->base .
'/include/Templater/plugins',
'plugins');
}
public function getEngine()
{
return $this->_engine;
}
public function __set($key, $val)
{
$this->_engine->assign($key, $val);
}
public function __get($key)
{
return $this->_engine->get_template_vars($key);
}
public function __isset($key)
{
return $this->_engine->get_template_vars($key) !== null;
}
public function __unset($key)
{
$this->_engine->clear_assign($key);
}
public function assign($spec, $value = null)
{
if (is_array($spec)) {
$this->_engine->assign($spec);
return;
}
$this->_engine->assign($spec, $value);
}
public function clearVars()
{
$this->_engine->clear_all_assign();
}
public function render($name)
{
return $this->_engine->fetch(strtolower($name));
}
public function _run()
{ }
}
?>
The error I am getting when I load the page is this:
Fatal error: Call to a member function fetch() on a non-object in /var/www/phpweb20/include/Templater.php on line 60
I understand it doesn't see $name as an object, but I don't know how to go about fixing this. Isn't the controller supposed to refer to the index.tpl? I haven't been able to discover what the $name variable represents and how to fix this to get the foundation working.
Any help you have is much appreciated!
The problem isn't with the $name variable but rather with the $_engine variable. It's currently empty. You need to verify that the path specification to Smarty.class.php is correct.
You might try this to begin your debugging:
$this->_engine = new Smarty();
print_r($this->_engine);
If it turns out that $_engine is correct at that stage then verify that it is still correctly populated within the render() function.
Zend has an example of creating a templating system which implements the Zend_View_Interface here: http://framework.zend.com/manual/en/zend.view.scripts.html#zend.view.scripts.templates.interface
That might save you some time from trying to debug a custom solution.
removing the __construct method, from the class, solved the similar issue I was facing.
Renaming __construct() to Tempater() worked for me.