Getting all module names in zf2 - php

I want to list all the modules , controllers and actions included in my project for acl purpose. But i dont know how can i fetch such information from zf2. Anyone has an idea of how to make this work? ThankYou :)

Try this,
$manager = $this->getServiceLocator()->get('ModuleManager');
$modules = $manager->getLoadedModules();
$loadedModules = array_keys($modules);
$skipActionsList = array('notFoundAction', 'getMethodFromAction');
foreach ($loadedModules as $loadedModule) {
$moduleClass = '\\' .$loadedModule . '\Module';
$moduleObject = new $moduleClass;
$config = $moduleObject->getConfig();
$controllers = $config['controllers']['invokables'];
foreach ($controllers as $key => $moduleClass) {
$tmpArray = get_class_methods($moduleClass);
$controllerActions = array();
foreach ($tmpArray as $action) {
if (substr($action, strlen($action)-6) === 'Action' && !in_array($action, $skipActionsList)) {
$controllerActions[] = $action;
}
}
echo $loadedModule . "\n";
echo $moduleClass . "\n";
print_r($controllerActions);
}
}

You can get a array of the loaded modules from the ModuleManager.
$moduleManager = $serviceManager->get('ModuleManager');
$loadedModules = $moduleManager->getLoadedModules();
For controllers you can retrieve them from the ControllerManager.
$controllerManager = $this->getServiceLocator()->get('ControllerLoader');
foreach ($controllerManager->getCanonicalNames() as $alias) {
$controller = $controllerManager->get($alias); // This will get you the controller instance
}
ZF2 doesn't have any convenience methods built in to retrieve all the controller actions. Using some reflection would be your best bet imo.
$reflection = new \ReflectionClass($controller);
$actions = array();
foreach ($reflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
$methodName = $method->getName();
if ($methodName == 'getMethodFromAction') {
continue;
}
if (substr_compare($methodName, 'Action', -strlen('Action')) === 0) {
$actions[] = substr($methodName, 0, strlen($methodName) - 6);
}
}
var_dump($actions);

Related

Joomla 3.9 - Home Page Disappeared When I published twice a custom Module Developed by me

I developed a joomla module, it was working fine. When it was published once but when i published it again on same page, then home page gone and i got 500 error, and if I tried to unpublished one module both got unpublished.
How to resolve that issue. As a guess i think i should create a dynamic id with every module. but i dont know how to do that in joomla.
This code is making problems.
function group_by_key($array) {
$result = array();
foreach ($array as $sub) {
foreach ($sub as $k => $v) {
$result[$k][] = $v;
}
}
return $result;
}
$features_list = array(
$features_list1 = group_by_key($features[0]),
$features_list2 = group_by_key($features[1]),
$features_list3 = group_by_key($features[2]),
$features_list4 = group_by_key($features[3]),
);
Because i am getting below error.
Fatal error: Cannot redeclare group_by_key() (previously declared in E:\xampp\htdocs\joomla\do\modules\mod_xp_comparison\tmpl\default.php:31) in E:\xampp\htdocs\joomla\do\modules\mod_xp_comparison\tmpl\default.php on line 40
You should try it this way:
if (!function_exists('group_by_key')) {
function group_by_key($array) {
$result = array();
foreach ($array as $sub) {
foreach ($sub as $k => $v) {
$result[$k][] = $v;
}
}
return $result;
}
}
$features_list = array(
$features_list1 = group_by_key($features[0]),
$features_list2 = group_by_key($features[1]),
$features_list3 = group_by_key($features[2]),
$features_list4 = group_by_key($features[3]),
);
The reason of the above is that you cannot include (or declare) the same function twice. So if it is already defined in a Global scope in your default.php for example then it's just causing a conflict. Thus if you are not sure, then you have to use that function inside an if (!function_exists('any_function_name')) { ...// function ... } condition statement.
If you want to follow standard Joomla practices, instead of placing custom functions in the layout, create a helper class (helper.php):
defined('_JEXEC') or die;
class ModXpComparisonHelper
{
public static function group_by_key($array)
{
$result = array();
foreach ($array as $sub)
{
foreach ($sub as $k => $v)
{
$result[$k][] = $v;
}
}
return $result;
}
}
Include the helper in main module file (mod_xp_comparison.php):
JLoader::register('ModXpComparisonHelper', __DIR__ . '/helper.php');
And then call the function when needed:
$features_list = array(
$features_list1 = ModXpComparisonHelper::group_by_key($features[0]),
$features_list2 = ModXpComparisonHelper::group_by_key($features[1]),
$features_list3 = ModXpComparisonHelper::group_by_key($features[2]),
$features_list4 = ModXpComparisonHelper::group_by_key($features[3]),
);

output and call array from class function (rollingcurl)

Excuse my English, please.
I use Rollingcurl to crawl various pages.
Rollingcurl: https://github.com/LionsAd/rolling-curl
My class:
<?php
class Imdb
{
private $release;
public function __construct()
{
$this->release = "";
}
// SEARCH
public static function most_popular($response, $info)
{
$doc = new DOMDocument();
libxml_use_internal_errors(true); //disable libxml errors
if (!empty($response)) {
//if any html is actually returned
$doc->loadHTML($response);
libxml_clear_errors(); //remove errors for yucky html
$xpath = new DOMXPath($doc);
//get all the h2's with an id
$row = $xpath->query("//div[contains(#class, 'lister-item-image') and contains(#class, 'float-left')]/a/#href");
$nexts = $xpath->query("//a[contains(#class, 'lister-page-next') and contains(#class, 'next-page')]");
$names = $xpath->query('//img[#class="loadlate"]');
// NEXT URL - ONE TIME
$Count = 0;
$next_url = "";
foreach ($nexts as $next) {
$Count++;
if ($Count == 1) {
/*echo "Next URL: " . $next->getAttribute('href') . "<br/>";*/
$next_link = $next->getAttribute('href');
}
}
// RELEASE NAME
$rls_name = "";
foreach ($names as $name) {
$rls_name .= $name->getAttribute('alt');
}
// IMDB TT0000000 RLEASE
if ($row->length > 0) {
$link = "";
foreach ($row as $row) {
$tt_info .= #get_match('/tt\\d{7}/is', $doc->saveHtml($row), 0);
}
}
}
$array = array(
$next_link,
$rls_name,
$tt_info,
);
return ($array);
}
}
Output/Return:
$array = array(
$next_link,
$rls_name,
$tt_info,
);
return ($array);
Call:
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
function get_match($regex, $content, $pos = 1)
{
/* do your job */
preg_match($regex, $content, $matches);
/* return our result */
return $matches[intval($pos)];
}
require "RollingCurl.php";
require "imdb_class.php";
$imdb = new Imdb;
if (isset($_GET['action']) || isset($_POST['action'])) {
$action = (isset($_GET['action'])) ? $_GET['action'] : $_POST['action'];
} else {
$action = "";
}
echo " 2222<br /><br />";
if ($action == "most_popular") {
$popular = '&num_votes=1000,&production_status=released&groups=top_1000&sort=moviemeter,asc&count=40&start=1';
if (isset($_GET['date'])) {
$link = "https://www.imdb.com/search/title?title_type=feature,tv_movie&release_date=,".$_GET['date'].$popular;
} else {
$link = "https://www.imdb.com/search/title?title_type=feature,tv_movie&release_date=,2018".$popular;
}
$urls = array($link);
$rc = new RollingCurl([$imdb, 'most_popular']); //[$imdb, 'most_popular']
$rc->window_size = 20;
foreach ($urls as $url) {
$request = new RollingCurlRequest($url);
$rc->add($request);
}
$stream = $rc->execute();
}
If I output everything as "echo" in the class, everything is also displayed. However, I want to call everything individually.
If I now try to output it like this, it doesn't work.
$stream[0]
$stream[1]
$stream[3]
Does anyone have any idea how this might work?
Thank you very much in advance.
RollingCurl doesn't do anything with the return value of the callback, and doesn't return it to the caller. $rc->execute() just returns true when there's a callback function. If you want to save anything, you need to do it in the callback function itself.
You should make most_popular a non-static function, and give it a property $results that you initialize to [] in the constructor.. Then it can do:
$this->results[] = $array;
After you do
$rc->execute();
you can do:
foreach ($imdb->results as $result) {
echo "Release name: $result[1]<br>TT Info: $result[2]<br>";
}
It would be better if you put the data you extracted from the document in arrays rather than concatenated strings, e.g.
$this->$rls_names = [];
foreach ($names as $name) {
$this->$rls_names[] = $name->getAttribute('alt');
}
$this->$tt_infos = [];
foreach ($rows as $row) {
$this->$tt_infos[] = #get_match('/tt\\d{7}/is', $doc->saveHtml($row), 0);
}
$this->next_link = $next[0]->getAttribute('href'); // no need for a loop to get the first element of an array

Get models list in CakePHP 2

I'm trying to get a complete list of all models under app/Model.
Already tried App::objects('Model') but it only retrieves loaded models.
Is this possible in CakePHP 2?
After some research I found that App::objects('Model') returns all models under app/Models but it doesn't include Plugin models.
To include all models (app models and plugin models) I created the next function:
/**
* Get models list
*
* #return array
*/
public static function getModels()
{
// Get app models
$models = App::objects('Model');
$models = array_combine($models, $models);
// Get plugins models
$pluginsFolder = new Folder(APP . 'Plugin');
$plugins = $pluginsFolder->read();
foreach ( $plugins[0] as $plugin ) {
$pluginModels = App::objects($plugin . '.Model');
foreach ($pluginModels as $pluginModel) {
$models[$plugin . '.' . $pluginModel] = $plugin . '.' . $pluginModel;
}
}
// Exclude tableless and application models
$dataSource = ConnectionManager::getDataSource('default');
$sources = $dataSource->listSources();
foreach($models as $key => $model) {
$table = Inflector::tableize(self::modelName($key));
if (stripos($model, 'AppModel') > -1 || !in_array($table, $sources)) {
unset($models[$key]);
}
}
return $models;
}
Maybe late but here is my version:
(loops through plugin models, and retrieves the table associated by opening the file, and searching for the variable $useTable)
/**
* Get models list.
* Retrieved from: https://stackoverflow.com/questions/38622473/get-models-list-in-cakephp-2
* #return array
*/
public static function getModels() {
// Get app models
$models = App::objects('Model');
$models = array_combine($models, $models);
// Get plugins models
$pluginsFolder = new Folder(APP . 'Plugin');
$plugins = $pluginsFolder->read();
foreach ( $plugins[0] as $plugin ) {
$pluginModels = App::objects($plugin . '.Model');
foreach ($pluginModels as $pluginModel) {
$fullPath = APP.'Plugin'.DS.$plugin.DS."Model".DS.$pluginModel.".php";
$models[$plugin . '.' . $pluginModel] = $fullPath;
}
}
foreach($models as $model => $modelPath) {
if(file_exists($modelPath)) {
$data = file_get_contents($modelPath);
$find = array();
$find[] = "useTable = '";
$find[] = "useTable='";
$find[] = "useTable= '";
$find[] = "useTable ='";
foreach($find as $condition) {
$pos = strrpos($data, $condition);
if($pos !== false ) {
$pos+=(strlen($condition));
$tableName = substr($data, $pos, (strpos($data, "';", $pos)-$pos));
debug($tableName);
}
}
}
}
}
CakePHP v2
In AppController
if (in_array('YOUR_MODEL', $this->uses)) {
//found
}

Returning JSON after a query in yii

I'm new to yii framework. I'm just trying to implement Restful APIs. In the simple case scenario (after following some tutorial) I've succeeded with this:
$result = [];
foreach($this->getData() as $record) {
$result[] = $record->getAttributes();
}
return $result;
Note that getData() is a built-in method. Where when trying to use queries for more advanced scenarios, it's done this way:
$attributeNames = 'udid,model,appverionid';
$connection = Yii::app()->db;
$command = $connection->createCommand('select ' . $attributeNames . ' from device');
$models = $command->queryAll();
$attributeNames = explode(',', $attributeNames);
$rows = array();
foreach ($models as $model) {
$row = array();
foreach ($attributeNames as $name) {
$row[$name] = CHtml::value($model, $name);
}
$rows[] = $row;
}
return $rows;
Is that the best practice to return get JSON from queries results, or maybe it can be done in a better way?
Update:
The final response is returned from the following method:
private function sendAjaxResponse(AjaxResponseInterface $interface)
{
$success = count($interface->getErrors()) === 0;
$responseCode = $success ? 200 : 404;
header("content-type: application/json", true, $responseCode);
echo json_encode([
'success' => $success,
'data' => $interface -> getResponseData(),
'errors' => $interface -> getErrors()
]);
Yii::app()->end();
}
And I found out that only these lines are sufficient:
$attributeNames = 'udid,model,appverionid';
$connection = Yii::app()->db;
$command = $connection->createCommand('select ' . $attributeNames . ' from device');
$models = $command->queryAll();
return $models;
The other part (the nested loop) seems for encoding with relations (see here) Then my question is what is encoding with relations and when it is helpful?
The Yii way of creating JSOn data is using CJson library
$query = "'select ' . $attributeNames . ' from device'";
$command = Yii::app()->db->createCommand($query);
$result = $command->queryAll();
$ret = array_values($result);
/* or ...
$ret = array();
foreach ($models as $model) {
$ret = array();
foreach ($attributeNames as $name) {
$row[$name] = CHtml::value($model, $name);
}
$ret[] = $row;
}
*/
echo CJSON::encode($ret);
Yii::app()->end();
I think you simply need to encode the value before return
foreach ($models as $model) {
$row = array();
foreach ($attributeNames as $name) {
$row[$name] = CHtml::value($model, $name);
}
$rows[] = $row;
}
return json_encode($rows);
Very Simple! Just add this line - \Yii::$app->response->format = \yii\web\Response:: FORMAT_JSON; in your method at start and do other code
normally.
for example,
public function actionHospitals()
{
\Yii::$app->response->format = \yii\web\Response:: FORMAT_JSON;
$hospitals = Hospitals::find()->select('speciality')->distinct()->all();
return ['hospitals' => $hospitals];
}

Entity metadata wrapper

i'm getting error with metadata wrapper.
i have a field test => entity reference multiple which is a selection list.I get the following Error EntityMetadataWrapperException : Invalid data value given. Be sure it matches the required data type and format.
$account = entity_load_single('user', $user->uid);
$acc_wrapper = entity_metadata_wrapper('user', $account);
$list = $acc_wrapper->test->value();
$exists = FALSE;
if (!empty($list)) {
foreach ($list as $item) {
if ($item->nid == $form_state['storage']['node']->nid) {
$exists = TRUE;
break;
}
}
}
if (!$exists) {
if (!$list) {
$list = array();
$list[] = $form_state['storage']['node']->nid;
}
$acc_wrapper->test->set($list);
$acc_wrapper->save();
1rst quick tips
$account = entity_load_single('user', $user->uid);
$acc_wrapper = entity_metadata_wrapper('user', $account);
You don't need to load the entity unless you need it loaded after (Or it's already loaded). All you need is the id, and let entity_metadata_wrapper magic operate.
$acc_wrapper = entity_metadata_wrapper('user', $user->uid);
I think your error is here
if (!$list) {
$list = array();
$list[] = $form_state['storage']['node']->nid;
}
$list is always initiated because of "$list = $acc_wrapper->test->value();", so you never fullfill the condition, and then you are trying to set it back and save it (because you are missing a '}' )... Makes no sense...
Could try this version ?
$acc_wrapper = entity_metadata_wrapper('user', $user->uid);
$list = $acc_wrapper->test->value();
$exists = FALSE;
if (!empty($list)) {
foreach ($list as $item) {
if ($item->nid == $form_state['storage']['node']->nid) {
$exists = TRUE;
break;
}
}
}
if (!$exists && !$list) {
$list = array($form_state['storage']['node']->nid);
$acc_wrapper->test = $list;
$acc_wrapper->save();
}

Categories