Viewed   233 times

Here is my folder structure:

Classes
  - CronJobs
    - Weather
      - WeatherSite.php

I want to load WeatherSite class from my script. Im using composer with autoload:

$loader = include(LIBRARY .'autoload.php');
$loader->add('ClassesWeather',CLASSES .'cronjobs/weather');
$weather = new ClassesWeatherWeatherSite();

Im assuming the above code is adding the namespace and the path that namespace resolves to. But when the page loads I always get this error:

 Fatal error: Class 'ClassesWeatherWeatherSite' not found

Here is my WeatherSite.php file:

namespace ClassesWeather;

class WeatherSite {

    public function __construct()
    {

    }

    public function findWeatherSites()
    {

    }

}

What am I doing wrong?

 Answers

3

You actually don't need custom autoloader, you can use PSR-4.

Update your autoload section in composer.json:

"autoload": {
    "psr-4": {
        "Classes\Weather\": "Classes/CronJobs/Weather"
    }
}

To explain: it's {"Namespace\": "directory to be found in"}

Don't forget to run composer dump-autoload to update Composer cache.

Then you can use it like this:

include(LIBRARY .'autoload.php');

$weather = new ClassesWeatherWeatherSite();
Tuesday, August 30, 2022
 
sami-l
 
2
  1. API 2 doesn't really exist: in GetResponse they say version "1.5.0 - this is last JSON/RPC version of our API", especially if you were speaking 10 months ago. Now they are preparing to beta-test v3. So I will assume you were speaking about 1.5 and answer about it (I'm not familiar with v3, maybe there it's different).

  2. You must send contact id with set_contact_customs, and you didn't.

  3. When it says, "request error: array", it doesn't relate to your array (even though the problem is in your array, because you don't send in it contact id), they are sending an array as a response with error messages.

  4. I'd love to tell you, where to get the contact id in order to send it, but I'm looking for it myself now. :)

UPDATE:

Ok, I combined it from pieces all over the internet, and now here's the working format.

  1. You don't need to add_contact and then update it, you can do it in one go, adding the 'customs' parameter to the add_contact call (GR say, that we shouldn't expect for the contact to be added immediately, so you might not even get whom to update, if you call that function right away).

    The fields for add_contact are described here.

  2. The 'customs' parameter should look differently. Instead of:

    array(
        'Survey Type' => $surveytype,
        'Survey Cost' => $surveycost
        )
    

    it should be:

    array(
        array( 'name' => 'Survey Type', 'content' => $surveytype ),
        array( 'name' => 'Survey Cost', 'content' => $surveycost )
        )
    

    By the way, from what I tested, - blessedly, you don't need to define in GR UI those custom fields first, whatever you send, will be added or updated (in their limits for the custom field names and values).

    I got error, when tried to send one custom field with empty content, when calling add_contact. When I sent it with set_contact_customs, I didn't get any error; I wanted to see, if it would delete the field or field value - it didn't do a thing.

  3. If you still wish to update the existing contact, here's how to send the contact id with the update call:

    $result = $client->set_contact_customs(
       $api_key, array(
          'contact' => $contact_id,
          'customs' => $custom_fields_array
        )
    );
    
  4. To first find contact id, you should call get_contacts. And since it's been said (I haven't tested it), that in different campaigns contacts with the same email address have different contact id, you should pass both the campaign, and the email with it.

    As you can see, campaign can be sent in 'campaigns' parameter (then campaign id, that you got for add_contact, should be used), or in 'get_campaigns' (then the campaign name or even prefix can be used).

    Here's the call with campaign id, for your code:

    $result = $client->get_contacts(
        $api_key, array(
           'campaigns' => array( 'My-Camp-ID' ),
           'email' => array( 'EQUALS' => $emailaddress )
        )
    );
    
  5. To retrieve contact id from get_contacts, do the same as recommended for retrieving campaign id:

    $contact_id = array_pop( array_keys( $result ) );
    if ( empty( $contact_id ) ) {
        //still not ok
    }
    else {
        //you can call set_contact_customs
    }
    
  6. In order for that error message to be more descriptive, instead of just 'Request have return error: Array', open your jsonRPCClient.php, which you most surely include in your file with these GR function calls, and look for the following line:

    !is_null($response['error']) => 'Request have return error: ' . $response['error'],
    

    and replace it with the following, at least:

    !is_null($response['error']) => 'Request have returned error: ' . var_export($response['error'], true),
    

    Now your code will use the beloved var_export function and if you make a mistake, you will see in your error log something like:

    Request have returned error: array (
      'message' => 'Invalid params',
      'code' => -32602,
    )
    

I dedicate this thorough answer to all those, who helped me endlessly here on , just giving their answers to someone else's questions, sometimes years ago. Thank you! Hopefully my answer will save someone time, efforts, and mood, too. :)

Thursday, November 10, 2022
 
4oby
 
4

It is possible with a simple autoloader and it is not so hard to do it:

function __autoload($className)
{
    $className = ltrim($className, '\');
    $fileName  = '';
    $namespace = '';
    if ($lastNsPos = strripos($className, '\')) {
        $namespace = substr($className, 0, $lastNsPos);
        $className = substr($className, $lastNsPos + 1);
        $fileName  = str_replace('\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
    }
    $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
    // $fileName .= $className . '.php'; //sometimes you need a custom structure
    //require_once "library/class.php"; //or include a class manually
    require $fileName;

}

But sometimes you have to adjust the $fileName so it works with all libraries. It depends on the standard for autoloading and how the class names of the libraries are named. Sometimes you have to split the classname on _ and use the first element for the direcotry name and add this also to the class name. I had for example a second library with a class like Library_Parser but the structure was Library/library-parser.php.

The first library worked directly with the above code and all classes were automatically loaded.

The code was taken from http://www.sitepoint.com/autoloading-and-the-psr-0-standard/ but I had to correct some code parts (additional underscores and backslashes). I have used the PSR-0 Standard solution.

PSR-4 version by https://.com/users/1740659/thibault:

function loadPackage($dir)
{
    $composer = json_decode(file_get_contents("$dir/composer.json"), 1);
    $namespaces = $composer['autoload']['psr-4'];

    // Foreach namespace specified in the composer, load the given classes
    foreach ($namespaces as $namespace => $classpaths) {
        if (!is_array($classpaths)) {
            $classpaths = array($classpaths);
        }
        spl_autoload_register(function ($classname) use ($namespace, $classpaths, $dir) {
            // Check if the namespace matches the class we are looking for
            if (preg_match("#^".preg_quote($namespace)."#", $classname)) {
                // Remove the namespace from the file path since it's psr4
                $classname = str_replace($namespace, "", $classname);
                $filename = preg_replace("#\\#", "/", $classname).".php";
                foreach ($classpaths as $classpath) {
                    $fullpath = $dir."/".$classpath."/$filename";
                    if (file_exists($fullpath)) {
                        include_once $fullpath;
                    }
                }
            }
        });
    }
}

loadPackage(__DIR__."/vendor/project");

new CompanyNamePackageNameTest();
Friday, September 9, 2022
 
qrystal
 
1

Classes/Contact/Contact.php and the composer rule "Classes\": "includes/libraries/Classes/" imply ClassesContactContact class, not ClassesContact.

So if you actually want ClassesContact class, move the Classes/Contact/Contact.php file up to the parent directory: Classes/Contact.php.

If, however, the desired namespace path to the class is ClassesContactContact, then change the use:

use ClassesContactContact;

And the namespace:

namespace ClassesContact;

class Contact {}

Example

??? composer.json
??? includes
?   ??? libraries
?       ??? Classes
?           ??? Contact
?               ??? Contact.php
??? test.php
??? vendor
    ??? autoload.php
    ??? composer
        ??? autoload_classmap.php
        ??? autoload_namespaces.php
        ??? autoload_psr4.php
        ??? autoload_real.php
        ??? autoload_static.php
        ??? ClassLoader.php
        ??? installed.json
        ??? LICENSE

The files under vendor/ are generated by composer.

composer.json

{
    "name": "testpsr4",
    "autoload": {
        "psr-4": {
            "Classes\": "includes/libraries/Classes"
        }
    }
}

test.php

<?php
require_once __DIR__ . '/vendor/autoload.php';

use ClassesContactContact;

$c = new Contact;
$c->test();

includes/libraries/Classes/Contact/Contact.php

<?php
namespace ClassesContact;

class Contact {
    public function test () {
        echo __METHOD__, PHP_EOL;
    }
}

Testing

composer update
php test.php

Output

ClassesContactContact::test
Sunday, November 6, 2022
 
5

As 'wc_course_order' is a custom email notification ID that I can't really test it with it (so for testing purpose I have commented it, when testing the function myself)…

Using the same way than you to get the email, I suppose that I am getting the first and last name in the code below (but I am not absolutely sure)

Now to add this emails as BCC, you will have to change of hook:

add_filter( 'woocommerce_email_headers', 'student_email_notification', 20, 3 );
function student_email_notification( $header, $email_id, $order ) {
    // Only for 'wc_course_order' notification
    if( 'wc_course_order' != $email_id ) return $header; 

    $student_emails = array();
    $enroll_num = 0;

    // Loop though  Order IDs
    foreach( $order->get_items() as $item_id => $item_data ){
        $course_qty = $item_data->get_quantity();
        $q = 1;
        while ( $q <= $course_qty){
            $enroll_num++;
            // Get the student full Name
            $full_name     = wc_get_order_item_meta( $item_id, 'First Name - '.$enroll_num, true );
            $full_name    .= ' ' . wc_get_order_item_meta( $item_id, 'Last Name - '.$enroll_num, true );
            // Get the student email
            $student_email = wc_get_order_item_meta( $item_id, 'Student Email - '.$enroll_num, true );
            if( ! empty($student_email) && $full_name != ' ' )
                // Format the name and the email and set it in an array
                $student_emails[] = utf8_decode($full_name . ' <' . $student_email . '>'); // Add name + email to the array
            $q++;
        }
    }

    // If any student email exist we add it
    if( count($student_emails) > 0 ){
        // Remove duplicates (if there is any)
        $student_emails = array_unique($student_emails);
        // Add the emails to existing recipients
        $header .= 'Bcc: ' . implode(',', $student_emails) . "rn";
    }
    return $header;
}

Code goes in function.php file of your active child theme (or active theme). Tested and works
(I can't really test your code at 100%, but it should work, I hope).


Related: How to get order ID in woocommerce_email_headers hook

Wednesday, November 9, 2022
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :