I am creating an application to manage ad groups through MVC using Power Shell Script Interaction. I have created a function that will return the values to fill in the razor components of HTML. However, when I passing the shell scripts from the base directory location the component is not getting filled with the value.
I have tried to set the path of the script using AppDomain.CurrentDomain.BaseDirectory, there is no error being generated nor I am getting any output.
** Razor Code **
#functions {
public string PowerShellExecutor(string script) {
var shell = PowerShell.Create();
string outString = "";
shell.Commands.AddScript(script);
var results = shell.Invoke();
if (results.Count>0)
{
var builder = new StringBuilder();
foreach (var psObj in results)
{
builder.Append(psObj.BaseObject.ToString() + "\r\n");
}
outString = Server.HtmlEncode(builder.ToString());
}
return outString;
}
<div class="row">
<div class="col-md-12">
#Html.TextBox("txtDir", #PowerShellExecutor(AppDomain.CurrentDomain.BaseDirectory.ToString()+ "Shell\\Get-StewardName.ps1"), new { #class = "form-control" })
#*#Html.TextBox("txtDirectory", #PowerShellExecutor("$env:USERDNSDOMAIN") , new { #class = "form-control"})*#
</div>
</div>
** Powershell Script **
$StewardName = Get-ADUser $env:USERNAME -Properties DisplayName | Select -ExpandProperty DisplayName
$EmployeeNumber = Get-ADUser $env:UserName -Properties EmployeeNumber| Select -ExpandProperty EmployeeNumber
Write-Output "Steward: $StewardName ($EmployeeNumber)"
When I type the environment variables I get the domain I am member of. When I pass script it should be getting some value.
Ok, so replacing AddScript() with AddCommand() executes the script however, while using environment variables to fetch the data it throws command not found exception.
I am developing a CRUD system in Phalcon PHP (version 1.3.4).
My goal is to create a link (delete row), that asks for confirmation on click (JavaScript confirmation box) and then goes (request type POST) to the link.
So lets say a user clicks on the "delete row" button.
JavaScript confirmation "Are you sure you want to delete this row?"
User clicks "yes"
Webpage does a POST to "/users/delete/1"
I know CakePHP has a function (FormHelper::postLink()) that does exactly that.
I was wondering if Phalcon PHP also had a function like this.
I see three possibilities to achieve what you want. One is to create a macro in Volt template, second is to add a function to your View. Third and closest to - what I understand is your wish - is to extend Phalcons tag helper and this is part I will describe here.
Phalcon has its own Tag helper to allow you to easily create some elements. postLink is not a part that is implemented there, but you can easily achieve it. In my example I have namespace of Application with class of Tag that extends from \Phalcon\Tag. This is my base for this tutorial.
// Tag.php
namespace Application;
class Tag extends \Phalcon\Tag
{
static public function postLink() {
return '<strong>TEST TAG</strong>';
}
}
To force Phalcon DI to use this class, it is necessary to override it's standard declaration from engine by declaring it by hand as a new DI service:
// services.php
$di['tag'] = function() {
return new \Application\Tag();
};
You can test if it is working properly by typing {{ tag.postLink() }} in Volt template or with $this->tag->postLink() if using phtml template.
Now you can fill your Tag::postLink() method with HTML and parameters you wish it will produce:
namespace Application;
class Tag extends \Phalcon\Tag
{
static $forms = [];
static public function postLink($title, $url, $options = array()) {
// random & unique form ID
while ($randId = 'f_' . mt_rand(9000, 999999)) {
if (!isset(self::$forms[$randId])) {
self::$forms[$randId] = true;
break;
}
}
// dialog message
$dialogMessage = isset($options['message']) && $options['message'] ? $options['message'] : 'Are you sure you want to go on?';
$html = <<<HTML
<form action="{$url}" method="post" id="{$randId}">
<!-- maybe not necessary part -->
<input type="hidden" name="confirmed" value="1" />
</form>
{$title}
HTML;
return $html;
}
}
Now you can run it like this:
{{ tag.postLink('delete', '/users/delete/1') }}
{% set formOptions = ['message' : 'Are you sure you want to delete user Kialia Kuliambro?'] %}
{{ tag.postLink('delete', '/users/delete/1', formOptions) }}
{{ tag.postLink('delete', '/users/delete/1', ['message' : 'Are you sure you want to delete user Kialia Kuliambro?']) }}
Have fun extending :)
There's a few ways to implement such behavior in phalcon. Before anything, we need to understand how views and view helpers work in phalcon. And if you pay close attention, you'll notice, both .volt and .phtml have direct access to the DI.
In volt, for example, you can access the flash service, and output its messages by calling:
{{ flash.output() }}
which gets converted to the phtml: <?php echo $this->flash->output(); ?>
Thus my solution focuses on defining a new service in the DI which volt can access. In CakePHP, the syntax for postLink(), looks something like: echo $this->Form->postLink() while the function is actually defined in a class named FormHelper. So my solution will do the same thing, define a class FormHelper, then inject it into the view under the name Form.
Create an app/helpers/ directory.
Update your app/config/config.php file adding a reference to our new directory: 'helpersDir'=> APP_PATH . '/app/helpers/'
Update your app/config/loader.php file adding $config->application->helpersDir to the registered directories.
Create a new file app/helpers/FormHelper.php
Copy-paste the following code into the file:
<?php
use Phalcon\Tag;
class FormHelper extends Tag
{
protected $_lastAction = '';
public function dottedNameToBracketNotation($name)
{
$parts=explode('.',$name);
$first = array_shift($parts);
$name=$first . ($parts ? '[' . implode('][', $parts) . ']' : '');
return $name;
}
protected function flatten(array $data, $separator = '.')
{
$result = [];
$stack = [];
$path = null;
reset($data);
while (!empty($data)) {
$key = key($data);
$element = $data[$key];
unset($data[$key]);
if (is_array($element) && !empty($element)) {
if (!empty($data)) {
$stack[] = [$data, $path];
}
$data = $element;
reset($data);
$path .= $key . $separator;
} else {
$result[$path . $key] = $element;
}
if (empty($data) && !empty($stack)) {
list($data, $path) = array_pop($stack);
reset($data);
}
}
return $result;
}
protected function _confirm($message, $okCode, $cancelCode = '', $options = [])
{
$message = json_encode($message);
$confirm = "if (confirm({$message})) { {$okCode} } {$cancelCode}";
if (isset($options['escape']) && $options['escape'] === false) {
$confirm = $this->h($confirm);
}
return $confirm;
}
public function h($text, $double = true, $charset = 'UTF-8')
{
return htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, $charset, $double);
}
protected function _lastAction($url)
{
$action = $url;//Router::url($url, true);
$query = parse_url($action, PHP_URL_QUERY);
$query = $query ? '?' . $query : '';
$this->_lastAction = parse_url($action, PHP_URL_PATH) . $query;
}
public function postLink($title, $url = null, array $options = [])
{
$out='';
$options += ['block' => null, 'confirm' => null];
$requestMethod = 'POST';
if (!empty($options['method'])) {
$requestMethod = strtoupper($options['method']);
unset($options['method']);
}
$confirmMessage = $options['confirm'];
unset($options['confirm']);
$formName = str_replace('.', '', uniqid('post_', true));
$formOptions = [
'name' => $formName,
'style' => 'display:none;',
'method' => 'post',
];
if (isset($options['target'])) {
$formOptions['target'] = $options['target'];
unset($options['target']);
}
$formOptions[0]=$url;
$out.=$this->form($formOptions);
$out .= $this->hiddenField(['_method','value' => $requestMethod]);
$fields = [];
if (isset($options['data']) && is_array($options['data'])) {
foreach ($this->flatten($options['data']) as $key => $value) {
$out .= $this->hiddenField([$this->dottedNameToBracketNotation($key),'value' => $value]);
}
unset($options['data']);
}
$out .= $this->endForm();
//This is currently unsupported
if ($options['block']) {
if ($options['block'] === true) {
$options['block'] = __FUNCTION__;
}
//$this->_View->append($options['block'], $out);
$out = '';
}
unset($options['block']);
$url = '#';
$onClick = 'document.' . $formName . '.submit();';
if ($confirmMessage) {
$options['onclick'] = $this->_confirm($confirmMessage, $onClick, '', $options);
} else {
$options['onclick'] = $onClick . ' ';
}
$options['onclick'] .= 'event.returnValue = false; return false;';
$options[0]=$url;
$options[1]=$title;
$options[2]=false;
$out .= $this->linkTo($options);
return $out;
}
}
Edit your app/config/services.php file and add in:
$di->set('Form',function () {
return new FormHelper();
});
(you could make "Form" lowercase if you want, both work. I made it capital to closer resemble CakePHP's syntax. Do note that Volt is case sensitive when trying to access services but phtml will lowercase it.)
Edit the template you want to test the code on, such as app/views/index/test.volt
Copy-paste the following code into there:
{{ Form.postLink(' Delete','',['confirm':'Are you sure you want to delete #4?','data':['a':['b','c']]]) }}
Alternatively for phtml, use: <?php echo $this->form->postLink(' Delete', '', array('confirm' => 'Are you sure you want to delete #4?', 'data' => array('a' => array('b', 'c')))); ?>
Run it, and watch it work its magic, just render your index/test.volt template by visiting /index/test in your address bar. (Make sure you defined such an action in your index controller)
In terms, of other solutions, you could also use $compiler->addFunction() to make functions available to volt, one at time. The page in the manual gives the example of $compiler->addFunction('shuffle', 'str_shuffle');. You can attempt to override the factoryDefault for "tag" in the DI, and use the helper we already defined which extends tag. So you'd just change it from "form" to "tag" like so: $di->set('tag',function () {return new FormHelper();}); but, as you can see, it won't make the function postLink() available to volt as a function, you'll notice you still need to access it as tag.postLink(). Rather, all the \Phalcon\Tag functions are actually hard-coded into the volt engine. You can see this clearly by viewing the zephir source code of the \Phalcon\Mvc\View\Engine\Volt\Compiler class available over here. For your convenience, and in case the link ever gets broken, I have posted a snippet here which shows the "tag" functions in volt are actually hard-coded into it:
if method_exists(className, method) {
let arrayHelpers = this->_arrayHelpers;
if typeof arrayHelpers != "array" {
let arrayHelpers = [
"link_to": true,
"image": true,
"form": true,
"select": true,
"select_static": true,
"submit_button": true,
"radio_field": true,
"check_field": true,
"file_field": true,
"hidden_field": true,
"password_field": true,
"text_area": true,
"text_field": true,
"email_field": true,
"date_field": true,
"tel_field": true,
"numeric_field": true,
"image_input": true
];
let this->_arrayHelpers = arrayHelpers;
}
if isset arrayHelpers[name] {
return "$this->tag->" . method . "(array(" . arguments . "))";
}
return "$this->tag->" . method . "(" . arguments . ")";
}
So, if you'd like to "hack" in a few more methods by extending the \Phalcon\Tags class, you're out of luck. However, as demonstrated on the volt documentation page, there exists the concept of registering custom extensions to work with volt. The documentation gives the example of: $compiler->addExtension(new PhpFunctionExtension());
Where the source of the class is:
<?php
class PhpFunctionExtension
{
/**
* This method is called on any attempt to compile a function call
*/
public function compileFunction($name, $arguments)
{
if (function_exists($name)) {
return $name . '('. $arguments . ')';
}
}
}
This would allow volt access to any function you'd like, without having to manually register every possible function you could possibly ever need. You can test this by trying to access str_shuffle in volt, like we did before with $compiler->addFunction('shuffle', 'str_shuffle'); but this time without having to register it.
In terms of other solutions, you could also try to integrate CakePHP and PhalconPHP together, and attempt to call CakePHP's view helpers from PhalconPHP, but then you'd run into a problem of CakePHP not understanding your router setup you have configured in Phalcon. But, if you're determined, you could code all the routes and config for CakePHP and run it alongside PhalconPHP, but I'd highly discourage such a desperate workaround. And, finally, if you understand how the function works, and you barely use it, you could get away with just hard-coding the HTML in the first place. Honestly, CakePHP's logic doesn't look so sound to me in the first place because it has to corrupt your HTML document with a form inserted which can bother your layout. I think it would make more sense to generate a form dynamically with JavaScript, if we're using JavaScript already, and append it to the <body> when the button is clicked, then submit the form we just created dynamically. But, you wanted a CakePHP implementation, so I coded it as close to the logic they used as possible. It's not perfect, in terms of supporting all their features, such as block, but it should suit most of your needs.
I can always revise my implementation, but I think it demonstrates how to work with Phalcon pretty well for those migrating from CakePHP.
I can't figure out how to do the following:
Before running my tests I would like to post (multipart) a file to the server. Our backend creates content profiles for these uploads which can then be accessed through the UI. It's this content profile I need to run tests on.
I am aware of the .fill() functionality but this does not apply as I do not want to do file uploads through the UI. Is there any way this can be achieved via CasperJS or javascript or can anyone point me to documentation that might help me?
As far as I have read the documentations of both casperjs and phantomjs, direct file submissions are not allowed. You may use curl like below:
curl http://some.testserver.com/post.php \
-F file_input=#/path/to/my/file.txt \
-F "text_field=Some Text Here" \
-F some_number=1234
You can however open a POST request on casperjs:
casper.start();
casper.open('http://some.testserver.com/post.php', {
method: 'post',
data: {
'title': 'Plop',
'body': 'Wow.'
},
headers: {
'Content-type': 'multipart/form-data'
}
});
casper.then(function() {
this.echo('POSTED it.');
});
casper.run();
Here is the relevant documentation:
http://docs.casperjs.org/en/latest/modules/casper.html#open
Check this.page.uploadfile, as the phantom browser does not have an ui to select the file, you can use it to point to file name, then hit submit.
phantom.casperPath = '{PATH_TO_CASPER_JS}';
phantom.injectJs(phantom.casperPath + '\\bin\\bootstrap.js');
var system = require('system')
var page = require('webpage').create();
var casper = require('casper').create();
function getReturnedText() {
return document.querySelector('#ocr-result').innerText;
}
casper.start('http://www.newocr.com/', function() {
this.page.uploadFile('input[type="file"]', '{PATH_TO_JPEG}');
this.click('button[name="preview"]');
});
casper.thenEvaluate(function() {
this.click('button[name="ocr"]');
});
casper.run(function() {
this.echo(getReturnedText());
phantom.exit(1);
});
Try this:
casper.thenOpen('about:blank', function(){
this.evaluate(function(){
var action = 'upload.php'
var html = '<form action="'+action+'" method="post" enctype="multipart/form-data">'
html += '<input type="file" name="files[]" multiple="multiple">'
html += '<button type="submit">Submit</button>'
html += '</form>'
document.write(html)
})
this.fill('form',{
'files[]': 'file.txt'
}, true)
this.waitFor(function(){
var uri = casper.evaluate(function(){
return document.documentURI
})
if ( 'about:blank' === uri ){
return false
}
return true
})
})
I am trying to set up an autocomplete input box on a form and although everything seems to work I an getting no data passed to the input box. Firebug reports a success but nothing there. I was wondering if some one could look at my code to see if there are any glaring errors that may be causing it.
Script is:
(function($){
$("#town").autocomplete({
source :"drivers/driver_gettown",
minLength : 3,
dataType:'JSON',
type:'POST'
});
})(jQuery);
Input Box is:
<div class="div">
<input name="town" id="town" type="text" class="txtSelect input required" value="<?php echo set_value('town'); ?>" />
<?php echo form_error('town'); ?>
</div>
Model is:
class Driver_model extends CI_Model
{
public function __construct() {
// Load the Database
parent::__construct();
$this->load->database();
}
function driver_get_towns($q)
{
// Get a list of Towns
// Search for row "place_name" from Table called "tbk_towns"
$this->db->select('place_name');
$this->db->like('place_name', $q);
$query = $this->db->get('tbk_towns');
if($query->num_rows > 0)
{
foreach ($query->result_array() as $row)
{
//build an array for the towns
$row_set[] = htmlentities(ucfirst($row['place_name']));
}
//format the array into json data
// header('Content-Type: application/x-json; charset=utf-8');
// echo json_encode($row_set);
$this->output
->set_content_type('application/json')
->set_output(json_encode($row_set));
}
}
}
and Finally the controller:
class Drivers extends CI_Controller
{
function __construct()
{
parent::__construct();
$this->load->model('driver_model');
$this->load->helper('url', 'form', 'html', 'json');
}
function index()
{
// Just loads the main Page of the Drivers Area
$data['metatitle'] = "Auto Ninja | Drivers Members Area | Locally Rated Garages & Mechanics";
$data['metadescription'] = "Garages & Mechanics";
$data['metakeywords'] = "Car Repair, Car Service, Car MOT";
$this->load->view('drivers/header_drivers.inc.php', $data);
$this->load->view('drivers/index');
$this->load->view('drivers/footer_index.inc.php');
}
public function driver_gettown()
{
if (isset($_GET['term'])){
exit;
}
$this->load->model('driver_model');
$q = ucfirst($_GET['term']);
$this->driver_model->driver_get_towns($q);
}
}
and comments/help would be gratefully appreciated.
function driver_addjob()
{
// Loads the Add New Job Form for the Website
$this->load->helper('form');
$this->load->library(array('form_validation', 'session'));
$this->load->model('driver_model');
$this ->form_validation->set_error_delimiters('<span class="error">', '</span>');
// Validate the form fields
$this->form_validation->set_rules('town', 'Nearest Town or City', 'trim|required|xss_clean');
// Populates dropdown "town" from the database ???
if ($this->form_validation->run() == FALSE)
{
$data['metatitle'] = "Auto Ninja | Drivers - Add New Job | Locally Rated Garages & Mechanics";
$data['metadescription'] = "Garages & Mechanics";
$data['metakeywords'] = "Car Repair, Car Service, Car MOT";
$this->load->view('drivers/header_drivers.inc.php', $data);
$this->load->view('drivers/driver_addjob.php');
$this->load->view('drivers/footer_index.inc.php');
}
else
{
$townid = $this->input->post('town');
$work_jobtitle = $this->input->post('jobtitle');
$this->driver_model->driver_add_job ($townid);
$this->session->set_flashdata('message', 'your work request has been added to the system');
$data['metatitle'] = "Auto Ninja | Drivers - Add New Jobs Success | Locally Rated Garages & Mechanics";
$data['metadescription'] = "Garages & Mechanics";
$data['metakeywords'] = "Car Repair, Car Service, Car MOT";
$this->load->view('drivers/header_drivers.inc.php', $data);
$this->load->view('drivers/driver_addjob_success');
$this->load->view('drivers/footer_index.inc.php');
}
}
Ok I finally figured this one out. For some reason the response URL is coming out at
http://php.codeigniter.server/drivers/drivers/driver_gettown?term=ed
so the controller is being added twice. I updated the Java to
(function($){
$("#town").autocomplete({
source :"driver_gettown",
minLength : 3,
dataType:'JSON',
type:'POST'
});
})(jQuery);
ie not including the controller and it works!!! So a tad confused as to how it knows which controller to find the method in but who cares it works. It would be nice to know though as it will probably still annoy me... Possibly the JSON call bring it over in the URL maby?
I'm using an old version of symfony 1.0.11
slot('breadcrumbs');
include_component('page','breadcrumbs',array('past_pages'=>array(
'/module/action/parameter/value'=>'Home ')));
end_slot();
The problem with this code is that parameter and value do not get passed, so If i click on home i get /module/action but the parameters are not being passed. Any suggestions?
Thanks.
There is also a way automatically set the breadcrumbs this is in the breadcrumbs actions:
// Get the full path without get parameters
$fullPath = $request->getPathInfo();
// get the get parameters
$urlParams = $request->getGetParameters();
// set get parameters as string for url
$this->extend = "";
foreach ($urlParams as $key => $urlParam) {
if (empty($this->extend)) {
$this->extend = "?";
}
this->extend .= $key."=".$urlParam;
}
// Get the URL path and Explode by /
$paths = explode('/', $fullPath);;
$this->paths = $paths;
then in the component itself, you can foreach through the paths and if empty just continue. And always give the GET variables with the link if the browser has some.
Home
<?php foreach($paths as $path):
if(empty($path))
continue;
if(empty($fullPath))
$fullPath = "";
$fullPath .= "/".$path.$extend;
$path = str_replace("-", " ", $path);
?>
<?php if(key($paths->getRawValue()) != (count($paths)-1)): ?>
<?php echo ucwords($path); ?>
<?php else: ?>
<span><?php echo ucwords($path); ?></span>
<?php endif; ?>
This way you never have to set your breadcrumbs if you have a correct url structure.
the way i fixed it is
include_component('page','breadcrumbs',array('past_pages'=>array(
'/module/action?parameter=value'=>'Home ')));