How to pass variable from Module to Controller in Yii2? - api

I am building restful stateless API using Yii2... So far so good. Now I failed at rookie problem.
I have decided to make API application (preferred by Yii) and make API as a module. So my structure is:
- modules
-- v1
--- components
--- controllers
--- models
Inside v1 folder of course there is Module.php. In here I do authentication like:
$behaviors['authenticator'] = [
'class' => HttpBasicAuth::className(),
'auth' => function($username, $password) {
... get user's data from DB ...
[HERE]
}
];
and at point [HERE] I sotre user's ID in public variable.
So far so good...
So when I for example call v1/abc/index abc controller loads in inside that controller I would like to access user's ID stored at point [HERE]. Any idea?

To access module from controller, you should simply use $this->module.
And from a view : $this->context->module.
No need to use getModule() here.
Read more : http://www.yiiframework.com/doc-2.0/yii-base-controller.html#$module-detail
PS: to access module outside its controllers/views you could use :
Yii::app()->getModule('module');

Have you tried
$v1Module = Yii::app()->getModule('v1');
And then simply
echo $v1Module->yourPublicVariable;

Related

How to move Laravel Events into subdirectories and still have them work when broadcasting?

I've moved my Laravel Events into subdirectories, and now my broadcasted messages are not being received. Pusher shows them ok, and if I move them out of the subdirectories then they work as expected, so I believe this is a namespacing issue, but I cannot figure out how to make it work.
The Event I'm focusing on is called TeamInvitationEvent and is located in the Events->Company->Memberships directory.
Here is my Listener:
public function getListeners()
{
$user_id = Auth::id();
return [
'refresh-navigation-top-menu' => '$refresh',
"echo-private:user.{$user_id},TeamInvitationEvent" => 'notifyInvitation',
"echo-private:user.{$user_id},TeamInvitationCancelledEvent" => 'notifyInvitationCancelled',
"echo-private:user.{$user_id},TeamInvitationAcceptedEvent" => 'notifyInvitationAccepted',
"echo-private:user.{$user_id},TeamMemberRemovedEvent" => 'notifyMemberRemoved',
];
}
Here is a screenshot of my Pusher debug console, showing that the user is subscribed to the correct private channel, and that the API Message is being broadcast on that channel:
Here is a list of different ways I've tried to correct for the new namespace:
App.Events.Company.Memberships.TeamInvitationEvent
App\Events\Company\Memberships\TeamInvitationEvent
/App/Events/Company/Memberships/TeamInvitationEvent
.TeamInvitationEvent
There are no errors in the Laravel logs, or in the Pusher logs, and as I mentioned it works as expected if I don't move them into the subdirectory.
I'm running the following in my app:
Laravel v8
Livewire v2
Laravel Echo v1
Pusher
This was embarrassingly obvious, but here's what fixed it:
"echo-private:user.{$user_id},Company\Memberships\TeamInvitationEvent" => 'notifyInvitation'
The docs are very clear that "App\Events" is prepended to all events, so naturally I just needed to add the rest of the namespace to get it working. I looked back and I had actually tried this earlier, but I must have forgot to clear the cache. Big shout-out to #joshhanley on the Livewire Discord chat for getting me sorted on this.
Side Note: using broadcastAs() made this much cleaner:
public function broadcastAs()
{
return 'team.invitation';
}
But don't forget to add a '.' before this custom name in your view, like this:
"echo-private:user.{$user_id},.team.invitation" => 'notifyInvitation'

How to use WHMCS Local api (internal API)

How to use WHMCS LocalAPI (InternaAPI)
Hi
I have a problem to use WHMCS LocalAPI
WHMCS Documentation is very poor and unclear about this problem
when I run this code a blank page appear and any thing is happened
<?php
require('../init.php');
require('../includes/api.php');
$command = 'AddOrder';
$postData = array(
'clientid' => '1',
'domain' => array('domain1.com'),
'billingcycle' => array('annually'),
'domaintype' => array('register',),
'regperiod' => array(1),
'nameserver1' => 'ns1.demo.com',
'nameserver2' => 'ns2.demo.com',
'paymentmethod' => 'zarinpalgw',
);
$adminUsername = 'myadminname'; // Optional for WHMCS 7.2 and later
$results = localAPI($command, $postData, $adminUsername);
print_r($results);
?>
I expected to add order after run this code
External API is very slow and not suitable for me for some reason such as
I have a dynamic IP and External API work with static IP because IP must be recognize in WHMCS->General setting->Security
The Internal API code in your example looks like it should work. Temporarily enabling PHP errors can help narrow down the exact cause of this issue (Setup > General Settings > Other > Display Errors), although I believe it is due to the way you are initializing the WHMCS environment in your PHP file.
WHMCS provides specific guidelines on building custom pages, which appears to be what you were trying to do in the example provided. Custom PHP files must be located in the root WHMCS directory, however require('../init.php'); indicates that your script is currently inside a subdirectory. You also should not be requiring api.php, as that is already being handled by init.php. Moving your script to the WHMCS root directory and commenting out the require('../includes/api.php'); line should hopefully fix the blank page issue.
Please note: the example you provided does not display the normal WHMCS client interface and does not check to see if the user is logged in. If that is functionality you will be needing as well, you can create a page with the same interface and functionality as a native WHMCS client area page. The following is a slightly modified version of the example code WHMCS provides in their guide for creating client area pages:
<?php
// Define WHMCS namespaces
use WHMCS\ClientArea;
use WHMCS\Database\Capsule;
// Initialize WHMCS client area
define('CLIENTAREA', true);
require __DIR__ . '/init.php';
$ca = new ClientArea();
$ca->setPageTitle('Your Page Title Goes Here');
$ca->addToBreadCrumb('index.php', Lang::trans('globalsystemname'));
$ca->addToBreadCrumb('mypage.php', 'Your Custom Page Name');
$ca->initPage();
// Uncomment to require a login to access this page
//$ca->requireLogin();
// Uncomment to assign variables to the template system
//$ca->assign('variablename', $value);
// Code to run when the current user IS logged in
if ($ca->isLoggedIn()) {
$clientName = Capsule::table('tblclients')->where('id', '=', $ca->getUserID())->pluck('firstname');
$ca->assign('clientname', $clientName);
// Code to run when the current user is NOT logged in
} else {
$ca->assign('clientname', 'Random User');
}
// Setup the primary and secondary sidebars
Menu::addContext();
Menu::primarySidebar('announcementList');
Menu::secondarySidebar('announcementList');
// Define the template filename to be used (without the .tpl extension)
$ca->setTemplate('mypage');
// Display the contents of the page (generated by the Smarty template)
$ca->output();

How can I get window.location.href in Elm?

I have an index.html which contains my Elm app. The Elm app uses various GETs to an API served by the same server as the one that serves the index.html.
Rather than hardcode the URLs in my Elm code for the GETs, e.g.:
url =
"http://localhost:8080/api/tasks"
is there a function which returns the value of window.location.href?
I'd like to do something like:
url =
getHref() ++ "/api/tasks"
In this way, if I move my server to somewhere else I will not need to update all the urls in my Elm code.
Whilst the above answers your question, I think there is a more straightforward solution to the problem:
If the application code is being served from the same server (URL) as the API you want to access you don't need to specify the server - just the root relative path for your api i.e. you can make requests to /api/tasks from your elm code and the browser will sort out the rest for you.
This is how I addressed the problem in my deployed code.
There is elm-history package with the location function for this, but it's deprecated and doesn't exist for 0.18 version.
Then you might want to use elm-navigation package and explicitly store the current location in your model.
Please have a look at this example. A program with navigation can be created via:
Navigation.program UrlChange
{ init = init
, view = view
, update = update
, subscriptions = (\_ -> Sub.none)
}
UrlChange here is a type of message, which triggers on every url change, so you can process it and set the current location:
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
UrlChange location ->
( { model | location = location }
, Cmd.none
)
And then purely get the location.href wherever the model is accessible.
In the provided application, this place is view: viewLocation model.location
In your application, it's, for example, something like this:
url model =
model.location.href ++ "/api/tasks"
Use URL Builder to link to anoter page on your site
There's no need to specify the base url:
import Url.Builder exposing (absolute)
url = absolute [ "api", "tasks" ] []
-- results in "http://localhost:8080/api/tasks"
-- if working in your developer environment
-- the URL will automatically change in production
-- to the correct URL assuming you don't have any crazy set ups
And you definitely will not need to worry if your server URL changes. So you can easily switch from a development to production/staging environments without any additional configuration.

How to have global $user variable in Laravel 5.2?

Context
Laravel ships with two authentication controllers out of the box, which are located in the App\Http\Controllers\Auth namespace.
...
You may access the authenticated user via the Auth facade: $user = Auth::user();
Reference: Laravel 5.2 Documentation
I'm able to log in successfully and I'm redirected to the correct place as defined in the AuthController.php, but now I need access to the $user object in most of my views such as for checking the user's information, access priveleges, etc.
Problem
How do I properly provide access to the $user variable on all of my views?
How other people have been doing it
User imJohnBen of Laracast asked how a Laravel 5 service provider can be used to share view variables. He later shares how he was able to use the existing ComposerServiceProvider and added a GlobalComposer to be able to share variables on all the views.
I followed his answer but there was a missing step. I couldn't contribute to the Laracast forums, thus leading to the creation of this StackOverflow question.
The Laravel version I'm using here is Laravel 5.2.*.
Answer
Find the existing ComposerServiceProvider class. I found mine in vendor/laravel/framework/src/Illuminate/Foundation/Providers/ComposerServiceProvider.php.
Import/reference the ViewFactory dependency at the top of the file.
use Illuminate\Contracts\View\Factory as ViewFactory;
Add the boot method, or modify it if it exists already. Make sure the ViewFactory was injected (add it as a parameter in the boot function):
/**
* Register bindings in the container.
*
* #return void
*/
public function boot(ViewFactory $view)
{
$view->composer('*', 'App\Http\ViewComposers\GlobalComposer');
}
Make a ViewComposers folder in your app/Http folder.
Make a GlobalComposer.php file in the ViewComposers folder, containing the following:
<?php
namespace App\Http\ViewComposers;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Auth;
class GlobalComposer {
/**
* Bind data to the view.
*
* #param View $view
* #return void
*/
public function compose(View $view)
{
$view->with('user', Auth::user());
}
}
(The missing step) Finally, make sure everything is wired up by going to your config/app.php file and making sure that ComposerServiceProvider is in your providers list.
'providers' = [
/*
* Laravel Framework Service Providers...
*/
Illuminate\Auth\AuthServiceProvider::class,
Illuminate\Broadcasting\BroadcastServiceProvider::class,
// etc...
Illuminate\Foundation\Providers\ComposerServiceProvider::class,
]
Afterwards, the $user variable and any other variables you define in the GlobalComposer will be accessible in any of the views you render.

Is it possible to init AdminController from outside Prestashop?

I am trying to initiate the AdminController module from outside the Prestashop. Basically, I am creating an external program which uses Prestashop to get current employee for which I should instantiate the AdminController, but its throwing error.
Many modules init the FrontController but I cannot find any example for AdminController like :
include(dirname(__FILE__).'/../../config/config.inc.php');
include(dirname(__FILE__).'/../../init.php');
Please advice.
I found the solution after all. Simply define _PS_ADMIN_DIR_ and init the config.inc.php, Prestashop will automatically load the admin environment. However, if you are loading this from a module, its tricky to find the admin directory as its not defined anywhere, so I have written this small script.
$admindir = '';
foreach (glob("../../*/ajaxfilemanager", GLOB_ONLYDIR) as $filename) {
$admindir = str_replace('../../', '', $filename);
$admindir = str_replace('/ajaxfilemanager', '', $admindir);
}
define('_PS_ADMIN_DIR_', getcwd().'/../../'.$admindir);
require(_PS_ADMIN_DIR_.'/../config/config.inc.php');
Enjoy!