zammad / zammad-api-client-php Goto Github PK
View Code? Open in Web Editor NEWPHP API client for Zammad Helpdesk/Support system
Home Page: https://zammad.org
License: Other
PHP API client for Zammad Helpdesk/Support system
Home Page: https://zammad.org
License: Other
Hi there
We would appreciate it if you could add the text_modules to the resources in order to support them nicely via the api client.
BR wucherpfennig
Just a small additional information for section "Fetching content of ticket article attachments",
where is mentioned:
$attachment_content = $ticket_article->getAttachmentContent(23);
Additonal information:
"The output of $ticket_article->getAttachmentContent() is a GuzzleHttp\Psr7\Stream Object. To access the content ("body") of this object, use
$guzzle_contents = $attachment_content->getContents();
"
It took me a while to figure out how to access the "body" or content of the GuzzleHttp\Psr7\Stream object for further processing. Maybe this addition to the documentation can save someone time.
By the way thank you for the great PHP client for Zammad API.
Since a few days the PHP-API doesn't return any result on the following search (a Single Select Object field):
$tickets = $client->resource(ResourceType::TICKET)->search('FIELD_NAME:KEY');
The $tickets-array is always empty. Regular full-text searches still work.
Can anyone suggest a new syntax or help out?
Hi, how do I access ticket messages/updates? There doesn't seem to be a demonstration of this in the examples folder.
Thank you very much for your time
Hi @jepf - we had to change the following API endpoints because of a security issue:
GET /api/v1/tags/add
-> POST /api/v1/tags/add
GET /api/v1/tags/remove
-> DELETE /api/v1/tags/remove
GET /api/v1/links/add
-> POST /api/v1/links/add
GET /api/v1/links/remove
-> DELETE /api/v1/links/remove
GET /api/v1/ticket_merge/:id_source/:id_target
-> PUT /api/v1/ticket_merge/:id_source/:id_target
Can you please check this and apply the required changes?
Currently the library only supports PHP 7.4
As of 28 November 2022 that version is EOL.
To make the Library available to new Projects using PHP 8.x at least a bump of the version within the composer.json PHP Version constraint would be needed.
Also the Github Workflow would need adjustments, I guess, to let all tests run within the max. supported version (PHP8.2 would be a good target at the moment as its the most recent stable version) but also with the min. supported Version (PHP 7.2) -- Question would be if a BC Breaking Major/Minor Version bump should be done and dropping PHP 7.x support all together enabling the Library to move forward with modern PHP Features. (But strongly optional, it would already be great if it installs on PHP8.x and is usable in modern/new applications)
Please add support for Guzzle 7 to allow laravel 8
Hi everyone,
we are having some problems with the case of the headers.
The Client/Response class has to decide if the body has to be parsed as json:
public function __construct(
$status_code,
$reason_phrase,
$body,
array $headers = []
)
{
$this->status_code = intval($status_code);
$this->reason_phrase = $reason_phrase;
$this->body = $body;
$this->headers = $headers;
// Store decoded JSON data, if present
if (
!empty( $this->headers['Content-Type'] )
&& mb_strpos( $this->headers['Content-Type'][0], 'application/json;' ) !== false
) {
$this->data = json_decode( $this->body, true );
if ( !empty( $this->data['error'] ) ) {
$this->error = $this->data['error'];
}
}
}
now our problem is that the response has all headers in lowercase, so the body is never parsed and the data field is never fulfilled. The solution looks easy but before I wanted to ask if no one had to solve this.
Hello here,
I have exactly the same issue than @MrGeneration and @heini23 (#25).
If I follow his example:
But, if I add "&sort_by=created_at" to the URL called by the client, Zammad return the user.
Tested with self-hosted Zammad 3.2 and 3.3.
To temporary fix this issue, I added the following line into src/Resource/AbstractResource.php search function:
$url_parameters['sort_by'] = 'created_at';
Maybe adding a param to this function to sort may be a good idea?
Thank you for your great work on Zammad!
$resource->all() does not fetch more then the default limit of 500.
See: zammad/zammad#768
we should really fetch all with iterating over pagination or set objects_per_page to default 500.
The Rich Text that is input into Zammad itself is rendered as html when accessed through the API.
When I try to submit some "formatted" text to a ticket article on ticket creation it is not working.
I understand that it would be risky to accept html as input for the article body but would it be possible to allow some sort of formatting like <b>
or <i>
tags or even a completely different format.
Creating a ticket via:
$ticket = $client->resource(ResourceType::TICKET);
$ticket_data = [
'title' => 'my-title',
'group' => 'GroupA',
'customer_id' => 'guess:[email protected]',
'article' => [
'body' => 'Test123',
],
];
$ticket->setValues($ticket_data);
$ticket->save();
will lead to:
Deprecated function: mb_strlen(): Passing null to parameter #1 ($string) of type string is deprecated in ZammadAPIClient\Client->request() (line 75 of /var/www/html/vendor/zammad/zammad-api-client-php/src/Client.php
Using PHP 8.1.
The problem is, that in line 75 "mb_strlen($this->on_behalf_of_user)" is called, but this variable is never set, which leads to the deprecation error.
In "Client.php" two functions are defined to handle "on_behalf_of_user":
Both functions are never actually used in Code, and "on_behalf_of_user" is neither set in the constructor. So my guess is, that "on_behalf_of_user" is never actually initialized and therefore NULL. Hence, the deprecation error.
Is it possible to fetch Knowledge Base entries with this API? Cheers
If I use Zammad with the "Professional" subscription and want to use this API client I have a conflict with the commercial use of this library under GPL. Does Zammad have a solution for customers using Zammad commercially via the hosting variant?
Hello! First of all, congratulations for your job, it's very useful to me :)
I'm intending to get the user ID from its mail, but I'm facing a private array. Here is the code:
`$email_address = '[email protected]';
$user_data = [
'login' => $email_address,
'email' => $email_address,
];
$user = $client->resource( ResourceType::USER );
$user->setValues($user_data);
$user->save();
$user_id = $user->getID();
if (is_null($user_id)){
$error = $user->getError();
var_dump($error);
if($error == 'Object already exists!'){
$user_by_email= $client->resource( ResourceType::USER )->search($email_address);
$user_by_email->getValue('id');
}
}`
With this code I'm getting this error:
PHP Fatal error: Uncaught Error: Call to a member function getValue() on array in /home/xxxxxx/git_projects/xxxxx/zammad test/zammadusers.php:30
So I tried accessing the user array by var_dump($user_by_email);
on the last line of the code. The problem is that I am encountering "private"arrays. How can I get the user ID?
array(1) { [0]=> object(ZammadAPIClient\Resource\User)#29 (4) { ["client":"ZammadAPIClient\Resource\AbstractResource":private]=> object(ZammadAPIClient\Client)#2 (2) { ........... } ["remote_data":"ZammadAPIClient\Resource\AbstractResource":private]=> array(42) { ["id"]=>3, [............... }
Thanks in advance! :)
Hi all
Does the api client support the file import to users / organizations / text_modules or should we "implement" this post request by ourselves?
BR wucherpfennig
Hi!
I get an error in the Client.php at line 7.
Somehow i don't get an response from the HTTP Client?
Greeds from Austria!
Just installed package in lumen 5.6 (php 7.2) project and caught this error.
PHP Fatal error: Declaration of ZammadAPIClient\HTTPClient::request($method, $uri, array $options = Array) must be compatible with GuzzleHttp\Client::request($method, $uri = '', array $options = Array) in /var/www/api-data/vendor/zammad/zammad-api-client-php/src/HTTPClient.php on line 143
[2018-05-14 07:26:57] lumen.ERROR: Symfony\Component\Debug\Exception\FatalErrorException: Declaration of ZammadAPIClient\HTTPClient::request($method, $uri, array $options = Array) must be compatible with GuzzleHttp\Client::request($method, $uri = '', array $options = Array) in /var/www/api-data/vendor/zammad/zammad-api-client-php/src/HTTPClient.php:143 Stack trace: #0 /var/www/api-data/vendor/laravel/lumen-framework/src/Concerns/RegistersExceptionHandlers.php(54): Laravel\Lumen\Application->handleShutdown() #1 [internal function]: Laravel\Lumen\Application->Laravel\Lumen\Concerns\{closure}() #2 {main} [] []
In HTTPClient.php line 143:
Declaration of ZammadAPIClient\HTTPClient::request($method, $uri, array $options = Array) must be compatible with GuzzleHttp\Client::request($method, $uri = '', array $options = Array)
RuntimeException: Unable to create HTTP client request. in ZammadAPIClient\Client->request() (Zeile 87 in ../vendor/zammad/zammad-api-client-php/src/Client.php).
Using Zammad Client in an Drupal 8 enviroment.
Zammad 2.4-dev
Zammad Client 1.2
PHP 7.0
Please update the links to the REST interface documentation in README.md.
Hi!
If i use the following:
->resource(ResourceType::TICKET)->search("test");
the Client finds several Tickets.
See:
0 => Ticket {#448 ▼ -client: Client {#648 ▶} -remote_data: array:47 [▼ "id" => 1267 "group_id" => 16 "priority_id" => 2 "state_id" => 1 "organization_id" => 2 "number" => "941267" "title" => "test" "owner_id" => 1 "customer_id" => 53 "note" => null "first_response_at" => null "first_response_escalation_at" => null "first_response_in_min" => null "first_response_diff_in_min" => null "close_at" => null "close_escalation_at" => null "close_in_min" => null "close_diff_in_min" => null "update_escalation_at" => null "update_in_min" => null "update_diff_in_min" =>
null`
But if i try to search using the field-syntax it just returns an empty array.
For example:
->resource(ResourceType::TICKET)->search("title:test");
I'm using Zammad 1.3.0. (PHP 7)
Any idea? :-)
Thx for your time!
Best Regards,
David
Addition to #24
@jepf I noticed that other resources support import too, see example: https://github.com/zammad/zammad/blob/5f3c793f373e3f508395893801ba8064303da2ae/app/controllers/organizations_controller.rb#L339
After checking the clients definition I assume that this API client supports import currently only with text_modules. Would you mind to update the client in order to support organizations and users too?
Hi,
there is a new feature which should get supported in the zammad apis:
issue:
zammad/zammad#1805
documentation:
https://docs.zammad.org/en/latest/api-intro.html#example-curl-request-on-behalf-of-a-different-user
Best regards,
Rolf
Hello,
I am currently trying to write a php application that uses the data from the Zammad API. To do this I added a custom field to store some extra data. When I manually access the tickets using the URL the field (finished) is present:
{
"id": 11,
"group_id": 1,
"priority_id": 2,
"state_id": 4,
...
"created_at": "2018-05-04T14:11:40.487Z",
"updated_at": "2018-05-11T13:04:24.610Z",
"finished": false
}
but when I get the data from within the PHP client the new field is not stored in the values.
Am I doing this wrong or are custom fields for some reason not included in the php Client? This kind of confused me because I was not able to find anything that would indicate this behaviour in the sources.
Hi! So occasionally when I am running a script I get the following error message:
PHP Fatal error: Call to a member function getStatusCode() on null in ../zammad/vendor/zammad/zammad-api-client-php/src/Client.php on line 72
The strange thing is that this only occurs sometimes and does not occur everytime I run the same exact script. Do you know what is going on here?
Dear all
Whilst creating new contacts via the API we are getting constantly the error:
Unable to create http client request
During development we cannot reproduce this kind of error. Does anybody have an idea why this error is thrown?
BR wucherpfennig
Sorry, wrong board. It not an API issue.
We try to configurate an extra overview for spam mails. At the management panel I created a new overview with the name “spam” , made it visible for agents, and selected the conditions as shown in the screenshot.
When I create the new overview, it shows right in the management panel which mails will be in this overview. (I love this feature 😉)
After I created the new overview there isn’t a single mail inside. We use the cloud version on zammad.com.
Edit:
sorry,
If we use the api to search for an user, we always get an empty return. Everything else – like searching for tickets - works well.
Example:
https://XXX.zammad.com/api/v1/users/search?query=Max&token=XXX
(the token has all available rights)
We have a user “Max Mustermann”, therefore we would assume to get his user profile as a return. But the return is empty.
Header Return:
- Status Code: 200 OK
- cache-control: max-age=0, private, must-revalidate
- content-encoding: gzip
- content-type: application/json; charset=utf-8
- csrf-token: XXX
- date: Wed, 27 Nov 2019 11:41:51 GMT
- etag: W/"XXX"
- referrer-policy: strict-origin-when-cross-origin
- server: nginx
- strict-transport-security: max-age=63072000
- x-content-type-options: nosniff
- x-download-options: noopen
- x-firefox-spdy: h2
- x-frame-options: DENY
- x-permitted-cross-domain-policies: none
- x-request-id: 6137ba5a-b0a0-40c0-ab90-d21e83f9bb77
- x-runtime: 0.026655
- x-xss-protection: 1; mode=block
(excuse me, if this is the wrong place to ask for such things, feel free to close the ticket if this isn't right here)
Hi, I'm already working with this client since a few month, but am missing one feature:
Is there a way to see linked tickets and link one ticket with an other through API?
Looks like this is only possible through zammad directly? I can't find anything in the docs, too, so I guess this isn't implemented in zammad.
I'm talking about this feature on right menu in zammad:
If I link an ticket with an other, there is no extra info in the object received from the API in any of these tickets.
Thanks!
Hi @jepf ,
as mentioned earlier: The TicketArticleTest currently fails because we changed the API capabilities when updating a Ticket Article in the scope of ZAA-2020-24. It's no longer possible to update Ticket Article attributes except the Type (internal
/external
).
The test currently fails with this error:
$ vendor/bin/phpunit
PHPUnit 7.5.20 by Sebastian Bergmann and contributors.
..................................................F............ 63 / 107 ( 58%)
............................................ 107 / 107 (100%)
Time: 1.03 minutes, Memory: 6.00 MB
There was 1 failure:
1) ZammadAPIClient\Resource\TicketArticleTest::testUpdate
Changed value of object must match expected one.
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'Unit test ticket article 1...5fb23c06ca87e6.25564933CHANGED'
+'Unit test ticket article 1...5fb23c06ca87e6.25564933'
/builds/zammad/zammad/zammad-api-client-php/test/ZammadAPIClient/Resource/AbstractBaseTest.php:240
FAILURES!
Tests: 107, Assertions: 691, Failures: 1.
I would like to set the created_by_id
value with the api to assign a message to an user.
$ticket->setValue("article", array(
"subject"=>"Test subject",
"body"=>"test message",
"created_by_id"=>$userId, // DOESNT WORK
"updated_by_id"=>$userId // DOESNT WORK
));
How does one go about setting a password for a user?
I've created a custom resource to search with sort/order, sadly it can't sort by last_contact_at
or updated_at
.
We use Zammad Cloud.
EDIT: Is there any chance to get this working? I have seen that other users should rebuild the serach indexes, but I don't know how I could do this 😄 .
EDIT2: I use the resoruce with this line of code
$client->resource( \App\Zammad\Resource\TicketCustom::class )->search('last_contact_at:*', null, null, 'last_contact_at', 'asc' );
<?php
namespace App\Zammad\Resource;
use ZammadAPIClient\Exception\AlreadyFetchedObjectException;
use ZammadAPIClient\ResourceType;
class TicketCustom extends \ZammadAPIClient\Resource\Ticket
{
const URLS = [
'get' => 'tickets/{object_id}',
'all' => 'tickets',
'create' => 'tickets',
'update' => 'tickets/{object_id}',
'delete' => 'tickets/{object_id}',
'search' => 'tickets/search',
];
/**
* Fetches TicketArticle objects of this Ticket object.
*
* @return Array of TicketArticle objects Returns array of ZammadAPIClient\Resource\TicketArticle objects or an empty array.
*/
public function getTicketArticles()
{
$this->clearError();
if ( empty( $this->getID() ) ) {
return [];
}
$ticket_articles = $this->getClient()->resource( ResourceType::TICKET_ARTICLE )->getForTicket( $this->getID() );
if ( !is_array($ticket_articles) ) {
$this->setError( $ticket_articles->getError() );
return [];
}
return $ticket_articles;
}
/**
* Fetches object data for searched objects of this type.
* This method will be used internally and automatically by search() to automate pagination
* to retrieve all available objects, ignoring the server side limit of fetchable objects.
*
* @return mixed Returns array of ZammadAPIClient\Resource\... objects
* or this object on failure.
*/
private function searchWithoutPagination($search_term)
{
$page = 1;
$objects_per_page = 100;
$objects = [];
$objects_of_page = [];
do {
$objects_of_page = $this->search( $search_term, $page, $objects_per_page );
if ( !is_array($objects_of_page) ) {
return $this;
}
$objects = array_merge( $objects, $objects_of_page );
$is_last_page = count($objects_of_page) < $objects_per_page
|| !count($objects_of_page);
$page++;
} while ( !$is_last_page );
return $objects;
}
/**
* Fetches object data for given search term.
* Pagination available.
*
* @param string $search_term Search term.
* @param integer $page Page of objects, optional, if given, $objects_per_page must also be given.
* @param integer $objects_per_page Number of objects per page, optional, if given, $page must also be given.
*
* @return mixed Returns array of ZammadAPIClient\Resource\... objects
* or this object on failure.
*/
public function search( $search_term, $page = null, $objects_per_page = null, $sort_by = null, $order_by = null )
{
if ( !empty( $this->getValues() ) ) {
throw new AlreadyFetchedObjectException('Object already contains values, search() not possible, use a new object');
}
if ( isset($page) && $page <= 0 ) {
throw new \RuntimeException('Parameter page must be a > 0');
}
if ( isset($objects_per_page) && $objects_per_page <= 0 ) {
throw new \RuntimeException('Parameter objects_per_page must be a > 0');
}
if (
( isset($page) && !isset($objects_per_page) )
|| ( !isset($page) && isset($objects_per_page) )
) {
throw new \RuntimeException('Parameters page and objects_per_page must both be given');
}
if ( !isset($page) || !isset($objects_per_page) ) {
return $this->searchWithoutPagination($search_term);
}
$url_parameters = [
'expand' => true,
'query' => $search_term,
];
if (isset($sort_by)) {
$url_parameters['sort_by'] = $sort_by;
}
if (isset($order_by)) {
$url_parameters['order_by'] = $order_by;
}
if ( isset($page) && isset($objects_per_page) ) {
$url_parameters['page'] = $page;
$url_parameters['per_page'] = $objects_per_page;
}
$url = $this->getURL('search');
$response = $this->getClient()->get(
$url,
$url_parameters
);
if ( $response->hasError() ) {
$this->setError( $response->getError() );
return $this;
}
$this->clearError();
// Return array of resource objects if no $object_id was given.
// Note: the resource object (this object) used to execute get() will be left empty in this case.
$objects = [];
foreach ( $response->getData() as $object_data ) {
$object = $this->getClient()->resource( get_class($this) );
$object->setRemoteData($object_data);
$objects[] = $object;
}
return $objects;
}
}
Hey,
in your documentation you write, that an field specific search is possible:
// Field specific search
$tickets = $client->resource( ResourceType::TICKET )->search('title:My Title');
unfortunately zammad always returns an empty result object if I try to search in fields.
Is this feature not yet implemented in the API?
Best regards,
J. Schurse
Please add support for Guzzle 7 to allow laravel 8
In
zammad-api-client-php/src/HTTPClient.php
Line 183 in 83f0129
getResponse()
method is undefined.
To reproduce it I put in the ZammadAPIClient\Client
constructor a wrong URL:
use ZammadAPIClient\Client;
$client = new Client([
'url' => 'https://wrong.zammad.url', // Wrong URL to my Zammad installation
...
]);
In this case $e
is an instance of GuzzleHttp\Exception\ConnectException
with no getResponse()
method.
Hello,
I just wanted to make a "quick" proof of concept without having a proper ssl certificate and tried to use the "verifySsl => false" option but I run in the open issue #36.
With a "dirty" workaround Guzzle returned: "Connection refused".
So, I checked the sources und found this:
In the documention is written "verifySsl":
use ZammadAPIClient\Client;
$client = new Client([
'url' => 'https://myzammad.com', // URL to your Zammad installation
'username' => '[email protected]', // Username to use for authentication
'password' => 'mypassword', // Password to use for authentication
// 'timeout' => 15, // Sets timeout for requests, defaults to 5 seconds, 0: no timeout
// 'debug' => true, // Enables debug output
// 'verifySsl' => true, // Enabled SSL verification. You can also give a path to a CA bundle file. Default is true.
]);
But in https://github.com/zammad/zammad-api-client-php/blob/master/src/HTTPClient.php "verify" is checked:
// Verify ssl
$verifySsl = true;
if (
array_key_exists('verify', $options)
&& (
is_bool($options['verify'])
|| (
is_string($options['verify'])
&& file_exists($options['verify'])
)
)
) {
$verifySsl = $options['verify'];
}
Cheers,
Tim
In a current project I'm often interacting with the Zammad API. Due to system maintenance or connection issues, my requests sometimes time out. If this happens often enough (especially in a maintenance window), this keeps more and more of my server threads busy, because your PHP API client / Guzzle (curl) waits forever for a connection by default. This leads to resource leaks until PHP max_execution_time kicks in, but that may take quite some time in queued jobs.
Please add an option to make Guzzles 'connect_timeout' configurable:
use ZammadAPIClient\Client;
$client = new Client([
'url' => 'https://myinstance.zammad.com',
'http_token' => 'something',
'timeout' => 15,
'connect_timeout' => 5, // new option
]);
Deleting users via this client ist mostly impossible, because of existing references to tickets etc. So is there a way to trigger a GDPR deleteion task with this client?
I'm currently working on a sync tool that uses the api. Due to the high number of users in my system the timeout excedes sometimes.
You should be able to set the timeout when creating a new Client instance.
e.g.
use ZammadAPIClient\Client;
$client = new Client([
'url' => 'https://myzammad.com', // URL to your Zammad installation
'username' => '[email protected]', // Username to use for authentication
'password' => 'mypassword', // Password to use for authentication
'timeout' => 15, // Sets timeout to 15 seconds
]);
Hi!
I have a question:
How do i create a TicketAttachment using your Api-Client?
Thanks for your time!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.