how to integrate SMF with CodeIgniter? - codeigniter

I am working on a project that will solely use the SMF member system. Meaning that SMF is the only member system that I am using to have logins, not my own system along with SMF, just plain SMF. However, I am running into one problem... I need to be able to get information from SMF based on a given ID_MEMBER. My article database uses SMF's ID_MEMBER field as the author information. Seeing that CodeIgniter is MVC and uses classes, I searched for a general SMF class all over the internet, but could not find one. I decided to write my own, but cannot get it to work correctly... I don't have much experience with OOP.
<?php
class smf {
var $context;
var $memberContext;
function __construct($who){
include('/../../forums/SSI.php');
$this->context = $context;
}
function user_context(){
return $this->context['user'];
}
function member_context($id = NULL){
loadMemberData($id);
loadMemberContext($id);
return $memberContext[$id];
}
}
The user_context function works fine, but not the member_context function. In the SSI.php file, the LoadmemberContext function compiles all of the information into an array called $memberContext[$id]. When I call the method from my CodeIgniter controller, I get an error saying that the $memberContext variable is undefined. Why is this happening?

I stumbled upon this question too and managed to fix it. Try this, it worked for me:
function member_context($id = NULL) {
loadMemberData($id);
loadMemberContext($id);
global $user_profile;
return $user_profile[$id];
}

Related

Laravel 5, check if class is registered in the container

Is there any way to check if a class exists in Laravel 5?
I had this solution for Laravel 4: try to make a specific class, and if I get a ReflectionException, I use a generic class.
In Laravel 5 looks like I can't intercept the ReflectionException and I get a "Whoops".
I was wondering if there is some better way to do this.
try {
$widgetObject = \App::make($widget_class);
} catch (ReflectionException $e) {
$widgetObject = \App::make('WidgetController');
$widgetObject->widget($widget);
}
Check whether your class is set in bindings by doing
app()->bound($classname);
Why don't you just use the PHP function class_exists?
if(class_exists($widget_class)){
// class exists
}
\App::bound() might be the proper way.
Latest laravel versions (Maybe >= 5.3, I don't know exactly) register service providers in alittle different way by default.
For example, a new way of registering:
$this->app->singleton(MyNamespace\MyClass::class, function()
{
/* do smth */ }
);
instead of the old one:
$this->app->singleton('MyClassOrAnyConvenientName', function()
{
/* do smth */ }
);
As a result we should use App::make('\MyNamespace\MyClass') instead of App::make('MyClassOrAnyConvenientName') to resolve a service.
We maintain a library which has to support both versions. So we use \App::bound() to determine whether old or new format of service name is registered in container. class_exists() did actually work for newer laravel but didn't work as expected for older ones because in old systems we didn't have a properly named Facade for that service (Facade's name differed from registered service name) and class_exists() returned false.
Use the getProvider method on the Application container:
if (app()->getProvider($classname)) {
// Do what you want when it exists.
}
It's been available since 5.0 and can be viewed here.

Magento Resources and API Data Sources

As I work with third-party APIs pretty frequently, I thought it would be helpful to create some Magento modules to enable easy connection and querying of them. Ideally, you could query an API like this...
$data = Mage::getModel( 'tools/apixyz_list' )->getCollection();
It would instantiate a model for one of the list items, then attempt to get a collection of them by querying the API. This would require some kind of hookup in the config between the Resource Model and the API and that's where I'm having a little trouble.
Is there a recommended way to do this? I'm having a lot of difficulty finding anything on the subject yet I feel like it should be a pretty common issue given the amount of APIs that generally need to get integrated from project to project.
Yes! I actually built this for Recurly - I'm trying to get it open sourced, but it's not open yet. Here's a snippet from the load() method which is the guts of it.
// TBT_Recurly_Model_Resource_Recurly_Abstract_Collection
public function load($printQuery = false, $logQuery = false)
{
if ($this->isLoaded()) {
return $this;
}
if ($this->_isCached()) {
return $this->_loadCache();
}
$this->_beforeLoad();
$this->_renderFilters()
->_renderOrders()
->_renderLimit();
$this->clear();
try {
# This is ultimately doing the API call
$recurly_list = $this->_getListSafe();
} catch (Recurly_Error $e) {
Mage::logException($e);
$this->setConnectionError($e->getMessage());
return $this;
}
foreach ($recurly_list as $recurly_item)
{
$item = $this->getNewEmptyItem();
$item->getResource()->setDataOnObject($item, $recurly_item);
// Recurly appears to sometimes return duplicate subscription items in it's list response.
if (!isset($this->_items[$item->getId()])) {
$this->addItem($item);
}
}
$this->_afterLoadRecurly();
// We have to setIsLoaded before we saveCache b/c otherwise it will infinite loop
$this->_setIsLoaded();
$this->_saveCache();
$this->_afterLoad();
return $this;
}
We actually ended up taking this and putting it into a base REST class, and it was really cool because it ended up being really easy to implement new REST APIs on top of it.
As far as best practice goes, I'm not sure that I've answered your question specifically. But basically I think the main things to do to make it clean are:
Follow the Magento models / collection method signatures for querying.
Implement caching
Implement the API communication in the resource model layer

CodeIgniter - Dynamic URL segments

I was wondering if someone could help me out.
Im building a forum into my codeigniter application and im having a little trouble figuring out how i build the segments.
As per the CI userguide the uri is built as follows
www.application.com/CLASS/METHOD/ARGUMENTS
This is fine except i need to structure that part a bit different.
In my forum i have categories and posts, so to view a category the following url is used
www.application.com/forums
This is fine as its the class name, but i want to have the next segment dynamic, for instance if i have a category called 'mycategory' and a post by the name of 'this-is-my-first-post', then the structure SHOULD be
www.application.com/forums/mycategory/this-is-my-first-post
I cant seem to achieve that because as per the documentation the 'mycategory' needs to be a method, even if i was to do something like /forums/category/mycategory/this-is-my-first-post it still gets confusing.
If anyone has ever done something like this before, could they shed a little light on it for me please, im quite stuck on this.
Cheers,
Nothing is confusing in the document but you are a little bit confused. Let me give you some suggestions.
You create a view where you create hyperlinks to be clicked and in the hyperlink you provide this instruction
First Post
In the controller you can easily get this
$category = $this->uri->segment(3);
$post = $this->uri->segment(4);
And now you can proceed.
If you think your requirements are something else you can use a hack i have created a method for this which dynamically assign segments.
Go to system/core/uri.php and add this method
function assing_segment($n,$num)
{
$this->segments[$n] = $num;
return $this->segments[$n];
}
How to use
$this->uri->assign_segment(3,'mycategory');
$this->uri->assign_segment(4,'this-is-my-first-post');
And if you have error 'The uri you submitted has disallowed characters' then go to application/config/config.php and add - to this
$config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-';
You could make a route that forwards to a lookup function.
For example in your routes.php add a line something like;
$route['product/(:any)/(:any)'] = "forums/cat_lookup/$1/$2";
This function would then do a database lookup to find the category.
...
public function cat_lookup($cat, $post) {
$catid = $this->forum_model->get_by_name($cat);
if ($catid == FALSE) {
redirect('/home');
}
$post_id = $this->post_model->get_by_name($post);
/* whatever else you want */
// then call the function you want or load the view
$this->load->view('show_post');
}
...
This method will keep the url looking as you want and handle any problems if the category does not exist.Don't forget you can store the category/posts in your database using underscores and use the uri_title() function to make them pretty,
Set in within config/routes.php
$route['song-album/(:any)/:num'] = 'Home/song_album/$id';
fetch in function with help of uri segment.
$this->uri->segment(1);

Codeigniter models loaded in controller overwritten by models loaded in models

I'm having Codeigniter object scope confusion.
Say I load a model in a controller:
$this->load->model('A');
$this->A->loadUser(123); // loads user with ID 123
// output of $this->A now shows user 123
$this->load->model('B');
$this->B->examineUser ();
// output of $this->A now shows user 345
class B extends Model
{
public function examineUser ()
{
$this->load->model('A');
$this->A->loadUser(345); // loads user with ID 345
}
}
I would have thought that $this->A would be different from $this->B->A but they are not. What is the best solution to this issue? It appears the ->load->model('A') in the examineUser () method does nothing because it was loaded in the controller. Then the call to loadUser () inside that method overwrites the stored properties of $this->A. This seems like a bugfest waiting to happen. If I needed global models, I would have use static classes. What I wanted was something scoped pretty much locally to the model object I was in.
Is there a way I can accomplish this but not go way outside of CI's normal way of operating?
Followup/related:
Where do most people put there "->load->model" calls? All at the beginning of a controller action? I figured it would be easier -- though perhaps not excellent programming from a dependency injection perspective -- to load them in the model itself (construct or each method).
Whenever you use the Loader Class ($this->load->), it will load the object into the main CI object. The CI object is the one you keep referring to as $this->. What you've done is load model A twice into the CI object.
Essentially, all object loaded using the Loader class goes into a single global scope. If you need two of the same type, give them different names, as per $this->load->model('A','C'). I don't know of any way around it unless you revert to using bog-standard PHP.
In my team's code, we generally load the models in the controller's constructor, then load the data to send to the view in the function, often _remap().
This is not how the loader works sadly. CodeIgniter implements a singleton pattern, which will check to see if the class is included, instantiated and set to $this->A then will be ignored if loaded again. Even if you are inside a model, $this->A will be referenced to the super-instance via the __get() in class Model. Alis it, or just do:
class B extends Model
{
public function examineUser ()
{
$user = new A;
$user->loadUser(345); // loads user with ID 345
}
}
Here's what I've decided to do, please comment if you have advice:
I've extended the CI Loader class:
<?php
class SSR_Loader extends CI_Loader
{
function __construct()
{
parent::__construct ();
}
/**
* Model Retriever
*
* Written by handerson#executiveboard.com to create and return a model instead of putting it into global $this
*
* Based on original 2.0.2 CI_Loader::model ()
*
*/
function get_model($model)
{
if (empty ($model))
{
return;
}
$name = basename ($model);
if (!in_array($name, $this->_ci_models, TRUE))
{
$this->model ($model);
}
$name = ucfirst($name);
return new $name ();
}
}
Do any CI guru's see a problem with that before I invest time in changing my code a bit to accept the return obj, ala:
// in a controller:
public function test ($user_id=null)
{
$this->_logged_in_user = $this->load->get_model ('/db/users');
$this->_viewed_user = $this->load->get_model ('/db/users');
$this->_logged_in_user->load($this->session->userdata ('user.id'));
$this->_viewed_user->load($user_id);
}
I could also do private $_logged_in_user to make it available in the controller but positively force it to be limited to just the current controller and not spill anywhere else, or I could just do $_logged_in_user = $this->load->get_model ('/db/users'); and limit it to just the current method, which is probably what I'll do more often.
This seems like a pretty straightforward way to "fix" this issue (I say "fix" b/c it's not really a bug, just a way of doing things that I think is a bad idea). Anyone see any flaws?

Customer session is different in different parts of a Magento website

I have a function inside of a Helper in Magento that returns whether or not a customer attribute equals one.
Here is my Helper class
class Nie_Nie_Helper_Data extends Mage_Core_Helper_Abstract {
public function isNieAdmin() {
if(Mage::getSingleton('customer/session')->getCustomer()->getNieAdmin() == 1) {
return true;
} else {
return false;
}
}
}
Now when I call this function from a class that extends Mage_Core_Block_Template, everything seems to work fine. However when I try to use this inside one of my controllers, it does not work. In fact when I do Mage::getSingleton('customer/session')->getCustomer()->debug() the only variable that is returned is the website_id.
Does anyone know what I have to do in order to get this to work?
At the time of the controller the session objects are not yet initialised (although the session variable must be) so it returns a blank model. My guess is the website_id is deliberately set in the creation of a customer object to act as a default.
You could access $_SESSION['customer'] directly to find what you need, but that is messy. An alternative would be to do what you want in an event that occurs later.
I hope someone can come up with a better answer than mine.
Ok it looks like I had to load up the session myself. I had to put the following in my functions:
Mage::getSingleton('core/session', array('name' => 'frontend'));
Hope this helps.

Resources