Symfony2 refactoring controller logic into a service - symfony

I'm slowly beginning to understand how things in Symfony2 are working.
I have set up a service which pulls json data from a live feed.
My controller uses this service to pull the data and then persist it to my database, I currently have 3 entities, though there are likely to be quite a few more.
All the logic at present is in FantasyPro/DataBundle
I'm currently breaking all sorts of rules, such as the logic for persisting my data is in a controller, so i'm thinking i need to take all this logic and put it into a service which i can use to persist the pulled data into my database via doctrine.
I would like to create this new PersistServce in the DataBundle
As the service will need to use doctrine all the entitys i have as well as the api service i'm not sure how to go about making these available to the service.
It probably worth mentioning that i intend to create commands so that i can run cron jobs to pull this data, in fact i don't think i will need the controller at all as they will only be used internally and not for generating requests.
I have it in a controller right now simply for testing purposes.
Whats the best way to refactor this code into a service?
Heres my messy controller code
<?php
namespace FantasyPro\DataBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use FantasyPro\DataBundle\Entity\Stadium;
use FantasyPro\DataBundle\Entity\Team;
use FantasyPro\DataBundle\Entity\Player;
class DefaultController extends Controller
{
public function indexAction($name)
{
return $this->render('DataBundle:Default:index.html.twig', array('name' => $name));
}
/**
* #return \Symfony\Component\HttpFoundation\Response
*/
public function updateStadiumAction(){
//get list of stadiums
$client = $this->container->get('fantasyapi');
$stadiumData = $client->Stadiums();
//get the entity manager
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('DataBundle:Stadium');
$log = array();
$log = $this->addStadiumList( $stadiumData, $repo, $em, $log );
$em->flush();
return $this->render('DataBundle:Default:index.html.twig', array('log' => $log));
}
public function updateTeamAction()
{
//get list of teams
$client = $this->container->get('fantasyapi');
$teamData = $client->Teams();
//get the entity manager
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('DataBundle:Team');
$log = array();
$log = $this->addTeamList( $teamData, $repo, $em, $log, 'Team' );
$em->flush();
return $this->render('DataBundle:Default:index.html.twig', array('log' => $log));
}
public function updatePlayerAction()
{
//get the api client
$client = $this->container->get('fantasyapi');
//get the manager
$em = $this->getDoctrine()->getManager();
$teamRepo = $em->getRepository('DataBundle:Team');
$playerRepo = $em->getRepository('DataBundle:Player');
$log = array();
//first we need to get a list of teams as players can only be collected via a teamID
/** #var Team $teams */
$teams = $client->Teams();
//var_dump($teams);die;
//loop through the teams and pull the playerData
foreach($teams as $team){
//log the team we are processing
$logData = ['action' => 'Processing Players for:', 'itemID' => $team['TeamID'], 'itemName' => $team['FullName']];
$log[] = $logData;
//get list players on this team
$players = $client->Players(['Team' => $team['Key']]);
//loop through the players
$log = $this->addPlayerList( $players, $playerRepo, $em, $log, 'Added Active Player' );
}
//now get free agents
$freeAgents = $client->FreeAgents();
$log = $this->addPlayerList($freeAgents, $playerRepo, $em, $log, 'Free Agent');
$em->flush();
return $this->render('DataBundle:Default:index.html.twig', array('log' => $log));
}
public function parseDate($dateString)
{
if ($dateString) {
preg_match( '/\/Date\((\d+)([-+])(\d+)\)\//', $dateString, $date );
$timestamp = $date[1] / 1000;
$operator = $date[2];
$hours = $date[3] * 36; // Get the seconds
// $datetime = new \DateTime($timestamp, new \DateTimeZone('America/New_York'));
$datetime = new \DateTime();
$datetime->setTimestamp($timestamp);
$datetime->modify( $operator.$hours.' seconds' );
$datetime->setTimezone(new \DateTimeZone('UTC'));
//$datetime->format( 'd-m-Y H:i:s' );
//var_dump( $datetime );
//echo('*');
return ($datetime);
}
return(null);
}
/**
* #param Array $players
* #param $playerRepo
* #param $em
* #param Array $log
*
* #param String $logTitle
*
* #return array
*/
public function addPlayerList( $players, $playerRepo, $em, $log, $logTitle )
{
foreach ($players as $player) {
// Get the current player in the list
$criteria = array( 'playerID' => $player['PlayerID'] );
/** #var Player $storedPlayer */
$storedPlayer = $playerRepo->FindOneBy( $criteria );
//var_dump($player);
if ( ! $storedPlayer) {
//no player exists with the PlayerID passed
//create a new entry
/** #var Player $entry */
$entry = new Player();
$entry->setTeam( $player['Team'] );
$entry->setPlayerID( $player['PlayerID'] );
$entry->setNumber( $player['Number'] );
$entry->setFirstName( $player['FirstName'] );
$entry->setLastName( $player['LastName'] );
$entry->setPosition( $player['Position'] );
$entry->setStatus( $player['Status'] );
$entry->setHeight( $player['Height'] );
$entry->setWeight( $player['Weight'] );
//need to parse the date on this field
$entry->setBirthDate( $this->parseDate( $player['BirthDate']));
$entry->setCollege( $player['College'] );
$entry->setExperience( $player['Experience'] );
$entry->setFantasyPosition( $player['FantasyPosition'] );
$entry->setActive( $player['Active'] );
$entry->setPositionCategory( $player['PositionCategory'] );
$entry->setName( $player['Name'] );
$entry->setAge( $player['Age'] );
$entry->setExperienceString( $player['ExperienceString'] );
$entry->setBirthDateString( $player['BirthDateString'] );
$entry->setPhotoUrl( $player['PhotoUrl'] );
$entry->setByeWeek( $player['ByeWeek'] );
$entry->setUpcomingGameOpponent( $player['UpcomingGameOpponent'] );
$entry->setUpcomingGameWeek( $player['UpcomingGameWeek'] );
$entry->setShortName( $player['ShortName'] );
$entry->setAverageDraftPos( $player['AverageDraftPosition'] );
$entry->setDepthPositionCategory( $player['DepthPositionCategory'] );
$entry->setDepthPosition( $player['DepthOrder'] );
$entry->setDepthDisplayOrder( $player['DepthDisplayOrder'] );
$entry->setCurrentTeam( $player['CurrentTeam'] );
$entry->setCollegeDraftTeam( $player['CollegeDraftTeam'] );
$entry->setCollegeDraftYear( $player['CollegeDraftYear'] );
$entry->setCollegeDraftRound( $player['CollegeDraftRound'] );
$entry->setCollegeDraftPick( $player['CollegeDraftPick'] );
$entry->setIsUndraftedFreeAgent( $player['IsUndraftedFreeAgent'] );
$entry->setHeightFeet( $player['HeightFeet'] );
$entry->setHeightInches( $player['HeightInches'] );
$entry->setUpcomingOpponentRank( $player['UpcomingOpponentRank'] );
$entry->setUpcomingOpponentPositionRank( $player['UpcomingOpponentPositionRank'] );
$entry->setCurrentStatus( $player['CurrentStatus'] );
$entry->setUpcomingSalary( $player['UpcomingSalary'] );
$em->persist( $entry );
$logData = [ 'action' => 'Added '.$logTitle,
'itemID' => $player['PlayerID'],
'itemName' => $player['Name']
];
$log[] = $logData;
} else {
$storedPlayer->setPlayerID( $player['PlayerID'] );
$storedPlayer->setTeam( $player['Team'] );
$storedPlayer->setPlayerID( $player['PlayerID'] );
$storedPlayer->setNumber( $player['Number'] );
$storedPlayer->setFirstName( $player['FirstName'] );
$storedPlayer->setLastName( $player['LastName'] );
$storedPlayer->setPosition( $player['Position'] );
$storedPlayer->setStatus( $player['Status'] );
$storedPlayer->setHeight( $player['Height'] );
$storedPlayer->setWeight( $player['Weight'] );
//need to parse the date on this field
$storedPlayer->setBirthDate( $this->parseDate( $player['BirthDate']));
$storedPlayer->setCollege( $player['College'] );
$storedPlayer->setExperience( $player['Experience'] );
$storedPlayer->setFantasyPosition( $player['FantasyPosition'] );
$storedPlayer->setActive( $player['Active'] );
$storedPlayer->setPositionCategory( $player['PositionCategory'] );
$storedPlayer->setName( $player['Name'] );
$storedPlayer->setAge( $player['Age'] );
$storedPlayer->setExperienceString( $player['ExperienceString'] );
$storedPlayer->setBirthDateString( $player['BirthDateString'] );
$storedPlayer->setPhotoUrl( $player['PhotoUrl'] );
$storedPlayer->setByeWeek( $player['ByeWeek'] );
$storedPlayer->setUpcomingGameOpponent( $player['UpcomingGameOpponent'] );
$storedPlayer->setUpcomingGameWeek( $player['UpcomingGameWeek'] );
$storedPlayer->setShortName( $player['ShortName'] );
$storedPlayer->setAverageDraftPos( $player['AverageDraftPosition'] );
$storedPlayer->setDepthPositionCategory( $player['DepthPositionCategory'] );
$storedPlayer->setDepthPosition( $player['DepthOrder'] );
$storedPlayer->setDepthDisplayOrder( $player['DepthDisplayOrder'] );
$storedPlayer->setCurrentTeam( $player['CurrentTeam'] );
$storedPlayer->setCollegeDraftTeam( $player['CollegeDraftTeam'] );
$storedPlayer->setCollegeDraftYear( $player['CollegeDraftYear'] );
$storedPlayer->setCollegeDraftRound( $player['CollegeDraftRound'] );
$storedPlayer->setCollegeDraftPick( $player['CollegeDraftPick'] );
$storedPlayer->setIsUndraftedFreeAgent( $player['IsUndraftedFreeAgent'] );
$storedPlayer->setHeightFeet( $player['HeightFeet'] );
$storedPlayer->setHeightInches( $player['HeightInches'] );
$storedPlayer->setUpcomingOpponentRank( $player['UpcomingOpponentRank'] );
$storedPlayer->setUpcomingOpponentPositionRank( $player['UpcomingOpponentPositionRank'] );
$storedPlayer->setCurrentStatus( $player['CurrentStatus'] );
$storedPlayer->setUpcomingSalary( $player['UpcomingSalary'] );
$em->persist( $storedPlayer );
$logData = [ 'action' => 'Updated '.$logTitle,
'itemID' => $player['PlayerID'],
'itemName' => $player['Name']
];
$log[] = $logData;
}
}
return ($log);
}
/**
* #param Array $teamData
* #param $repo
* #param $em
* #param String $logTitle
*
* #return array
*/
public function addTeamList( $teamData, $repo, $em, $log, $logTitle )
{
foreach ($teamData as $team) {
// Get the current team in the list
$criteria = array( 'teamID' => $team['TeamID'] );
//var_dump($criteria);
/** #var Team $storedTeam */
$storedTeam = $repo->FindOneBy( $criteria );
if ( ! $storedTeam) {
//no stadium exists with the StadiumID passed
//create a new entry
/** #var Team $entry */
$entry = new Team();
$entry->setTeamKey( $team['Key'] );
$entry->setTeamID( $team['TeamID'] );
$entry->setPlayerID( $team['PlayerID'] );
$entry->setCity( $team['City'] );
$entry->setName( $team['Name'] );
$entry->setConference( $team['Conference'] );
$entry->setDivision( $team['Division'] );
$entry->setFullName( $team['FullName'] );
$entry->setStadiumID( $team['StadiumID'] );
$entry->setByeWeek( $team['ByeWeek'] );
$entry->setAvergageDraftPos( $team['AverageDraftPosition'] );
$entry->setAverageDraftPosPPR( $team['AverageDraftPositionPPR'] );
$entry->setHeadCoach( $team['HeadCoach'] );
$entry->setOffensiveCoordinator( $team['OffensiveCoordinator'] );
$entry->setDefensiveCoordinator( $team['DefensiveCoordinator'] );
$entry->setSpecialTeamsCoach( $team['SpecialTeamsCoach'] );
$entry->setOffensiveScheme( $team['OffensiveScheme'] );
$entry->setDefensiveScheme( $team['DefensiveScheme'] );
$entry->setUpcomingSalary( $team['UpcomingSalary'] );
$entry->setUpcomingOpponentRank( $team['UpcomingOpponentRank'] );
$entry->setUpcomingOpponentPositionRank( $team['UpcomingOpponentPositionRank'] );
$em->persist( $entry );
$logData = [ 'action' => 'Added New '.$logTitle , 'itemID' => $team['TeamID'], 'itemName' => $team['Name'] ];
$log[] = $logData;
} else {
$storedTeam->setTeamKey( $team['Key'] );
$storedTeam->setPlayerID( $team['PlayerID'] );
$storedTeam->setCity( $team['City'] );
$storedTeam->setName( $team['Name'] );
$storedTeam->setConference( $team['Conference'] );
$storedTeam->setDivision( $team['Division'] );
$storedTeam->setFullName( $team['FullName'] );
$storedTeam->setStadiumID( $team['StadiumID'] );
$storedTeam->setByeWeek( $team['ByeWeek'] );
$storedTeam->setAvergageDraftPos( $team['AverageDraftPosition'] );
$storedTeam->setAverageDraftPosPPR( $team['AverageDraftPositionPPR'] );
$storedTeam->setHeadCoach( $team['HeadCoach'] );
$storedTeam->setOffensiveCoordinator( $team['OffensiveCoordinator'] );
$storedTeam->setDefensiveCoordinator( $team['DefensiveCoordinator'] );
$storedTeam->setSpecialTeamsCoach( $team['SpecialTeamsCoach'] );
$storedTeam->setOffensiveScheme( $team['OffensiveScheme'] );
$storedTeam->setDefensiveScheme( $team['DefensiveScheme'] );
$storedTeam->setUpcomingSalary( $team['UpcomingSalary'] );
$storedTeam->setUpcomingOpponentRank( $team['UpcomingOpponentRank'] );
$storedTeam->setUpcomingOpponentPositionRank( $team['UpcomingOpponentPositionRank'] );
$em->persist( $storedTeam );
$logData = [ 'action' => 'Updated '.$logTitle , 'itemID' => $team['TeamID'], 'itemName' => $team['Name'] ];
$log[] = $logData;
}
}
return $log;
}
/**
* #param Array $stadiumData
* #param $repo
* #param $em
* #param $log
*
* #return array
*/
public function addStadiumList( $stadiumData, $repo, $em, $log )
{
foreach ($stadiumData as $stadium) {
// Get the current stadium in the list
$criteria = array( 'stadiumID' => $stadium['StadiumID'] );
//var_dump($criteria);
/** #var Stadium $storedStadium */
$storedStadium = $repo->FindOneBy( $criteria );
if ( ! $storedStadium) {
//no stadium exists with the StadiumID passed
//create a new entry
/** #var Stadium $entry */
$entry = new Stadium();
$entry->setStadiumID( $stadium['StadiumID'] );
$entry->setName( $stadium['Name'] );
$entry->setCity( $stadium['City'] );
$entry->setState( $stadium['State'] );
$entry->setCountry( $stadium['Country'] );
$entry->setCapacity( $stadium['Capacity'] );
$entry->setPlayingSurface( $stadium['PlayingSurface'] );
$em->persist( $entry );
$logData = [ 'action' => 'Added New Stadium',
'itemID' => $stadium['StadiumID'],
'itemName' => $stadium['Name']
];
$log[] = $logData;
} else {
$storedStadium->setStadiumID( $stadium['StadiumID'] );
$storedStadium->setName( $stadium['Name'] );
$storedStadium->setCity( $stadium['City'] );
$storedStadium->setState( $stadium['State'] );
$storedStadium->setCountry( $stadium['Country'] );
$storedStadium->setCapacity( $stadium['Capacity'] );
$storedStadium->setPlayingSurface( $stadium['PlayingSurface'] );
$em->persist( $storedStadium );
$logData = [ 'action' => 'Updated Stadium',
'itemID' => $stadium['StadiumID'],
'itemName' => $stadium['Name']
];
$log[] = $logData;
}
}
return $log;
}
}

The best way to handle your purposes for me is to create extended repository classes for your entities.
See Symfony2 - Doctrine documentation
In your case this might be:
namespace SomeBundle\Repository;
use Doctrine\ORM\EntityRepository;
class PlayerRepository extends EntityRepository
{
/**
* #param Array $players
* #param $playerRepo
* #param $em
* #param Array $log
*
* #param String $logTitle
*
* #return array
*/
public function addPlayerList($players, $log, $logTitle)
{
foreach ($players as $player) {
// Get the current player in the list
$criteria = array('playerID' => $player['PlayerID']);
/** #var Player $storedPlayer */
$storedPlayer = $this->findOneBy($criteria);
if (!$storedPlayer) {
$storedPlayer = new Player();
$logData = [
'action' => 'Added '.$logTitle,
'itemID' => $player['PlayerID'],
'itemName' => $player['Name']
];
$log[] = $logData;
} else {
$logData = [
'action' => 'Updated '.$logTitle,
'itemID' => $player['PlayerID'],
'itemName' => $player['Name']
];
$log[] = $logData;
}
$storedPlayer->setPlayerID($player['PlayerID']);
$storedPlayer->setTeam($player['Team']);
$storedPlayer->setPlayerID($player['PlayerID']);
$storedPlayer->setNumber($player['Number']);
$storedPlayer->setFirstName($player['FirstName']);
$storedPlayer->setLastName($player['LastName']);
$storedPlayer->setPosition($player['Position']);
$storedPlayer->setStatus($player['Status']);
$storedPlayer->setHeight($player['Height']);
$storedPlayer->setWeight($player['Weight']);
//need to parse the date on this field
$storedPlayer->setBirthDate($this->parseDate($player['BirthDate']));
$storedPlayer->setCollege($player['College']);
$storedPlayer->setExperience($player['Experience']);
$storedPlayer->setFantasyPosition($player['FantasyPosition']);
$storedPlayer->setActive($player['Active']);
$storedPlayer->setPositionCategory($player['PositionCategory']);
$storedPlayer->setName($player['Name']);
$storedPlayer->setAge($player['Age']);
$storedPlayer->setExperienceString($player['ExperienceString']);
$storedPlayer->setBirthDateString($player['BirthDateString']);
$storedPlayer->setPhotoUrl($player['PhotoUrl']);
$storedPlayer->setByeWeek($player['ByeWeek']);
$storedPlayer->setUpcomingGameOpponent($player['UpcomingGameOpponent']);
$storedPlayer->setUpcomingGameWeek($player['UpcomingGameWeek']);
$storedPlayer->setShortName($player['ShortName']);
$storedPlayer->setAverageDraftPos($player['AverageDraftPosition']);
$storedPlayer->setDepthPositionCategory($player['DepthPositionCategory']);
$storedPlayer->setDepthPosition($player['DepthOrder']);
$storedPlayer->setDepthDisplayOrder($player['DepthDisplayOrder']);
$storedPlayer->setCurrentTeam($player['CurrentTeam']);
$storedPlayer->setCollegeDraftTeam($player['CollegeDraftTeam']);
$storedPlayer->setCollegeDraftYear($player['CollegeDraftYear']);
$storedPlayer->setCollegeDraftRound($player['CollegeDraftRound']);
$storedPlayer->setCollegeDraftPick($player['CollegeDraftPick']);
$storedPlayer->setIsUndraftedFreeAgent($player['IsUndraftedFreeAgent']);
$storedPlayer->setHeightFeet($player['HeightFeet']);
$storedPlayer->setHeightInches($player['HeightInches']);
$storedPlayer->setUpcomingOpponentRank($player['UpcomingOpponentRank']);
$storedPlayer->setUpcomingOpponentPositionRank($player['UpcomingOpponentPositionRank']);
$storedPlayer->setCurrentStatus($player['CurrentStatus']);
$storedPlayer->setUpcomingSalary($player['UpcomingSalary']);
}
return ($log);
}
}
Also on my own I'll rather created date parser class to parse date inside this repositories like
$date = (new CustomDateTimeParser('your fancy date string here'))->getDateTime();

Related

I can't update form fields values on my custom shipping method Woocommerce

I really hope someone can help me, cause i'm running out of ideas.
I made this custom shipping methon on Woocommerce, copying and pasting from the website documentation and other StakO topics.
Everything seems to be okay, apart of when i try to update my only one field called "Store Address", it doesn't works and values are not updated.
Here's the code. Thanks to everyone
if ( ! defined( 'WPINC' ) ) {
die;
}
if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
function pickupinstore_shipping_method() {
if ( ! class_exists( 'PickupInStore_Shipping_Method' ) ) {
class PickupInStore_Shipping_Method extends WC_Shipping_Method {
/**
* Constructor for your shipping class
*
* #access public
* #return void
*/
public function __construct( $instance_id = 0 ) {
$this->id = 'pickupinstore';
$this->instance_id = absint( $instance_id );
$this->method_title = __( 'Pickup in Store', 'pickupinstore' );
$this->method_description = __( 'Custom Shipping Method - Pickup in Store', 'pickupinstore' );
$this->supports = array(
'shipping-zones',
'instance-settings',
'instance-settings-modal',
);
$this->init();
$this->title = isset( $this->settings['title'] ) ? "Ritiro in Negozio | ".$this->settings['title'].": GRATIS" : __( 'Pickup in Store', 'pickupinstore' ); }
/**
* Init your settings
*
* #access public
* #return void
*/
function init() {
// Load the settings API
$this->init_form_fields();
$this->init_settings();
// Save settings in admin if you have any defined
add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
}
/**
* Define settings field for this shipping
* #return void
*/
function init_form_fields() {
$this->form_fields = array(
'title' => array(
'title' => __( 'Ritiro in Negozio', 'pickupinstore' ),
'type' => 'text',
'description' => __( 'Store Address', 'pickupinstore' ),
'default' => __( '197, Brooklyn Road', 'New York' ),
'desc_tip' => true,
),
);
}
/**
* This function is used to calculate the shipping cost. Within this function we can check for weights, dimensions and other parameters.
*
* #access public
* #param mixed $package
* #return void
*/
public function calculate_shipping( $package = array() ) {
$cost = 0;
$this->add_rate( array(
'id' => $this->id,
'label' => $this->title,
'cost' => $cost
) );
}
}
}
}
add_action( 'woocommerce_shipping_init', 'pickupinstore_shipping_method' );
function add_pickupinstore_shipping_method( $methods ) {
$methods['pickupinstore'] = 'PickupInStore_Shipping_Method';
return $methods;
}
add_filter( 'woocommerce_shipping_methods', 'add_pickupinstore_shipping_method' );
}
Edit:
I tried using #docker code, but when I save changes nothing compares in the title section (backend). Otherwise the form field seems to be saved, but as you can see, not diplayed.
In front end, it displays the name of the custom shipping method instead of the title I save.
Move the $this->title definition to the init() method and use $this->get_option() instead of $this->settings.
function init() {
// Load the settings API
$this->init_form_fields();
$this->init_settings();
$this->title = null != $this->get_option('title') ? "Ritiro in Negozio | " . $this->get_option('title') . ": GRATIS" : __( 'Pickup in Store', 'pickupinstore' );
// Save settings in admin if you have any defined
add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
}
Additionally in the init_form_fields() method you should use $this->instance_form_fields.
function init_form_fields() {
$this->instance_form_fields = array(
'title' => array(
'title' => __( 'Ritiro in Negozio', 'pickupinstore' ),
'type' => 'text',
'description' => __( 'Store Address', 'pickupinstore' ),
'default' => __( '197, Brooklyn Road', 'New York' ),
'desc_tip' => true,
),
);
}
In some cases you may need the get_instance_from_fields() method but I have a working solution without it:
/**
* Get setting form fields for instances of this shipping method within zones.
*
* #return array
*/
public function get_instance_form_fields() {
return parent::get_instance_form_fields();
}
EDIT:
This is the full working code:
<?php
/**
* Plugin Name: Pickup in Store
* Plugin URI: https://www.perspectiveweb.it/
* Description: Pickup in store - Custom Shipping Method
* Version: 1.0.0
* Author: Perspective Web
* Author URI: https://www.perspectiveweb.it/
* License: GPL-3.0+
* License URI: http://www.gnu.org/licenses/gpl-3.0.html
* Domain Path: /lang
* Text Domain: perspectiveweb
*/
if ( ! defined( 'WPINC' ) ) {
die;
}
if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
function pickupinstore_shipping_method() {
if ( ! class_exists( 'PickupInStore_Shipping_Method' ) ) {
class PickupInStore_Shipping_Method extends WC_Shipping_Method {
/**
* Constructor for your shipping class
*
* #access public
* #return void
*/
public function __construct( $instance_id = 0 ) {
$this->id = 'pickupinstore';
$this->instance_id = absint( $instance_id );
$this->method_title = __( 'Pickup in Store', 'pickupinstore' );
$this->method_description = __( 'Custom Shipping Method - Pickup in Store', 'pickupinstore' );
$this->supports = array(
'shipping-zones',
'instance-settings',
'instance-settings-modal',
);
$this->init();
}
/**
* Init your settings
*
* #access public
* #return void
*/
public function init() {
// Load the settings API
$this->init_form_fields();
$this->init_settings();
$this->title = null != $this->get_option('title') ? "Ritiro in Negozio | " . $this->get_option('title') . ": GRATIS" : __( 'Pickup in Store', 'pickupinstore' );
// Save settings in admin if you have any defined
add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
}
/**
* Define settings field for this shipping
* #return void
*/
public function init_form_fields() {
$this->instance_form_fields = array(
'title' => array(
'title' => __( 'Ritiro in Negozio', 'pickupinstore' ),
'type' => 'text',
'description' => __( 'Store Address', 'pickupinstore' ),
'default' => __( '197, Brooklyn Road', 'New York' ),
'desc_tip' => true,
),
);
}
/**
* This function is used to calculate the shipping cost. Within this function we can check for weights, dimensions and other parameters.
*
* #access public
* #param mixed $package
* #return void
*/
public function calculate_shipping( $package = array() ) {
$cost = 0;
$this->add_rate( array(
'id' => $this->id,
'label' => $this->title,
'cost' => $cost
) );
}
}
}
}
add_action( 'woocommerce_shipping_init', 'pickupinstore_shipping_method' );
function add_pickupinstore_shipping_method( $methods ) {
$methods['pickupinstore'] = 'PickupInStore_Shipping_Method';
return $methods;
}
add_filter( 'woocommerce_shipping_methods', 'add_pickupinstore_shipping_method' );
}

Woocommerce REST API extending order response

I'm looking for a way to extend the wc-api/vX/orders/ reponse. I've added multiple custom fields to the checkout (for eg: relation number, delivery date etc). These meta are saved within the order (wp_postmeta table). But why are they not returned with the api?
Normally you can extend the api response with some code like:
add_action( 'rest_api_init', 'custom_register_api_fields' );
function custom_register_api_fields() {
register_rest_field( 'shop_order','relation_number',
array(
'get_callback' => 'custom_api_meta_callback',
'update_callback' => null,
'schema' => null,
)
);
}
/**
*
* #param array $object Details of current post.
* #param string $field_name Name of field.
* #param WP_REST_Request $request Current request
*
* #return mixed
*/
function custom_api_meta_callback( $object, $field_name, $request ) {
return get_post_meta( $object[ 'id' ], $field_name, true );
}
But when I test the response (with Postman and the php lib), my-website.co/wc-api/v2/orders the custom meta are not visible.
Is there a way to register api fields for the wc-api?
Tnx!
i have the same requirement, add new value to "line_items" in order response
am using wc api v2
https://website.com/wp-json/wc/v2/orders
function get_product_order_image( $response, $object, $request ) {
if( empty( $response->data ) )
return $response;
$order_pid= $response->data['line_items'][0]['product_id'];
$l_w_product_meta = get_post_meta($response->data['line_items'][0]['product_id']);
$order_imgUrl= wp_get_attachment_url( $l_w_product_meta['_thumbnail_id'][0], 'full' );
$response->data['line_items'][0]['cover_image'] = $order_imgUrl;
return $response;
}
add_filter( "woocommerce_rest_prepare_shop_order_object", array( $this, "get_product_order_image"), 10, 3 );
Result
cover image added to line item result
i hope this will help someone in future.
REST API hook for add new value (product image) to "line_items" in order response for simple product and variable product both
Also Use for multiple products
function get_product_order_image( $response, $object, $request ) {
if( empty( $response->data ) )
return $response;
$images = array();
foreach($response->data['line_items'] as $key => $productItems){
$productID = $productItems['product_id'];
$variationID = $productItems['variation_id'];
if($variationID == 0){
$thumbnailID = get_post_meta( $productID, '_thumbnail_id', true);
$attachment = wp_get_attachment_image_src($thumbnailID, 'woocommerce_thumbnail' );
$image = $attachment[0];
}else{
$variation = new WC_Product_Variation( $variationID );
$image_id = $variation->get_image_id();
$attachment = wp_get_attachment_image_src($image_id, 'woocommerce_thumbnail' );
$image = $attachment[0];
}
$response->data['line_items'][$key]['image'] = $image;
}
return $response;
}
add_filter( "woocommerce_rest_prepare_shop_order_object", "get_product_order_image", 10, 3 );
Request:
wp-json/wc/v3/orders
wp-json/wc/v3/orders/XXX
wp-json/wc/v3/orders/?customers=XXX

jsmPayment etsPaymentOgone gives me an error The controller must return a response

I'm trying to implement JSMPayment and EtsPaymentOgoneBundle without success.
I get the error : "The controller must return a response". I'm agree with that but it's so written in the documentation. So am I something wrong or is it a bug/error in the documentation.
The error may be this but it's so written in doc...
return array(
'form' => $form->createView()
);
Now, if I change this line and return to a twig template, I only get one radio button. Why ?
Any help will very help me because, I'm really lost.
My all controller
/**
*
*/
class PaymentController extends Controller
{
/** #DI\Inject */
private $request;
/** #DI\Inject */
private $router;
/** #DI\Inject("doctrine.orm.entity_manager") */
private $em;
/** #DI\Inject("payment.plugin_controller") */
private $ppc;
/**
*
* #param \CTC\Bundle\OrderBundle\Controller\Order $order
* #return RedirectResponse
*/
public function detailsAction(Order $order, Request $request)
{
$form = $this->getFormFactory()->create('jms_choose_payment_method', null, array(
'amount' => $order->getPackage()->getAmount(),
'currency' => 'EUR',
'default_method' => 'ogone_gateway', // Optional
'predefined_data' => array(
'ogone_gateway' => array(
'tp' => '', // Optional
'PM' => $pm, // Optional - Example value: "CreditCard" - Note: You can consult the list of PM values on Ogone documentation
'BRAND' => $brand, // Optional - Example value: "VISA" - Note: If you send the BRAND field without sending a value in the PM field (‘CreditCard’ or ‘Purchasing Card’), the BRAND value will not be taken into account.
'CN' => $billingAddress->getFullName(), // Optional
'EMAIL' => $this->getUser()->getEmail(), // Optional
'OWNERZIP' => $billingAddress->getPostalCode(), // Optional
'OWNERADDRESS' => $billingAddress->getStreetLine(), // Optional
'OWNERCTY' => $billingAddress->getCountry()->getName(), // Optional
'OWNERTOWN' => $billingAddress->getCity(), // Optional
'OWNERTELNO' => $billingAddress->getPhoneNumber(), // Optional
'lang' => $request->getLocale(), // 5 characters maximum, for e.g: fr_FR
'ORDERID' => '123456', // Optional, 30 characters maximum
),
),
));
if ('POST' === $this->request->getMethod()) {
$form->bindRequest($this->request);
if ($form->isValid()) {
$this->ppc->createPaymentInstruction($instruction = $form->getData());
$order->setPaymentInstruction($instruction);
$this->em->persist($order);
$this->em->flush($order);
return new RedirectResponse($this->router->generate('payment_complete', array(
'orderNumber' => $order->getOrderNumber(),
)));
}
}
return array(
'form' => $form->createView()
);
}
/**
*
*/
public function completeAction(Order $order)
{
$instruction = $order->getPaymentInstruction();
if (null === $pendingTransaction = $instruction->getPendingTransaction()) {
$payment = $this->ppc->createPayment($instruction->getId(), $instruction->getAmount() - $instruction->getDepositedAmount());
} else {
$payment = $pendingTransaction->getPayment();
}
$result = $this->ppc->approveAndDeposit($payment->getId(), $payment->getTargetAmount());
if (Result::STATUS_PENDING === $result->getStatus()) {
$ex = $result->getPluginException();
if ($ex instanceof ActionRequiredException) {
$action = $ex->getAction();
if ($action instanceof VisitUrl) {
return new RedirectResponse($action->getUrl());
}
throw $ex;
}
} else if (Result::STATUS_SUCCESS !== $result->getStatus()) {
throw new \RuntimeException('Transaction was not successful: '.$result->getReasonCode());
}
// payment was successful, do something interesting with the order
}
public function cancelAction(Order $order)
{
die('cancel the payment');
}
/** #DI\LookupMethod("form.factory") */
protected function getFormFactory() { }
}
if you use
return array(
'form' => $form->createView()
);
at the controller, then you should add #Template annotation to the controller action
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class PaymentController extends Controller
{
...
/**
*
* #param \CTC\Bundle\OrderBundle\Controller\Order $order
* #Template()
* #return RedirectResponse
*/
public function detailsAction(Order $order, Request $request)
or you should return "render" with a template
return $this->render('MyAppSomeBundle:Payment:details.html.twig', array( 'form' => $form->createView());

Woocommerce booking :Fatal error: Call to a member function has_persons() on a non-object in

I need your great skills on WordPress and woocommerce, I have an issue that I don't know why woocommerce booking throw this :
**Fatal error: Call to a member function `has_persons()` on a non-object in `xxx/plugins/woocommerce-bookings/includes/class-wc-booking.php` on line 557**
and it stop all scripts executions.
the woocommerce booking class :
<?php
/**
* Main model class for all bookings, this handles all the data
*/
class WC_Booking {
/** #public int */
public $id;
/** #public string */
public $booking_date;
/** #public string */
public $start;
/** #public string */
public $end;
/** #public bool */
public $all_day;
/** #public string */
public $modified_date;
/** #public object */
public $post;
/** #public int */
public $product_id;
/** #public object */
public $product;
/** #public int */
public $order_id;
/** #public object */
public $order;
/** #public int */
public $customer_id;
/** #public string */
public $status;
/** #public array - contains all post meta values for this booking */
public $custom_fields;
/** #public bool */
public $populated;
/** #private array - used to temporarily hold order data for new bookings */
private $order_data;
/**
* Constructor, possibly sets up with post or id belonging to existing booking
* or supplied with an array to construct a new booking
* #param int/array/obj $booking_data
*/
public function __construct( $booking_data = false ) {
$populated = false;
if ( is_array( $booking_data ) ) {
$this->order_data = $booking_data;
$populated = false;
} else if ( is_int( intval( $booking_data ) ) && 0 < $booking_data ) {
$populated = $this->populate_data( $booking_data );
} else if ( is_object( $booking_data ) && isset( $booking_data->ID ) ) {
$this->post = $booking_data;
$populated = $this->populate_data( $booking_data->ID );
}
$this->populated = $populated;
}
/**
* Actual create for the new booking belonging to an order
* #param string Status for new order
*/
public function create( $status = 'unpaid' ) {
$this->new_booking( $status, $this->order_data );
$this->schedule_events();
}
/**
* Schedule events for this booking
*/
public function schedule_events() {
switch ( get_post_status( $this->id ) ) {
case "paid" :
if ( $this->start && $this->get_order() ) {
$order_status = $this->get_order()->get_status();
if ( ! in_array( $order_status, array( 'cancelled', 'refunded', 'pending', 'on-hold' ) ) ) {
wp_schedule_single_event( strtotime( '-' . absint( apply_filters( 'woocommerce_bookings_remind_before_days', 1 ) ) . ' day', $this->start ), 'wc-booking-reminder', array( $this->id ) );
}
}
if ( $this->end ) {
wp_schedule_single_event( $this->end, 'wc-booking-complete', array( $this->id ) );
}
break;
default :
wp_clear_scheduled_hook( 'wc-booking-reminder', array( $this->id ) );
wp_clear_scheduled_hook( 'wc-booking-complete', array( $this->id ) );
break;
}
}
/**
* Makes the new booking belonging to an order
* #param string $status The status for this new booking
* #param array $order_data Array with all the new order data
*/
private function new_booking( $status, $order_data ) {
global $wpdb;
$order_data = wp_parse_args( $order_data, array(
'user_id' => 0,
'resource_id' => '',
'product_id' => '',
'order_item_id' => '',
'persons' => array(),
'cost' => '',
'start_date' => '',
'end_date' => '',
'all_day' => 0,
'parent_id' => 0,
) );
// Get parent data
if ( $order_data['parent_id'] ) {
if ( ! $order_data['order_item_id'] ) {
$order_data['order_item_id'] = get_post_meta( $order_data['parent_id'], '_booking_order_item_id', true );
}
if ( ! $order_data['user_id'] ) {
$order_data['user_id'] = get_post_meta( $order_data['parent_id'], '_booking_customer_id', true );
}
}
// Get order ID from order item
if ( $order_data['order_item_id'] ) {
$order_id = $wpdb->get_var( $wpdb->prepare( "SELECT order_id FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d", $order_data['order_item_id'] ) );
} else {
$order_id = 0;
}
$booking_data = array(
'post_type' => 'wc_booking',
'post_title' => sprintf( __( 'Booking – %s', 'woocommerce-bookings' ), strftime( _x( '%b %d, %Y # %I:%M %p', 'Booking date parsed by strftime', 'woocommerce-bookings' ) ) ),
'post_status' => $status,
'ping_status' => 'closed',
'post_parent' => $order_id
);
$this->id = wp_insert_post( $booking_data );
// Setup the required data for the current user
if ( ! $order_data['user_id'] ) {
if ( is_user_logged_in() ) {
$order_data['user_id'] = get_current_user_id();
} else {
$order_data['user_id'] = 0;
}
}
// Convert booking start and end to requried format
if ( is_numeric( $order_data['start_date'] ) ) {
// Convert timestamp
$order_data['start_date'] = date( 'YmdHis', $order_data['start_date'] );
$order_data['end_date'] = date( 'YmdHis', $order_data['end_date'] );
} else {
$order_data['start_date'] = date( 'YmdHis', strtotime( $order_data['start_date'] ) );
$order_data['end_date'] = date( 'YmdHis', strtotime( $order_data['end_date'] ) );
}
$meta_args = array(
'_booking_order_item_id' => $order_data['order_item_id'],
'_booking_product_id' => $order_data['product_id'],
'_booking_resource_id' => $order_data['resource_id'],
'_booking_persons' => $order_data['persons'],
'_booking_cost' => $order_data['cost'],
'_booking_start' => $order_data['start_date'],
'_booking_end' => $order_data['end_date'],
'_booking_all_day' => intval( $order_data['all_day'] ),
'_booking_parent_id' => $order_data['parent_id'],
'_booking_customer_id' => $order_data['user_id'],
);
foreach ( $meta_args as $key => $value ) {
update_post_meta( $this->id, $key, $value );
}
WC_Cache_Helper::get_transient_version( 'bookings', true );
do_action( 'woocommerce_new_booking', $this->id );
}
/**
* Assign this booking to an order and order item by ID
* #param int $order_id
* #param int $order_item_id
*/
public function set_order_id( $order_id, $order_item_id ) {
$this->order_id = $order_id;
wp_update_post( array( 'ID' => $this->id, 'post_parent' => $this->order_id ) );
update_post_meta( $this->id, '_booking_order_item_id', $order_item_id );
}
/**
* Populate the data with the id of the booking provided
* Will query for the post belonging to this booking and store it
* #param int $booking_id
*/
public function populate_data( $booking_id ) {
if ( ! isset( $this->post ) ) {
$post = get_post( $booking_id );
}
if ( is_object( $post ) ) {
// We have the post object belonging to this booking, now let's populate
$this->id = $post->ID;
$this->booking_date = $post->post_date;
$this->modified_date = $post->post_modified;
$this->customer_id = $post->post_author;
$this->custom_fields = get_post_meta( $this->id );
$this->status = $post->post_status;
$this->order_id = $post->post_parent;
// Define the data we're going to load: Key => Default value
$load_data = array(
'product_id' => '',
'resource_id' => '',
'persons' => array(),
'cost' => '',
'start' => '',
'customer_id' => '',
'end' => '',
'all_day' => 0,
'parent_id' => 0,
);
// Load the data from the custom fields (with prefix for this plugin)
$meta_prefix = '_booking_';
foreach ( $load_data as $key => $default ) {
if ( isset( $this->custom_fields[ $meta_prefix . $key ][0] ) && $this->custom_fields[ $meta_prefix . $key ][0] !== '' ) {
$this->$key = maybe_unserialize( $this->custom_fields[ $meta_prefix . $key ][0] );
} else {
$this->$key = $default;
}
}
// Start and end date converted to timestamp
$this->start = strtotime( $this->start );
$this->end = strtotime( $this->end );
// Save the post object itself for future reference
$this->post = $post;
return true;
}
return false;
}
/**
* Will change the booking status once the order is paid for
* #return bool
*/
public function paid() {
$current_status = $this->status;
$event = wp_get_schedule( 'wc-booking-reminder', array( $this->id ) );
if ( $this->populated && in_array( $current_status, array( 'unpaid', 'confirmed' ) ) ) {
$this->update_status( 'paid' );
if ( ! empty( $event ) ) {
$this->schedule_events();
}
return true;
}
return false;
}
/**
* Set the new status for this booking
* #param string $status
* #return bool
*/
public function update_status( $status ) {
$current_status = $this->get_status( true );
$allowed_statuses = array( 'unpaid', 'pending-confirmation', 'confirmed', 'paid', 'cancelled', 'complete', 'in-cart', 'was-in-cart' );
if ( $this->populated ) {
if ( in_array( $status, $allowed_statuses ) ) {
wp_update_post( array( 'ID' => $this->id, 'post_status' => $status ) );
// Reschedule cron
$this->schedule_events();
// Trigger actions
do_action( 'woocommerce_booking_' . $current_status . '_to_' . $status, $this->id );
do_action( 'woocommerce_booking_' . $status, $this->id );
// Note in the order
if ( $order = $this->get_order() ) {
$order->add_order_note( sprintf( __( 'Booking #%d status changed from "%s" to "%s', 'woocommerce-bookings' ), $this->id, $current_status, $status ) );
}
return true;
}
}
return false;
}
/**
* Checks the booking status against a passed in status.
*
* #return bool
*/
public function has_status( $status ) {
return apply_filters( 'woocommerce_booking_has_status', ( is_array( $status ) && in_array( $this->get_status(), $status ) ) || $this->get_status() === $status ? true : false, $this, $status );
}
/**
* Returns the status of this booking
* #param Bool to ask for pretty status name (if false)
* #return String of the booking status
*/
public function get_status( $raw = true ) {
if ( $this->populated ) {
if ( $raw ) {
return $this->status;
} else {
$status_object = get_post_status_object( $this->status );
return $status_object->label;
}
}
return false;
}
/**
* Returns the id of this booking
* #return Id of the booking or false if booking is not populated
*/
public function get_id() {
if ( $this->populated ) {
return $this->id;
}
return false;
}
/**
* Get the product ID for the booking
* #return int or false if booking is not populated
*/
public function get_product_id() {
if ( $this->populated ) {
return $this->product_id;
}
return false;
}
/**
* Returns the object of the order corresponding to this booking
* #return Product object or false if booking is not populated
*/
public function get_product() {
if ( empty( $this->product ) ) {
if ( $this->populated && $this->product_id ) {
$this->product = get_product( $this->product_id );
} else {
return false;
}
}
return $this->product;
}
/**
* Returns the object of the order corresponding to this booking
* #return Order object or false if booking is not populated
*/
public function get_order() {
if ( empty( $this->order ) ) {
if ( $this->populated && ! empty( $this->order_id ) && 'shop_order' === get_post_type( $this->order_id ) ) {
$this->order = wc_get_order( $this->order_id );
} else {
return false;
}
}
return $this->order;
}
/**
* Returns the cancel URL for a booking
*
* #param string $redirect
* #return string
*/
public function get_cancel_url( $redirect = '' ) {
$cancel_page = get_permalink( wc_get_page_id( 'myaccount' ) );
if ( ! $cancel_page ) {
$cancel_page = home_url();
}
return apply_filters( 'bookings_cancel_booking_url', wp_nonce_url( add_query_arg( array( 'cancel_booking' => 'true', 'booking_id' => $this->id, 'redirect' => $redirect ), $cancel_page ), 'woocommerce-bookings-cancel_booking' ) );
}
/**
* Return if all day event
* #return boolean
*/
public function is_all_day() {
if ( $this->populated ) {
if ( $this->all_day ) {
return true;
} else {
return false;
}
}
return false;
}
/**
* See if this booking is booked on said date
* #return boolean
*/
public function is_booked_on_day( $block_start, $block_end ) {
if ( $this->populated ) {
$loop_date = $this->start;
$multiday_booking = date( 'Y-m-d', $this->start ) < date( 'Y-m-d', $this->end );
if ( $multiday_booking ) {
if ( date( 'YmdHi', $block_end ) > date( 'YmdHi', $this->start ) || date( 'YmdHi', $block_start ) < date( 'YmdHi', $this->end ) ) {
return true;
}
return false;
}
while ( $loop_date <= $this->end ) {
if ( date( 'Y-m-d', $loop_date ) === date( 'Y-m-d', $block_start ) ) {
return true;
}
$loop_date = strtotime( "+1 day", $loop_date );
}
}
return false;
}
/**
* See if this booking can still be cancelled by the user or not
* #return boolean
*/
public function passed_cancel_day() {
$booking = $this->get_product();
if ( $booking !== false ) {
$cancel_limit = $booking->wc_booking_cancel_limit;
$cancel_limit_unit = $cancel_limit > 1 ? $booking->wc_booking_cancel_limit_unit . 's' : $booking->wc_booking_cancel_limit_unit;
$cancel_string = sprintf( 'now +%d %s', $cancel_limit, $cancel_limit_unit );
if ( strtotime( $cancel_string ) >= $this->start ) {
return true;
}
}
return false;
}
/**
* Returns booking start date
* #return string Date formatted via date_i18n
*/
public function get_start_date( $date_format = null, $time_format = null ) {
if ( $this->populated && ! empty( $this->start ) ) {
if ( is_null( $date_format ) ) {
$date_format = apply_filters( 'woocommerce_bookings_date_format', 'M jS Y' );
}
if ( is_null( $time_format ) ) {
$time_format = apply_filters( 'woocommerce_bookings_time_format', ', g:ia' );
}
if ( $this->is_all_day() ) {
return date_i18n( $date_format, $this->start );
} else {
return date_i18n( $date_format . $time_format, $this->start );
}
}
return false;
}
/**
* Returns booking end date
* #return string Date formatted via date_i18n
*/
public function get_end_date( $date_format = null, $time_format = null ) {
if ( $this->populated && ! empty( $this->end ) ) {
if ( is_null( $date_format ) ) {
$date_format = apply_filters( 'woocommerce_bookings_date_format', 'M jS Y' );
}
if ( is_null( $time_format ) ) {
$time_format = apply_filters( 'woocommerce_bookings_time_format', ', g:ia' );
}
if ( $this->is_all_day() ) {
return date_i18n( $date_format, $this->end );
} else {
return date_i18n( $date_format . $time_format, $this->end );
}
}
return false;
}
/**
* Returns information about the customer of this order
* #return array containing customer information
*/
public function get_customer() {
if ( $this->populated ) {
$order = $this->get_order();
if ( $order )
return (object) array(
'name' => trim( $order->billing_first_name . ' ' . $order->billing_last_name ),
'email' => $order->billing_email,
'user_id' => $order->customer_user,
);
elseif ( $this->customer_id ) {
$user = get_user_by( 'id', $this->customer_id );
return (object) array(
'name' => $user->display_name,
'email' => $user->user_email,
'user_id' => $this->customer_id
);
}
}
return false;
}
/**
* Returns if persons are enabled/needed for the booking product
* #return boolean
*/
public function has_persons() {
return $this->get_product()->has_persons();
}
/**
* Returns if resources are enabled/needed for the booking product
* #return boolean
*/
public function has_resources() {
return $this->get_product()->has_resources();
}
/**
* Return a array with the booking persons.
* #return array
*/
public function get_persons() {
return (array) $this->persons;
}
/**
* Return the amount of persons for this booking.
* #return int
*/
public function get_persons_total() {
return array_sum( $this->get_persons() );
}
/**
* Get the resource id
* #return int
*/
public function get_resource_id() {
if ( $this->populated ) {
return absint( $this->resource_id );
}
return 0;
}
/**
* Get the resource/type for this booking if applicable.
* #return bool|object WP_Post
*/
public function get_resource() {
$resource_id = $this->get_resource_id();
if ( ! $resource_id || ! ( $product = $this->get_product() ) || ! method_exists( $product, 'get_resource' ) ) {
return false;
}
return $product->get_resource( $resource_id );
}
}
and on line 57
/**
* Returns if persons are enabled/needed for the booking product
* #return boolean
*/
public function has_persons() {
return $this->get_product()->has_persons();
}
Can someone help me please?
Thank you
I solved exactly the same error message with this fix :
In folder
/var/www/html/wp-content/plugins/woocommerce-bookings/includes
In file :
class-wc-booking.php
Replace :
/**
* Returns if persons are enabled/needed for the booking product
* #return boolean
*/
public function has_persons() {
return $this->get_product()->has_persons();
}
By :
/**
* Returns if persons are enabled/needed for the booking product
* #return boolean
*/
public function has_persons() {
if ($this->get_product()) {
return $this->get_product()->has_persons();
} else
{
return 0;
}
}

JMSPaymentPaypalBundle blank order summary

hi i was wondering on how to show order summary in paypal with JMSPaymentPaypalBundle ?!
ay tips will be greatly appreciated ..
here is my paypalController code in case needed
<?php
namespace Splurgin\EventsBundle\Controller;
use JMS\DiExtraBundle\Annotation as DI;
use JMS\Payment\CoreBundle\Entity\Payment;
use JMS\Payment\CoreBundle\PluginController\Result;
use JMS\Payment\CoreBundle\Plugin\Exception\ActionRequiredException;
use JMS\Payment\CoreBundle\Plugin\Exception\Action\VisitUrl;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\RedirectResponse;
class PaymentController
{
/** #DI\Inject */
private $request;
/** #DI\Inject */
private $router;
/** #DI\Inject("doctrine.orm.entity_manager") */
private $em;
/** #DI\Inject("payment.plugin_controller") */
private $ppc;
/**
* #DI\Inject("service_container")
*
*/
private $container;
/**
* #Template
*/
public function detailsAction($package)
{
// note this ticket at this point in inactive ...
$order = $this->container->get('ticket')->generateTicket($package);
$order = $this->em->getRepository('SplurginEventsBundle:SplurginEventTickets')->find($order);
$packageId = $order->getPackageId();
$package = $this->em->getRepository('SplurginEventsBundle:SplurginEventPackages')->find($package);
$price = $package->getPrice();
var_dump($price);
if($price == null){
throw new \RuntimeException('Package was not found: '.$result->getReasonCode());
}
$form = $this->getFormFactory()->create('jms_choose_payment_method', null, array(
'amount' => $price,
'currency' => 'USD',
'default_method' => 'payment_paypal', // Optional
'predefined_data' => array(
'paypal_express_checkout' => array(
'return_url' => $this->router->generate('payment_complete', array(
'order' => $order->getId(),
), true),
'cancel_url' => $this->router->generate('payment_cancel', array(
'order' => $order->getId(),
), true)
),
),
));
if ('POST' === $this->request->getMethod()) {
$form->bindRequest($this->request);
if ($form->isValid()) {
$this->ppc->createPaymentInstruction($instruction = $form->getData());
$order->setPaymentInstruction($instruction);
$this->em->persist($order);
$this->em->flush($order);
return new RedirectResponse($this->router->generate('payment_complete', array(
'order' => $order->getId(),
)));
}
}
return array(
'form' => $form->createView(),
'order'=>$order->getId(),
);
}
/** #DI\LookupMethod("form.factory") */
protected function getFormFactory() { }
/**
*/
public function completeAction($order)
{
$order = $this->em->getRepository('SplurginEventsBundle:SplurginEventTickets')->find($order);
$instruction = $order->getPaymentInstruction();
if (null === $pendingTransaction = $instruction->getPendingTransaction()) {
$payment = $this->ppc->createPayment($instruction->getId(), $instruction->getAmount() - $instruction->getDepositedAmount());
} else {
$payment = $pendingTransaction->getPayment();
}
$result = $this->ppc->approveAndDeposit($payment->getId(), $payment->getTargetAmount());
if (Result::STATUS_PENDING === $result->getStatus()) {
$ex = $result->getPluginException();
if ($ex instanceof ActionRequiredException) {
$action = $ex->getAction();
if ($action instanceof VisitUrl) {
return new RedirectResponse($action->getUrl());
}
throw $ex;
}
} else if (Result::STATUS_SUCCESS !== $result->getStatus()) {
throw new \RuntimeException('Transaction was not successful: '.$result->getReasonCode());
}
}
public function cancelAction($order)
{
die('cancel the payment');
}
}
i really dont know why this is not a part of the docs , but the bundle is capable of setting checkout parameters out of the box ...
here is how i have done it
$form = $this->getFormFactory()->create('jms_choose_payment_method', null, array(
'amount' => $price,
'currency' => 'USD',
'default_method' => 'payment_paypal', // Optional
'predefined_data' => array(
'paypal_express_checkout' => array(
'return_url' => $this->router->generate('payment_complete', array(
'order' => $order->getId(),
), true),
'cancel_url' => $this->router->generate('payment_cancel', array(
'order' => $order->getId(),
), true),
'checkout_params' => array(
'L_PAYMENTREQUEST_0_NAME0' => 'event',
'L_PAYMENTREQUEST_0_DESC0' => 'some event that the user is trying to buy',
'L_PAYMENTREQUEST_0_AMT0'=> 6.00, // if you get 10413 , then visit the api errors documentation , this number should be the total amount (usually the same as the price )
// 'L_PAYMENTREQUEST_0_ITEMCATEGORY0'=> 'Digital',
),
),
),
));
error code can be found here
SetExpressCheckout Request Fields here
i will provide a pull request to the documentation as soon as i can .. :)

Resources