import of HttpSocket in Paypal in cakephp - cakephp

Well, here's what i got. I have a line of code here that imports HttpSocket in my CakePHP-paypal integration.
It is located in my /app/PaypalIpn/Model/DataSource/PaypalIpnSource.php. Here it is:
function __construct(){
if (!class_exists('HttpSocket')) {
if(App::uses('HttpSocket', 'Network/Http')){
$this->log('http socket imported','paypal');
}
}
else{
$this->log('http socket not imported','paypal');
}
$this->Http = new HttpSocket();
}
By the way, my HttpSocket.php is located here:
C:\xampp\htdocs\wifidrivescanportal\lib\Cake\Network\Http\HttpSocket.php
So everytime i try to access this function in my HttpSocket.php:
public function post($uri = null, $data = array(), $request = array()) {
//$this->log('entered post in http socket','paypal');
$request = Set::merge(array('method' => 'POST', 'uri' => $uri, 'body' => $data), $request);
return $this->request($request);
}
via this line of code inside my PaypalIpnSource.php:
function isValid($data){
// .... other codes
$response = $this->Http->post($server, $data);
return $response;
}
nothing happens. It doesn't log anything despite that i indicated it to log something particularly in some portions in /app/PaypalIpn/Model/DataSource/PaypalIpnSource.php

Debug the raw response data in the HttpSocket class. In 1.3 I had a few cases in the past were I had the same issue with this class.
Try http://api13.cakephp.org/view_source/http-socket/#l-292 debug($this->request['raw']) after this line.
The raw data might contain something that the 1.3 class does not pick up.

Well here's what I did these line of codes
function isValid($data){
// .... other codes
$response = $this->Http->post($server, $data);
return $response;
}
I made it this way:
function isValid($data){
// .... other codes
return $this->Http->post($server, $data);
}
Not so certain with the difference but it worked out this way. Once I finished my paypal integration in cakephp, i'll make sure i'll provide a tutorial for beginners like me. Hope I could help that way. My next goal is to do the encryption using ppcrypto.

Related

Creating Rest API without views using cakePHP 3.5

I'm trying to create Rest API without view and planning to use these api's in angular 2 application. does have any idea about it?
Cake makes this incredibly easy. A few things I have learned building without views.
Set the _serialize variable
$data = ['cheeses' => ['gouda', 'pepper jack', 'cheddar']];
$this->set('responseData', $data);
$this->set('_serialize', 'responseData');
Throw bad request exceptions and other network related exceptions
Cake will render nice json views for you.
Set your accept header when issuing and ajax request to be application/json
You can use cake prefixes for api versions
Look at Stateless Authentication for your api
In your AppController.php, with these parameters, all of your controllers will be render in json
public function beforeRender(Event $event)
{
$this->RequestHandler->renderAs($this, 'json');
$this->response->type('application/json');
$this->set('_serialize', true);
}
CakePHP will render json easily.
In your Controller,look like something.
protected $responseBody = [];
public function beforeRender(Event $event){
foreach($this->responseBody as $responseKey=>$response){
$this->set($responseKey, $response);
}
$this->set('_serialize', array_keys($this->responseBody));
}
public function initialize()
{
parent::initialize();
$this->RequestHandler->renderAs($this, 'json');
}
public function index(){
$this->request->allowMethod(['get']); // Method like post,get..
$this->responseBody["statusCode"] = 200;
$this->responseBody["statusDescription"] = ''; //You send any text in json.
$this->responseBody["data"] = []; // All data that you can send.
}
For further informations , You can see CakePHP Cookbook REST API to click here

CakePHP 3.4.2 Testing POST's response always returning NULL

i'm currently testing an app that simply searches a record by the given id.
It works fine but the testing refuses to return the response in the code. Strangely it is ONLY shown in the CLI.
I'm using phpunit provided by cakephp:
"phpunit/phpunit": "^5.7|^6.0"
Here is the conflicting code:
$this->post('/comunas/findByBarrio',[
'barrio_id'=>1
]);
var_dump($this->_response->body());die(); //This is just a test which always returns NULL... while the CLI shows the actual response, which is a JSON.
Also the same problem occurrs while doing GET or POST to any other action.
But here is the targeted controller's code:
public function findByBarrio()
{
$this->autoRender = false;
if ($this->request->is('POST'))
{
$data = $this->request->getData();
if (!empty($data['barrio_id']))
{
$this->loadModel('Comuna');
$barrio_id = $data['barrio_id'];
$comuna = $this->Comuna->find('list',['conditions' => ['barrio_id'=>$barrio_id]])
->hydrate(false)
->toArray();
if ($comuna)
{
echo json_encode($comuna);
}
else
{
throw new NotFoundException('0');
//echo 0; //Comuna no encontrada para el barrio recibido
}
}
else
{
echo -1;
}
}
}
Thank you in advance!
UPDATE 1: I've only managed to get the output by using "ob_start()" and "ob_get_clean()" around the "$this->post" method. I wish there were a cleaner way though...
UPDATE 2: Now it's working! Just by using the PSR-7 compliant interface. Thank you!
Here is the corrected controller:
public function findByBarrio()
{
$this->autoRender = false;
$this->response = $this->response->withType('json'); //CORRECTION
if ($this->request->is('POST'))
{
$data = $this->request->getData();
if (!empty($data['barrio_id']))
{
$this->loadModel('Comuna');
$barrio_id = $data['barrio_id'];
$comuna = $this->Comuna->find('list',['conditions' => ['barrio_id'=>$barrio_id]])
->hydrate(false)
->toArray();
if ($comuna)
{
$json = json_encode($comuna);
$this->response->getBody()->write($json); //CORRECTION
}
else
{
//Comuna no encontrada para el barrio recibido
$this->response->getBody()->write(0); //CORRECTION
}
}
else
{
//No se recibió el barrio
$this->response->getBody()->write(-1); //CORRECTION
}
}
return $this->response; //CORRECTION
}
Controller actions are not supposed to echo data, even though it might work in some, maybe even most situations. The correct way of outputting data that doesn't stem from a rendered view template, is to configure and return the response object, or to use serialized views.
The test environment relies on doing this properly, as it doesn't buffer possible output, but will use the actual value returned from the controller action.
The following is basically a copy from https://stackoverflow.com/a/42379581/1392379
Quote from the docs:
Controller actions generally use Controller::set() to create a context that View uses to render the view layer. Because of the conventions that CakePHP uses, you don’t need to create and render the view manually. Instead, once a controller action has completed, CakePHP will handle rendering and delivering the View.
If for some reason you’d like to skip the default behavior, you can return a Cake\Network\Response object from the action with the fully created response.
* As of 3.4 that would be \Cake\Http\Response
Cookbook > Controllers > Controller Actions
Configure the response
Using the PSR-7 compliant interface
$content = json_encode($comuna);
$this->response->getBody()->write($content);
$this->response = $this->response->withType('json');
// ...
return $this->response;
The PSR-7 compliant interface uses immutable methods, hence the utilization of the return value of withType(). Unlike setting headers and stuff, altering the body by writing to an existing stream doesn't change the state of the response object.
CakePHP 3.4.3 will add an immutable withStringBody method that can be used alternatively to writing to an existing stream.
$this->response = $this->response->withStringBody($content);
Using the deprecated interface
$content = json_encode($comuna);
$this->response->body($content);
$this->response->type('json');
// ...
return $this->response;
Use a serialized view
$content = json_encode($comuna);
$this->set('content', $content);
$this->set('_serialize', 'content');
This requires to also use the request handler component, and to enable extensing parsing and using correponsing URLs with .json appended, or to send a proper request with a application/json accept header.
See also
Cookbook > Controllers > Controller Actions
Cookbook > Views > JSON and XML views
PHP FIG Standards > PSR-7 HTTP message interfaces

Cakephp validation bug in controller?

I am trying to invalidate a field by a condition in controller instead of Model.
$this->Model->invalidate('check_out_reason', __('Please specify check out reason.', true));
The above won't work to invalidate the field. Instead, I need the below:
$this->Model->invalidate('Model.check_out_reason', __('Please specify check out reason.', true));
However, if I wish get the error message show up in the "field" itself ($this->model->validationErrors), it needs to be "check_out_reason" instead of "Model.check_out_reason". That means, I can't get the error message to show up in the field itself if I wish to invalidate the input in controller.
May I know is this a bug in CakePHP?
i created a test controller called "Invoices", just for testing, and i developed the following function
public function index(){
if (!empty($this->request->data)) {
$this->Invoice->invalidate('nombre', __('Please specify check out reason.'));
if ($this->Invoice->validates()) {
// it validated logic
if($this->Invoice->save($this->request->data)){
# everthing ok
} else {
# not saved
}
} else {
// didn't validate logic
$errors = $this->Invoice->validationErrors;
}
}
}
i think it worked for me
Change the field "nombre" for your field called "check_out_reason" to adapt the function to your code
I found a workaround for manual invalidates from controller. Reading a lot on this issue I found out that the save() function doesn't take in consideration the invalidations set through invalidate() function called in controller, but (this is very important) if it is called directly from the model function beforeValidate() it's working perfectly.
So I recommend to go in AppModel.php file and create next public methods:
public $invalidatesFromController = array();
public function beforeValidate($options = array()) {
foreach($this->invalidatesFromController as $item){
$this->invalidate($item['fieldName'], $item['errorMessage'], true);
}
return parent::beforeValidate($options);
}
public function invalidateField($fieldName, $errorMessage){
$this->invalidatesFromController[] = array(
'fieldName' => $fieldName,
'errorMessage' => $errorMessage
);
}
After that, make sure that your model's beforeValidate() function calls the parent's one:
public function beforeValidate($options = array()) {
return parent::beforeValidate($options);
}
In your controller for invalidating a field use next line:
$this->MyModel->invalidateField('fieldName', "error message");
Hope it helps! For me it's working!

Cakephp 2.0 change password

I am attempting to create a change password form in cakephp 2.0. I found a behavior that EuroMark created for 1.3 and now am having a tough time converting this code to work with 2.0. I know that it has something to do with the Auth Component as there were major changes to this component in 2.0.
public function validateCurrentPwd(Model $Model, $data) {
if (is_array($data)) {
$pwd = array_shift($data);
} else {
$pwd = $data;
}
$uid = null;
if ($Model->id) {
$uid = $Model->id;
} elseif (!empty($Model->data[$Model->alias]['id'])) {
$uid = $Model->data[$Model->alias]['id'];
} else {
return false;
}
if (class_exists('AuthExtComponent')) {
$this->Auth = new AuthExtComponent();
} elseif (class_exists($this->settings[$Model->alias]['auth'].'Component')) {
$auth = $this->settings[$Model->alias]['auth'].'Component';
$this->Auth = new $auth();
} else {
return true;
}
return $this->Auth->verifyUser($uid, $pwd);
}
I am getting an error on the line that reads $this->Auth = new $auth();
The error is as follows:
Argument 1 passed to Component::__construct() must be an instance of ComponentCollection, none given, called in C:\UniServer\www\new_company_test\app\Model\Behavior\change_password.php on line 117 and defined [CORE\Cake\Controller\Component.php, line 77]
and
Undefined variable: collection [CORE\Cake\Controller\Component.php, line 78]
it's also throwing this
Call to undefined method AuthComponent::verifyUser() in C:\UniServer\www\new_company_test\app\Model\Behavior\change_password.php on line 121
I am not sure if there is anything else that needs to be addressed in the script, I'm guessing not as there is no other place where Auth is used.
Any suggestions on what I need to do to get this to work? Any help is appreciated.
Thanks
you did discover that there is also a 2.0 branch, didnt you? :)
it should contain the same behavior:
https://github.com/dereuromark/tools/tree/2.0
either way, you need to pass a component collection into it:
$this->Auth = new AuthExtComponent(new ComponentCollection());
You should create a method verifyUser in your custom AuthExt Component which extends Auth Component for "current password" to work like so:
/**
* Quickfix
* TODO: improve - maybe use Authenticate
* #return bool $success
*/
public function verifyUser($id, $pwd) {
$options = array(
'conditions' => array('id'=>$id, 'password'=>$this->password($pwd)),
);
return $this->getModel()->find('first', $options);
$this->constructAuthenticate();
$this->request->data['User']['password'] = $pwd;
return $this->identify($this->request, $this->response);
}
/**
* returns the current User model
* #return object $User
*/
public function getModel() {
return ClassRegistry::init(CLASS_USER);
}
Maybe it is also possible to use the existing identify method in combination with a fake request object in the behavior directly?
I am thinking about using
$this->authenticate = array('Form'=>array('fields'=>array('username' => 'id')));
feel free to fork the behavior and submit a pull request.
"current password" is the only thing that is not yet cleanly solved right now.

Cakephp - how to make error pages have its own layouts?

I wanna have a different layout for the page not found 404 page. How can i set a different layout for that page?
Savant from the IRC helped me out and he suggest in using beforeRender(){} in the app_controller
// Before Render
function beforeRender() {
if($this->name == 'CakeError') {
//$this->layout = 'error';
}
}
CakeError is a catchAll for errors :D
In CakePHP 2.2.2 I changed the ExceptionRenderer in core.php with my own, like this:
app/Config/core.php:
Configure::write('Exception', array(
'handler' => 'ErrorHandler::handleException',
'renderer' => 'MyExceptionRenderer', // this is ExceptionRenderer by default
'log' => true
));
app/Lib/Error/MyExceptionRenderer.php:
App::uses('ExceptionRenderer', 'Error');
class MyExceptionRenderer extends ExceptionRenderer {
protected function _outputMessage($template) {
$this->controller->layout = 'error';
parent::_outputMessage($template);
}
}
Just you need to make layout changes in your error400.ctp file under /app/View/Errors/error400.ctp
Open that file and set layout by
<?php $this->layout=''; //set your layout here ?>
better to create an error.php file in your app folder
class AppError extends ErrorHandler {
function error404($params) {
$this->controller->layout = 'error';
parent::error404($params);
}
}
so you can avoid the if-testing at EVERY page render that savants' solution introduces
My solution for CakePHP 2.3
Change the ExceptionRenderer in core.php to use your own renderer.
app/Config/core.php:
Configure::write('Exception', array(
'handler' => 'ErrorHandler::handleException',
'renderer' => 'MyExceptionRenderer',
'log' => true
));
app/Lib/Error/MyExceptionRenderer.php:
App::uses('ExceptionRenderer', 'Error');
class MyExceptionRenderer extends ExceptionRenderer
{
/**
* Overrided, to always use a bare controller.
*
* #param Exception $exception The exception to get a controller for.
* #return Controller
*/
protected function _getController($exception) {
if (!$request = Router::getRequest(true)) {
$request = new CakeRequest();
}
$response = new CakeResponse(array('charset' => Configure::read('App.encoding')));
$controller = new Controller($request, $response);
$controller->viewPath = 'Errors';
$controller->layout = 'error';
return $controller;
}
}
The advantage to this approach is that it ensures any exceptions thrown from AppController don't cause an endless loop when rendering the exception. Forces a basic rendering of the exception message every time.
This simplest way I know of is to create this function in your AppController:
function appError($method, $messages)
{
}
You can then do whatever you want with the error, display it however you like, or not display it at all, send an email etc.. (I'm not sure if this method if still valid.)
There is also an option of creating app_error.php in your app root, with class AppError extends ErrorHandler in it, which enables you to override all kinds of errors. But I haven't done this yet, so I can't tell you more about it.
See cake/libs/error.php and cake/libs/object.php and of course The Book for more info.
Edit: Forgot to mention, once you caught the error, there's nothing preventing you to - for example - store the error in session, redirect to your "error handling controller", and then display it in your controller however you want.

Resources