I was looking at this code and noticed it seemed a lot of code just to run 2 checks, and I remembered coding in C# and there was a way to shorten the code to just one check but add a (something ? something) in it, is there a way to do something like this in PHP?
if ($config->get('core:twig.caching.enabled')) {
$this->twig = new \Twig_Environment($loader, array(
'cache' => $config->get('core:template.cache_directory'),
));
}
else {
$this->twig = new \Twig_Environment($loader);
}
I would do it this way:
$cache = $config->get('core:twig.caching.enabled');
$arr = ($cache) ? array('cache' => $cache) : array();
$this->twig = new \Twig_Environment($loader, $arr);
Because I'm not 100% sure what $config->get('core:twig.caching.enabled'); do return the above solution will work as your original one.
But if the return value is only true or false and if its ok to hand over array('cache' => true) or array('cache' => false) than you can reduce this furthermore:
$this->twig = new \Twig_Environment($loader, array(
'cache' => $config->get('core:twig.caching.enabled')
));
Related
I am new at PHP. We are creating REST API in Phalcon and I've created a put request. It already works, but I would like to check if update has really happened before sending a success response. So I've created a conditional for that ( if (!$product->update()) ), but it always returns 'true'. How can I check if any field has changed in a record?
public function put()
{
$id = $this->getParam('id');
$input = $this->getRawData();
$product = Product::findFirst([
'conditions' => 'id = :id:',
'bind' => ['id' => $id]
]);
if ($product === null){
throw new NotFoundException();
}
$product->assign($input);
$product->update();
if (!$product->update()) {
$this->errorResponse($product->getMessages());
} else {
$this->successResponse($product->toArray($product->update()));
}
}
You can use Model Events, i.e. afterUpdate and notSaved, like:
use Phalcon\Mvc\Model;
use Phalcon\Http\Response;
class ModelBase extends Model
{
public function afterUpdate()
{
$response = new Response();
$response->setJsonContent([
'success' => true,
'message' => "Record updated"
])->send();
}
public function notSaved()
{
$response = new Response();
$response->setJsonContent([
'success' => false,
'message' => 'Record not saved'
])->send();
}
}
The Product and all other models will extend ModelBase. Then your code could be:
public function put()
{
$id = $this->getParam('id');
$input = $this->getRawData();
$product = Product::findFirst([
'conditions' => 'id = :id:',
'bind' => ['id' => $id]
]);
if ($product === null){
throw new NotFoundException();
}
$product->assign($input);
$product->update();
}
And Phalcon event will respond if the model was updated or not. If you prefer, you can also use custom http response codes for update or notSaved. More information about Model Events in the documentation
You are calling $product->update() three times. You do it once after the assign, then again for your if test, which is why it's always returning TRUE there I believe, and once inside the toArray() which may not actually return anything since the second and third updates don't have any data to update (not sure about that though).
I would code this as follows:
$product->assign($input);
$results = $product->update();
if (!results) {
$this->errorResponse($product->getMessages());
} else {
$this->successResponse($results->toArray());
}
I am assuming that the $product->assign($input); statement is working as expected to update the $product data for you. I don't use that. I prefer to do direct assignments for updates so nothing is left to chance, ie. $product->whatever = $input['whatever'];.
Give this a try and hopefully it will work as expected for you.
I have a class named webserviceCall.
This is my class structure :
Constructor --->
Initiate webservice clients and DB handler class and some properties :
public function __construct()
{
$this->username = $GLOBALS['WEBSRVC']['username'];
$this->password = $GLOBALS['WEBSRVC']['password'];
$this->api = $GLOBALS['WEBSRVC']['api'];
$this->loginClient = new SoapClient(NULL, array(
'location' => "http://domain.com/webservice/kks/server.php",
'uri' => "urn://test/webservice") );
$this->booksClient = new SoapClient(null, array(
'location' => "http://domain.com/webservice/kks/books.php",
'uri' => "urn://test/webservice"
));
$this->shopClient = new SoapClient(null, array(
'location' => "http://domain.com/webservice/kks/newShop.php",
'uri' => "urn://test/webservice/shop"
) );
$this->db = new dbHandler($GLOBALS['DBVAR']['dbn'], $GLOBALS['DBVAR']['usn'], $GLOBALS['DBVAR']['psw']);
$this->param = self::freshLogin( $this->username, $this->password, $this->api);
}//__Construct
And there's a method for check Login, based on webservice needs:
protected function freshLogin($username, $password, $api)
{
$currentInfo = $this->db->simple_search('webservice');
$token = ( ($currentInfo[0]['token'] != '') ? $currentInfo[0]['token'] : false );
if( $token == false )
{
$token = $this->loginClient->__soapCall('authenticate', array($currentInfo[0]['username'], $currentInfo[0]['password'], $currentInfo[0]['api']) );
//update token in table
$updateToken = $this->db->update_single('webservice', 'token', $token, true, 'api', $api);
return $token . '||' . $api;
}//token is empty - first login
else
{
$checkToken = $this->loginClient->__soapCall('checkToken', array($token, $api) );
if( isset($checkToken) && $checkToken > 0 )
{
return $token . '||' . $api;
}//if token is valid
else
{
$token = $this->loginClient->__soapCall('authenticate', array($currentInfo[0]['username'], $currentInfo[0]['password'], $currentInfo[0]['api']) );
//update token in table
$updateToken = $this->db->update_single('webservice', 'token', $token, true, 'api', $api);
return $token . '||' . $api;
}//authenticate again, save token and create param value
}//token exists
}//function freshLogin
And finally, there's a method for transact webservice :
public function getBooks()
{
return $this->booksClient->__soapCall('getAllBooks', array($this->param) );
}//function getAllBooks
When I check getBooks() function with getAllBooks method, it seems the browser is waiting for the response, and there's no result. This is error:
Maximum execution time of 30 seconds exceeded in C:\xampp\htdocs\ketabTheme\PHP\classes\webserviceCall.php on line 114
But When I check exactly the same request in another file, out of a class, it's OK. Besides, when I call another method of webservice inside getBooks method, again everything is fine.
Would you please help me to find out what's wrong here?
Note :
getBooks method should have an array with 1935 index in result.
UPDATE :
When I check this request in another file outside a class, this is the request-response timeline :
When you say "But When I check exactly the same request in another file, out of a class, it's OK.", how long does it take?
You should try increasing the max_execution_time in the php.ini file or by setting: ini_set('max_exeution_time', 60 /*seconds*/) in your PHP script?
I have to generate an URL in a task but I get an incorrect url of type:
./symfony/user/edit/id
when I need
/user/edit/id
My first try was:
protected function execute($arguments = array(), $options = array())
{
$configuration = ProjectConfiguration::getApplicationConfiguration('frontend', $options['env'], true);
$this->context = sfContext::createInstance($configuration);
$baseurl = $this->context->getController()->genUrl(array('module' => 'user','action' => 'edit', 'id' => $id));
// ...
}
My second try, following this answer gives the same incorrect url:
protected function execute($arguments = array(), $options = array())
{
$configuration = ProjectConfiguration::getApplicationConfiguration('frontend', $options['env'], true);
$this->context = sfContext::createInstance($configuration);
$routing = $this->context->getRouting();
$baseurl = $routing->generate('user_edit', array('id' => $id));
// ...
}
How can I get the correct URL ?
Have you tried the solution from the snippet? I use this one in many projects.
I was also using almost the same second solution you describe but a bit different:
// you get the context the same way
$context = sfContext::createInstance($configuration);
$this->controller = $context->getController();
$baseurl = $this->controller->genUrl('user_edit?id='.$id);
Check parameters for genUrl, you can give true/false as second argument for absolute url.
I solved adding the --application option!
protected function configure()
{
$this->addOptions(array(
new sfCommandOption('env', null, sfCommandOption::PARAMETER_REQUIRED, 'The environment', 'dev'),
new sfCommandOption('application', null, sfCommandOption::PARAMETER_REQUIRED, 'The application name', 'frontend'),
));
//...
}
I didn't know that it was required even if I write directly its name in the getApplicationConfiguration params.
$configuration = ProjectConfiguration::getApplicationConfiguration('frontend', $options['env'], true);
Playing around with twig templates (not a part of Symfony, in CodeIgniter) and it doesn't look like I can get a global sandbox to work correctly. I'm pretty sure I'm just doing something stupid, but I really can't see it.
Functions to make twig work:
public function twig_setup($configs = NULL)
{
Twig_Autoloader::register();
$env = array(
'cache' => config_item('cache_dir'),
'strict_variables' => TRUE,
'auto_reload' => TRUE,
'extension' => 'php',
'filesystem' => NULL
);
if (!is_null($configs))
{
$env = array_merge($env, $configs);
}
$this->set_extension($env['extension']);
if (is_null($env['filesystem']))
{
$env['filesystem'] = VIEWPATH;
}
else
{
$env['filesystem'] = VIEWPATH .'/'. ltrim($env['filesystem'],'/');
}
$this->set_filesystem($env['filesystem']);
// These two things should not get set to the environment
unset($env['extension']);
unset($env['filesystem']);
$this->set_environment($env);
}
public function set_sandbox($tags, $filters, $methods, $properties, $functions, $is_global = TRUE)
{
$user_policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties, $functions);
$user_sandbox = new Twig_Extension_Sandbox($user_policy, $is_global);
$this->twig->addExtension($user_sandbox);
}
public function disable_logic()
{
$tags = array('for', 'block', 'include');
$filters = array();
$methods = array();
$properties = array();
$functions = array('parent', 'block');
$this->set_sandbox($tags, $filters, $methods, $properties, $functions);
}
Usage:
$twig = new TwigThing();
$twig->twig_setup();
$twig->disable_logic();
Now, once I render a template, I should not be able to use something like raw or url_encode
{{ my_var|url_encode }}
That should kick out an error, or something, but it just encodes the var...wtf am I doing wrong here?
So far I have been unable to successfully implement ACLs (permissions) in SabreDAV.
I have implemented SabreDAV in Code Igniter with my own Auth, Principal and CalDAV backend. This the actual code from the controller:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class CalDAV extends CI_Controller {
public function _remap() {
$this->load->library('SabreDAV');
$authBackend = new SabreDAV_DAV_Auth_Backend_Tank_Auth;
$principalBackend = new Sabre_DAVACL_PrincipalBackend_Click4Time;
$calendarBackend = new Sabre_CalDAV_Backend_Click4Time;
// Directory tree
$tree = array(
new Sabre_DAVACL_PrincipalCollection($principalBackend),
new Sabre_CalDAV_CalendarRootNode($principalBackend, $calendarBackend)
);
// The object tree needs in turn to be passed to the server class
$server = new Sabre_DAV_Server($tree);
// You are highly encouraged to set your WebDAV server base url. Without it,
// SabreDAV will guess, but the guess is not always correct. Putting the
// server on the root of the domain will improve compatibility.
$server->setBaseUri('/caldav/');
// Authentication plugin
$authPlugin = new Sabre_DAV_Auth_Plugin($authBackend, 'SabreDAV');
$server->addPlugin($authPlugin);
// CalDAV plugin
$caldavPlugin = new Sabre_CalDAV_Plugin();
$server->addPlugin($caldavPlugin);
// ACL plugin
$aclPlugin = new Sabre_DAVACL_Custom;
$server->addPlugin($aclPlugin);
// Support for html frontend
$browser = new Sabre_DAV_Browser_Plugin();
$server->addPlugin($browser);
$server->exec();
}
}
My current attempt at implementing permissions has been through my custom ACL Plugin:
<?php
class Sabre_DAVACL_Custom extends Sabre_DAVACL_Plugin {
public $allowAccessToNodesWithoutACL = false;
private function _getCurrentUserName() {
$authPlugin = $this->server->getPlugin('auth');
if (is_null($authPlugin)) return null;
return $authPlugin->getCurrentUser();
}
public function getACL($node) {
$user = $this->_getCurrentUserName();
$path = $node->getName();
if ($path == 'calendars' || $path == 'principals' || $path == 'root') {
return array(
array(
'privilege' => '{DAV:}read',
'principal' => 'principals/' . $user,
'protected' => true,
)
);
}
else if ($path == 'calendars/' . $user) {
return array(
array(
'privilege' => '{DAV:}read',
'principal' => 'principals/' . $user,
'protected' => true,
)
);
}
return array();
}
}
This code pretty much works except the second check which should authorize the user to see his or her own calendar(s). I am unable to get the full path name for $node.
This may be the wrong way to implement but I have been unable to find any documentation to confirm that this is the way to implement ACLs.
i'm using a different attempt, i extended the plugin, just like you did but then i replaced getSupportedPrivilegeSet($node) instead.
in sabredav 1.8.6 it looks like this:
public function getSupportedPrivilegeSet($node) {
if (is_string($node)) {
$node = $this->server->tree->getNodeForPath($node);
}
if ($node instanceof IACL) {
$result = $node->getSupportedPrivilegeSet();
if ($result)
return $result;
}
return self::getDefaultSupportedPrivilegeSet();
}
now you can use the classes instead of the path which i found more usefull, i.e.:
class DavCalAcl extends \Sabre\DAVACL\Plugin {
public function getSupportedPrivilegeSet($node) {
if (is_string($node)) {
$node = $this->server->tree->getNodeForPath($node);
}
if($node instanceof \Sabre\CalDAV\Calendar || $node instanceof \Sabre\CalDAV\CalendarObject) {
return array(
array(
'privilege' => '{DAV:}read',
'aggregates' => array(
array(
'privilege' => '{DAV:}read-acl',
'abstract' => true,
),
array(
'privilege' => '{DAV:}read-current-user-privilege-set',
'abstract' => true,
),
),
)
);
}
if ($node instanceof \Sabre\DAVACL\IACL) {
$result = $node->getSupportedPrivilegeSet();
if ($result)
return $result;
}
return self::getDefaultSupportedPrivilegeSet();
}
}
this is my current attempt to get iCal to recognize a calendar as read-only... i'm not quite there yet but maybe this will help you in better identifying the objects
if you want the absolute path of a node i guess you could always go to the root search it for your current node and by doing so recording the path which took you there. as far as i checked the nodes in sabredav do not support a parent or a root property.
[UPDATE]
the best way seems to be to override getACL in the plugin. here you can test for the node's class and return what you really want on instead of the stuff which is returned by the default objects (for instance look at UserCalendars->getACL().
here's my working solution for read-only enforcement based on the object types:
class DavCalAcl extends \Sabre\DAVACL\Plugin {
/**
* Returns the full ACL list.
*
* Either a uri or a DAV\INode may be passed.
*
* null will be returned if the node doesn't support ACLs.
*
* #param string|DAV\INode $node
* #return array
*/
public function getACL($node) {
if (is_string($node)) {
$node = $this->server->tree->getNodeForPath($node);
}
if (!$node instanceof \Sabre\DAVACL\IACL) {
return null;
}
if( $node instanceof \Sabre\CalDAV\Calendar ||
$node instanceof \Sabre\CalDAV\CalendarObject ||
$node instanceof \Sabre\CalDAV\UserCalendars
) {
$acl = array(
array(
'privilege' => '{DAV:}read',
'principal' => $node->getOwner(),
'protected' => true,
),
);
} else {
$acl = $node->getACL();
}
foreach($this->adminPrincipals as $adminPrincipal) {
$acl[] = array(
'principal' => $adminPrincipal,
'privilege' => '{DAV:}all',
'protected' => true,
);
}
return $acl;
}
}