I am trying to bind the form data before I set the edited form data as I don't want to lose values which hasn't be changed. It actually throws me an error and the ZF2 website doesn't provide me a good working example. I am stuck and I don't want to wrote a dirty workaround, someone? :)
I've created a model as follow:
namespace Application\Model;
class Advertisement {
public $id;
public $name;
public $code;
public $banner;
public $fileupload;
public function exchangeArray($data)
{
$this->id = isset($data['id']) ? $data['id'] : null;
$this->name = isset($data['name']) ? $data['name'] : null;
$this->code = isset($data['code']) ? $data['code'] : null;
$this->banner = isset($data['banner']) ? $data['banner'] : '';
$this->fileupload = isset($data['fileupload']) ? $data['fileupload'] : '';
}
public function exchangeJsonToPhpArray($json)
{
}
public function getArrayCopy()
{
return get_object_vars($this);
}
}
My Controller;
public function editAction()
{
# Get Request and Params
$request = $this->getRequest();
$language = $this->params('language');
$id = $this->params('id');
# Get advertisement data
$oAdvertisement = new Advertisement();
if (!$oAdvertisement = $this->getAdvertisementTable()->selectAdvertisementToEdit(array('id' => $id)))
return $this->redirect()->toRoute('admin/advertisement');
# Advertisement form
$sm = $this->getServiceLocator();
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$form = new AdvertisementForm($dbAdapter, $this->params('language'));
$form->bind($oAdvertisement);
# Post request
$request = $this->getRequest();
if ($request->isPost()) {
# Set post data
$post = array_merge_recursive($this->request->getPost()->toArray(), $this->request->getFiles()->toArray());
$form->setData($post);
# Validate form
if ($form->isValid()) {
# Get form data
$formData = $form->getData();
Debug::dump($form->getData());
# Get service config
$serviceLocator = $this->getServiceLocator();
$config = $serviceLocator->get('config');
$sBannerName = $config['banner_upload_path'] . '/' . md5(mt_rand()) .'.jpg';
# Insert into database
$oAdvertisement->exchangeArray($formData);
# Validate and rename image upload
//.. image upload
Debug::dump($oAdvertisement);
exit;
# Update database record
$this->getAdvertisementTable()->updateAdvertisement($oAdvertisement, $id);
// success..
} else {
// false..
}
}
# Return view model
return new ViewModel(array(
'form' => $form,
));
}
Error;
Fatal error: Cannot use object of type Application\Model\Advertisement as array in ..../module/Application/src/Application/Model/Advertisement.php on line 29
In exchangeArray () method try to test the type of the parameter $ data.
Personally, I put systematically:
if ($data instanceof IteratorAggregate) {
$data = iterator_to_array($data->getIterator(), true);
} elseif ($data instanceof Iterator) {
$data = iterator_to_array($data, true);
} elseif (! is_array($data)) {
throw new Exception(_('Data provided is not an array, nor does it implement Iterator or IteratorAggregate'));
}
Related
To test my android application in a more concrete way, and since my company has no API yet, I decided to "create" it in a simplified way for testing purpose (and learning, i'm only an intern).
The Android app uses Retrofit.
Anyway, I followed one tutorial for a "login" method, where I use the "Post" method in android, passing login and password as #field datas, and everything worked fine, I could retrieve the data in my android app and log in (I do not manage security yet, this will be added later when they hire a devOp)
The problem is after that I wanted to create a Router for more complicated urls (like "/model/client/:id/contracts") and now nothing work anymore. I do not use framework, only composer. I end my internship in two days I do not really have time to learn a big thing.
So, here are the classes that were working before I make the router :
/src/Model/client/login.php :
<?php
namespace App\Model\client;
// required headers
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: access');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Credentials: true');
header('Content-Type: application/json');
// include database and object files
include_once 'src/config/Database.php';
include_once 'src/Model/client/client.php';
// Instantiate database and connect
$database = new Database();
$db = $database->connect();
// prepare product object
$client = new Client($db);
console.log("Login launched");
// set ID property of record to read
$client->login = isset($_POST['login']) ? $_POST['login'] : die();
$client->password = isset($_POST['password']) ? $_POST['password'] : die();
// read the details of product to be edited
$result = $client->readOne();
$num = $result->rowCount();
//Check if corresponding client
if($num>0){
if($client->city==3){
$client->city = "Valenciennes";
}
$row = $result->fetch(PDO::FETCH_ASSOC);
if($row['city']==3){
$city = "Valenciennes";
} else {$city='randomname';}
$client->id = $row['id'];
$client->login = $row['login'];
$client->raison = $row['raison'];
$client->addr1 = $row['addr1'];
$client->addr2 = $row['addr2'];
$client->city = $city;
$client->telephone = $row['telephone'];
$client->portable = $row['portable'];
$client->fax = $row['fax'];
$client->email = $row['email'];
$client->tva_intra = $row['tva_intra'];
$client->siret = $row['siret'];
$client->gtr = $row['gtr'];
$client->password = $row['password'];
// create array
$logged_client = array(
'id' => $client->id,
'login'=> $client->login,
'raison' => $client->raison,
'addr1' => $client->addr1,
'addr2' => $client->addr2,
'city' => $client->city,
'telephone'=>$client->telephone,
'portable'=>$client->portable,
'fax'=>$client->fax,
'email'=>$client->email,
'tva_intra'=>$client->tva_intra,
'siret'=>$client->siret,
'password'=>$client->password);
// set response code - 200 OK
http_response_code(200);
// make it json format
echo json_encode($logged_client);
}
else {
// set response code - 404 Not found
http_response_code(404);
// tell the user product does not exist
echo json_encode(array("message" => "Client does not exist.".$client->login));
}
?>
The class of the object I need to retrieve (src/Model/client/client):
<?php
class Client{
//db stuff
private $cnx;
private $table_name='client';
//client properties
public $id;
public $login;
public $nom;
public $raison;
public $addr1;
public $addr2;
public $city;
public $telephone;
public $portable;
public $fax;
public $email;
public $tva_intra;
public $siret;
public $gtr;
public $password;
//constructor
public function __construct($db){
$this->cnx = $db;
}
//GetOne ###########################################################################
function readOne(){
$query = 'SELECT * FROM '.$this->table_name.' WHERE login = ? AND password = ?';
// prepare query statement
$stmt = $this->cnx->prepare($query);
// bind id of product to be updated
$stmt->bindParam(1, $this->login);
$stmt->bindParam(2, $this->password);
// execute query
$stmt->execute();
// get retrieved row
return $stmt;
}
}
?>
The database exists, here is the connection and it worked fine :
<?php
class Database {
//DB Params
private $host='localhost';
private $db_name='techcrea';
private $username = 'root';
private $pwd = '';
private $cnx;
//DB Connect
public function connect(){
$this->cnx = null;
try {
$this->cnx = new PDO('mysql:host='.$this->host.';dbname='. $this->db_name, $this->username,$this->pwd);
$this->cnx->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}catch(PDOException $e){
echo 'Connection Error:'.$e->getMessage();
}
return $this->cnx;
}
}
So here are the problems starting : this are the classes I added and now nothing works anymore, I get router exception errors (no matching routes) etc..., not only in my android app that returns an "onfailure" response, but also when i try the url in my navigator :
1 - Index :
<?php
require 'vendor/autoload.php';
$router= new App\Router\Router($_GET['url']);
$router->get('/', function(){
echo "homepage";
});
$router->post('/Model/client/login', function(){
//require_once 'src/Model/client/login.php';
});
$router->get('/Model/client/:id/contrats', function($id){
echo "contrats";
});
$router->run();
2 - Router
<?php
namespace App\Router;
class Router {
private $url;
private $routes =[];
private $namedRoutes= [];
public function __construct($url){
$this->url = $url;
}
public function get($path, $callable, $name =null){
return $this->add($path,$callable,$name,'GET');
}
public function post($path, $callable, $name=null){
return $this->add($path,$callable,$name,'POST');
}
public function patch($path, $callable, $name=null){
return $this->add($path,$callable,$name,'PATCH');
}
public function put($path, $callable, $name=null){
return $this->add($path,$callable,$name,'PUT');
}
public function delete($path, $callable, $name=null){
return $this->add($path,$callable,$name,'DELETE');
}
private function add($path, $callable,$name,$method){
$route = new Route($path, $callable);
$this->routes[$method][]= $route;
if($name){
$this->namedRoutes[$name] = $route;
}
return $route;
}
public function url($name,$params = []){
if(!isset($this->namedRoutes[$name])){
throw new RouterException("no match name route");
}
$this->namedRoutes[$name]->getUrl($params);
}
public function run(){
if(!isset($this->routes[$_SERVER['REQUEST_METHOD']])){
throw new RouterException('request method does not exist');
}
foreach($this->routes[$_SERVER['REQUEST_METHOD']] as $route){
if($route->match($this->url)){
return $route->call();
}
}
throw new RouterException('no matching routes');
}
}
3 - Route
namespace App\Router;
class Route {
private $path;
private $callable;
private $matches = [];
private $params = [];
public function __construct($path, $callable){
$this->path = trim($path,'/');
$this->callable = $callable;
}
public function with($param, $regex){
$this->params[$param] = str_replace('(','(?:', $regex);
return $this;
}
public function match($url){
$url=trim($url, '/');
$path = preg_replace_callback('#:([\w]+)#', [$this, 'paramMatch'], $this->path);
$regex = "#^$path$#i";
if(!preg_match($regex, $url, $matches)){
return false;
}
array_shift($matches);
$this->matches= $matches;
return true;
}
public function call(){
if(is_string($this->callable)){
$params = explode('#', $this->callable);
$controller = "App\\Controller\\".$params[0]."Controller";
$controller = new $controller();
$action = $params[1];
return $controller->$action();
} else {
return call_user_func_array($this->callable, $this->matches);
}}
private function paramMatch($match){
if(isset($this->params[$match[1]])){
return '('.$this->params[$match[1]].')';
}
return '([^/]+)';
}
public function getUrl($params){
$path = $this->path;
foreach($params as $k=>$v){
$path= str_replace(":$k",$v, $path);
}
return $path;
}
}
and the htaccess doc :
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
Thank you very much if you help me
I am getting data as an object in response from laravel fractal library by default for all APIs.
I don't want data instead I want some custom name instead of data but I am not able to do that.
How to customize the code from the fractal library to get the item instead of data.
Create DataSerializer Class:
namespace App\{Your Project Name}\Serializers;
use League\Fractal\Serializer\ArraySerializer;
class DataSerializer extends ArraySerializer
{
public function collection($resourceKey, array $data)
{
if ($resourceKey) {
return [$resourceKey => $data];
}
return $data;
}
public function item($resourceKey, array $data)
{
if ($resourceKey) {
return [$resourceKey => $data];
}
return $data;
}
}
Add setResponseData function in Base Controller:
public function setResponseData($default=true, $data, $transformer, $includes = null){
if($default){
$resource = fractal($data, $transformer);
if($includes){
$resource->parseIncludes($includes);
}
return $resource;
}
$resource = null;
if($data instanceof LengthAwarePaginator){
$dataCollection = $data->getCollection();
$resource = new Collection($dataCollection, $transformer, 'data');
$resource->setPaginator(new IlluminatePaginatorAdapter($data));
} elseif($data instanceof \Illuminate\Database\Eloquent\Collection){
$resource = new Collection($data, $transformer, 'data');
} elseif($data instanceof Model){
$resource = new Item($data, $transformer, 'data');
} else{
return [];
}
$manager = new Manager();
$manager->setSerializer(new DataSerializer());
if($includes){
$manager->parseIncludes($includes);
}
$content = [];
if($resource){
$content = $manager->createData($resource)->toArray();
}
return $content;
}
Call setResponseData function from your Derived Controller:
$response = $this->setResponseData(false, $data, new YourTransformer(), ['include-1']);
I'm working on a Joomla 3 component. Currently I'm programming the backend. I'm having a form to add new data and it is working quite well. But when I want to update the data the component creates a new item instead of updating the existing.
I was searching for position which let Joomla know, that this is an update, but without success.
So my question: what is the information that makes Joomla updating the data?
My Code:
Table:ia.php
class mkTableia extends JTable
{
/**
* Constructor
*
* #param object Database connector object
*/
function __construct(&$db)
{
parent::__construct('#__tbl_ia', 'ID', $db);
}
}
Model: ia.php
class mkModelia extends JModelAdmin
{
public function getTable($type = 'ia', $prefix = 'mkTable', $config = array())
{
return JTable::getInstance($type, $prefix, $config);
}
public function getForm($data = array(), $loadData = true)
{
// Get the form.
$form = $this->loadForm('com_mk.ia', 'ia',
array('control' => 'jform', 'load_data' => $loadData));
if (empty($form))
{
return false;
}
return $form;
}
protected function loadFormData()
{
// Check the session for previously entered form data.
$data = JFactory::getApplication()->getUserState('com_mk.edit.ia.data', array());
if (empty($data))
{
$data = $this->getItem();
}
return $data;
}
}
View:view.html.php
class mkViewia extends JViewLegacy
{
/**
* display method of Hello view
* #return void
*/
public function display($tpl = null)
{
// get the Data
$form = $this->get('Form');
$item = $this->get('Item');
// Check for errors.
if (count($errors = $this->get('Errors')))
{
JError::raiseError(500, implode('<br />', $errors));
return false;
}
// Assign the Data
$this->form = $form;
$this->item = $item;
// Set the toolbar
$this->addToolBar();
// Display the template
parent::display($tpl);
}
/**
* Setting the toolbar
*/
protected function addToolBar()
{
$input = JFactory::getApplication()->input;
$input->set('hidemainmenu', true);
$isNew = ($this->item->ID == 0);
JToolBarHelper::title($isNew ? JText::_('COM_MK_MANAGER_MK_NEW')
: JText::_('COM_MK_MANAGER_MK_EDIT'));
JToolBarHelper::save('IA.save');
JToolBarHelper::cancel('IA.cancel', $isNew ? 'JTOOLBAR_CANCEL'
: 'JTOOLBAR_CLOSE');
}
}
Im busy with an image moving function so im overriding some controller functions, and unfortuantly i required the items id for the image name so i changed form save() to postSaveHook() as i was not able to get the item id in save() but now im facing another problem i cant set form data to the newly renamed image.
Here's the code:
public function postSaveHook($model, $validData){
$item = $model->getItem();
$id = $item->get('id');
$path = JPath::clean(JPATH_SITE. DS ."images". DS ."menu_slider". DS );
$input=JFactory::getApplication()->input;
$input->get('jform', NULL, NULL);
$src_image = $this->moveOriginal($path,$id);
$imageTest = $this->findImages($src_image);
if(!empty($imageTest)){
foreach($imageTest as $images){
$this->createImageSlices($images,$src_image,$path);
}
}else{
echo 'all images are there';
}
/*this part no longer works*/
$data = JRequest::getVar( 'jform', null, 'post', 'array' );
$data['image'] = 'images'.DS.'menu_slider'.DS.'original'.DS.$src_image;
$input->post->set('jform',$data);
return parent::postSaveHook($model, $validData);
}
is there anyway i can save the data from this? or if i revert back to save, how would i get the id?
Any Help Greatly Appreciated.
I tried different ways and the absolute safest way for me was to add the following code in the model
class DPCasesModelCase extends JModelAdmin {
public function save($data) {
new EventHandler(JDispatcher::getInstance(), $this);
return parent::save($data);
}
}
class EventHandler extends JEvent {
private $model = null;
public function __construct(&$subject, $model) {
parent::__construct($subject);
$this->model = $model;
}
public function onContentChangeState($context, $pks, $value) {
if ($context != 'com_dpcases.case' && $context != 'com_dpcases.form') {
return;
}
if (! is_array($pks)) {
$pks = array($pks);
}
foreach ( $pks as $pk ) {
$this->dowork($this->model->getItem($pk), 'edit');
}
}
public function onContentAfterSave($context, $object, $isNew) {
if ($context != 'com_dpcases.case' && $context != 'com_dpcases.form') {
return;
}
$this->dowork($object, $isNew ? 'create' : 'edit');
}
private function dowork($object, $action) {
...
}
}
I want to retrieve data from my first form into my function executeAddDomaines to use these into a second form called by this function but when i give $form in parameters to this function i have this error :
Catchable fatal error: Argument 2 passed to domaineActions::executeAddDomaines() must be an instance of sfForm, none given, called in /home/webs/extranet100p100.net/htdocs/lib/vendor/symfony/lib/action/sfActions.class.php on line 60 and defined in /home/webs/extranet100p100.net/htdocs/apps/backend/modules/domaine/actions/actions.class.php on line 206
This is my code:
protected function processForm(sfWebRequest $request, sfForm $form)
{
$name = $form->getName();
$form->bind($request->getParameter($name), $request->getFiles($name));
if($form->isValid())
{
if($form->isNew())
{
$this->executeAddDomaines($request, $form);
$this->redirect('#add_domaines');
}
[...]
}
public function executeAddDomaines(sfWebRequest $request, sfForm $form)
{
$name = $form->getName();
$params = $request->getParameter($name);
$this->list_domaines = $params;
$this->form = new AddDomainesForm();
$this->setTemplate('listDomaines');
}
So how i can do it ?
Thank you :)
You can try to save the form data in session and then get it in the 2nd action.
Try this (i didn't test):
protected function processForm(sfWebRequest $request, sfForm $form)
{
$name = $form->getName();
$form->bind($request->getParameter($name), $request->getFiles($name));
if($form->isValid())
{
if($form->isNew())
{
# Replaced
$request->setAttribute("form", $form);
$this->redirect('#add_domaines');
}
[...]
}
public function executeAddDomaines(sfWebRequest $request)
{
# Added
$form = $request->getAttribute("form");
$name = $form->getName();
$params = $request->getParameter($name);
$this->list_domaines = $params;
$this->form = new AddDomainesForm();
$this->setTemplate('listDomaines');
}
After use it, you can clean the attribute form from the request